CloudFormation can pull secret values directly from AWS Secrets Manager, bypassing the need to store sensitive data in your template.

Let’s see it in action with a simple AWS::SSM::Parameter resource that references a secret.

Resources:
  MySecretParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: my-app-db-password
      Type: String
      Value: !Ref MySecret
  MySecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: my-app-db-password
      # You would typically add SecretString or generate a new secret here
      # For demonstration, we assume the secret already exists in Secrets Manager
      # and we are just creating a reference to it.

Here, MySecretParameter is configured to store its value from MySecret. The !Ref MySecret intrinsic function tells CloudFormation to look up the value of the MySecret resource. If MySecret is of type AWS::SecretsManager::Secret, CloudFormation knows to fetch the secret value from AWS Secrets Manager.

The core problem this solves is avoiding the hardcoding of credentials or sensitive configuration data within your infrastructure-as-code templates. Storing secrets directly in CloudFormation templates is a major security vulnerability. By dynamically referencing secrets, you ensure that sensitive information remains securely managed within AWS Secrets Manager, with its own access control policies and rotation capabilities.

When CloudFormation processes a template that references a secret, it doesn’t directly embed the secret’s value into the template’s output or the deployed resource’s metadata. Instead, it uses the SecretsManager service’s API to retrieve the secret’s value at deployment time. This means the secret value is only present in memory for the brief period CloudFormation needs it to provision the target resource.

The AWS::SSM::Parameter resource is often used as an intermediary because it’s a common pattern to store application configuration in Systems Manager Parameter Store, and then reference those parameters from your applications. You can also directly reference secrets in other resource types, like AWS::RDS::DBInstance for database passwords, or AWS::EC2::LaunchTemplate for user data scripts.

Consider this example for an RDS instance:

Resources:
  MyRDSInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: my-database
      AllocatedStorage: 20
      Engine: postgres
      MasterUsername: admin
      MasterUserPassword: !Ref DBSecretPassword
      # ... other RDS properties
  DBSecretPassword:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: my-rds-db-password
      # ... secret configuration

In this scenario, the MasterUserPassword for the RDS instance is pulled directly from a secret named my-rds-db-password managed by AWS Secrets Manager. CloudFormation handles the lookup and injection.

The !Ref intrinsic function is your primary tool here. When used with a resource of type AWS::SecretsManager::Secret, it triggers the retrieval of the secret’s value. If you are referencing an existing secret not defined within the same CloudFormation stack, you’ll use the Fn::ImportValue or Fn::Sub functions in conjunction with an exported output from another stack, or directly use the Fn::Join or Fn::Sub to construct the ARN and then use Fn::GetAtt to retrieve the secret value, though !Ref is the most direct for secrets defined within or referenced by the current template.

To ensure this works, the IAM role or user executing the CloudFormation stack must have permissions to secretsmanager:GetSecretValue for the specific secret(s) being referenced. Without this permission, CloudFormation will fail during stack creation or update with an AccessDenied error.

One subtle but powerful aspect is how CloudFormation handles updates. If you update the secret in Secrets Manager after the resource has been deployed, CloudFormation will not automatically update the deployed resource with the new secret value unless you explicitly trigger a stack update. This is a safety mechanism to prevent unexpected changes to running resources. To update the secret value on the resource, you would typically need to modify a property of the resource that depends on the secret, forcing CloudFormation to re-evaluate and re-fetch the updated secret value. For example, you might update a dummy parameter in your AWS::RDS::DBInstance resource to trigger a re-deployment.

The next challenge you’ll likely encounter is managing the lifecycle of these secrets, specifically how to rotate them securely and have CloudFormation or your applications consume the rotated credentials without downtime.

Want structured learning?

Take the full Cloudformation course →