
AWS Secret Manager is a great solution for secret management. It is similar to HarshiCorp Vault, but with better integrations with other AWS services, e.g. IAM, RDS, Redshift, DocumentDB.
As illustrated above, I created a database in RDS and a credential in Secret Manager, then attached the credential to the database for dynamic reference. The benefit of doing that is I don’t need to provide the hardcoded password when creating the database, it is generated by secret manager and associate with the database. So whenever the credential in secret manager is changed (e.g password rotation), the database will change the password in RDS accordingly. To access the database, the EC2 instance or any services that can assume roles retrieve the password from the secret manager.
Here is the CloudFormation sample:
Resources:
DbMasterUserPassword:
Type: 'AWS::SecretsManager::Secret'
Properties:
Name: !Sub /${AppName}/database/master
Description: !Sub DB master user (postgres) password for ${AppName}-${Env}
GenerateSecretString:
SecretStringTemplate: '{"username": "postgres"}'
GenerateStringKey: "password"
PasswordLength: 16
ExcludeCharacters: '"@/\'
KmsKeyId: !ImportValue EnvKmsKeyId
Tags:
- Key: Name
Value: !Join [ "-", [ !Ref AppName, !Ref Env, db ] ]
Db:
Type: "AWS::RDS::DBInstance"
Properties:
AllocatedStorage: !Ref DbAllocatedStorage
AutoMinorVersionUpgrade: !Ref DbAutoMinorVersionUpgrade
BackupRetentionPeriod: !Ref DbBackupRetentionPeriod
DBName: !If [RestoreFromSnapshot, !Ref 'AWS::NoValue', !Ref DbName]
DBInstanceClass: !Ref DbInstanceClass
DBInstanceIdentifier: !Join [ "-", [ !Ref AppName, !Ref Env, db ] ]
DBSubnetGroupName: !Ref DbSubnetGroup
DBSnapshotIdentifier: !If [RestoreFromSnapshot, !Ref RestoreSnapshot, !Ref 'AWS::NoValue']
Engine: postgres
EngineVersion: !Ref DbEngineVersion
Iops: !If [DbProvisionedIops, !Ref DbIops, !Ref 'AWS::NoValue']
KmsKeyId: !If [UseDatabaseEncryption, !ImportValue EnvKmsKeyId, !Ref 'AWS::NoValue']
MasterUsername: postgres
MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref DbMasterUserPassword, ':SecretString:password}}' ]]
MultiAZ: !Ref DbMultiAZ
StorageEncrypted: !If [UseDatabaseEncryption, !Ref DbAllocatedStorageEncrypted, !Ref 'AWS::NoValue']
StorageType: !If [DbProvisionedIops, io1, gp2]
Tags:
- Key: Name
Value: !Join [ "-", [ !Ref AppName, !Ref Env, db ] ]
SecretRDSInstanceAttachment:
Type: "AWS::SecretsManager::SecretTargetAttachment"
Properties:
SecretId: !Ref DbMasterUserPassword
TargetId: !Ref Db
TargetType: AWS::RDS::DBInstance
To retrieve the password from the AWS secret manager, you can use AWS CLI or SDK. Also Ansible lookup plugin supports it too. Here is a example to retrieve above password.
"{{ (lookup('aws_secret', '/AppName/database/master', region='ap-southeast-2')| from_json).get('password') }}"
One thought on “Use AWS Secret Manager to handle credentials”