Skip to content

Instantly share code, notes, and snippets.

@monkey-codes
Last active June 17, 2020 01:13
Show Gist options
  • Select an option

  • Save monkey-codes/e988f9c2721a3b05812e972ce04f3db7 to your computer and use it in GitHub Desktop.

Select an option

Save monkey-codes/e988f9c2721a3b05812e972ce04f3db7 to your computer and use it in GitHub Desktop.
CFN Generate Credentials
Resources:
...
GenerateCredentialsRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub "${AWS::StackName}-GenerateCredentials-Lambda"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'sts:AssumeRole'
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: WriteCloudWatchLogs
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: 'arn:aws:logs:*:*:*'
- PolicyName: paramspolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: 'Allow'
Action:
- 'ssm:GetParameters'
- 'ssm:DescribeParameters'
- 'ssm:PutParameter'
- 'ssm:GetParameter'
- 'ssm:DeleteParameter'
Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*'
- PolicyName: InvokeLambdaFunction
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'lambda:InvokeFunction'
Resource: 'arn:aws:lambda:*:*:function:*'
GenerateCredentialsLambda:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: !Sub "${AWS::StackName}-GenerateCredentials"
Runtime: python3.6
Code:
S3Bucket: !Ref CodeBucket
S3Key: !Ref CodeBucketKey
Handler: generate_credentials.handler
Timeout: '180'
Role: !GetAtt GenerateCredentialsRole.Arn
Resources:
...
GenerateCredentialsCallout:
Type: Custom::LambdaCallout
DependsOn: [ KMSKey ]
Properties:
ServiceToken: {'Fn::ImportValue': !Sub '${CfnLambdasStackName}:GenerateCredentialsLambda'}
Arguments:
Hierarchy: !Sub '/${Environment}/rds/cluster'
Username: !Ref ClusterUsername
SSMUsernameKey: !Ref ClusterUsernameSSMKey
SSMPasswordKey: !Ref ClusterPasswordSSMKey
KMSKeyId: !Ref KMSKey
DBCluster:
Type: AWS::RDS::DBCluster
Properties:
AvailabilityZones: [!Select [ 0, !GetAZs '' ], !Select [ 1, !GetAZs '' ]]
BackupRetentionPeriod: 1
Engine: aurora-postgresql
DBClusterIdentifier: !Sub '${AWS::StackName}-Cluster'
DBClusterParameterGroupName: !Ref DBClusterParameterGroup
DBSubnetGroupName: !Ref DBSubnetGroup
MasterUsername: !Ref ClusterUsername
MasterUserPassword: !GetAtt GenerateCredentialsCallout.Password
PreferredBackupWindow: '16:00-18:00'
PreferredMaintenanceWindow: 'sun:13:30-sun:15:30'
Port: !Ref Port
StorageEncrypted: 'true'
VpcSecurityGroupIds:
- !Ref SecurityGroup
...
def handle(event, context):
log.info(event)
arguments = event['ResourceProperties']['Arguments']
ssm_username_key = arguments['SSMUsernameKey']
ssm_password_key = arguments['SSMPasswordKey']
hierarchy = arguments['Hierarchy']
username = get_parameter_safely('%s/%s' % (hierarchy, ssm_username_key), False)
password = get_parameter_safely('%s/%s' % (hierarchy, ssm_password_key), True)
if not username or username != arguments['Username']:
log.info("Creating or updating username")
username = arguments['Username']
response = client.put_parameter(
Name = '%s/%s' % (hierarchy,ssm_username_key),
Value = username,
Type = 'String',
Overwrite = True
)
log.info(response)
if not password:
log.info("Creating or updating password")
password = generate_password()
response = client.put_parameter(
Name = '%s/%s' % (hierarchy, ssm_password_key),
Value = password,
Type = 'SecureString',
KeyId = arguments['KMSKeyId'],
Overwrite = False
)
log.info(response)
return {
"PhysicalResourceId": "arn:aws:fake:generate-credentials",
"Data": {
"Username": username,
"Password": password
}
}
def get_parameter_safely(name, decrypt):
try:
client = boto3.client('ssm', region_name='ap-southeast-2')
response = client.get_parameter(
Name = name,
WithDecryption = decrypt
)
return response['Parameter']['Value']
except ClientError as e:
log.error("Cannot get parameter {} safely: {}".format(name, e))
return None
@handler.create
def create_credentials(event, context):
log.info("Creating credentials")
return handle(event, context)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment