Skip to content

Commit

Permalink
DAC-2203 Secret not scheduled for rotation (#536)
Browse files Browse the repository at this point in the history
Add redshift-rotate-secret lambda handler and tests
Add IaC code for lambda and related resources
Add new ensureDefined util to utils
Remove some duplicated code from quicksight-add-users handler
Add @aws-sdk/client-secrets-manager dependency and client in clients.ts
Add knex and pg dependencies for redshift access
Add some external packages to esbuild in build-lambdas script as a result of the new knex and pg dependencies
  • Loading branch information
hdavey-gds authored Feb 8, 2024
1 parent 3ce9f56 commit 78d540a
Show file tree
Hide file tree
Showing 14 changed files with 1,069 additions and 38 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pull-request-deploy-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
deploy-to-feature:
needs: [validate-deployment-or-teardown]
if: needs.validate-deployment-or-teardown.outputs.valid == 'true'
# These permissions are needed to interact with GitHub's OIDC Token endpoint (enabling the aws-actions/configure-aws-credentials action)
permissions:
id-token: write
Expand Down
8 changes: 8 additions & 0 deletions iac/main/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ Parameters:
Description: The ARN of the role that will used by secure pipelines to run integration tests
Default: none
AllowedPattern: (none)|(arn:aws:iam::.*:role/.*)
RedshiftSecretLength:
Type: Number
Description: Length of the redshift password stored in secretsmanager
Default: 16
RedshiftSecretExcludeCharacters:
Type: String
Description: String of characters to exclude from the redshift password stored in secretsmanager
Default: '"''@/\'

Conditions:
UseCodeSigning: !Not
Expand Down
14 changes: 14 additions & 0 deletions iac/main/resources/global.yml
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,20 @@ VPCEndpointS3:
RouteTableIds:
- !Ref RouteTableForDAP

VPCEndpointSecretsManager:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName: com.amazonaws.eu-west-2.secretsmanager
VpcId: !Ref VPCForDAP
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref LambdaSecurityGroup
SubnetIds:
- !Ref SubnetForDAP1
- !Ref SubnetForDAP2
- !Ref SubnetForDAP3

VPCEndpointSQS:
Type: AWS::EC2::VPCEndpoint
Properties:
Expand Down
87 changes: 82 additions & 5 deletions iac/main/resources/redshift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,98 @@ RedshiftSecret:
Properties:
Description: This is a Secrets Manager secret for a Redshift cluster
GenerateSecretString:
SecretStringTemplate: '{"username": "admin"}'
# based on https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_secret_json_structure.html#reference_secret_json_structure_RS
SecretStringTemplate: !Sub |
{
"engine": "redshift",
"host": "${Environment}-redshift-serverless-workgroup.${AWS::AccountId}.${AWS::Region}.redshift-serverless.amazonaws.com",
"username": "admin",
"dbname": "${Environment}-redshift",
"port": "5439"
}
GenerateStringKey: password
PasswordLength: 16
ExcludeCharacters: '"''@/\'
PasswordLength: !Ref RedshiftSecretLength
ExcludeCharacters: !Ref RedshiftSecretExcludeCharacters
KmsKeyId: !Ref KmsKey
Tags:
- Key: RedshiftUser
Value: admin

RedshiftSecretRotationSchedule:
Type: AWS::SecretsManager::RotationSchedule
Properties:
RotationLambdaARN: !GetAtt RedshiftSecretRotationLambda.Arn
RotationRules:
ScheduleExpression: cron(0 2 1 * ? *) # the first day of every month at 2am
SecretId: !Ref RedshiftSecret

RedshiftSecretRotationLambda:
# checkov:skip=CKV_AWS_116: DLQ not needed
Type: AWS::Serverless::Function
Properties:
FunctionName: redshift-rotate-secret
Handler: redshift-rotate-secret.handler
Policies:
- AWSLambdaBasicExecutionRole
- Statement:
- Effect: Allow
Action:
- 'sqs:DeleteMessage'
- 'sqs:GetQueueAttributes'
- 'sqs:ReceiveMessage'
Resource: !If [UsePlaceholderTxMAQueue, !GetAtt EventConsumerQueue.Arn, '{{resolve:ssm:TxMAEventQueueARN}}']
- Effect: Allow
Action:
- secretsmanager:DescribeSecret
- secretsmanager:GetSecretValue
- secretsmanager:PutSecretValue
- secretsmanager:UpdateSecretVersionStage
Resource: !Ref RedshiftSecret
- Effect: Allow
Action: secretsmanager:GetRandomPassword
Resource: '*'
- Effect: Allow
Action:
- kms:Decrypt
- kms:DescribeKey
- kms:GenerateDataKey
Resource: !GetAtt KmsKey.Arn
Condition:
StringEquals:
kms:EncryptionContext:SecretARN: !Ref RedshiftSecret
ReservedConcurrentExecutions: 10
Environment:
# checkov:skip=CKV_AWS_173: These environment variables do not require encryption
Variables:
PASSWORD_LENGTH: !Ref RedshiftSecretLength
PASSWORD_EXCLUDE_CHARS: !Ref RedshiftSecretExcludeCharacters
ENVIRONMENT: !Ref Environment
Tags:
Environment: !Ref Environment
MemorySize: 256
VpcConfig:
SecurityGroupIds:
- !Ref LambdaSecurityGroup
- !Ref RedshiftAccessEC2SecurityGroup
SubnetIds:
- !Ref SubnetForDAP1
- !Ref SubnetForDAP2
- !Ref SubnetForDAP3

RedshiftSecretRotationLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref RedshiftSecretRotationLambda
Action: lambda:InvokeFunction
Principal: secretsmanager.amazonaws.com
SourceArn: !Ref RedshiftSecret

RedshiftServerlessNamespace:
Type: 'AWS::RedshiftServerless::Namespace'
Properties:
AdminUsername: !Sub '{{resolve:secretsmanager:${RedshiftSecret}::username}}'
AdminUserPassword: !Sub '{{resolve:secretsmanager:${RedshiftSecret}::password}}'
DbName: !Sub '${Environment}-redshift'
DbName: !Sub '{{resolve:secretsmanager:${RedshiftSecret}::dbname}}'
DefaultIamRoleArn: !GetAtt IAMRoleRedshiftServerless.Arn
IamRoles:
- !GetAtt IAMRoleRedshiftServerless.Arn
Expand All @@ -74,7 +151,7 @@ RedshiftServerlessWorkgroup:
BaseCapacity: 64
EnhancedVpcRouting: false
NamespaceName: !Ref RedshiftServerlessNamespace
Port: 5439
Port: !Sub '{{resolve:secretsmanager:${RedshiftSecret}::port}}'
PubliclyAccessible: false
SubnetIds:
- !Ref SubnetForDAP1
Expand Down
Loading

0 comments on commit 78d540a

Please sign in to comment.