ca: when the Root CA is updated in the security config, update all TLS creds too#1983
Conversation
| if s.ClientTLSCreds != nil { | ||
| previousConfig := s.ClientTLSCreds.Config() | ||
| // can't error because we know for sure the root pool is valid | ||
| newConfig, _ := NewClientTLSConfig(&previousConfig.Certificates[0], rootCA.Pool, previousConfig.ServerName) |
There was a problem hiding this comment.
Do we know for sure that previousConfig.Certificates has at least one item?
There was a problem hiding this comment.
Is there a possibility of a race here? Say the node's certificate gets renewed at the same moment, and there's a call to LoadNewTLSConfig in these calls to Config and LoadNewTLSConfig. Wouldn't we overwrite the new node certificate?
There was a problem hiding this comment.
@aaronlehmann Good point - I guess the lock needs to be on the mutable TLS object.
Codecov Report
@@ Coverage Diff @@
## master #1983 +/- ##
==========================================
+ Coverage 53.69% 53.86% +0.17%
==========================================
Files 109 109
Lines 18925 18943 +18
==========================================
+ Hits 10161 10203 +42
+ Misses 7538 7501 -37
- Partials 1226 1239 +13Continue to review full report at Codecov.
|
dd0743c to
b043029
Compare
| func (c *MutableTLSCreds) UpdateCAs(rootCAs, clientCAs *x509.CertPool) { | ||
| c.Lock() | ||
| defer c.Unlock() | ||
| // TODO(cyli): on upgrade to go 1.8.x, use c.config.Clone() instead |
There was a problem hiding this comment.
Clone exists in 1.7.
Would you mind switching to it before merging?
AFAIK there's no reason we need to support Go 1.6. @vdemeester do you know if there is?
There was a problem hiding this comment.
Hm... do I have something horribly misconfigured?
$ go test -race github.com/docker/swarmkit/ca
ca/transport.go:142: c.config.Clone undefined (type *tls.Config has no field or method Clone, but does have tls.clone)
$ go version
go version go1.7.4 darwin/amd64
There was a problem hiding this comment.
https://github.com/golang/go/blob/release-branch.go1.7/src/crypto/tls/common.go#L426 seems to only have Config.clone(), but https://github.com/golang/go/blob/release-branch.go1.8/src/crypto/tls/common.go#L550 has the exported function (I could just be missing an exported function in 1.7 in a different file, though)
There was a problem hiding this comment.
I looked for Clone on both branches to verify, but did not notice it's unexported in 1.7.
I remember https://github.com/docker/docker/blob/master/pkg/tlsconfig dealing with this, and I see this was back in September. I thought it happened before Go 1.7 was released. Apparently it was right after. My apologies.
Anyway, would you mind vendoring/importing github.com/docker/docker/pkg/tlsconfig in this PR?
There was a problem hiding this comment.
Not at all - as I've said before, my machine is haunted :) And go vet still produces errors on my machine that no one else seems to be able to replicate so I totally would believe something is wrong with my setup.
And sure, will do.
b043029 to
a4b6560
Compare
| } | ||
|
|
||
| s.rootCA = &rootCA | ||
| return err |
a4b6560 to
21dbca4
Compare
21dbca4 to
89f5ff4
Compare
| return | ||
| } | ||
|
|
||
| return |
There was a problem hiding this comment.
How about return cfcsr.ParseRequest(req) for clarity?
| // ExternalCA returns the external CA. | ||
| func (s *SecurityConfig) ExternalCA() *ExternalCA { | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() |
There was a problem hiding this comment.
I don't believe it's necessary to hold this lock. s.externalCA seems to be set when the SecurityConfig is created, and never changed to point to anything else. updateCluster uses this field without holding the lock.
There was a problem hiding this comment.
Do we want to be conservative in both places?
|
Needs a rebase |
…erver, client, and external CA TLS credentials all also use the new root pool. Signed-off-by: cyli <ying.li@docker.com>
89f5ff4 to
598a7ed
Compare
| } | ||
|
|
||
| // ExternalCA returns the external CA. | ||
| func (s *SecurityConfig) ExternalCA() *ExternalCA { |
| func (c *MutableTLSCreds) UpdateCAs(rootCAs, clientCAs *x509.CertPool) { | ||
| c.Lock() | ||
| defer c.Unlock() | ||
| config := tlsconfig.Clone(c.config) |
There was a problem hiding this comment.
why do we need to clone instead of directly modifying it?
There was a problem hiding this comment.
I tried that originally, but it's not really safe to modify a tls.Config while it's being used I think. I ended up with a data race in the tests, since a tls.Config stores some handshake/session state. The comment for tls.Config contains:
After one has been passed to a TLS function it must not be modified.
So that both can use the new root CA pool to validate peers.