AWS Secrets Manager helps us to manage, retrieve, and rotate database credentials, application credentials, OAuth tokens, API keys, and other secrets throughout their lifecycles. Many AWS services store and use secrets in Secrets Manager.

Secrets Manager also helps us to improve our security posture, because we no longer need hard-coded credentials in application source code. Storing the credentials in Secrets Manager helps avoid possible compromise by anyone who can inspect our application or the components. We replace hard-coded credentials with a runtime call to the Secrets Manager service to retrieve credentials dynamically when our application need them.

With Secrets Manager, we can configure an automatic rotation schedule for our secrets. This enables us to replace long-term secrets with short-term ones, significantly reducing the risk of compromise. Since the credentials are no longer stored with the application, rotating credentials no longer requires updating the application codes and deploying changes to application clients.

Envelope Encryption

Secrets Manager uses envelope encryption with AWS KMS keys and data keys to protect each secret value. Whenever the secret value in a secret changes, Secrets Manager requests a new data key from AWS KMS to protect it. The data key is encrypted under a KMS key and stored in the metadata of the secret. To decrypt the secret, Secrets Manager first decrypts the encrypted data key using the KMS key in AWS KMS.

Secrets Manager does not use the KMS key to encrypt the secret value directly. Instead, it uses the KMS key to generate and encrypt a 256-bit Advanced Encryption Standard (AES) symmetric data key, and uses the data key to encrypt the secret value. Secrets Manager uses the plaintext data key to encrypt the secret value outside of AWS KMS, and then removes it from memory. It stores the encrypted copy of the data key in the metadata of the secret.

Example Code with Ruby

require 'aws-sdk-secretsmanager'
require 'json'

def get_secret(secrets_client, secret_name)
  # Retrieve the secret from Secrets Manager
  response = secrets_client.get_secret_value({
    secret_id: secret_name
  })
  secret = response.secret_string

  # Parse the secret and remove from memory
  parsed_secret = JSON.parse(secret)
  secret.clear  # Clear the secret from memory
  parsed_secret
end

# Initialize AWS client
region = 'your-region'
secrets_client = Aws::SecretsManager::Client.new(region: region)

# Retrieve the secret_name from environment variable
secret_name = ENV['SECRET_NAME']

# Retrieve the secret using the secret_name
secrets = get_secret(secrets_client, secret_name)
puts secrets