From 1b6b6ff16d81d0827970fb227d30a697745797e1 Mon Sep 17 00:00:00 2001 From: rosstimothy <39066650+rosstimothy@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:02:35 -0500 Subject: [PATCH] Expose configuration to set maximum number of PKCS#11 sessions (#52768) The PKCS#11 that we use defaults to allowing 1024 concurrent sessions. If an HSM is configured with a lower limit it results in broken UX since the PKCS#11 library does not reuse open and available sessions until it has opened the maximum number of sessions that it can. While the library behavior is out of our control, we now allow users the ability to specify what their desired max and propagate it on to the PKCS#11 library so that it will not open more sessions than the HSM will allow. The auth config reference was updated to include `ca_key_params`. While these config options were somewhat discoverable via individual HSM guides, they were not mentioned in the auth reference. --- .../admin-guides/deploy-a-cluster/hsm.mdx | 9 ++++++ .../config-reference/auth-service.yaml | 31 +++++++++++++++++++ lib/auth/keystore/pkcs11.go | 9 +++--- lib/config/configuration.go | 1 + lib/config/configuration_test.go | 21 +++++++++++++ lib/config/fileconf.go | 2 ++ lib/service/servicecfg/auth.go | 13 ++++++++ 7 files changed, 82 insertions(+), 4 deletions(-) diff --git a/docs/pages/admin-guides/deploy-a-cluster/hsm.mdx b/docs/pages/admin-guides/deploy-a-cluster/hsm.mdx index 688d02f7eae53..b08146ca06738 100644 --- a/docs/pages/admin-guides/deploy-a-cluster/hsm.mdx +++ b/docs/pages/admin-guides/deploy-a-cluster/hsm.mdx @@ -284,6 +284,11 @@ auth_service: pin: ":" # pin_path can optionally be used to read the pin from a file # pin_path: /path/to/pin_file + + # max_sessions configures the maximum number of open sessions for the HSM. + # If not set, it will default to the minimum of 1024 or the MaxRWSessionCount + # reported by the PKCS#11 module for the token. If set, must be greater than 1. + max_sessions: 10 ``` @@ -308,6 +313,10 @@ auth_service: pin: "85cfpassword" # pin_path can optionally be used to read the pin from a file # pin_path: /path/to/pin_file + + # Optionally specify the maximum number of open sessions for the HSM. + # If not set, it will default to 1024. If set, must be greater than 1. + max_sessions: 10 ``` diff --git a/docs/pages/includes/config-reference/auth-service.yaml b/docs/pages/includes/config-reference/auth-service.yaml index 6967c5f814c02..e2cdc903fe838 100644 --- a/docs/pages/includes/config-reference/auth-service.yaml +++ b/docs/pages/includes/config-reference/auth-service.yaml @@ -415,3 +415,34 @@ auth_service: report_results: s3://audit-long-term/report_results # (Optional) Athena workgroup used by access monitoring queries (if not set, the default primary workgroup will be used). workgroup: access_monitoring_workgroup + # Enables storing CAs in an external Hardware Security Module(HSM) or Key Management Service(KMS) + # Only one of the options can be enbabled at a given time. + ca_key_params: + # Persist CAs to Google Cloud KMS. + gcp_kms: + # The fully qualified path to the GCP key ring where CAs are to be stored. + keyring: 'projects//locations//keyRings/' + # The protection level of the keys. Must be either SOFTWARE or HSM. + protection_level: 'SOFTWARE' + # Persist CAs to AWS KMS. + aws_kms: + # The AWS account where keys should be stored. + account: '123456789012' + # The AWS region where keys will be stored. + region: 'us-west-2' + # Persist CAs to a PKCS#11 compliant HSM. + pkcs11: + # this is the default install location of the PKCS#11 module for the HSM. + module_path: /opt/cloudhsm/lib/libcloudhsm_pkcs11.so + # slot_number is the PKCS#11 slot number to use for HSM connections. + slot_number: 0 + # token_label is the label of the PKCS#11 token to use for HSM connections. + token_label: 'hsm1' + # max_sessions configures the maximum number of open sessions for the HSM. + # If not set, it will default to the minimum of 1024 or the MaxRWSessionCount + # reported by the PKCS#11 module for the token. If set, must be greater than 1. + max_sessions: 10 + # pin is the PKCS#11 pin to use for HSM connections. + pin: '0001password' + # pin_path can optionally be used to read the pin from a file + # pin_path: /path/to/pin_file diff --git a/lib/auth/keystore/pkcs11.go b/lib/auth/keystore/pkcs11.go index ed48e8e789a8d..8e4630732a053 100644 --- a/lib/auth/keystore/pkcs11.go +++ b/lib/auth/keystore/pkcs11.go @@ -50,10 +50,11 @@ type pkcs11KeyStore struct { func newPKCS11KeyStore(config *servicecfg.PKCS11Config, opts *Options) (*pkcs11KeyStore, error) { cryptoConfig := &crypto11.Config{ - Path: config.Path, - TokenLabel: config.TokenLabel, - SlotNumber: config.SlotNumber, - Pin: config.PIN, + Path: config.Path, + TokenLabel: config.TokenLabel, + SlotNumber: config.SlotNumber, + Pin: config.PIN, + MaxSessions: config.MaxSessions, } ctx, err := crypto11.Configure(cryptoConfig) diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 326f276989fa8..5dfcfd2058e2f 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -1119,6 +1119,7 @@ func applyPKCS11Config(pkcs11Config *PKCS11, cfg *servicecfg.Config) error { cfg.Auth.KeyStore.PKCS11.TokenLabel = pkcs11Config.TokenLabel cfg.Auth.KeyStore.PKCS11.SlotNumber = pkcs11Config.SlotNumber + cfg.Auth.KeyStore.PKCS11.MaxSessions = pkcs11Config.MaxSessions cfg.Auth.KeyStore.PKCS11.PIN = pkcs11Config.PIN if pkcs11Config.PINPath != "" { diff --git a/lib/config/configuration_test.go b/lib/config/configuration_test.go index 1a5b7b3a58852..836c64a8af983 100644 --- a/lib/config/configuration_test.go +++ b/lib/config/configuration_test.go @@ -3180,6 +3180,27 @@ func TestApplyKeyStoreConfig(t *testing.T) { worldReadablePinFilePath, ), }, + { + name: "correct config with max sessions", + auth: Auth{ + CAKeyParams: &CAKeyParams{ + PKCS11: &PKCS11{ + ModulePath: securePKCS11LibPath, + TokenLabel: "foo", + SlotNumber: &slotNumber, + MaxSessions: 100, + }, + }, + }, + want: servicecfg.KeystoreConfig{ + PKCS11: servicecfg.PKCS11Config{ + TokenLabel: "foo", + SlotNumber: &slotNumber, + MaxSessions: 100, + Path: securePKCS11LibPath, + }, + }, + }, { name: "correct gcp config", auth: Auth{ diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index 44e72850c65ae..baf6ac16c0d3c 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -893,6 +893,8 @@ type PKCS11 struct { // Trailing newlines will be removed, other whitespace will be left. Set // this or Pin to set the pin. PINPath string `yaml:"pin_path,omitempty"` + // MaxSessions is the upper limit of sessions allowed by the HSM. + MaxSessions int `yaml:"max_sessions"` } // GoogleCloudKMS configures Google Cloud Key Management Service to to be used for diff --git a/lib/service/servicecfg/auth.go b/lib/service/servicecfg/auth.go index 1b09042215aed..5f8bb96a9c316 100644 --- a/lib/service/servicecfg/auth.go +++ b/lib/service/servicecfg/auth.go @@ -235,6 +235,8 @@ type PKCS11Config struct { TokenLabel string // PIN is the PKCS11 PIN for the given token. PIN string + // MaxSessions is the upper limit of sessions allowed by the HSM. + MaxSessions int } // CheckAndSetDefaults checks that required parameters of the config are @@ -246,6 +248,17 @@ func (cfg *PKCS11Config) CheckAndSetDefaults() error { if cfg.SlotNumber == nil && cfg.TokenLabel == "" { return trace.BadParameter("must provide one of SlotNumber or TokenLabel") } + + switch { + case cfg.MaxSessions < 0: + return trace.BadParameter("the value of PKCS11 MaxSessions must not be negative") + case cfg.MaxSessions == 1: + return trace.BadParameter("the minimum value for PKCS11 MaxSessions is 2") + case cfg.MaxSessions == 0: + // A value of zero is acceptable and indicates to the pkcs11 library to use the default value. + default: + } + return nil }