Securing passwords in AWS Quick Starts using AWS Secrets Manager
A secure password is more than eight characters long and is complex — including lowercase letters, uppercase letters, numbers, and special characters. Complex passwords tend to be hard to remember, which is partly what makes them more secure. Complex passwords can also be hard to come up with. For these reasons, prompting a human for a password might not be suitable during an automated deployment.
Secrets Manager can generate a Secure password and store it for use, which negates the need for human interaction in an automation workflow.
The following code block demonstrates how this is done through AWS CloudFormation by using the AWS:: SecretsManager:: Secret resource type.
RestoreModeSecrets:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub ‘RestoreModeSecrets-${AWS::StackName}’
Description: Restore Mode Password for AD Quick Start
GenerateSecretString:
SecretStringTemplate: ‘{“username”: “Administrator”}’ GenerateStringKey: “password”
PasswordLength: 30
By default, Secrets Manager will create a 32-character password that includes uppercase letters, lowercase letters, numbers, and special characters. You can also use several properties with theGenerateSecretString
property type to customize the password as needed. TheSecretStringTemplate
in this case is setting the user name for this secret. TheGenerateStringKey
is specifying the key for which you want to generate the random string.
I prompt for the password through AWS CloudFormation parameters. Admin credentials are prompted for by using a code block that is similar to the following SQL Service parameter example.
SQLServiceAccount:
AllowedPattern: '[a-zA-Z0-9]*'
Default: sqlsa
Description: User name for the SQL Server Service Account.
MaxLength: '25'
MinLength: '5'
Type: String
SQLServiceAccountPassword:
Description: Password for the SQL Service account.
MaxLength: '32'
MinLength: '8'
NoEcho: 'true'
Type: String
In the SQLServiceAccountPasswordparameter, I use theNoEchoproperty type, which ensures that the password doesn’t appear in clear text while the template is launched.
SQLSecrets:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub 'AWSQuickStart/${AWS::StackName}/SQLSecrets'
Description: MS SQL Credentials for Quick Start
SecretString: !Sub '{ "username" : "${SQLServiceAccount}", "password" : "${SQLServiceAccountPassword}" }'
Retrieving secrets
You can retrieve secrets from Secrets Manager by using Windows PowerShell and Python within a script. And you can retrieve secrets from Secrets Manager for use within AWS CloudFormation.
The following sample code, retrieves a password.
import boto3
from botocore.exceptions import ClientError
from botocore.exceptions import ClientError
def get_secret():
secret_name = "MySecretName"
region_name = "us-west-2"
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name,
)
try:
get_secret_value_response = client.get_secret_value( SecretId=secret_name
)
except ClientError as e:
if e.response['Error']['Code'] == 'ResourceNotFoundException': print("The requested secret " + secret_name + " was not found") elif e.response['Error']['Code'] == 'InvalidRequestException': print("The request was invalid due to:", e)
elif e.response['Error']['Code'] == 'InvalidParameterException':
print("The request had invalid params:", e)
else:
# Secrets Manager decrypts the secret value using the associated KMSCMK
# Depending on whether the secret was a string or binary, only one of these fields will be populated if 'SecretString' in get_secret_value_response:
text_secret_data = get_secret_value_response['SecretString']
else:
binary_secret_data = get_secret_value_response['SecretBinary']
# Your code goes here.
Another way to pass secrets in AWS CloudFormation is by using dynamic references in the stack template.
MyRDSInstance:
Type: 'AWS::RDS::DBInstance'
Properties:
DBName: MyRDSInstance
AllocatedStorage: '20'
DBInstanceClass: db.t2.micro
Engine: mysql MasterUsername:'{{resolve:secretsmanager:MyRDSSecret:SecretString:username}' MasterUserPassword:'{{resolve:secretsmanager:MyRDSSecret:SecretString:password}}'