Files
threshold/internal/server/service_rotate_roots.go
T
Jeff Mitchell 5716a30813 Update nodeenrollment to fix TLS issue; add debug (#3231)
* Add more logging to worker auth rotation and test flags

This makes it much easier to figure out when and why rotation is
happening and control it for tests/debugging.

* Update auth rotation logic

Because we were looking at validity period of client certs, which may
not have matched the actual rotation interval, it was possible (mostly
in test scenarios) for the rotation to happen multiple times on the
roots before we actually hit the worker rotation interval.

This changes how the interval is calculated by looking at the difference
between not-after values on the certs to understand the rotation
interval being used by the controller. We then use that as the starting
point for calculating a next-rotation time.
2023-05-19 17:18:26 -04:00

80 lines
2.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package server
import (
"context"
"fmt"
"time"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/rotation"
"github.com/hashicorp/nodeenrollment/types"
)
// RotateRoots is a domain service function that initiates a rotation of root
// certificates via a call to the nodenenrollment RotateRootCertificates
// function. Accepts the nodeenrollment option
// WithCertificateLifetime(time.Duration) to specify the lifetime of the
// generated cert(s).
func RotateRoots(ctx context.Context, workerAuthRepo *WorkerAuthRepositoryStorage, opt ...nodeenrollment.Option) (*types.RootCertificates, error) {
const op = "server.RotateRoots"
if workerAuthRepo == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing workerAuthRepo")
}
// Get current root certs so we can pass along the version
rootCerts := &types.RootCertificates{Id: CaId}
err := workerAuthRepo.Load(ctx, rootCerts)
if err != nil && err != nodeenrollment.ErrNotFound {
return nil, errors.Wrap(ctx, err, op)
}
opt = append(opt,
nodeenrollment.WithState(rootCerts.GetState()),
)
var current, next string
if rootCerts.Current != nil {
current = rootCerts.Current.GetId()
}
if rootCerts.Next != nil {
next = rootCerts.Next.GetId()
}
roots, err := rotation.RotateRootCertificates(ctx, workerAuthRepo, opt...)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
if roots != nil && (roots.Current.GetId() != current || roots.Next.GetId() != next) {
var args []any
currentKeyId, err := nodeenrollment.KeyIdFromPkix(roots.Current.PublicKeyPkix)
if err != nil {
event.WriteError(ctx, op, fmt.Errorf("error deriving pkix string from current ca certificate public key after rotation: %w", err))
} else {
args = append(args,
"current_ca_cert_id", currentKeyId,
"current_ca_cert_not_before", roots.Current.GetNotBefore().AsTime().Format(time.RFC3339),
"current_ca_cert_not_after", roots.Current.GetNotAfter().AsTime().Format(time.RFC3339),
)
}
nextKeyId, err := nodeenrollment.KeyIdFromPkix(roots.Next.PublicKeyPkix)
if err != nil {
event.WriteError(ctx, op, fmt.Errorf("error deriving pkix string from next ca certificate public key after rotation: %w", err))
} else {
args = append(args,
"next_ca_cert_id", nextKeyId,
"next_ca_cert_not_before", roots.Next.GetNotBefore().AsTime().Format(time.RFC3339),
"next_ca_cert_not_after", roots.Next.GetNotAfter().AsTime().Format(time.RFC3339),
)
}
event.WriteSysEvent(ctx, op, "worker auth root certificates were rotated", args...)
}
return roots, nil
}