From 254361fa90eb9e74e852a33bdea9b17e355a7151 Mon Sep 17 00:00:00 2001 From: Nic Klaassen Date: Tue, 17 Sep 2024 12:55:34 -0700 Subject: [PATCH] wip --- api/types/authentication.go | 72 +++++++- lib/auth/auth_with_roles.go | 11 ++ .../clusterconfig/clusterconfigv1/service.go | 41 +++-- lib/auth/grpcserver.go | 4 + lib/auth/helpers.go | 7 + lib/auth/init.go | 15 ++ lib/auth/init_test.go | 172 ++++++++++++++++++ lib/auth/keystore/manager.go | 9 + lib/config/configuration.go | 7 + 9 files changed, 324 insertions(+), 14 deletions(-) diff --git a/api/types/authentication.go b/api/types/authentication.go index d00c5576a7c33..7c405967d22c6 100644 --- a/api/types/authentication.go +++ b/api/types/authentication.go @@ -178,6 +178,13 @@ type AuthPreference interface { GetSignatureAlgorithmSuite() SignatureAlgorithmSuite // SetSignatureAlgorithmSuite sets the signature algorithm suite. SetSignatureAlgorithmSuite(SignatureAlgorithmSuite) + // SetDefaultSignatureAlgorithmSuite sets default signature algorithm suite + // based on the params. This is meant for a default auth preference in a + // brand new cluster or after resetting the auth preference. + SetDefaultSignatureAlgorithmSuite(SignatureAlgorithmSuiteParams) + // CheckSignatureAlgorithmSuite returns an error if the current signature + // algorithm suite is incompatible with [params]. + CheckSignatureAlgorithmSuite(SignatureAlgorithmSuiteParams) error // String represents a human readable version of authentication settings. String() string @@ -216,7 +223,15 @@ func newAuthPreferenceWithLabels(spec AuthPreferenceSpecV2, labels map[string]st // DefaultAuthPreference returns the default authentication preferences. func DefaultAuthPreference() AuthPreference { - authPref, _ := newAuthPreferenceWithLabels(AuthPreferenceSpecV2{}, map[string]string{ + authPref, _ := newAuthPreferenceWithLabels(AuthPreferenceSpecV2{ + // This is useful as a static value, but the real default signature + // algorithm suite depends on the cluster FIPS and HSM settings, and + // gets written by [AuthPreferenceV2.SetDefaultSignatureAlgorithmSuite] + // wherever a default auth preference will actually be persisted. + // It is set here so that many existing tests using this get the + // benefits of the balanced-v1 suite. + SignatureAlgorithmSuite: SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1, + }, map[string]string{ OriginLabel: OriginDefaults, }) return authPref @@ -567,6 +582,61 @@ func (c *AuthPreferenceV2) SetSignatureAlgorithmSuite(suite SignatureAlgorithmSu c.Spec.SignatureAlgorithmSuite = suite } +// SignatureAlgorithmSuiteParams is a set of parameters used to determine if a +// configured signature algorithm suite is valid, or to set a default signature +// algorithm suite. +type SignatureAlgorithmSuiteParams struct { + // FIPS should be true if running in FIPS mode. + FIPS bool + // UsingHSMOrKMS should be true if the auth server is configured to + // use an HSM or KMS. + UsingHSMOrKMS bool +} + +// SetDefaultSignatureAlgorithmSuite sets default signature algorithm suite +// based on the params. This is meant for a default auth preference in a +// brand new cluster or after resetting the auth preference. +func (c *AuthPreferenceV2) SetDefaultSignatureAlgorithmSuite(params SignatureAlgorithmSuiteParams) { + switch { + case params.FIPS: + c.SetSignatureAlgorithmSuite(SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_FIPS_V1) + case params.UsingHSMOrKMS: + c.SetSignatureAlgorithmSuite(SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1) + default: + c.SetSignatureAlgorithmSuite(SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1) + } +} + +var ( + errNonFIPSSignatureAlgorithmSuite = &trace.BadParameterError{Message: `non-FIPS compliant authentication setting: "signature_algorithm_suite" must be "fips-v1" or "legacy"`} + errNonHSMSignatureAlgorithmSuite = &trace.BadParameterError{Message: fmt.Sprintf(`configured "signature_algorithm_suite" is unsupported when "ca_key_params" configures an HSM or KMS, supported values: %v`, []string{"hsm-v1", "fips-v1", "legacy"})} +) + +// CheckSignatureAlgorithmSuite returns an error if the current signature +// algorithm suite is incompatible with [params]. +func (c *AuthPreferenceV2) CheckSignatureAlgorithmSuite(params SignatureAlgorithmSuiteParams) error { + switch c.GetSignatureAlgorithmSuite() { + case SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_UNSPECIFIED, + SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_LEGACY, + SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_FIPS_V1: + // legacy, fips-v1, and unspecified are always valid. + case SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1: + if params.FIPS { + return errNonFIPSSignatureAlgorithmSuite + } + case SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1: + if params.FIPS { + return trace.Wrap(errNonFIPSSignatureAlgorithmSuite) + } + if params.UsingHSMOrKMS { + return trace.Wrap(errNonHSMSignatureAlgorithmSuite) + } + default: + return trace.Errorf("unhandled signature_algorithm_suite: this is a bug") + } + return nil +} + // CheckAndSetDefaults verifies the constraints for AuthPreference. func (c *AuthPreferenceV2) CheckAndSetDefaults() error { c.setStaticFields() diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 9b6ed728ed75d..af92630a82e3d 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -4699,6 +4699,13 @@ func (a *ServerWithRoles) SetAuthPreference(ctx context.Context, newAuthPref typ } } + if err := newAuthPref.CheckSignatureAlgorithmSuite(types.SignatureAlgorithmSuiteParams{ + FIPS: a.authServer.fips, + UsingHSMOrKMS: a.authServer.keyStore.UsingHSMOrKMS(), + }); err != nil { + return trace.Wrap(err) + } + if err := dtconfig.ValidateConfigAgainstModules(newAuthPref.GetDeviceTrust()); err != nil { return trace.Wrap(err) } @@ -4752,6 +4759,10 @@ func (a *ServerWithRoles) ResetAuthPreference(ctx context.Context) error { } defaultAuthPref := types.DefaultAuthPreference() + defaultAuthPref.SetDefaultSignatureAlgorithmSuite(types.SignatureAlgorithmSuiteParams{ + FIPS: a.authServer.fips, + UsingHSMOrKMS: a.authServer.keyStore.UsingHSMOrKMS(), + }) _, err = a.authServer.UpsertAuthPreference(ctx, defaultAuthPref) var msg string diff --git a/lib/auth/clusterconfig/clusterconfigv1/service.go b/lib/auth/clusterconfig/clusterconfigv1/service.go index 80f3d055b2077..62d47421740ac 100644 --- a/lib/auth/clusterconfig/clusterconfigv1/service.go +++ b/lib/auth/clusterconfig/clusterconfigv1/service.go @@ -72,12 +72,13 @@ type Backend interface { // ServiceConfig contain dependencies required to create a [Service]. type ServiceConfig struct { - Cache Cache - Backend Backend - Authorizer authz.Authorizer - Emitter apievents.Emitter - AccessGraph AccessGraphConfig - ReadOnlyCache ReadOnlyCache + Cache Cache + Backend Backend + Authorizer authz.Authorizer + Emitter apievents.Emitter + AccessGraph AccessGraphConfig + ReadOnlyCache ReadOnlyCache + SignatureAlgorithmSuiteParams types.SignatureAlgorithmSuiteParams } // AccessGraphConfig contains the configuration about the access graph service @@ -99,12 +100,13 @@ type AccessGraphConfig struct { type Service struct { clusterconfigpb.UnimplementedClusterConfigServiceServer - cache Cache - backend Backend - authorizer authz.Authorizer - emitter apievents.Emitter - accessGraph AccessGraphConfig - readOnlyCache ReadOnlyCache + cache Cache + backend Backend + authorizer authz.Authorizer + emitter apievents.Emitter + accessGraph AccessGraphConfig + readOnlyCache ReadOnlyCache + signatureAlgorithmSuiteParams types.SignatureAlgorithmSuiteParams } // NewService validates the provided configuration and returns a [Service]. @@ -130,7 +132,7 @@ func NewService(cfg ServiceConfig) (*Service, error) { cfg.ReadOnlyCache = readOnlyCache } - return &Service{cache: cfg.Cache, backend: cfg.Backend, authorizer: cfg.Authorizer, emitter: cfg.Emitter, accessGraph: cfg.AccessGraph, readOnlyCache: cfg.ReadOnlyCache}, nil + return &Service{cache: cfg.Cache, backend: cfg.Backend, authorizer: cfg.Authorizer, emitter: cfg.Emitter, accessGraph: cfg.AccessGraph, readOnlyCache: cfg.ReadOnlyCache, signatureAlgorithmSuiteParams: cfg.SignatureAlgorithmSuiteParams}, nil } // GetAuthPreference returns the locally cached auth preference. @@ -179,6 +181,10 @@ func (s *Service) CreateAuthPreference(ctx context.Context, p types.AuthPreferen return nil, trace.Wrap(err) } + if err := p.CheckSignatureAlgorithmSuite(s.signatureAlgorithmSuiteParams); err != nil { + return nil, trace.Wrap(err) + } + created, err := s.backend.CreateAuthPreference(ctx, p) if err != nil { return nil, trace.Wrap(err) @@ -230,6 +236,10 @@ func (s *Service) UpdateAuthPreference(ctx context.Context, req *clusterconfigpb return nil, trace.Wrap(err) } + if err := req.AuthPreference.CheckSignatureAlgorithmSuite(s.signatureAlgorithmSuiteParams); err != nil { + return nil, trace.Wrap(err) + } + req.AuthPreference.SetOrigin(types.OriginDynamic) original, err := s.cache.GetAuthPreference(ctx) @@ -293,6 +303,10 @@ func (s *Service) UpsertAuthPreference(ctx context.Context, req *clusterconfigpb return nil, trace.Wrap(err) } + if err := req.AuthPreference.CheckSignatureAlgorithmSuite(s.signatureAlgorithmSuiteParams); err != nil { + return nil, trace.Wrap(err) + } + req.AuthPreference.SetOrigin(types.OriginDynamic) original, err := s.cache.GetAuthPreference(ctx) @@ -347,6 +361,7 @@ func (s *Service) ResetAuthPreference(ctx context.Context, _ *clusterconfigpb.Re } defaultPreference := types.DefaultAuthPreference() + defaultPreference.SetDefaultSignatureAlgorithmSuite(s.signatureAlgorithmSuiteParams) newSecondFactor := defaultPreference.GetSecondFactor() const iterationLimit = 3 // Attempt a few iterations in case the conditional update fails diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 25feaab22dfb9..548d6fbce52ff 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -5367,6 +5367,10 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { Insecure: cfg.APIConfig.AccessGraph.Insecure, }, ReadOnlyCache: cfg.AuthServer.ReadOnlyCache, + SignatureAlgorithmSuiteParams: types.SignatureAlgorithmSuiteParams{ + FIPS: cfg.AuthServer.fips, + UsingHSMOrKMS: cfg.AuthServer.keyStore.UsingHSMOrKMS(), + }, }) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/auth/helpers.go b/lib/auth/helpers.go index 006136e458ee8..212e8f791ba3d 100644 --- a/lib/auth/helpers.go +++ b/lib/auth/helpers.go @@ -57,6 +57,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/events/eventstest" "github.com/gravitational/teleport/lib/limiter" + "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/services/suite" @@ -93,6 +94,10 @@ type TestAuthServerConfig struct { // RunWhileLockedRetryInterval is the interval to retry the run while locked // operation. RunWhileLockedRetryInterval time.Duration + // FIPS means the cluster should run in FIPS mode. + FIPS bool + // KeystoreConfig is configuration for the CA keystore. + KeystoreConfig servicecfg.KeystoreConfig } // CheckAndSetDefaults checks and sets defaults @@ -298,6 +303,8 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) { ClusterName: clusterName, HostUUID: uuid.New().String(), AccessLists: accessLists, + FIPS: cfg.FIPS, + KeyStoreConfig: cfg.KeystoreConfig, }, WithClock(cfg.Clock), ) diff --git a/lib/auth/init.go b/lib/auth/init.go index e9c767d628a67..0f6465ac0aefa 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -777,6 +777,13 @@ func initializeAuthPreference(ctx context.Context, asrv *Server, newAuthPref typ if storedAuthPref == nil { log.Infof("Creating cluster auth preference: %v.", newAuthPref) + + // Set a default signature algorithm suite for a new cluster. + newAuthPref.SetDefaultSignatureAlgorithmSuite(types.SignatureAlgorithmSuiteParams{ + FIPS: asrv.fips, + UsingHSMOrKMS: asrv.keyStore.UsingHSMOrKMS(), + }) + _, err := asrv.CreateAuthPreference(ctx, newAuthPref) if trace.IsAlreadyExists(err) { continue @@ -785,6 +792,14 @@ func initializeAuthPreference(ctx context.Context, asrv *Server, newAuthPref typ return trace.Wrap(err) } + if newAuthPref.Origin() == types.OriginDefaults { + // Never overwrite a stored signature algorithm suite with a default + // signature algorithm suite. This prevents the suite from being + // "upgraded" by a Teleport version upgrade alone, even if defaults + // are used on both versions. + newAuthPref.SetSignatureAlgorithmSuite(storedAuthPref.GetSignatureAlgorithmSuite()) + } + newAuthPref.SetRevision(storedAuthPref.GetRevision()) _, err = asrv.UpdateAuthPreference(ctx, newAuthPref) if trace.IsCompareFailed(err) { diff --git a/lib/auth/init_test.go b/lib/auth/init_test.go index 45f2b0d88da87..9e36900c3d4ad 100644 --- a/lib/auth/init_test.go +++ b/lib/auth/init_test.go @@ -35,6 +35,7 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "golang.org/x/crypto/ssh" @@ -44,15 +45,19 @@ import ( "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" apisshutils "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" + "github.com/gravitational/teleport/lib/auth/keystore" "github.com/gravitational/teleport/lib/auth/state" "github.com/gravitational/teleport/lib/auth/storage" "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/backend/lite" + "github.com/gravitational/teleport/lib/cryptosuites" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/observability/tracing" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/suite" "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/utils/proxy" @@ -161,6 +166,173 @@ func TestBadIdentity(t *testing.T) { require.IsType(t, trace.BadParameter(""), err) } +func TestSignatureAlgorithmSuite(t *testing.T) { + ctx := context.Background() + + modules.SetTestModules(t, &modules.TestModules{ + TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.HSM: {Enabled: true}, + }, + }, + }) + + setupInitConfig := func(t *testing.T, fips, hsm bool) InitConfig { + cfg := setupConfig(t) + cfg.FIPS = fips + if hsm { + cfg.KeyStoreConfig = keystore.HSMTestConfig(t) + } + // Pre-generate all CAs to keep tests fast esp. with SoftHSM. + for _, caType := range types.CertAuthTypes { + cfg.BootstrapResources = append(cfg.BootstrapResources, suite.NewTestCAWithConfig(suite.TestCAConfig{ + Type: caType, + ClusterName: cfg.ClusterName.GetClusterName(), + Clock: cfg.Clock, + })) + } + return cfg + } + + testCases := map[string]struct { + fips bool + hsm bool + expectDefaultSuite types.SignatureAlgorithmSuite + expectUnallowedSuites []types.SignatureAlgorithmSuite + }{ + "basic": { + expectDefaultSuite: types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1, + }, + "fips": { + fips: true, + expectDefaultSuite: types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_FIPS_V1, + expectUnallowedSuites: []types.SignatureAlgorithmSuite{ + types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1, + types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1, + }, + }, + "hsm": { + hsm: true, + expectDefaultSuite: types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1, + expectUnallowedSuites: []types.SignatureAlgorithmSuite{ + types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1, + }, + }, + "fips and hsm": { + fips: true, + hsm: true, + expectDefaultSuite: types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_FIPS_V1, + expectUnallowedSuites: []types.SignatureAlgorithmSuite{ + types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_BALANCED_V1, + types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1, + }, + }, + } + + // Test the behavior of auth server init. A default signature algorithm + // suite should never overwrite a persisted signature algorithm suite for an + // existing cluster, even if that was also a default. + t.Run("init", func(t *testing.T) { + t.Parallel() + for desc, tc := range testCases { + t.Run(desc, func(t *testing.T) { + // Assert that a fresh cluster gets expected default suite. + cfg := setupInitConfig(t, tc.fips, tc.hsm) + authServer, err := Init(ctx, cfg) + require.NoError(t, err) + t.Cleanup(func() { authServer.Close() }) + authPref, err := authServer.GetAuthPreference(ctx) + require.NoError(t, err) + assert.Equal(t, types.OriginDefaults, authPref.GetMetadata().Labels[types.OriginLabel]) + assert.Equal(t, tc.expectDefaultSuite, authPref.GetSignatureAlgorithmSuite()) + + // Reset to unspecified suite and persist (still with + // OriginDefaults) to mimic an older cluster with the old defaults + // that later gets upgraded. + authPref.SetSignatureAlgorithmSuite(types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_UNSPECIFIED) + _, err = authServer.UpsertAuthPreference(ctx, authPref) + require.NoError(t, err) + authPref, err = authServer.GetAuthPreference(ctx) + require.NoError(t, err) + // Sanity check it persisted as a default. + assert.Equal(t, types.OriginDefaults, authPref.GetMetadata().Labels[types.OriginLabel]) + assert.Equal(t, types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_UNSPECIFIED, authPref.GetSignatureAlgorithmSuite()) + + // Start a second brand new auth server sharing the same config and + // backend. The new auth starting up would apply the new default + // auth preference and persist it to the backend, but it should not + // modify the existing signature algorithm suite even though it's + // unspecified. This is meant to test that a v16 auth server + // upgraded to v17 will still have an unspecified signature + // algorithm suite and won't get a new one until explicitly opting + // in. + authServer, err = Init(ctx, cfg) + require.NoError(t, err) + t.Cleanup(func() { authServer.Close() }) + authPref, err = authServer.GetAuthPreference(ctx) + require.NoError(t, err) + assert.Equal(t, types.OriginDefaults, authPref.GetMetadata().Labels[types.OriginLabel]) + assert.Equal(t, types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_UNSPECIFIED, authPref.GetSignatureAlgorithmSuite()) + + // Assert that the selected algorithm is RSA2048 when the suite is + // unspecified. + alg, err := cryptosuites.AlgorithmForKey(ctx, + cryptosuites.GetCurrentSuiteFromAuthPreference(authServer), + cryptosuites.UserTLS) + require.NoError(t, err) + require.Equal(t, cryptosuites.RSA2048, alg) + }) + } + }) + + suiteName := func(suite types.SignatureAlgorithmSuite) string { + suiteName, err := suite.MarshalText() + require.NoError(t, err) + return string(suiteName) + } + + // Test that the auth preference cannot be upserted with a signature + // algorithm suite incompatible with the cluster FIPS and HSM settings. + t.Run("upsert", func(t *testing.T) { + t.Parallel() + for desc, tc := range testCases { + t.Run(desc, func(t *testing.T) { + t.Parallel() + cfg := TestAuthServerConfig{ + Dir: t.TempDir(), + FIPS: tc.fips, + } + if tc.hsm { + cfg.KeystoreConfig = keystore.HSMTestConfig(t) + } + testAuthServer, err := NewTestAuthServer(cfg) + require.NoError(t, err) + tlsServer, err := testAuthServer.NewTestTLSServer() + require.NoError(t, err) + clt, err := tlsServer.NewClient(TestAdmin()) + require.NoError(t, err) + + for _, suiteValue := range types.SignatureAlgorithmSuite_value { + suite := types.SignatureAlgorithmSuite(suiteValue) + t.Run(suiteName(suite), func(t *testing.T) { + authPref, err := types.NewAuthPreference(types.AuthPreferenceSpecV2{ + SignatureAlgorithmSuite: suite, + }) + require.NoError(t, err) + _, err = clt.UpsertAuthPreference(ctx, authPref) + if slices.Contains(tc.expectUnallowedSuites, suite) { + var badParameterErr *trace.BadParameterError + assert.ErrorAs(t, err, &badParameterErr) + } else { + assert.NoError(t, err) + } + }) + } + }) + } + }) +} + type testDynamicallyConfigurableParams struct { withDefaults, withConfigFile, withAnotherConfigFile func(*testing.T, *InitConfig) types.ResourceWithOrigin setDynamic func(*testing.T, *Server) diff --git a/lib/auth/keystore/manager.go b/lib/auth/keystore/manager.go index 8d46840511676..3fb4ebac11308 100644 --- a/lib/auth/keystore/manager.go +++ b/lib/auth/keystore/manager.go @@ -643,10 +643,19 @@ func (m *Manager) hasUsableKeys(ctx context.Context, keySet types.CAKeySet) (*Us return result, nil } +// DeleteUnusedKeys deletes any keys from the backend that were created by this +// cluster and are not present in [activeKeys]. func (m *Manager) DeleteUnusedKeys(ctx context.Context, activeKeys [][]byte) error { return trace.Wrap(m.backendForNewKeys.deleteUnusedKeys(ctx, activeKeys)) } +// UsingHSMOrKMS returns true if the keystore is configured to use an HSM or KMS +// when generating new keys. +func (m *Manager) UsingHSMOrKMS() bool { + _, usingSoftware := m.backendForNewKeys.(*softwareKeyStore) + return !usingSoftware +} + // keyType returns the type of the given private key. func keyType(key []byte) types.PrivateKeyType { if bytes.HasPrefix(key, pkcs11Prefix) { diff --git a/lib/config/configuration.go b/lib/config/configuration.go index d294c3cb670fc..e2b0caf87b5ab 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -2548,6 +2548,13 @@ func Configure(clf *CommandLineFlags, cfg *servicecfg.Config, legacyAppFlags boo } } + if err := cfg.Auth.Preference.CheckSignatureAlgorithmSuite(types.SignatureAlgorithmSuiteParams{ + FIPS: clf.FIPS, + UsingHSMOrKMS: cfg.Auth.KeyStore != (servicecfg.KeystoreConfig{}), + }); err != nil { + return trace.Wrap(err) + } + // apply --skip-version-check flag. if clf.SkipVersionCheck { cfg.SkipVersionCheck = clf.SkipVersionCheck