func TestParseValidateAndSignCSR(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-") assert.NoError(t, err) defer os.RemoveAll(tempBaseDir) paths := ca.NewConfigPaths(tempBaseDir) rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA) assert.NoError(t, err) csr, _, err := ca.GenerateAndWriteNewKey(paths.Node) assert.NoError(t, err) signedCert, err := rootCA.ParseValidateAndSignCSR(csr, "CN", "OU", "ORG") assert.NoError(t, err) assert.NotNil(t, signedCert) parsedCert, err := helpers.ParseCertificatesPEM(signedCert) assert.NoError(t, err) assert.Equal(t, 2, len(parsedCert)) assert.Equal(t, "CN", parsedCert[0].Subject.CommonName) assert.Equal(t, 1, len(parsedCert[0].Subject.OrganizationalUnit)) assert.Equal(t, "OU", parsedCert[0].Subject.OrganizationalUnit[0]) assert.Equal(t, 3, len(parsedCert[0].Subject.Names)) assert.Equal(t, "ORG", parsedCert[0].Subject.Organization[0]) assert.Equal(t, "rootCN", parsedCert[1].Subject.CommonName) }
func TestNodeCertificateRenewalsDoNotRequireToken(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err := tc.NodeCAClients[2].IssueNodeCertificate(context.Background(), issueRequest) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipAccepted, issueResponse.NodeMembership) statusRequest := &api.NodeCertificateStatusRequest{NodeID: issueResponse.NodeID} statusResponse, err := tc.NodeCAClients[2].NodeCertificateStatus(context.Background(), statusRequest) assert.Equal(t, api.IssuanceStateIssued, statusResponse.Status.State) assert.NotNil(t, statusResponse.Certificate.Certificate) assert.Equal(t, role, statusResponse.Certificate.Role) role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err = tc.NodeCAClients[1].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipAccepted, issueResponse.NodeMembership) statusRequest = &api.NodeCertificateStatusRequest{NodeID: issueResponse.NodeID} statusResponse, err = tc.NodeCAClients[2].NodeCertificateStatus(context.Background(), statusRequest) require.NoError(t, err) assert.Equal(t, api.IssuanceStateIssued, statusResponse.Status.State) assert.NotNil(t, statusResponse.Certificate.Certificate) assert.Equal(t, role, statusResponse.Certificate.Role) }
func TestGetRemoteSignedCertificateWithPending(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() // Create a new CSR to be signed csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) updates, cancel := state.Watch(tc.MemoryStore.WatchQueue(), state.EventCreateNode{}) defer cancel() completed := make(chan error) go func() { _, err := ca.GetRemoteSignedCertificate(context.Background(), csr, tc.WorkerToken, tc.RootCA.Pool, tc.Remotes, nil, nil) completed <- err }() event := <-updates node := event.(state.EventCreateNode).Node.Copy() // Directly update the status of the store err = tc.MemoryStore.Update(func(tx store.Tx) error { node.Certificate.Status.State = api.IssuanceStateIssued return store.UpdateNode(tx, node) }) assert.NoError(t, err) // Make sure GetRemoteSignedCertificate didn't return an error assert.NoError(t, <-completed) }
func TestNodeCertificateWithEmptyPolicies(t *testing.T) { policy := api.AcceptancePolicy{ Policies: []*api.AcceptancePolicy_RoleAdmissionPolicy{}, } tc := testutils.NewTestCA(t, policy) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) assert.NotNil(t, csr) role := api.NodeRoleWorker issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err := tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipPending, issueResponse.NodeMembership) role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipPending, issueResponse.NodeMembership) }
func TestGetRemoteSignedCertificate(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() // Create a new CSR to be signed csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) certs, err := ca.GetRemoteSignedCertificate(context.Background(), csr, tc.ManagerToken, tc.RootCA.Pool, tc.Remotes, nil, nil) assert.NoError(t, err) assert.NotNil(t, certs) // Test the expiration for a manager certificate parsedCerts, err := helpers.ParseCertificatesPEM(certs) assert.NoError(t, err) assert.Len(t, parsedCerts, 2) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter)) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter)) assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.ManagerRole) // Test the expiration for an agent certificate certs, err = ca.GetRemoteSignedCertificate(tc.Context, csr, tc.WorkerToken, tc.RootCA.Pool, tc.Remotes, nil, nil) assert.NoError(t, err) assert.NotNil(t, certs) parsedCerts, err = helpers.ParseCertificatesPEM(certs) assert.NoError(t, err) assert.Len(t, parsedCerts, 2) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter)) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter)) assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.AgentRole) }
func TestIssueNodeCertificateAgentFromDifferentOrgRenewal(t *testing.T) { tc := testutils.NewTestCA(t, ca.DefaultAcceptancePolicy()) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Since we're using a client that has a different Organization, this request will be treated // as a new certificate request, not allowing auto-renewal role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err := tc.NodeCAClients[3].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipPending, issueResponse.NodeMembership) tc.MemoryStore.View(func(readTx store.ReadTx) { storeNodes, err := store.FindNodes(readTx, store.All) assert.NoError(t, err) assert.NotEmpty(t, storeNodes) found := false for _, node := range storeNodes { if node.ID == issueResponse.NodeID { found = true assert.Equal(t, api.IssuanceStatePending, node.Certificate.Status.State) } } assert.True(t, found) }) }
func TestRenewTLSConfigManager(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Get a new nodeConfig with a TLS cert that has the default Cert duration nodeConfig, err := tc.WriteNewNodeConfig(ca.ManagerRole) assert.NoError(t, err) // Create a new RootCA, and change the policy to issue 6 minute certificates newRootCA, err := ca.NewRootCA(tc.RootCA.Cert, tc.RootCA.Key, ca.DefaultNodeCertExpiration) assert.NoError(t, err) newRootCA.Signer.SetPolicy(&cfconfig.Signing{ Default: &cfconfig.SigningProfile{ Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, Expiry: 6 * time.Minute, }, }) // Create a new CSR and overwrite the key on disk csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issue a new certificate with the same details as the current config, but with 6 min expiration time c := nodeConfig.ClientTLSCreds signedCert, err := newRootCA.ParseValidateAndSignCSR(csr, c.NodeID(), c.Role(), c.Organization()) assert.NoError(t, err) assert.NotNil(t, signedCert) // Overwrite the certificate on disk with one that expires in 1 minute err = ioutils.AtomicWriteFile(tc.Paths.Node.Cert, signedCert, 0644) assert.NoError(t, err) // Get a new nodeConfig with a TLS cert that has 6 minutes to live var success, timeout bool renew := make(chan struct{}) updates := ca.RenewTLSConfig(ctx, nodeConfig, tc.TempDir, tc.Picker, renew) for { select { case <-time.After(2 * time.Second): timeout = true case certUpdate := <-updates: assert.NoError(t, certUpdate.Err) assert.NotNil(t, certUpdate) assert.Equal(t, ca.ManagerRole, certUpdate.Role) success = true } if timeout { assert.Fail(t, "TestRenewTLSConfig timed-out") break } if success { break } } }
func TestNodeCertificateRenewalsDoNotRequireSecret(t *testing.T) { hashPwd, _ := bcrypt.GenerateFromPassword([]byte("secret-data"), 0) policy := api.AcceptancePolicy{ Policies: []*api.AcceptancePolicy_RoleAdmissionPolicy{ { Role: api.NodeRoleWorker, Autoaccept: true, Secret: &api.AcceptancePolicy_RoleAdmissionPolicy_HashedSecret{ Data: hashPwd, Alg: "bcrypt", }, }, { Role: api.NodeRoleManager, Autoaccept: true, Secret: &api.AcceptancePolicy_RoleAdmissionPolicy_HashedSecret{ Data: hashPwd, Alg: "bcrypt", }, }, }, } tc := testutils.NewTestCA(t, policy) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err := tc.NodeCAClients[2].IssueNodeCertificate(context.Background(), issueRequest) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipAccepted, issueResponse.NodeMembership) statusRequest := &api.NodeCertificateStatusRequest{NodeID: issueResponse.NodeID} statusResponse, err := tc.NodeCAClients[2].NodeCertificateStatus(context.Background(), statusRequest) assert.Equal(t, api.IssuanceStateIssued, statusResponse.Status.State) assert.NotNil(t, statusResponse.Certificate.Certificate) assert.Equal(t, role, statusResponse.Certificate.Role) role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err = tc.NodeCAClients[1].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipAccepted, issueResponse.NodeMembership) statusRequest = &api.NodeCertificateStatusRequest{NodeID: issueResponse.NodeID} statusResponse, err = tc.NodeCAClients[2].NodeCertificateStatus(context.Background(), statusRequest) require.NoError(t, err) assert.Equal(t, api.IssuanceStateIssued, statusResponse.Status.State) assert.NotNil(t, statusResponse.Certificate.Certificate) assert.Equal(t, role, statusResponse.Certificate.Role) }
func TestRenewTLSConfigWithNoNode(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Get a new nodeConfig with a TLS cert that has the default Cert duration nodeConfig, err := tc.WriteNewNodeConfig(ca.ManagerRole) assert.NoError(t, err) // Create a new RootCA, and change the policy to issue 6 minute certificates. // Because of the default backdate of 5 minutes, this issues certificates // valid for 1 minute. newRootCA, err := ca.NewRootCA(tc.RootCA.Cert, tc.RootCA.Key, ca.DefaultNodeCertExpiration) assert.NoError(t, err) newRootCA.Signer.SetPolicy(&cfconfig.Signing{ Default: &cfconfig.SigningProfile{ Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, Expiry: 6 * time.Minute, }, }) // Create a new CSR and overwrite the key on disk csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issue a new certificate with the same details as the current config, but with 1 min expiration time c := nodeConfig.ClientTLSCreds signedCert, err := newRootCA.ParseValidateAndSignCSR(csr, c.NodeID(), c.Role(), c.Organization()) assert.NoError(t, err) assert.NotNil(t, signedCert) // Overwrite the certificate on disk with one that expires in 1 minute err = ioutils.AtomicWriteFile(tc.Paths.Node.Cert, signedCert, 0644) assert.NoError(t, err) // Delete the node from the backend store err = tc.MemoryStore.Update(func(tx store.Tx) error { node := store.GetNode(tx, nodeConfig.ClientTLSCreds.NodeID()) assert.NotNil(t, node) return store.DeleteNode(tx, nodeConfig.ClientTLSCreds.NodeID()) }) assert.NoError(t, err) renew := make(chan struct{}) updates := ca.RenewTLSConfig(ctx, nodeConfig, tc.TempDir, tc.Remotes, renew) select { case <-time.After(10 * time.Second): assert.Fail(t, "TestRenewTLSConfig timed-out") case certUpdate := <-updates: assert.Error(t, certUpdate.Err) assert.Contains(t, certUpdate.Err.Error(), "not found when attempting to renew certificate") } }
func TestIssueNodeCertificateAgentFromDifferentOrgRenewal(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Since we're using a client that has a different Organization, this request will be treated // as a new certificate request, not allowing auto-renewal. Therefore, the request will fail. issueRequest := &api.IssueNodeCertificateRequest{CSR: csr} _, err = tc.NodeCAClients[3].IssueNodeCertificate(context.Background(), issueRequest) assert.Error(t, err) }
func TestGetRemoteSignedCertificateNodeInfo(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() // Create a new CSR to be signed csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) info := make(chan api.IssueNodeCertificateResponse, 1) cert, err := ca.GetRemoteSignedCertificate(context.Background(), csr, tc.WorkerToken, tc.RootCA.Pool, tc.Remotes, nil, info) assert.NoError(t, err) assert.NotNil(t, cert) assert.NotEmpty(t, <-info) }
func TestGetRemoteSignedCertificateNodeInfo(t *testing.T) { tc := testutils.NewTestCA(t, testutils.AcceptancePolicy(true, true, "")) defer tc.Stop() // Create a new CSR to be signed csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) info := make(chan api.IssueNodeCertificateResponse, 1) cert, err := ca.GetRemoteSignedCertificate(context.Background(), csr, ca.ManagerRole, "", tc.RootCA.Pool, tc.Picker, nil, info) assert.NoError(t, err) assert.NotNil(t, cert) assert.NotEmpty(t, <-info) }
func TestEncryptECPrivateKey(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-") assert.NoError(t, err) defer os.RemoveAll(tempBaseDir) paths := ca.NewConfigPaths(tempBaseDir) _, key, err := ca.GenerateAndWriteNewKey(paths.Node) assert.NoError(t, err) encryptedKey, err := ca.EncryptECPrivateKey(key, "passphrase") assert.NoError(t, err) keyBlock, _ := pem.Decode(encryptedKey) assert.NotNil(t, keyBlock) assert.Equal(t, keyBlock.Headers["Proc-Type"], "4,ENCRYPTED") assert.Contains(t, keyBlock.Headers["DEK-Info"], "AES-256-CBC") }
func TestNewNodeCertificateBadToken(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issuance fails if wrong secret is provided role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") }
func TestGenerateAndWriteNewKey(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-") assert.NoError(t, err) defer os.RemoveAll(tempBaseDir) paths := ca.NewConfigPaths(tempBaseDir) csr, key, err := ca.GenerateAndWriteNewKey(paths.Node) assert.NoError(t, err) assert.NotNil(t, csr) assert.NotNil(t, key) perms, err := permbits.Stat(paths.Node.Key) assert.NoError(t, err) assert.False(t, perms.GroupRead()) assert.False(t, perms.OtherRead()) _, err = helpers.ParseCSRPEM(csr) assert.NoError(t, err) }
func TestNewNodeCertificateBadSecret(t *testing.T) { managerHashPwd, _ := bcrypt.GenerateFromPassword([]byte("secret-data-manager"), 0) badSecret := &api.AcceptancePolicy_RoleAdmissionPolicy_HashedSecret{ Data: managerHashPwd, Alg: "sha1", } policy := api.AcceptancePolicy{ Policies: []*api.AcceptancePolicy_RoleAdmissionPolicy{ { Role: api.NodeRoleWorker, Autoaccept: true, Secret: badSecret, }, { Role: api.NodeRoleManager, Autoaccept: true, Secret: badSecret, }, }, } tc := testutils.NewTestCA(t, policy) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issuance fails if wrong secret is provided role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: hash algorithm not supported: sha1") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: hash algorithm not supported: sha1") }
func TestNewRootCANonDefaultExpiry(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-") assert.NoError(t, err) defer os.RemoveAll(tempBaseDir) paths := ca.NewConfigPaths(tempBaseDir) rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA) assert.NoError(t, err) newRootCA, err := ca.NewRootCA(rootCA.Cert, rootCA.Key, 1*time.Hour) assert.NoError(t, err) // Create and sign a new CSR csr, _, err := ca.GenerateAndWriteNewKey(paths.Node) assert.NoError(t, err) cert, err := newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG") assert.NoError(t, err) parsedCerts, err := helpers.ParseCertificatesPEM(cert) assert.NoError(t, err) assert.Len(t, parsedCerts, 2) assert.True(t, time.Now().Add(time.Minute*59).Before(parsedCerts[0].NotAfter)) assert.True(t, time.Now().Add(time.Hour).Add(time.Minute).After(parsedCerts[0].NotAfter)) // Sign the same CSR again, this time with a 59 Minute expiration RootCA (under the 60 minute minimum). // This should use the default of 3 months newRootCA, err = ca.NewRootCA(rootCA.Cert, rootCA.Key, 59*time.Minute) assert.NoError(t, err) cert, err = newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG") assert.NoError(t, err) parsedCerts, err = helpers.ParseCertificatesPEM(cert) assert.NoError(t, err) assert.Len(t, parsedCerts, 2) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter)) assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter)) }
func TestNewNodeCertificateRequiresSecret(t *testing.T) { agentHashPwd, _ := bcrypt.GenerateFromPassword([]byte("secret-data-worker"), 0) managerHashPwd, _ := bcrypt.GenerateFromPassword([]byte("secret-data-manager"), 0) agentSecret := &api.AcceptancePolicy_RoleAdmissionPolicy_HashedSecret{ Data: agentHashPwd, Alg: "bcrypt", } managerSecret := &api.AcceptancePolicy_RoleAdmissionPolicy_HashedSecret{ Data: managerHashPwd, Alg: "bcrypt", } policy := api.AcceptancePolicy{ Policies: []*api.AcceptancePolicy_RoleAdmissionPolicy{ { Role: api.NodeRoleWorker, Autoaccept: true, Secret: agentSecret, }, { Role: api.NodeRoleManager, Autoaccept: true, Secret: managerSecret, }, }, } tc := testutils.NewTestCA(t, policy) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issuance fails if no secret is provided role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: invalid policy or secret") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: invalid policy or secret") // Issuance fails if wrong secret is provided role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: crypto/bcrypt: hashedPassword is not the hash of the given password") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: crypto/bcrypt: hashedPassword is not the hash of the given password") // Issuance fails if secret for the other role is provided role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "secret-data-worker"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: crypto/bcrypt: hashedPassword is not the hash of the given password") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "secret-data-manager"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid secret token is necessary to join this cluster: crypto/bcrypt: hashedPassword is not the hash of the given password") // Issuance succeeds if correct secret is provided role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "secret-data-manager"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Secret: "secret-data-worker"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) }
func TestNewNodeCertificateRequiresToken(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) // Issuance fails if no secret is provided role := api.NodeRoleManager issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") // Issuance fails if wrong secret is provided role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: "invalid-secret"} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") // Issuance succeeds if correct token is provided role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: tc.ManagerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: tc.WorkerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) // Rotate manager and worker tokens var ( newManagerToken string newWorkerToken string ) assert.NoError(t, tc.MemoryStore.Update(func(tx store.Tx) error { clusters, _ := store.FindClusters(tx, store.ByName(store.DefaultClusterName)) newWorkerToken = ca.GenerateJoinToken(&tc.RootCA) clusters[0].RootCA.JoinTokens.Worker = newWorkerToken newManagerToken = ca.GenerateJoinToken(&tc.RootCA) clusters[0].RootCA.JoinTokens.Manager = newManagerToken return store.UpdateCluster(tx, clusters[0]) })) time.Sleep(500 * time.Millisecond) // Old token should fail role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: tc.ManagerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: tc.WorkerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.EqualError(t, err, "rpc error: code = 3 desc = A valid join token is necessary to join this cluster") // New token should succeed role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: newManagerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) role = api.NodeRoleWorker issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role, Token: newWorkerToken} _, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) assert.NoError(t, err) }
func TestNodeCertificateAccept(t *testing.T) { tc := testutils.NewTestCA(t, ca.DefaultAcceptancePolicy()) defer tc.Stop() csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node) assert.NoError(t, err) testNode := &api.Node{ ID: "nodeID", Spec: api.NodeSpec{ Membership: api.NodeMembershipAccepted, Role: api.NodeRoleWorker, }, Certificate: api.Certificate{ CN: "nodeID", CSR: csr, Status: api.IssuanceStatus{State: api.IssuanceStatePending}, }, } err = tc.MemoryStore.Update(func(tx store.Tx) error { assert.NoError(t, store.CreateNode(tx, testNode)) return nil }) assert.NoError(t, err) statusRequest := &api.NodeCertificateStatusRequest{NodeID: "nodeID"} resp, err := tc.NodeCAClients[1].NodeCertificateStatus(context.Background(), statusRequest) assert.NoError(t, err) assert.NotEmpty(t, resp.Certificate) assert.NotEmpty(t, resp.Status) assert.NotNil(t, resp.Certificate.Certificate) assert.Equal(t, api.IssuanceStateIssued, resp.Status.State) tc.MemoryStore.View(func(readTx store.ReadTx) { storeNodes, err := store.FindNodes(readTx, store.All) assert.NoError(t, err) assert.NotEmpty(t, storeNodes) var found bool for _, node := range storeNodes { if node.ID == "nodeID" { assert.Equal(t, api.IssuanceStateIssued, node.Certificate.Status.State) found = true } } assert.True(t, found) }) // Try it one more time for Worker, this time end-to-end role := api.NodeRoleWorker issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err := tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipAccepted, issueResponse.NodeMembership) // Try it one more time for Worker, this time end-to-end with manager role = api.NodeRoleManager issueRequest = &api.IssueNodeCertificateRequest{CSR: csr, Role: role} issueResponse, err = tc.NodeCAClients[0].IssueNodeCertificate(context.Background(), issueRequest) require.NoError(t, err) assert.NotNil(t, issueResponse.NodeID) assert.Equal(t, api.NodeMembershipPending, issueResponse.NodeMembership) }