-
Notifications
You must be signed in to change notification settings - Fork 988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V2 certificate format #1216
base: master
Are you sure you want to change the base?
V2 certificate format #1216
Conversation
q, | ||
cache.Get(u.l), | ||
) | ||
r(netip.AddrPortFrom(netip.AddrFrom16(rua.Addr).Unmap(), (rua.Port>>8)|((rua.Port&0xff)<<8)), buffer[:n]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use binary
to avoid endianness issues
return fmt.Errorf("error while signing with PKCS#11: %w", err) | ||
|
||
if version == cert.Version1 { | ||
// If we are asked to mint a v1 certificate only then we cant just ignore any v6 addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We arent ignoring them
9f75b80
to
a09f39f
Compare
--------- Co-authored-by: Jack Doan <jackdoan@rivian.com>
cert/sign.go
Outdated
if curve != t.Curve { | ||
return nil, fmt.Errorf("curve in cert and private key supplied don't match") | ||
} | ||
|
||
//TODO: make sure we have all minimum properties to sign, like a public key | ||
//TODO: we need to verify networks and unsafe networks (no duplicates, max of 1 of each version for v2 certs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which checks are we missing that we want to include?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in #1266
@@ -91,40 +92,60 @@ func AddRelay(l *logrus.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp neti | |||
func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *NebulaControl) (*Relay, error) { | |||
relay, ok := relayHostInfo.relayState.CompleteRelayByIdx(m.InitiatorRelayIndex, m.ResponderRelayIndex) | |||
if !ok { | |||
rm.l.WithFields(logrus.Fields{"relay": relayHostInfo.vpnIp, | |||
//TODO: we need to handle possibly logging deprecated fields as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
if msg.OldRelayFromAddr > 0 || msg.OldRelayToAddr > 0 { | ||
v = cert.Version1 | ||
|
||
//TODO: yeah this is junk but maybe its less junky than the other options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
if v == cert.Version1 { | ||
peer := peerHostInfo.vpnAddrs[0] | ||
if !peer.Is4() { | ||
//TODO: log cant do it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
relay_manager.go
Outdated
@@ -310,11 +357,11 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N | |||
f.SendMessageToHostInfo(header.Control, 0, peer, msg, make([]byte, 12), make([]byte, mtu)) | |||
rm.l.WithFields(logrus.Fields{ | |||
//TODO: IPV6-WORK another lazy used to use the req object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
relay_manager.go
Outdated
|
||
if v == cert.Version1 { | ||
if !h.vpnAddrs[0].Is4() { | ||
//TODO: log it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
relay_manager.go
Outdated
@@ -360,11 +419,11 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N | |||
f.SendMessageToHostInfo(header.Control, 0, h, msg, make([]byte, 12), make([]byte, mtu)) | |||
rm.l.WithFields(logrus.Fields{ | |||
//TODO: IPV6-WORK more lazy, used to use resp object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
pki.go
Outdated
return p.cs.Load() | ||
} | ||
|
||
func (p *PKI) GetCAPool() *cert.CAPool { | ||
return p.caPool.Load() | ||
// TODO: We should remove this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
pki.go
Outdated
return p.cs.Load().GetDefaultCertificate() | ||
} | ||
|
||
// TODO: We should remove this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
} | ||
|
||
} else if currentState.v1Cert != nil { | ||
//TODO: we should be able to tear this down |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
p.cs.Store(cs) | ||
p.cs.Store(newState) | ||
|
||
//TODO: newState needs a stringer that does json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
return nil, util.NewContextualError("v1 and v2 curve are not the same, ignoring", nil, nil) | ||
} | ||
|
||
//TODO: make sure v2 has v1s address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve TODO
…didn't work on the first try (#1268)
if ok { | ||
whereToPunch = newDest | ||
} else { | ||
//TODO this means the destination will have no addresses in common with the punch-ee |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve
TODO: |
This PR no longer exports the certificate structs; neither v1 or v2:
Before:
It is going to be a big breaking change and inconvenience for anyone who has used and uses the libraries. Would prefer to keep these exported. I see that it is a breaking change PR, but it should at least allow restoring the same functionality as was available before. |
I see now it’s switched to a factory approach, with TBSCertificate that is exported. 👍 A few thoughts to consider: A helper function for converting a Certificate back to a TBSCertificate would be useful to complete the factory loop and allow manipulation of existing signed certificates (as unsigned ones). There are also some Marshal functions like Marshal(), but without a corresponding Unmarshal(). I imagine most people are using pem encoded certs, but if Marshal() is exposed there should probably be a corresponding Unmarshal(). |
cert/cert_v2.go
Outdated
networks []netip.Prefix | ||
unsafeNetworks []netip.Prefix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mentioned this as a reply to a resolved comment already, but in case it's folded and not seen: I think the name networks
and unsafeNetworks
are confusing. The former one is an address + its on-link network prefix, while the latter is just a network prefix. For the former, only a single address is routable to the host, while all addresses in the network is routable to the host for the latter.
I would propose the name to be addresses
(I think it's fine even though this expects an CIDR, as the input is same as what ip address add
command expects) which clearly indicate that the address part of the network prefix is significant, and routable_networks
(or maybe unsafe_routable_networks
) which clearly indicates that these are CIDRs for routing only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I share concerns of confusion with the naming here. I'm also comfortable sticking with the old name which at least creates no new confusion (especially with respect to existing documentation and discussions): #1216 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also be open to the name addresses
for the networks
field. I think the name networks
came up when we were considering it in the context of a CA certificate? Using that same field name for two very-similar-but-different purposes muddies the waters a little bit, but the intent was that it shows which networks (as V2 certs let you have more than one!) the host participates in, as well as the actual address assignment on non-CA certs. However, the ip address add
argument is very persuasive and probably much more obvious to new users.
Naming unsafeNetworks
is a little trickier. When the addresses
field is named networks
, I think it's a pretty logical name, but unsafeAddresses
doesn't really work. I'd propose something like unsafeRouterFor
: the prefix unsafe
links it mentally to unsafe_routes
in the config, and I think RouterFor
shows that the field expresses a capability, rather than something that might affect how "regular" Nebula traffic is routed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think addresses places emphasis on the use of the ip; networks on the prefix use. But ultimately both are used and the content passed in is CIDRs? Perhaps better to reflect what it is and what is passed in by the user rather than the things it’s used for (similar to before where it was called Ips but CIDRs would probably be more accurate).
The bigger challenge before was having to manually change the ip when using ParseCIDR because it returned the base address instead of the provided IP, and the confusion of the certificate field ‘subnets’. Both of those are no longer an issue so bounds better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As Jack said, the issue is that the field is used for dual purposes. For a non-CA cert, addresses
and unsafeRouterFor
makes more sense, but for CA cert, networks
and unsafeNetworks
make more sense. I would say it makes more sense to cater for the non-CA cert case since there're more of them, or perhaps they can have different names for different nebula-cert commands?
* enforce certificate correctness in TBSCertificate.SignWith * check length, not nil * Address review comments * github hates me --------- Co-authored-by: Nate Brown <nbrown.us@gmail.com> Co-authored-by: Jack Doan <me@jackdoan.com>
This is a near complete implementation of an ipv6 enabled overlay network. There are a handful of pull requests targeting this branch in addition to a number of incomplete issues within this PR.
I have tried to highlight the main trouble spots with comments on the PR and in addition here are my internal notes:
nebula-cert
is defaulting to mint bothv1
andv2
certificates and nebula config is defaulting to transmitv1
certificates if both are present. This will lead to a situation where net new adopters will be stuck using v1 certificates. Should this be the default behavior?Currently nebula wont allow you to remove a
v1
certificate on reload but this means a restart is required to complete a migration tov2
. A comment on this review highlights this, we should allow it.Currently there are a few spots (control, ssh) where we return the certificate in use but they only return 1 cert, should we leave it returning the default or force folks to consume both? How do we indicate which one is default?
Every time we encounter a certificate we need to sort the networks as well as only record the union of applicable addresses. See [cert-v2] punchy-respond on an address in common with the querying host #1261
We need to take extra care to ensure we never allow a ipv4 mapped ipv6 address. This is not currently addressed in this PR.
There may be an opportunity to improve the lighthouse protocol by directly using the
MarshalBinary
andUnmarshalBinary
functions fornetip
objects. This is more of a nit than anything but we should agree on this before merging.nebula-cert
sign
help text needs to talk about primary vpn address (or the union of effective addresses) being the first one after being sorted and what that means for tunnels.The firewall config still uses naming like
ca-sha
should we alias this toca-fingerprint
to normalize the verbiage?The firewall config still uses naming like
ip
should we alias this tonetwork
to normalize the verbiageNormalize all names for
Marshal*
andUnmarshal*
, we have someFrom*
/To*
and others withoutFrom
/To
.Should we use this moment to swap p256 keys to use their compressed form? Saves ~32 bytes.
Once this is merged the upgrade path should likely be:
pki.default_version
to1
. Everything continues to usev1
protocols.am_relay: true
hostspki.default_version
to2
. Relays can now initiatev2
tunnels, but this is an uncommon flow.pki.default_version
to2
. Lighthouses will reply tov2
hosts usingv2
protocols.pki.default_version
to2
.v1
certs from all hosts