-
-
Save monkey-codes/7791936dbdfe3c25e256697740a10af8 to your computer and use it in GitHub Desktop.
CFN Create Database Callout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Resources: | |
| ... | |
| CreateDatabaseRole: | |
| Type: 'AWS::IAM::Role' | |
| Properties: | |
| RoleName: !Sub "${AWS::StackName}-CreateDatabase-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' | |
| - 'ssm:DeleteParameters' | |
| 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:*' | |
| CreateDatabaseSecurityGroup: | |
| Type: AWS::EC2::SecurityGroup | |
| Properties: | |
| GroupName: !Sub '${AWS::StackName}-createdb-sg' | |
| GroupDescription: 'Used to provide lambda access to rds' | |
| VpcId: {'Fn::ImportValue': !Sub '${NetworkStackName}:VpcId'} | |
| SecurityGroupEgress: | |
| - IpProtocol: '-1' | |
| FromPort: '-1' | |
| ToPort: '-1' | |
| CidrIp: 0.0.0.0/0 | |
| CreateDatabaseLambda: | |
| Type: 'AWS::Lambda::Function' | |
| Properties: | |
| FunctionName: !Sub "${AWS::StackName}-CreateDatabase" | |
| Runtime: python3.6 | |
| Code: | |
| S3Bucket: !Ref CodeBucket | |
| S3Key: !Ref CodeBucketKey | |
| Handler: create_database.handler | |
| Timeout: '180' | |
| VpcConfig: | |
| SecurityGroupIds: [ !Ref CreateDatabaseSecurityGroup ] | |
| SubnetIds: | |
| - {'Fn::ImportValue': !Sub '${NetworkStackName}:PrivateSubnet1'} | |
| - {'Fn::ImportValue': !Sub '${NetworkStackName}:PrivateSubnet2'} | |
| Role: !GetAtt CreateDatabaseRole.Arn |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ... | |
| @handler.create | |
| def create_database(event, context): | |
| log.info("Creating RDS Database") | |
| handle(event, context) | |
| return {"PhysicalResourceId": "arn:aws:fake:rds-database"} | |
| def handle(event, context): | |
| arguments = event['ResourceProperties']['Arguments'] | |
| result = generate_credentials.handle(event, context) | |
| username = result["Data"]["Username"] | |
| password = result["Data"]["Password"] | |
| db_name = arguments["DatabaseName"] | |
| db_host = arguments["DatabaseHost"] | |
| db_port = arguments["DatabasePort"] | |
| db_admin_username = get_parameter_safely(arguments["SSMDBAdminUsernameKey"], False) | |
| db_admin_password = get_parameter_safely(arguments["SSMDBAdminPasswordKey"], True) | |
| create_db(db_host, db_port, db_admin_username, db_admin_password, db_name, username, password) | |
| def create_db(host, port, username, password, db_name, db_user, db_password): | |
| log.info('here') | |
| log.info('username: %s, host: %s, port: %s' % (username, host, port)) | |
| con = psycopg2.connect(database="postgres", user=username, password=password, host=host, port=port) | |
| con.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) | |
| log.info('Connected to db') | |
| if not db_exists(con, db_name): | |
| log.info("Creating database %s" % db_name) | |
| execute_update(con,"CREATE DATABASE %s" % db_name, {}) | |
| if not user_exists(con, db_user): | |
| log.info("Creating user %s" % db_user) | |
| params = { "username": db_user, "db_name": db_name, "password": db_password } | |
| execute_update(con, "CREATE USER %(username)s WITH ENCRYPTED PASSWORD '%(password)s'" % params, {}) | |
| execute_update(con, "GRANT ALL PRIVILEGES on DATABASE %(db_name)s to %(username)s" % params, {}) | |
| con.close() | |
| def db_exists(con, db_name): | |
| cur = con.cursor() | |
| cur.execute("SELECT 1 FROM pg_database WHERE datname = %(db_name)s", {"db_name": db_name}) | |
| rows = cur.fetchall() | |
| return len(rows) > 0 | |
| def user_exists(con, username): | |
| cur = con.cursor() | |
| cur.execute("SELECT 1 FROM pg_roles WHERE rolname = %(username)s", {"username": username}) | |
| rows = cur.fetchall() | |
| return len(rows) > 0 | |
| def execute_update(con, query, params): | |
| cur = con.cursor() | |
| cur.execute(query, params) | |
| con.commit() | |
| cur.close() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Resources: | |
| ... | |
| CreateServiceDatabase: | |
| Type: 'Custom::CreateDatabaseLambda' | |
| Properties: | |
| ServiceToken: {'Fn::ImportValue': !Sub '${CfnLambdasStackName}:CreateDatabaseLambda'} | |
| StackName: !Sub '${AWS::StackName}' | |
| Arguments: | |
| Hierarchy: !Sub '/${Environment}/${ServiceName}/db' | |
| Username: !Sub '${Environment}_${ServiceName}_user' | |
| SSMUsernameKey: 'username' | |
| SSMPasswordKey: 'password' | |
| KMSKeyId: !Ref KMSKey | |
| DatabaseName: !Sub '${Environment}_${ServiceName}' | |
| DatabaseHost: {'Fn::ImportValue': !Sub '${RDSStackName}:DBClusterEndpointAddress'} | |
| DatabasePort: {'Fn::ImportValue': !Sub '${RDSStackName}:DBClusterPort'} | |
| SSMDBAdminUsernameKey: !Sub '/${Environment}/rds/cluster/username' | |
| SSMDBAdminPasswordKey: !Sub '/${Environment}/rds/cluster/password' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment