func TestLoadSecurityConfigInvalidCert(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() // Write some garbage to the cert ioutil.WriteFile(tc.Paths.Node.Cert, []byte(`-----BEGIN CERTIFICATE-----\n some random garbage\n -----END CERTIFICATE-----`), 0644) krw := ca.NewKeyReadWriter(tc.Paths.Node, nil, nil) _, err := ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw) assert.Error(t, err) nodeConfig, err := tc.RootCA.CreateSecurityConfig(tc.Context, krw, ca.CertificateRequestConfig{ Remotes: tc.Remotes, }) assert.NoError(t, err) assert.NotNil(t, nodeConfig) assert.NotNil(t, nodeConfig.ClientTLSCreds) assert.NotNil(t, nodeConfig.ServerTLSCreds) assert.Equal(t, tc.RootCA, *nodeConfig.RootCA()) }
func TestLoadSecurityConfigIncorrectPassphrase(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() paths := ca.NewConfigPaths(tc.TempDir) _, err := tc.RootCA.IssueAndSaveNewCertificates(ca.NewKeyReadWriter(paths.Node, []byte("kek"), nil), "nodeID", ca.WorkerRole, tc.Organization) require.NoError(t, err) _, err = ca.LoadSecurityConfig(tc.Context, tc.RootCA, ca.NewKeyReadWriter(paths.Node, nil, nil)) require.IsType(t, ca.ErrInvalidKEK{}, err) }
func TestLoadSecurityConfigInvalidKey(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() // Write some garbage to the Key ioutil.WriteFile(tc.Paths.Node.Key, []byte(`-----BEGIN EC PRIVATE KEY-----\n some random garbage\n -----END EC PRIVATE KEY-----`), 0644) krw := ca.NewKeyReadWriter(tc.Paths.Node, nil, nil) _, err := ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw, false) assert.Error(t, err) nodeConfig, err := tc.RootCA.CreateSecurityConfig(tc.Context, krw, ca.CertificateRequestConfig{ ConnBroker: tc.ConnBroker, }) assert.NoError(t, err) assert.NotNil(t, nodeConfig) assert.NotNil(t, nodeConfig.ClientTLSCreds) assert.NotNil(t, nodeConfig.ServerTLSCreds) assert.Equal(t, tc.RootCA, *nodeConfig.RootCA()) }
func (n *Node) loadSecurityConfig(ctx context.Context) (*ca.SecurityConfig, error) { paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory)) var securityConfig *ca.SecurityConfig krw := ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{}) if err := krw.Migrate(); err != nil { return nil, err } // Check if we already have a valid certificates on disk. rootCA, err := ca.GetLocalRootCA(paths.RootCA) if err != nil && err != ca.ErrNoLocalRootCA { return nil, err } if err == nil { securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw) if err != nil { _, isInvalidKEK := errors.Cause(err).(ca.ErrInvalidKEK) if isInvalidKEK { return nil, ErrInvalidUnlockKey } else if !os.IsNotExist(err) { return nil, errors.Wrapf(err, "error while loading TLS certificate in %s", paths.Node.Cert) } } } if securityConfig == nil { if n.config.JoinAddr == "" { // if we're not joining a cluster, bootstrap a new one - and we have to set the unlock key n.unlockKey = nil if n.config.AutoLockManagers { n.unlockKey = encryption.GenerateSecretKey() } krw = ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{}) rootCA, err = ca.CreateRootCA(ca.DefaultRootCN, paths.RootCA) if err != nil { return nil, err } log.G(ctx).Debug("generated CA key and certificate") } else if err == ca.ErrNoLocalRootCA { // from previous error loading the root CA from disk rootCA, err = ca.DownloadRootCA(ctx, paths.RootCA, n.config.JoinToken, n.remotes) if err != nil { return nil, err } log.G(ctx).Debug("downloaded CA certificate") } // Obtain new certs and setup TLS certificates renewal for this node: // - If certificates weren't present on disk, we call CreateSecurityConfig, which blocks // until a valid certificate has been issued. // - We wait for CreateSecurityConfig to finish since we need a certificate to operate. // Attempt to load certificate from disk securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw) if err == nil { log.G(ctx).WithFields(logrus.Fields{ "node.id": securityConfig.ClientTLSCreds.NodeID(), }).Debugf("loaded TLS certificate") } else { if _, ok := errors.Cause(err).(ca.ErrInvalidKEK); ok { return nil, ErrInvalidUnlockKey } log.G(ctx).WithError(err).Debugf("no node credentials found in: %s", krw.Target()) securityConfig, err = rootCA.CreateSecurityConfig(ctx, krw, ca.CertificateRequestConfig{ Token: n.config.JoinToken, Availability: n.config.Availability, Remotes: n.remotes, }) if err != nil { return nil, err } } } n.Lock() n.role = securityConfig.ClientTLSCreds.Role() n.nodeID = securityConfig.ClientTLSCreds.NodeID() n.roleCond.Broadcast() n.Unlock() return securityConfig, nil }
func TestLoadSecurityConfigExpiredCert(t *testing.T) { tc := testutils.NewTestCA(t) defer tc.Stop() _, key, err := ca.GenerateNewCSR() require.NoError(t, err) require.NoError(t, ioutil.WriteFile(tc.Paths.Node.Key, key, 0600)) certKey, err := helpers.ParsePrivateKeyPEM(key) require.NoError(t, err) rootKey, err := helpers.ParsePrivateKeyPEM(tc.RootCA.Key) require.NoError(t, err) rootCert, err := helpers.ParseCertificatePEM(tc.RootCA.Cert) require.NoError(t, err) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) require.NoError(t, err) genCert := func(notBefore, notAfter time.Time) { derBytes, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ CommonName: "CN", OrganizationalUnit: []string{"OU"}, Organization: []string{"ORG"}, }, NotBefore: notBefore, NotAfter: notAfter, }, rootCert, certKey.Public(), rootKey) require.NoError(t, err) certBytes := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: derBytes, }) require.NoError(t, ioutil.WriteFile(tc.Paths.Node.Cert, certBytes, 0644)) } krw := ca.NewKeyReadWriter(tc.Paths.Node, nil, nil) now := time.Now() // A cert that is not yet valid is not valid even if expiry is allowed genCert(now.Add(time.Hour), now.Add(time.Hour*2)) _, err = ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw, false) require.Error(t, err) require.IsType(t, x509.CertificateInvalidError{}, errors.Cause(err)) _, err = ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw, true) require.Error(t, err) require.IsType(t, x509.CertificateInvalidError{}, errors.Cause(err)) // a cert that is expired is not valid if expiry is not allowed genCert(now.Add(time.Hour*-3), now.Add(time.Hour*-1)) _, err = ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw, false) require.Error(t, err) require.IsType(t, x509.CertificateInvalidError{}, errors.Cause(err)) // but it is valid if expiry is allowed _, err = ca.LoadSecurityConfig(tc.Context, tc.RootCA, krw, true) require.NoError(t, err) }