🗂
CloudFormation スタック削除保護の自動設定
やりたいこと
CloudFormationの変更セットを削除する際に誤ってスタックごと削除することが多いので自動で削除保護を有効化したい
構成図
Configで検知をしてリソース情報をSystemsManagerの自動修復機能を使用して削除保護を付与する構成

CloudFormation
sampleとしてcfnのテンプレートを載せておきます
注意点
- Timestampはcfnを更新した際にSSMドキュメント名が重複するとデプロイ失敗するのでつけてます
- SSMドキュメントのPython versionは適宜更新してください
AWSTemplateFormatVersion: "2010-09-09"
Description: "CloudFormation Auto Protection"
Parameters:
Timestamp:
Type: String
Resources:
# ------------------------------------------------------------#
# IAM : IAM Role & Policy for CloudFormation Termination Protection
# ------------------------------------------------------------#
IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: "cfn-termination-protection-role"
AssumeRolePolicyDocument:
{
"Version": "2012-10-17",
"Statement":
[
{
"Effect": "Allow",
"Principal": { "Service": "ssm.amazonaws.com" },
"Action": "sts:AssumeRole",
},
],
}
IAMPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: "cfn-termination-protection-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "AWSConfig"
Effect: Allow
Action:
- config:ListDiscoveredResources
- ssm:GetAutomationExecution
- iam:DeleteAccessKey
- ssm:StartAutomationExecution
- iam:GetAccessKeyLastUsed
- iam:UpdateAccessKey
- iam:GetUser
- iam:GetLoginProfile
- iam:DeleteLoginProfile
- iam:ListAccessKeys
Resource:
- !Sub "arn:aws:config:*:${AWS::AccountId}:config-rule/*"
- Sid: "AWSCloudFormation"
Effect: Allow
Action:
- cloudformation:UpdateTerminationProtection
Resource:
- !Sub "arn:aws:cloudformation:*:${AWS::AccountId}:stack/*"
Roles:
- !Ref IAMRole
# ------------------------------------------------------------#
# Config : Config Rule for CloudFormation Termination Protection
# ------------------------------------------------------------#
ConfigRule:
Type: "AWS::Config::ConfigRule"
Properties:
ConfigRuleName: "cfn-termination-protection-config-rule"
Scope:
ComplianceResourceTypes:
- "AWS::CloudFormation::Stack"
Source:
Owner: "CUSTOM_POLICY"
SourceDetails:
- EventSource: "aws.config"
MessageType: "ConfigurationItemChangeNotification"
- EventSource: "aws.config"
MessageType: "OversizedConfigurationItemChangeNotification"
CustomPolicyDetails:
PolicyRuntime: "guard-2.x.x"
PolicyText: "rule checkcompliance when resourceType == 'AWS::CloudFormation::Stack' {configuration.enableTerminationProtection == true}"
EnableDebugLogDelivery: true
ConfigRemediationConfiguration:
Type: "AWS::Config::RemediationConfiguration"
Properties:
Automatic: true
MaximumAutomaticAttempts: 5
RetryAttemptSeconds: 60
ConfigRuleName: !Ref ConfigRule
TargetId: !Ref SSMDocument
TargetType: "SSM_DOCUMENT"
Parameters:
AutomationAssumeRole:
StaticValue:
Values:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/cfn-termination-protection-role"
stackNameArn:
ResourceValue:
Value: "RESOURCE_ID"
# ------------------------------------------------------------#
# SystemsManager : SSM Document for CloudFormation Termination Protection
# ------------------------------------------------------------#
SSMDocument:
Type: "AWS::SSM::Document"
Properties:
Name: !Sub "cfn-termination-protection-ssm-document-${Timestamp}"
DocumentType: "Automation"
DocumentFormat: YAML
Content:
schemaVersion: '0.3'
parameters:
AutomationAssumeRole:
type: String
stackNameArn:
type: String
assumeRole: '{{ AutomationAssumeRole }}'
mainSteps:
- name: EnableStackProtection
action: aws:executeScript
isEnd: true
inputs:
Runtime: python3.11
Handler: script_handler
InputPayload:
stackNameArn: '{{ stackNameArn }}'
Script: |-
import boto3
import re
def script_handler(events, context):
stackNameArn = events['stackNameArn']
client = boto3.client('cloudformation')
stackName = re.search(r'stack/([^/]+)', stackNameArn)
response = client.update_termination_protection(
EnableTerminationProtection=True,
StackName=stackName.group(1)
)
Discussion