Skip to content

Commit

Permalink
[GD-1819] Add readonly user to default RDS for givesource
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Ebmeier committed May 27, 2021
1 parent 2e5ae3f commit c05de1d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "givesource",
"version": "2.1.0",
"version": "2.1.1",
"description": "Pay-as-you-go highly scalable software application that helps community foundations set up and manage a platform where they can raise funds for non-profits through event pages.",
"license": "Apache-2.0",
"repository": {
Expand Down
42 changes: 42 additions & 0 deletions packages/cloudformation/templates/givesource-aurora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Parameters:
MinLength: '1'
Type: String
Default: readwrite
DatabaseReadonlyUser:
AllowedPattern: "[a-zA-Z0-9_]+"
ConstraintDescription: must be between 1 to 16 alphanumeric characters.
Description: The database readonly account user name, between 1 to 16 alphanumeric characters.
MaxLength: '16'
MinLength: '1'
Type: String
Default: readonly
DatabaseName:
Type: String
Default: givesource
Expand Down Expand Up @@ -132,6 +140,37 @@ Resources:
Roles:
- !Ref LambdaRole
- !Ref SecureLambdaRole
ReadonlyUserSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub ${StackName}/ReadonlyUserSecret
Description: Givesource database auto-generated readonly user password
GenerateSecretString:
SecretStringTemplate: !Sub '{"username": "${DatabaseReadonlyUser}", "database": "${DatabaseName}"}'
GenerateStringKey: password
PasswordLength: 32
ExcludeCharacters: '"@/\'
ReadonlyUserSecretAttachment:
Type: AWS::SecretsManager::SecretTargetAttachment
Properties:
SecretId: !Ref ReadonlyUserSecret
TargetId: !Ref RDSCluster
TargetType: AWS::RDS::DBCluster
SecretsManagerPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: readonly_user_secret_get
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- !Ref ReadonlyUserSecret
Roles:
- !Ref LambdaRole
- !Ref SecureLambdaRole
DBClusterParameterGroup:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Expand Down Expand Up @@ -199,6 +238,7 @@ Resources:
- !Ref AdminUserSecret
- !Ref MaintenanceUserSecret
- !Ref ReadwriteUserSecret
- !Ref ReadonlyUserSecret
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
BootstrapDatabaseLambdaFunction:
Expand All @@ -216,6 +256,7 @@ Resources:
ADMIN_DATABASE_SECRET_ID: !Sub ${StackName}/AdminUserSecret
MAINTENANCE_DATABASE_SECRET_ID: !Sub ${StackName}/MaintenanceUserSecret
READWRITE_DATABASE_SECRET_ID: !Sub ${StackName}/ReadwriteUserSecret
READONLY_DATABASE_SECRET_ID: !Sub ${StackName}/ReadonlyUserSecret
DATABASE_NAME: !Ref DatabaseName
FunctionName: !Sub ${StackName}-BootstrapDatabase
Handler: index.handle
Expand All @@ -237,6 +278,7 @@ Resources:
- AdminUserSecretAttachment
- MaintenanceUserSecretAttachment
- ReadwriteUserSecretAttachment
- ReadonlyUserSecretAttachment
MigrateDatabaseLambdaRole:
Type: AWS::IAM::Role
Properties:
Expand Down
8 changes: 6 additions & 2 deletions packages/lambda/src/database/bootstrapDatabase/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ exports.handle = function (event, context, callback) {
return Promise.all([
secretsManager.getSecretValue(process.env.AWS_REGION, process.env.ADMIN_DATABASE_SECRET_ID),
secretsManager.getSecretValue(process.env.AWS_REGION, process.env.MAINTENANCE_DATABASE_SECRET_ID),
secretsManager.getSecretValue(process.env.AWS_REGION, process.env.READWRITE_DATABASE_SECRET_ID)
secretsManager.getSecretValue(process.env.AWS_REGION, process.env.READWRITE_DATABASE_SECRET_ID),
secretsManager.getSecretValue(process.env.AWS_REGION, process.env.READONLY_DATABASE_SECRET_ID)
]);
}).then(function (secrets) {
const dbHost = process.env.DATABASE_HOST;
const dbName = process.env.DATABASE_NAME;
const adminSecret = JSON.parse(secrets.find(it => it['Name'] === process.env.ADMIN_DATABASE_SECRET_ID).SecretString);
const maintenanceSecret = JSON.parse(secrets.find(it => it['Name'] === process.env.MAINTENANCE_DATABASE_SECRET_ID).SecretString);
const readwriteSecret = JSON.parse(secrets.find(it => it['Name'] === process.env.READWRITE_DATABASE_SECRET_ID).SecretString);
const readonlySecret = JSON.parse(secrets.find(it => it['Name'] === process.env.READONLY_DATABASE_SECRET_ID).SecretString);

sequelize = new Sequelize({
host: adminSecret.host,
Expand All @@ -85,7 +87,9 @@ exports.handle = function (event, context, callback) {
'CREATE USER IF NOT EXISTS "' + maintenanceSecret.username + '"@"%" IDENTIFIED BY "' + maintenanceSecret.password + '"; ' +
'GRANT ALL PRIVILEGES ON `' + dbName+ '`.* TO "' + maintenanceSecret.username + '"@"%"; ' +
'CREATE USER IF NOT EXISTS "' + readwriteSecret.username + '"@"%" IDENTIFIED BY "' + readwriteSecret.password + '"; ' +
'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TEMPORARY TABLES, EXECUTE ON `' + dbName+ '`.* TO "' + readwriteSecret.username + '"@"%";'
'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TEMPORARY TABLES, EXECUTE ON `' + dbName+ '`.* TO "' + readwriteSecret.username + '"@"%";' +
'CREATE USER IF NOT EXISTS "' + readonlySecret.username + '"@"%" IDENTIFIED BY "' + readonlySecret.password + '"; ' +
'GRANT SELECT ON `' + dbName+ '`.* TO "' + readonlySecret.username + '"@"%";'
);
}).then(function () {
response.send(event, context, response.SUCCESS);
Expand Down

0 comments on commit c05de1d

Please sign in to comment.