Skip to content

Commit 892df2a

Browse files
authored
add a shedule for blocking s3 bucket for writing (#319)
1 parent ccf17fa commit 892df2a

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

data-exports/deploy/data-exports-aggregation.yaml

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,23 @@ Parameters:
117117
Type: String
118118
Description: Leave Empty. A Bucket name for optional supplementary data replication. If not empty, the export data will be replicated to this bucket in addition to the default replication destination. Keep it empty if unsure.
119119
Default: ''
120+
AddScheduleForBlockingWrite:
121+
Type: String
122+
Description: 'Set yes to schedule Disabling/Enabling schedule to stop CUR replication for a short period of time to secure QuickSight Dataset refresh.'
123+
Default: "no"
124+
AllowedValues: ["yes", "no"]
125+
DisableWriteCronSchedule:
126+
Type: String
127+
Description: 'Cron expression for disabling replication (UTC)'
128+
Default: '0 1 * * ? *'
129+
AllowedPattern: '^[0-9*,\-/\s?]+$'
130+
ConstraintDescription: Must be a valid cron expression
131+
EnableWriteCronSchedule:
132+
Type: String
133+
Description: 'Cron expression for enabling replication (UTC)'
134+
Default: '0 3 * * ? *'
135+
AllowedPattern: '^[0-9*,\-/\s?]+$'
136+
ConstraintDescription: Must be a valid cron expression
120137

121138
Conditions:
122139
EmptySourceAccountIds: !Equals [ !Ref SourceAccountIds, '']
@@ -162,6 +179,10 @@ Conditions:
162179
NeedLakeFormationEnabledCOH: !And [!Condition NeedLakeFormationEnabledDB, !Condition ManageCOH]
163180
NeedLakeFormationEnabledCUR2: !And [!Condition NeedLakeFormationEnabledDB, !Condition ManageCUR2]
164181
NeedLakeFormationEnabledFOCUS: !And [!Condition NeedLakeFormationEnabledDB, !Condition ManageFOCUS]
182+
DeployWriteBlocker:
183+
Fn::And:
184+
- !Condition IsDestinationAccount
185+
- !Equals [!Ref AddScheduleForBlockingWrite, "yes"]
165186

166187
Mappings:
167188
DataExports:
@@ -502,6 +523,118 @@ Resources:
502523
- !Sub "arn:${AWS::Partition}:s3:::${ResourcePrefix}-${DestinationAccountId}-data-exports/*/${AWS::AccountId}/*"
503524
- !If [NonEmptySecondaryDestinationBucket, !Sub "arn:${AWS::Partition}:s3:::${SecondaryDestinationBucket}/*/${AWS::AccountId}/*", !Ref 'AWS::NoValue']
504525

526+
BucketWriteBlockerLambdaRole:
527+
Type: AWS::IAM::Role
528+
Condition: DeployWriteBlocker
529+
Properties:
530+
AssumeRolePolicyDocument:
531+
Version: '2012-10-17'
532+
Statement:
533+
- Effect: Allow
534+
Principal:
535+
Service: lambda.amazonaws.com
536+
Action: sts:AssumeRole
537+
ManagedPolicyArns:
538+
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
539+
Policies:
540+
- PolicyName: BucketPolicyAccess
541+
PolicyDocument:
542+
Version: '2012-10-17'
543+
Statement:
544+
- Effect: Allow
545+
Action:
546+
- s3:GetBucketPolicy
547+
- s3:PutBucketPolicy
548+
Resource: !GetAtt DestinationS3.Arn
549+
550+
BucketWriteBlockerPolicyLambda:
551+
Type: AWS::Lambda::Function
552+
Condition: DeployWriteBlocker
553+
Properties:
554+
Runtime: python3.12
555+
Handler: index.lambda_handler
556+
FunctionName: !Sub ${ResourcePrefix}-CID-WriteBlocker
557+
Role: !GetAtt BucketWriteBlockerLambdaRole.Arn
558+
Code:
559+
ZipFile: |
560+
import os
561+
import json
562+
import boto3
563+
564+
POLICY_SID = os.environ['POLICY_SID']
565+
BUCKET_NAME = os.environ['BUCKET_NAME']
566+
s3 = boto3.client('s3')
567+
568+
def lambda_handler(event, context):
569+
action = event.get('action', 'enable') # 'enable' or 'disable'
570+
try:
571+
policy = json.loads(s3.get_bucket_policy(Bucket=BUCKET_NAME)['Policy'])
572+
# Find and modify the policy statement
573+
for statement in policy['Statement']:
574+
if statement.get('Sid') == POLICY_SID:
575+
statement['Effect'] = 'Allow' if action == 'enable' else 'Deny'
576+
break
577+
else:
578+
raise Exception(f'{POLICY_SID} statement not found in policy')
579+
s3.put_bucket_policy(Bucket=BUCKET_NAME, Policy=json.dumps(policy))
580+
return {'statusCode': 200, 'body': f'Successfully {action}d {POLICY_SID} statement'}
581+
except Exception as e:
582+
return {'statusCode': 500, 'body': str(e) }
583+
Environment:
584+
Variables:
585+
BUCKET_NAME: !Ref DestinationS3
586+
POLICY_SID: 'AllowReplicationWrite'
587+
MemorySize: 128
588+
Timeout: 60
589+
Metadata:
590+
cfn_nag:
591+
rules_to_suppress:
592+
- id: 'W89'
593+
reason: "This Lambda does not require VPC"
594+
- id: 'W92'
595+
reason: "One Time execution. No need for ReservedConcurrentExecutions"
596+
DisableRuleSchedule:
597+
Type: AWS::Events::Rule
598+
Condition: DeployWriteBlocker
599+
Properties:
600+
Description: !Sub "Schedule for disabling replication using cron: ${DisableWriteCronSchedule}"
601+
ScheduleExpression: !Sub "cron(${DisableWriteCronSchedule})"
602+
State: ENABLED
603+
Targets:
604+
- Arn: !GetAtt BucketWriteBlockerPolicyLambda.Arn
605+
Id: "DisableReplicationTarget"
606+
Input: '{"action": "disable"}'
607+
608+
EnableRuleSchedule:
609+
Type: AWS::Events::Rule
610+
Condition: DeployWriteBlocker
611+
Properties:
612+
Description: !Sub "Schedule for enabling replication using cron: ${EnableWriteCronSchedule}"
613+
ScheduleExpression: !Sub "cron(${EnableWriteCronSchedule})"
614+
State: ENABLED
615+
Targets:
616+
- Arn: !GetAtt BucketWriteBlockerPolicyLambda.Arn
617+
Id: "EnableReplicationTarget"
618+
Input: '{"action": "enable"}'
619+
620+
LambdaPermissionDisable:
621+
Type: AWS::Lambda::Permission
622+
Condition: DeployWriteBlocker
623+
Properties:
624+
FunctionName: !Ref BucketWriteBlockerPolicyLambda
625+
Action: lambda:InvokeFunction
626+
Principal: events.amazonaws.com
627+
SourceArn: !GetAtt DisableRuleSchedule.Arn
628+
629+
LambdaPermissionEnable:
630+
Type: AWS::Lambda::Permission
631+
Condition: DeployWriteBlocker
632+
Properties:
633+
FunctionName: !Ref BucketWriteBlockerPolicyLambda
634+
Action: lambda:InvokeFunction
635+
Principal: events.amazonaws.com
636+
SourceArn: !GetAtt EnableRuleSchedule.Arn
637+
505638
# CUR2
506639

507640
## Deploy Data Export natively via CFN resource in regions that support native CFN

0 commit comments

Comments
 (0)