Signed-off-by: Ying Li <ying.li@docker.com>
Ying Li authored on 2017/05/09 09:14:34... | ... |
@@ -14,12 +14,15 @@ import ( |
14 | 14 |
"sync" |
15 | 15 |
"time" |
16 | 16 |
|
17 |
+ "github.com/cloudflare/cfssl/csr" |
|
17 | 18 |
"github.com/cloudflare/cfssl/helpers" |
19 |
+ "github.com/cloudflare/cfssl/initca" |
|
18 | 20 |
"github.com/docker/docker/api/types" |
19 | 21 |
"github.com/docker/docker/api/types/container" |
20 | 22 |
"github.com/docker/docker/api/types/swarm" |
21 | 23 |
"github.com/docker/docker/integration-cli/checker" |
22 | 24 |
"github.com/docker/docker/integration-cli/daemon" |
25 |
+ "github.com/docker/swarmkit/ca" |
|
23 | 26 |
"github.com/go-check/check" |
24 | 27 |
) |
25 | 28 |
|
... | ... |
@@ -930,3 +933,72 @@ func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) { |
930 | 930 |
out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top") |
931 | 931 |
c.Assert(err, checker.IsNil, check.Commentf(out)) |
932 | 932 |
} |
933 |
+ |
|
934 |
+func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) { |
|
935 |
+ m := s.AddDaemon(c, true, true) |
|
936 |
+ w := s.AddDaemon(c, true, false) |
|
937 |
+ |
|
938 |
+ info, err := m.SwarmInfo() |
|
939 |
+ c.Assert(err, checker.IsNil) |
|
940 |
+ |
|
941 |
+ currentTrustRoot := info.Cluster.TLSInfo.TrustRoot |
|
942 |
+ |
|
943 |
+ // rotate multiple times |
|
944 |
+ for i := 0; i < 4; i++ { |
|
945 |
+ var cert, key []byte |
|
946 |
+ if i%2 != 0 { |
|
947 |
+ cert, _, key, err = initca.New(&csr.CertificateRequest{ |
|
948 |
+ CN: "newRoot", |
|
949 |
+ KeyRequest: csr.NewBasicKeyRequest(), |
|
950 |
+ CA: &csr.CAConfig{Expiry: ca.RootCAExpiration}, |
|
951 |
+ }) |
|
952 |
+ c.Assert(err, checker.IsNil) |
|
953 |
+ } |
|
954 |
+ expectedCert := string(cert) |
|
955 |
+ m.UpdateSwarm(c, func(s *swarm.Spec) { |
|
956 |
+ s.CAConfig.SigningCACert = expectedCert |
|
957 |
+ s.CAConfig.SigningCAKey = string(key) |
|
958 |
+ s.CAConfig.ForceRotate++ |
|
959 |
+ }) |
|
960 |
+ |
|
961 |
+ // poll to make sure update succeeds |
|
962 |
+ var clusterTLSInfo swarm.TLSInfo |
|
963 |
+ for j := 0; j < 18; j++ { |
|
964 |
+ info, err := m.SwarmInfo() |
|
965 |
+ c.Assert(err, checker.IsNil) |
|
966 |
+ c.Assert(info.Cluster.Spec.CAConfig.SigningCACert, checker.Equals, expectedCert) |
|
967 |
+ // the desired CA key is always redacted |
|
968 |
+ c.Assert(info.Cluster.Spec.CAConfig.SigningCAKey, checker.Equals, "") |
|
969 |
+ |
|
970 |
+ clusterTLSInfo = info.Cluster.TLSInfo |
|
971 |
+ |
|
972 |
+ if !info.Cluster.RootRotationInProgress { |
|
973 |
+ break |
|
974 |
+ } |
|
975 |
+ |
|
976 |
+ // root rotation not done |
|
977 |
+ time.Sleep(250 * time.Millisecond) |
|
978 |
+ } |
|
979 |
+ c.Assert(clusterTLSInfo.TrustRoot, checker.Not(checker.Equals), currentTrustRoot) |
|
980 |
+ if cert != nil { |
|
981 |
+ c.Assert(clusterTLSInfo.TrustRoot, checker.Equals, expectedCert) |
|
982 |
+ } |
|
983 |
+ // could take another second or two for the nodes to trust the new roots after the've all gotten |
|
984 |
+ // new TLS certificates |
|
985 |
+ for j := 0; j < 18; j++ { |
|
986 |
+ mInfo := m.GetNode(c, m.NodeID).Description.TLSInfo |
|
987 |
+ wInfo := m.GetNode(c, w.NodeID).Description.TLSInfo |
|
988 |
+ |
|
989 |
+ if mInfo.TrustRoot == clusterTLSInfo.TrustRoot && wInfo.TrustRoot == clusterTLSInfo.TrustRoot { |
|
990 |
+ break |
|
991 |
+ } |
|
992 |
+ |
|
993 |
+ // nodes don't trust root certs yet |
|
994 |
+ time.Sleep(250 * time.Millisecond) |
|
995 |
+ } |
|
996 |
+ |
|
997 |
+ c.Assert(m.GetNode(c, m.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo) |
|
998 |
+ c.Assert(m.GetNode(c, w.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo) |
|
999 |
+ currentTrustRoot = clusterTLSInfo.TrustRoot |
|
1000 |
+ } |
|
1001 |
+} |