Skip to content
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

Ensuring root rotation works #1768

Merged
merged 4 commits into from
Nov 26, 2016

Conversation

diogomonica
Copy link
Contributor

This PR fixes the client-side certificate rotation to also update the current Root CA being used by the server.

1.14 will bring CA Root Rotation, so it would be ideal if the break in compatibility was 1.12, and not 1.13.

Cert []byte
Pool *x509.CertPool
// Digest of the serialized bytes of the certificate
Digest digest.Digest
// This signer will be nil if the node doesn't have the appropriate key material
Signer cfsigner.Signer
// Stores the location on disk where the RootCA lives
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path stores the location...

@codecov-io
Copy link

codecov-io commented Nov 19, 2016

Current coverage is 55.06% (diff: 69.38%)

Merging #1768 into master will increase coverage by 0.21%

@@             master      #1768   diff @@
==========================================
  Files           102        102          
  Lines         16854      16873    +19   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           9245       9291    +46   
+ Misses         6459       6420    -39   
- Partials       1150       1162    +12   

Sunburst

Powered by Codecov. Last update 53fcdeb...4bcc648

@@ -545,9 +574,9 @@ func CreateRootCA(rootCN string, paths CertPaths) (RootCA, error) {

// GetRemoteSignedCertificate submits a CSR to a remote CA server address,
// and that is part of a CA identified by a specific certificate pool.
func GetRemoteSignedCertificate(ctx context.Context, csr []byte, rootCAPool *x509.CertPool, config CertificateRequestConfig) ([]byte, error) {
func GetRemoteSignedCertificate(ctx context.Context, csr []byte, rootCAPool *x509.CertPool, config CertificateRequestConfig) ([]byte, []byte, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should just return the NodeCertificateStatusResponse.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

// However, there might have been a server-side root rotation, so we verify this cert with a new pool.
// If we got a valid rootCABundle, turn it into a Pool, and verify the newly minted certificate using it.
rootCAPool := rca.Pool
newRootCA, newRootErr := NewRootCA(rootCABundle, nil, rca.Path, time.Minute)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't all this be conditional on rootCABundle not being empty?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is it possible to skip all this, particularly saving the root CA cert to disk, if the received bundle is identical to what we already have?

Certificate: &node.Certificate,
Status: &node.Certificate.Status,
Certificate: &node.Certificate,
RootCABundle: s.securityConfig.RootCA().Cert,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure there's any need to fill this field in right now while there's no CA-side support for root rotation - unless it's useful for testing or something.

@aaronlehmann
Copy link
Collaborator

I think this looks reasonable for 1.13. You'll need to get sign-off from @vieux to put it in after the feature freeze. Since this is more of a forward compatibility change than an actual feature, it might be okay.

I'd suggest setting this up this in such a way that this new code is never triggered in a pure 1.13 environment. For example, if the client only rotates root certs when it receives a RootCABundle, and 1.13's CA never sends a RootCABundle, then this would be a low risk change. During the 1.14 cycle we would have time to fully test root rotation end-to-end and across versions, and only enable it on the CA side once we're confident in it.

@diogomonica
Copy link
Contributor Author

/cc @aluzzardi would be great if this got in for 1.13, ensuring backwards compatibility break on 1.12 for root-rotation.

@aluzzardi
Copy link
Member

What would we be breaking in 1.12?

/cc @vieux

@diogomonica
Copy link
Contributor Author

@aluzzardi the goal is for 1.14 to support adding a new root CA, reissue all the certificates for all the nodes, and removing the old CA. 1.12 nodes will not be able to add a new root CA, and therefore will not be able to continue participating in the cluster without manual intervention. If we don't get this in, the same will happen for 1.13 nodes.

if err == nil {
// No errors, swam the current rootCA
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "swam the current rootCA" mean?

@@ -339,10 +295,6 @@ func TestRequestAndSaveNewCertificates(t *testing.T) {
_, _, err = unencryptedKeyReader.Read()
require.Error(t, err)

_, _, err = ca.NewKeyReadWriter(tc.Paths.Node, []byte("kek!"), nil).Read()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to delete this assertion?

@cyli
Copy link
Contributor

cyli commented Nov 21, 2016

LGTM aside from minor nitpicks :)

Signed-off-by: Diogo Monica <diogo.monica@gmail.com>
…on NodeStatus

Signed-off-by: Diogo Monica <diogo.monica@gmail.com>
@diogomonica diogomonica force-pushed the ensuring-root-rotation-works branch 2 times, most recently from faa81a1 to 5d2d0c0 Compare November 22, 2016 00:38
@aluzzardi
Copy link
Member

@vieux @icecrime @thaJeztah:

In 1.14+, there's going to be a way to rotate the root CA. Older agents of course won't be able to perform the rotation, therefore either they'll fail (meh) or we'll just block rotation if any older engine is connected (better).

Pseudo random example:

$ docker swarm update --rotate-ca
Error from daemon: Oh noz! node-1234 is running an older version of engine (1.12.2). Please upgrade before rotating the CA or use --force to rotate anyway

This PR adds agent-side rotation support (e.g. making sure an agent can fetch a new CA bundle from the manager) which means 1.13 agents would be able to perform rotation (so the --rotate-ca command would work with 1.13 and 1.14, only 1.12 would fail).

Question is: Are we comfortable with this kind of change during the freeze?

@diogomonica Did I summarize the problem correctly?

@diogomonica
Copy link
Contributor Author

@aluzzardi perfectly so. <3

Signed-off-by: Diogo Monica <diogo.monica@gmail.com>
@aluzzardi
Copy link
Member

LGTM - let's merge in master.

Need sign-off from @vieux in order to cherry pick to 1.13.x (rc3 at this point)

…re test

Signed-off-by: Diogo Monica <diogo.monica@gmail.com>
@diogomonica
Copy link
Contributor Author

Added one more test, for the case where the server returns a nil CABundle

@vieux
Copy link
Contributor

vieux commented Nov 24, 2016

LGTM

@@ -594,7 +629,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, rootCAPool *x50
}

// If the certificate was issued, return
if statusResponse.Status.State == api.IssuanceStateIssued {
if statusResponse.Status != nil && statusResponse.Status.State == api.IssuanceStateIssued {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find!

Copy link
Contributor

@cyli cyli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@thaJeztah
Copy link
Member

Question is: Are we comfortable with this kind of change during the freeze?

@diogomonica @aluzzardi is this going to cause issues for 1.13-rc1/rc2? (no top priority, but good to know if there are possible issues)

@diogomonica
Copy link
Contributor Author

@thaJeztah shouldn't have any impact. But we should merge this ASAP.

@thaJeztah
Copy link
Member

@diogomonica Looks like I don't have permissions in this repo to merge, but I see enough LGTM's, so should be ready to go 😄

@thaJeztah
Copy link
Member

does this need squashing?

@diogomonica diogomonica merged commit b035a18 into moby:master Nov 26, 2016
@diogomonica diogomonica deleted the ensuring-root-rotation-works branch November 29, 2016 22:12
@aaronlehmann
Copy link
Collaborator

Removing cherry-pick label, since this was backported to 1.13 in a separate PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants