diff --git a/cmd/common-main.go b/cmd/common-main.go index 243af20ee..0b9ea911d 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -24,6 +24,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/gob" + "encoding/pem" "errors" "fmt" "io/ioutil" @@ -798,7 +799,29 @@ func handleCommonEnvVars() { endpoints = append(endpoints, strings.Join(lbls, "")) } } - certificate, err := tls.LoadX509KeyPair(env.Get(config.EnvKESClientCert, ""), env.Get(config.EnvKESClientKey, "")) + // Manually load the certificate and private key into memory. + // We need to check whether the private key is encrypted, and + // if so, decrypt it using the user-provided password. + certBytes, err := os.ReadFile(env.Get(config.EnvKESClientCert, "")) + if err != nil { + logger.Fatal(err, "Unable to load KES client certificate as specified by the shell environment") + } + keyBytes, err := os.ReadFile(env.Get(config.EnvKESClientKey, "")) + if err != nil { + logger.Fatal(err, "Unable to load KES client private key as specified by the shell environment") + } + privateKeyPEM, rest := pem.Decode(bytes.TrimSpace(keyBytes)) + if len(rest) != 0 { + logger.Fatal(errors.New("private key contains additional data"), "Unable to load KES client private key as specified by the shell environment") + } + if x509.IsEncryptedPEMBlock(privateKeyPEM) { + keyBytes, err = x509.DecryptPEMBlock(privateKeyPEM, []byte(env.Get(config.EnvKESClientPassword, ""))) + if err != nil { + logger.Fatal(err, "Unable to decrypt KES client private key as specified by the shell environment") + } + keyBytes = pem.EncodeToMemory(&pem.Block{Type: privateKeyPEM.Type, Bytes: keyBytes}) + } + certificate, err := tls.X509KeyPair(certBytes, keyBytes) if err != nil { logger.Fatal(err, "Unable to load KES client certificate as specified by the shell environment") } diff --git a/docs/kms/README.md b/docs/kms/README.md index f5ec16e7d..1f1cda4df 100644 --- a/docs/kms/README.md +++ b/docs/kms/README.md @@ -120,6 +120,20 @@ Encrypted : X-Amz-Server-Side-Encryption: AES256 ``` +## Encrypted Private Key + +MinIO supports encrypted KES client private keys. Therefore, you can use +an password-protected private keys for `MINIO_KMS_KES_KEY_FILE`. + +When using password-protected private keys for accessing KES you need to +provide the password via: +``` +export MINIO_KMS_KES_KEY_PASSWORD= +``` + +Note that MinIO only supports encrypted private keys - not encrypted certificates. +Certificates are no secrets and sent in plaintext as part of the TLS handshake. + ## Explore Further - [Use `mc` with MinIO Server](https://docs.min.io/docs/minio-client-quickstart-guide) diff --git a/internal/config/constants.go b/internal/config/constants.go index 94a97dd7f..05a9f2674 100644 --- a/internal/config/constants.go +++ b/internal/config/constants.go @@ -62,13 +62,14 @@ const ( EnvUpdate = "MINIO_UPDATE" - EnvKMSSecretKey = "MINIO_KMS_SECRET_KEY" - EnvKMSSecretKeyFile = "MINIO_KMS_SECRET_KEY_FILE" - EnvKESEndpoint = "MINIO_KMS_KES_ENDPOINT" - EnvKESKeyName = "MINIO_KMS_KES_KEY_NAME" - EnvKESClientKey = "MINIO_KMS_KES_KEY_FILE" - EnvKESClientCert = "MINIO_KMS_KES_CERT_FILE" - EnvKESServerCA = "MINIO_KMS_KES_CAPATH" + EnvKMSSecretKey = "MINIO_KMS_SECRET_KEY" + EnvKMSSecretKeyFile = "MINIO_KMS_SECRET_KEY_FILE" + EnvKESEndpoint = "MINIO_KMS_KES_ENDPOINT" + EnvKESKeyName = "MINIO_KMS_KES_KEY_NAME" + EnvKESClientKey = "MINIO_KMS_KES_KEY_FILE" + EnvKESClientPassword = "MINIO_KMS_KES_KEY_PASSWORD" + EnvKESClientCert = "MINIO_KMS_KES_CERT_FILE" + EnvKESServerCA = "MINIO_KMS_KES_CAPATH" EnvEndpoints = "MINIO_ENDPOINTS" // legacy EnvWorm = "MINIO_WORM" // legacy