使用Amazon CloudFormation使用的模板Amazon Backup - Amazon Backup
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用Amazon CloudFormation使用的模板Amazon Backup

正式发布

与Amazon CloudFormation,您可以预置和管理Amazon使用自己创建的模板以安全、可重复的方式发布。您可以使用 Amazon CloudFormation 模板管理备份计划、备份资源选择和备份文件库。有关使用Amazon CloudFormation,请参阅的方式Amazon CloudFormation工作?中的Amazon CloudFormation用户指南

在创建 Amazon CloudFormation 堆栈之前,您应该考虑以下几点:

  • 我们建议您为备份计划和备份文件库创建单独的模板。由于只有在备份文件库为空时才能将其删除,因此如果备份文件库包含任何恢复点,则无法删除包含备份文件库的堆栈。

  • 在创建堆栈之前,请确保您具有可用的服务角色。首次将资源分配给备份计划时,系统会为您创建 Amazon Backup 默认服务角色。如果您尚未执行此操作,则默认服务角色不可用。您还可以指定自己创建的自定义角色。有关 角色的更多信息,请参阅IAM 服务角色

我们提供两个样本Amazon CloudFormation模板以供参考。第一个模板创建一个简单的备份计划。第二个模板启用备份计划中的 VSS 备份。

Description: Backup Plan template to back up all resources tagged with backup=daily daily at 5am UTC. Resources: KMSKey: Type: AWS::KMS::Key Properties: Description: "Encryption key for daily" EnableKeyRotation: True Enabled: True KeyPolicy: Version: "2012-10-17" Statement: - Effect: Allow Principal: "AWS": { "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:root" } Action: - kms:* Resource: "*" BackupVaultWithDailyBackups: Type: "AWS::Backup::BackupVault" Properties: BackupVaultName: "BackupVaultWithDailyBackups" EncryptionKeyArn: !GetAtt KMSKey.Arn BackupPlanWithDailyBackups: Type: "AWS::Backup::BackupPlan" Properties: BackupPlan: BackupPlanName: "BackupPlanWithDailyBackups" BackupPlanRule: - RuleName: "RuleForDailyBackups" TargetBackupVault: !Ref BackupVaultWithDailyBackups ScheduleExpression: "cron(0 5 ? * * *)" DependsOn: BackupVaultWithDailyBackups DDBTableWithDailyBackupTag: Type: "AWS::DynamoDB::Table" Properties: TableName: "TestTable" AttributeDefinitions: - AttributeName: "Album" AttributeType: "S" KeySchema: - AttributeName: "Album" KeyType: "HASH" ProvisionedThroughput: ReadCapacityUnits: "5" WriteCapacityUnits: "5" Tags: - Key: "backup" Value: "daily" BackupRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "backup.amazonaws.com" Action: - "sts:AssumeRole" ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/service-role" TagBasedBackupSelection: Type: "AWS::Backup::BackupSelection" Properties: BackupSelection: SelectionName: "TagBasedBackupSelection" IamRoleArn: !GetAtt BackupRole.Arn ListOfTags: - ConditionType: "STRINGEQUALS" ConditionKey: "backup" ConditionValue: "daily" BackupPlanId: !Ref BackupPlanWithDailyBackups DependsOn: BackupPlanWithDailyBackups
注意

如果您使用的是默认服务角色,请将服务角色替换为AWSBackupServiceRolePolicyForBackup

使用 Windows VSS

Description: Backup Plan template to enable Windows VSS and add backup rule to take backup of assigned resources daily at 5am UTC. Resources: KMSKey: Type: AWS::KMS::Key Properties: Description: "Encryption key for daily" EnableKeyRotation: True Enabled: True KeyPolicy: Version: "2012-10-17" Statement: - Effect: Allow Principal: "AWS": { "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:root" } Action: - kms:* Resource: "*" BackupVaultWithDailyBackups: Type: "AWS::Backup::BackupVault" Properties: BackupVaultName: "BackupVaultWithDailyBackups" EncryptionKeyArn: !GetAtt KMSKey.Arn BackupPlanWithDailyBackups: Type: "AWS::Backup::BackupPlan" Properties: BackupPlan: BackupPlanName: "BackupPlanWithDailyBackups" AdvancedBackupSettings: - ResourceType: EC2 BackupOptions: WindowsVSS: enabled BackupPlanRule: - RuleName: "RuleForDailyBackups" TargetBackupVault: !Ref BackupVaultWithDailyBackups ScheduleExpression: "cron(0 5 ? * * *)" DependsOn: BackupVaultWithDailyBackups

有关使用Amazon CloudFormation替换为Amazon Backup,请参阅Amazon Backup资源类型参考中的Amazon CloudFormation用户指南

有关控制对的访问的更多信息Amazon使用时的服务资源Amazon CloudFormation,请参阅使用 控制访问Amazon Identity and Access Management中的Amazon CloudFormation用户指南

使用Amazon CloudFormation使用 Organizations

将以下 YAML 和 Python 文件与Amazon CloudFormation部署到Amazon BackupOrganizations 级别的政策。

AWSTemplateFormatVersion: '2010-09-09' Description: This template deploys Backup Policies required to manage backups at an organization level. Parameters: ImpactedAccounts: Description: "CSV list of the Org Ids" Type: CommaDelimitedList Default: "" ConfigBucket: Description: S3 Bucket for the Custom Lambda Code and Templates Type: String Default: mb3-venkitas ConfigBucketKey: Description: S3 Key for the Custom Lambda Code and Templates Type: String Default: IaC/cfn-templates/Backup/ Resources: #Type='SERVICE_CONTROL_POLICY'|'TAG_POLICY'|'BACKUP_POLICY'|'AISERVICES_OPT_OUT_POLICY' GoldDailyBackupPolicySyd: Type: Custom::OrgPolicy Properties: PolicyName: GoldDailyBackupPolicySyd PolicyType: BACKUP_POLICY PolicyTargets : !Ref ImpactedAccounts PolicyDescription: >- BackupPolicy for Daily Backup as per the resource selection criteria PolicyContents: |- { "plans": { "OrgDailyBackupPlan": { "regions": { "@@assign": [ "REGION" ] }, "rules": { "OrgDailyBackupRule": { "schedule_expression": { "@@assign": "SCHEDULE_EXPRESSION" }, "start_backup_window_minutes": { "@@assign": "480" }, "complete_backup_window_minutes": { "@@assign": "720" }, "lifecycle": { "delete_after_days": { "@@assign": "1" } }, "target_backup_vault_name": { "@@assign": "DailyBackupVault" }, "recovery_point_tags": { "project": { "tag_key": { "@@assign": "TAG_KEY" }, "tag_value": { "@@assign": "TAG_VALUE" } } } } }, "backup_plan_tags": { "project": { "tag_key": { "@@assign": "TAG_KEY" }, "tag_value": { "@@assign": "TAG_VALUE" } } }, "selections": { "tags": { "OrgDailyBackupSelection": { "iam_role_arn": { "@@assign": "arn:aws:iam::$account:role/BackupRole" }, "tag_key": { "@@assign": "TAG_KEY" }, "tag_value": { "@@assign": [ "TAG_VALUE" ] } } } } } } } Variables: - REGION : !Ref 'AWS::Region' - TAG_KEY : project - TAG_VALUE : aws-backup-demo - SCHEDULE_EXPRESSION : "cron(0 5 ? * * *)" ServiceToken: !GetAtt OrgPolicyCustomResourceManager.Arn DenyVaultAndLogBucketOperationsSCP: Type: Custom::OrgPolicy Properties: PolicyName: SCP_DENY_VAULT_AND_LOG_BUCKET_OPERATIONS PolicyType: SERVICE_CONTROL_POLICY PolicyTargets : !Ref ImpactedAccounts PolicyDescription: >- This SCP denies operations on Vault and log bucket that are tagged with a specific project name. PolicyContents: |- { "Version": "2012-10-17", "Statement": [ { "Sid": "DenyLogBucketOperations", "Effect": "Deny", "Action": [ "s3:DeleteBucket", "s3:DeleteBucketPolicy", "s3:DeleteJobTagging", "s3:DeleteAccessPointPolicy", "s3:DeleteAccessPoint", "s3:DeleteBucketWebsite" ], "Resource": [ "arn:aws:s3:::LOG_BUCKET-*" ] }, { "Sid": "DenyLogBucketObjectOperations", "Effect": "Deny", "Action": [ "s3:DeleteObject", "s3:DeleteObjectTagging", "s3:DeleteObjectVersion", "s3:DeleteObjectVersionTagging" ], "Resource": [ "arn:aws:s3:::LOG_BUCKET-*/*" ] }, { "Sid": "DenyVaultOperations", "Effect": "Deny", "Action": [ "backup:DeleteBackupVault", "backup:DeleteBackupSelection", "backup:DeleteBackupPlan", "backup:DeleteBackupVaultAccessPolicy", "backup:DeleteBackupVaultNotifications", "backup:DeleteRecoveryPoint", "backup:UntagResource" ], "Resource": [ "*" ], "Condition": { "StringEquals": { "aws:ResourceTag/TAG_KEY": [ "TAG_VALUE" ] } } } ] } Variables: - REGION : !Ref 'AWS::Region' - LOG_BUCKET : backup-log-bucket - TAG_KEY : project - TAG_VALUE : aws-backup-demo ServiceToken: !GetAtt OrgPolicyCustomResourceManager.Arn OrgPolicyCustomResourceManager: Type: AWS::Lambda::Function Properties: FunctionName: OrgPolicyCustomResourceManager Description: Lambda function to deploy CloudFormation custom resources for Organization SCPs. Handler: OrgPolicyCustomResourceManager.lambda_handler Code: S3Bucket: !Ref ConfigBucket S3Key: !Sub - '${S3Prefix}OrgPolicyCustomResourceManager.zip' - { S3Prefix: !Ref ConfigBucketKey } Role: !GetAtt OrgPolicyCustomResourceManagerRole.Arn Runtime: python3.7 MemorySize: 256 Timeout: 300 Tags: - Key: Name Value: OrgPolicyCustomResourceManager OrgPolicyCustomResourceManagerRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: 'lambda.amazonaws.com' Action: - 'sts:AssumeRole' Path: '/' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: AssumeOrgRole PolicyDocument: Statement: - Effect: Allow Action: - sts:AssumeRole Resource: '*' - PolicyName: OrgPermissions PolicyDocument: Statement: - Effect: Allow Action: - organizations:CreatePolicy - organizations:DeletePolicy - organizations:AttachPolicy - organizations:DetachPolicy - organizations:ListPolicies Resource: '*' - PolicyName: S3Permissions PolicyDocument: Statement: - Effect: Allow Action: - s3:Get* Resource: !Sub - 'arn:aws:s3:::${Bucket}/*' - { Bucket: !Ref ConfigBucket }
import boto3 #https://pypi.org/project/cfnresponse/ import cfnresponse as cfn import logging import uuid logger = logging.getLogger() logger.setLevel(logging.INFO) client = boto3.client('organizations') def get_policy(event): policy_contents = '' if 'PolicyContents' in event['ResourceProperties']: policy_contents = event['ResourceProperties']['PolicyContents'] else: s3_bucket = event['ResourceProperties']['PolicyBucket'] s3_object = event['ResourceProperties']['PolicyLocation'] s3 = boto3.resource('s3') policy_file = s3.Object(s3_bucket, s3_object) policy_contents = policy_file.get()['Body'].read().decode('utf-8') #Check for replacement variables if 'Variables' in event['ResourceProperties']: variables= event['ResourceProperties']['Variables'] logger.info(f"variables : {variables}") for variable in variables: for key, value in variable.items(): logger.info(f"Replacing Key : {key} with value : {value}") policy_contents = policy_contents.replace(key,value ) return policy_contents def lambda_handler(event, context): try: #create physical resource id customResourcePhysicalID = uuid.uuid4().hex if 'PhysicalResourceId' in event: customResourcePhysicalID = event['PhysicalResourceId'] logger.info(f"OrgPolicyCustomResourceManager Request: {event}") resource_action = event['RequestType'] policy_name = event['ResourceProperties']['PolicyName'] policy_contents = get_policy(event) policy_type = event['ResourceProperties']['PolicyType'] policy_description = event['ResourceProperties']['PolicyDescription'] policyTargetList=[] if 'PolicyTargets' in event['ResourceProperties']: policy_targets = event['ResourceProperties']['PolicyTargets'] policyTargetList = policy_targets logger.info(f"policy_targets: {policy_targets}") if resource_action == 'Create': logger.info(f"Action : {resource_action} policy") response = client.create_policy( Content=policy_contents, Description=policy_description, Name=policy_name, Type=policy_type ) logger.info(f"Response: {response}") policyId = response['Policy']['PolicySummary']['Id'] #Attach the policy in target accounts for policyTarget in policyTargetList: try: logger.info(f"Attaching {policyId} on Account {policyTarget}") response = client.attach_policy(PolicyId=policyId, TargetId=policyTarget) logger.info(f"Attached {policyId} on Account {policyTarget}") except Exception as e: logger.error(str(e)) cfn.send(event, context, cfn.SUCCESS, {'Message': "Policy created successfully."}, customResourcePhysicalID) elif resource_action == 'Update' or resource_action == 'Delete': logger.info(f" Action: {resource_action} policy, policy_type: {policy_type}, policy_name {policy_name}") response = client.list_policies(Filter=policy_type) policy = list(filter(lambda item: item['Name'] == policy_name, response["Policies"])) logger.info(f"Policy Found : {policy}") if len(policy) == 0: return {'Status': 'Policy not found for name ' + policy_name} policyId=policy[0]['Id'] if resource_action == 'Delete': #Detach the policy detachPolicy(policyTargetList,policyId) while True: try: response = client.delete_policy(PolicyId=policyId) logger.info(f"deletePolicy response: {response}") cfn.send(event, context, cfn.SUCCESS, {'Message': "Policy modified successfully."}, customResourcePhysicalID) break except client.exceptions.PolicyInUseException as e: #try detaching the policy again detachPolicy(policyTargetList,policyId) logger.error(str(e)) else: response = updatePolicy(resource_action,policyId, policy_contents) logger.info(f"updatePolicy response: {response}") cfn.send(event, context, cfn.SUCCESS, {'Message': "Policy modified successfully."}, customResourcePhysicalID) else: logger.error(f"Unexpected Action : {resource_action}") cfn.send(event, context, cfn.FAILED, {'Message': 'Unexpected event received from CloudFormation'}, customResourcePhysicalID) except Exception as exc: logger.error(f"Exception: {str(exc)}") cfn.send(event, context, cfn.FAILED, {'Message': str(exc)}, customResourcePhysicalID) def detachPolicy(policyTargetList,policyId): #Detach the policy in target accounts for policyTarget in policyTargetList: try: logger.info(f"Detaching {policyId} from Account {policyTarget}") response = client.detach_policy(PolicyId=policyId, TargetId=policyTarget) logger.info(f"Detached {policyId} from Account {policyTarget}") except Exception as e: logger.error(str(e)) def updatePolicy(resource_action, policyId, policy_contents): logger.info(f"updatePolicy with action : {resource_action}, policyId : {policyId}") if (resource_action == 'Update'): response = client.update_policy( PolicyId=policyId, Content=policy_contents ) return response