[EN]Multi-account environment with CloudFormation StackSets
안녕하세요.
최근 다중 계정 환경에서의 자동화와 관련한 재미있는 실습을 해봤습니다. 제가 구현한 환경은 다음과 같습니다:
- 관리 계정에서 Organization Unit에 있는 여러개의 계정을 대상으로 암호화된 AMI를 사용하는 오토 스케일링 그룹을 배치하기
여러 계정에 오토 스케일링 그룹을 배치하기 위해서 다음과 같은 작업이 요구됩니다:
- 관리 계정에서 Customer Managed KMS key를 생성
- 생성한 KMS key로 EBS 볼륨이 암호화된 EC2 인스턴스를 생성
- EC2로부터 AMI를 생성하고, Organization Unit에 AMI와 KMS key를 공유
- 각각의 계정에서 공유받은 AMI와 KMS key를 통해 오토 스케일링 그룹을 생성
4번 작업을 진행할 때, 만약 대상 계정이 몇 개 없다면 각각의 계정에서 오토 스케일링 그룹을 생성하는 것이 훨씬 빠를겁니다. 하지만 대상 계정이 100개라면 어떻게 해야 할까요?
여러분에게 여러가지 선택지가 있습니다:
- Terraform을 이용한 구성
- 회사의 master-slave 구조를 이용해 명령 하달
- CloudFormation StackSets 사용
1번 선택지의 경우, 100개 계정의 자격 증명을 얻는 일은 굉장히 귀찮은 일입니다. 2번 선택지는 의외로 괜찮은 선택지인데요, 본인의 administrative overhead를 남들에게 분산시키는(..) 방법입니다. 하지만 저희는 오늘 3번 선택지인 AWS의 IaC 서비스 CloudFormation StackSets를 활용하여 문제를 효율적으로 해결해보겠습니다!
이번 게시글을 통해 알 수 있는 정보는 다음과 같습니다:
- CloudFormation StackSets
- CloudFormation Lambda-backed Custom Resource을 사용하여 CloudFormation StackSets Output을 중앙 관리 계정으로 전송하기
- CloudFormation StackSets으로 Auto Scaling Groups 생성하기 & 고려사항
CloudFormation
AWS CloudFormation is a service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS.
- CloudFormation template 은 JSON이나 YAML 형식의 텍스트 파일입니다.
- CloudFormation에서 생성되는 리소스 유닛 단위는 stack이라고 부릅니다.
- Stack에 포함된 모든 리소스는 CloudFormation template에 기록하여 관리합니다.
따라서, template을 사용함으로써 stack을 생성하고, 수정하고, 삭제할 수 있습니다. Terraform과 비슷합니다. 하지만 테라폼과 똑같이 대응되지는 않습니다. CloudFormation이 할 수 있는 몇가지 기능들을 알아봅시다!
CloudFormation StackSets
A stack set lets you create stacks in AWS accounts across regions by using a single CloudFormation template.
CloudFormation StackSets를 사용하여 Administrator account에서 여러개의 대상 계정에 stack을 생성할 수 있습니다.
- Administrator account 은 stack sets를 생성하는 AWS 계정으로, organization의 관리 계정 또는 사용자가 정의하는 delegated administrator account이 될 수 있습니다.
- 다중 계정에 StackSets을 배포하기 전에 administrator 계정과 대상 계정 사이에 trust relationship 을 구성해야 합니다.
Setting up trust relationships
With service-managed permissions, you can deploy stack instances to accounts managed by AWS Organizations. Using this permissions model, you don't have to create the necessary IAM roles; StackSets creates the IAM roles on your behalf. With this model, you can also turn on automatic deployments to accounts that you add to your organization in the future.
Trust relationship 설정은 관리자 계정과 대상 계정 간의 상호작용이 필요하지만, 우리는 서비스 관리 권한을 사용하여 과정을 단순화할 것입니다. 서비스 관리 권한을 사용하면 모든 계정과 관리자 계정 간에 이미 신뢰 관계가 설정되어 있습니다. 따라서 AWS Organizations에서 모든 기능을 활성화(Enable all features)해야 합니다 (기본적으로 활성화되어 있습니다).
NOTE: Enable all features in AWS Organizations
통합 청구 기능만 활성화된 상태에서는 서비스 관리 권한을 사용해 스택 세트를 생성할 수 없습니다.
Create EC2 with shared AMI
이 챕터에서는 다음 리소스를 설정할 것입니다. AMI와 KMS를 생성 및 공유하기 위한 설정이 이미 완료되었다고 가정합니다. 각 계정에 EC2 인스턴스를 배포하기 위해 다음과 같은 템플릿을 작성할 것입니다.
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation Template to create an EC2 instance using specified parameters for InstanceType and AMI ID and store outputs in a centralized S3 bucket.
Parameters:
InstanceType:
Description: EC2 Instance Type
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t3.micro
ConstraintDescription: t2.micro or t3.micro only.
ImageId:
Description: AMI ID for the EC2 instance
Type: AWS::EC2::Image::Id
Default: ami-005b0bdedc5ed724b
ConstraintDescription: must be a valid AMI ID.
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: !Ref ImageId
SecurityGroups:
- Ref: MySecurityGroup
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH and HTTP access
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
템플릿에 대한 설명입니다:
- Parameters 섹션은 템플릿 실행 시 입력할 수 있는 매개변수를 정의합니다. Parameters를 활용하면 템플릿의 재사용성을 크게 향상시킬 수 있습니다.
- Resources 섹션은 CloudFormation이 생성할 실제 리소스를 정의합니다.
- MyEC2Instance는 우리가 생성할 EC2 인스턴스 리소스입니다. ImageId 필드에 AMI ID를 입력하면 이전에 공유된 AMI를 사용할 수 있습니다.
- MySecurityGroup은 EC2 인스턴스에 할당될 보안 그룹입니다. 테스트 목적으로 생성된 리소스이므로 권한은 열려 있습니다.
이제 CloudFormation 템플릿을 사용해 스택 세트를 생성합시다. CloudFormation의 강력한 이점을 여기서 확인할 수 있습니다. 관리 계정에서 작업 중이므로 기본 AWS 관리 권한을 사용할 수 있습니다. 이를 통해 조직 내 여러 계정에서 리소스를 생성, 수정, 삭제할 권한을 개별적으로 확인하지 않고도 얻을 수 있습니다.
템플릿을 적용하는 것은 매우 간단합니다. 관리자 계정에서 CloudFormation StackSets 섹션으로 이동하세요.
Permissions 섹션에서 Service-managed permissions를 사용합니다. 서비스 관리 권한을 사용하여 AWS Organizations 내의 계정에 접근할 수 있습니다.
미리 준비된 템플릿 파일을 업로드하세요.
대상을 OU 단위로 선택할 수 있습니다. 또한 스택을 배포할 지역을 선택할 수 있습니다. 이 글에서는 자세히 다루지 않지만 CloudFormation Stack을 생성할 때 선택할 수 있는 다양한 옵션이 있습니다.
배포 중에 옵션을 선택할 수 있습니다. 스택을 여러 계정에 병렬로 배포하거나, 하나씩 순차적으로 배포할 수 있습니다. 또한 실패 허용 설정을 정의하여 일정 수의 스택이 실패하면 전체 작업을 롤백할지 결정할 수 있습니다.
리소스가 생성되었습니다! 👏👏
하지만 아직 해결해야 할 문제가 있습니다. 이 시나리오에서는 여러 AWS 계정에 EC2 인스턴스를 성공적으로 생성했지만, 여전히 인스턴스의 엔드포인트를 알지 못합니다. 이를 확인하려면 각 AWS 계정에 수동으로 로그인하여 Public IPv4 주소를 가져와야 합니다. 이 문제도 해결해봅시다!
Centralize CloudFormation StackSets Outputs
CloudFormation으로 생성된 리소스의 Public IPv4를 얻기 위해 AWS Lambda 함수를 사용할 것입니다. 그러나 CloudFormation은 프로비저닝 도구입니다. Lambda 함수를 생성할 수는 있지만, 어떻게 실행할까요?
Lambda-backed CloudFormation Custom Resources
When you associate a Lambda function with a custom resource, the function is invoked whenever the custom resource is created, updated, or deleted. CloudFormation calls a Lambda API to invoke the function and to pass all the request data (such as the request type and resource properties) to the function.
Lambda-backed CloudFormation Custom Resource를 사용하여 스택 배포 중에 Lambda 함수를 트리거할 수 있습니다! 이를 통해 AWS SDK 사용, 로깅 등 다양한 작업을 수행할 수 있습니다. 이것이 CloudFormation의 강력한 기능 중 하나입니다.
그럼 구현해 봅시다. 먼저 S3 버킷을 생성하고 조직에 권한을 부여하기 위해 리소스 기반 정책(S3 버킷 정책)을 할당하세요.
KMS 권한 설정과 유사하게, 특정 OU만 허용하려면 다음과 같은 형식을 사용할 수 있습니다:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::centralized-cloudformation-stacksets-output-logs-488357298470/*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-n0g4bvykxt"
},
"ForAnyValue:StringLike": {
"aws:PrincipalOrgPaths": "o-n0g4bvykxt/r-goqx/ou-goqx-c5la1jns/*"
}
}
}
]
}
다음으로 S3 버킷에 로그 정보를 기록하는 Lambda 함수를 생성합니다:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: S3WritePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource: arn:aws:s3:::centralized-cloudformation-stacksets-output-logs-488357298470/*
OutputToS3Function:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Runtime: python3.9
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
import json
import boto3
import urllib3
s3_client = boto3.client('s3')
http = urllib3.PoolManager()
def handler(event, context):
try:
bucket_name = 'centralized-cloudformation-stacksets-output-logs-488357298470'
account_id = context.invoked_function_arn.split(":")[4]
outputs = {
'InstancePublicIP': event['ResourceProperties']['InstancePublicIP'],
'InstanceId': event['ResourceProperties']['InstanceId']
}
# Store in S3
s3_client.put_object(
Bucket=bucket_name,
Key=f"outputs/{account_id}-outputs.json",
Body=json.dumps(outputs)
)
# Response for CF
response_data = {
'Status': 'SUCCESS',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': outputs
}
# In case of failure
except Exception as e:
response_data = {
'Status': 'FAILED',
'Reason': str(e),
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId']
}
# Send response back to CF
response_url = event['ResponseURL']
http.request('PUT', response_url, body=json.dumps(response_data))
return {
'statusCode': 200,
'body': json.dumps(response_data)
}
MyCustomResource:
Type: Custom::OutputToS3
Properties:
ServiceToken: !GetAtt OutputToS3Function.Arn
InstancePublicIP: !GetAtt MyEC2Instance.PublicIp
InstanceId: !Ref MyEC2Instance
DependsOn: OutputToS3Function
DeletionPolicy: Retain
MyCustomResource 는 OutputToS3Function Lambda 함수를 트리거합니다. 이 함수는 생성된 InstancePublicIP와 InstanceId를 속성으로 전달하여 Lambda 함수가 S3 버킷에 로그를 기록할 때 사용할 수 있도록 합니다.
Lambda 함수가 실행된 후에는 CloudFormation에 실행이 완료되었음을 알려야 합니다. 이는 http.request() 함수를 사용하여 정보를 CloudFormation에 다시 전송함으로써 이루어집니다. 이 단계를 거치지 않으면 CloudFormation 스택은 CREATE_IN_PROGRESS 상태에서 멈춘 채로 남게 됩니다.
실행 결과, 중앙 계정에 로그가 생성되었군요! 이를 통해 각 인스턴스의 메타데이터를 확인할 수 있습니다. 👍
Creating Auto Scaling Groups with CloudFormation StackSets
이제 각 계정에서 암호화된 AMI를 사용해 오토 스케일링 그룹을 생성해봅시다. 오토 스케일링 그룹을 생성할 때 고려해야 할 점이 있습니다.
- AWS CLI을 이용해 KMS key를 grant 해야 한다
- ASG가 AMI에 접근하려면 KMS 키 사용 권한이 있어야 합니다.
- ASG를 사용하려면 KMS 키를 오토 스케일링 그룹 Service-linked Role에 부여해야 합니다.
aws kms create-grant --key-id [KEY_ID] \\ --grantee-principal [SLR ARN] \\ --operations Decrypt Encrypt GenerateDataKey GenerateDataKeyWithoutPlaintext \\ ReEncryptFrom ReEncryptTo CreateGrant DescribeKey
- KEY_ID는 공유된 KMS 키의 ID를 의미합니다.
- SLR ARN은 EC2 인스턴스를 스케일하기 위해 Auto Scaling Group에서 사용하는 IAM 역할입니다. 하지만 여기서 또 다른 문제가 발생합니다
- 한번도 ASG를 생성한 적이 없는 계정에는 ASG SLR이 존재하지 않는다
- 따라서, AWS CLI 또는 다른 방법을 사용해 수동으로 Auto Scaling Group을 위한 서비스 연결 역할을 생성해야 합니다.
- 다행히 SLR을 생성하는 AWS CLI가 있습니다.
create-service-linked-role --aws-service-name autoscaling.amazonaws.com
AWS SDK(boto3)를 사용하는 Lambda 함수로 문제를 해결해봅시다.
Lambda Function to create Auto Scaling Group Service Linked Role
import boto3
import json
import urllib3
iam_client = boto3.client('iam')
http = urllib3.PoolManager()
def handler(event, context):
try:
try:
iam_client.get_role(
RoleName='AWSServiceRoleForAutoScaling'
)
role_exists = True
except iam_client.exceptions.NoSuchEntityException:
role_exists = False
if not role_exists:
iam_client.create_service_linked_role(
AWSServiceName='autoscaling.amazonaws.com'
)
response_data = {
'Status': 'SUCCESS',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': {'Message': 'Service-linked role created successfully or already exists'}
}
except Exception as e:
response_data = {
'Status': 'FAILED',
'Reason': str(e),
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId']
}
response_url = event['ResponseURL']
http.request('PUT', response_url, body=json.dumps(response_data))
return {
'statusCode': 200,
'body': json.dumps(response_data)
}
Lambda Function to grant KMS key
import boto3
import json
import urllib3
import time
kms_client = boto3.client('kms')
http = urllib3.PoolManager()
def handler(event, context):
key_id = event['ResourceProperties']['KeyId']
slr_arn = 'arn:aws:iam::' + context.invoked_function_arn.split(":")[4] + ':role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling'
time.sleep(5)
try:
kms_client.create_grant(
KeyId=key_id,
GranteePrincipal=slr_arn,
Operations=[
'Decrypt', 'Encrypt', 'GenerateDataKey',
'GenerateDataKeyWithoutPlaintext', 'ReEncryptFrom',
'ReEncryptTo', 'CreateGrant', 'DescribeKey'
]
)
response_data = {
'Status': 'SUCCESS',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': {'Message': 'KMS grant created successfully'}
}
except Exception as e:
response_data = {
'Status': 'FAILED',
'Reason': str(e),
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId']
}
response_url = event['ResponseURL']
http.request('PUT', response_url, body=json.dumps(response_data))
return {
'statusCode': 200,
'body': json.dumps(response_data)
}
이 함수에서는 boto3를 사용해 KMS 키를 SLR에 할당합니다. 코드에서 time.sleep(5) 명령을 볼 수 있는데, 이는 SLR이 생성되어 사용 가능해지기까지 몇 초가 걸리기 때문입니다. 즉시 명령을 실행하면 SLR ARN이 유효하지 않다는 오류가 발생할 가능성이 큽니다.
따라서 5초의 지연 시간을 추가했고, 함수가 시간 초과되지 않도록 Lambda의 기본 타임아웃 시간을 3초에서 10초로 연장했습니다.
Custom Resources & ASG Config
InvokeCreateSLRFunction:
Type: Custom::CreateResources
Properties:
ServiceToken: !GetAtt CreateSLRFunction.Arn
DeletionPolicy: Retain
InvokeCreateKMSGrantFunction:
Type: Custom::CreateKMSGrant
Properties:
ServiceToken: !GetAtt CreateKMSGrantFunction.Arn
KeyId: !Ref KeyId
DependsOn: InvokeCreateSLRFunction
DeletionPolicy: Retain
MyLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
SecurityGroups:
- !Ref MySecurityGroup
DependsOn: [InvokeCreateSLRFunction, InvokeCreateKMSGrantFunction]
여기서 주목해야 할 중요한 점은 DependsOn 속성입니다. 이 속성은 리소스 생성 순서를 조정하는 데 사용합니다.
리소스 생성 순서는 다음과 같아야 합니다: SLR이 생성된 후, SLR을 사용해 KMS Grant를 적용하고, 부여된 권한으로 ASG가 생성됩니다. 따라서 그에 맞게 InvokeCreateKMSGrantFunction의 DependsOn에는 InvokeCreateSLRFunction을, MyLaunchTemplate에는 InvokeCreateSLRFunction과 InvokeCreateKMSGrantFunction을 추가했습니다.
Entire code:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation Template to create an ASG with encrypted AMI.
Parameters:
InstanceType:
Description: EC2 Instance Type
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t3.micro
ConstraintDescription: t2.micro or t3.micro only.
ImageId:
Description: Encrypted AMI ID for the EC2 instances
Type: AWS::EC2::Image::Id
Default: ami-005b0bdedc5ed724b
ConstraintDescription: must be a valid AMI ID.
KeyId:
Description: KMS Key ID for the encrypted AMI
Type: String
Default: arn:aws:kms:ap-northeast-2:211125378002:key/926dcb9b-382a-4a37-b9dc-d287d3a714d5
ConstraintDescription: must be a valid KMS Key ID.
Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: AllowCreateServiceLinkedRoleAndKMSGrant
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
- iam:GetRole
- kms:CreateGrant
Resource: "*"
# create SLR
CreateSLRFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Runtime: python3.9
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
import boto3
import json
import urllib3
iam_client = boto3.client('iam')
http = urllib3.PoolManager()
def handler(event, context):
try:
try:
iam_client.get_role(
RoleName='AWSServiceRoleForAutoScaling'
)
role_exists = True
except iam_client.exceptions.NoSuchEntityException:
role_exists = False
if not role_exists:
iam_client.create_service_linked_role(
AWSServiceName='autoscaling.amazonaws.com'
)
response_data = {
'Status': 'SUCCESS',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': {'Message': 'Service-linked role created successfully or already exists'}
}
except Exception as e:
response_data = {
'Status': 'FAILED',
'Reason': str(e),
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId']
}
response_url = event['ResponseURL']
http.request('PUT', response_url, body=json.dumps(response_data))
return {
'statusCode': 200,
'body': json.dumps(response_data)
}
# create KMS grant
CreateKMSGrantFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Runtime: python3.9
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 10
Code:
ZipFile: |
import boto3
import json
import urllib3
import time
kms_client = boto3.client('kms')
http = urllib3.PoolManager()
def handler(event, context):
key_id = event['ResourceProperties']['KeyId']
slr_arn = 'arn:aws:iam::' + context.invoked_function_arn.split(":")[4] + ':role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling'
time.sleep(5)
try:
kms_client.create_grant(
KeyId=key_id,
GranteePrincipal=slr_arn,
Operations=[
'Decrypt', 'Encrypt', 'GenerateDataKey',
'GenerateDataKeyWithoutPlaintext', 'ReEncryptFrom',
'ReEncryptTo', 'CreateGrant', 'DescribeKey'
]
)
# Prepare response for CloudFormation
response_data = {
'Status': 'SUCCESS',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': {'Message': 'KMS grant created successfully'}
}
except Exception as e:
response_data = {
'Status': 'FAILED',
'Reason': str(e),
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId']
}
# Send response back to CloudFormation
response_url = event['ResponseURL']
http.request('PUT', response_url, body=json.dumps(response_data))
return {
'statusCode': 200,
'body': json.dumps(response_data)
}
InvokeCreateSLRFunction:
Type: Custom::CreateResources
Properties:
ServiceToken: !GetAtt CreateSLRFunction.Arn
DeletionPolicy: Retain
InvokeCreateKMSGrantFunction:
Type: Custom::CreateKMSGrant
Properties:
ServiceToken: !GetAtt CreateKMSGrantFunction.Arn
KeyId: !Ref KeyId
DependsOn: InvokeCreateSLRFunction
DeletionPolicy: Retain
MyLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
SecurityGroups:
- !Ref MySecurityGroup
DependsOn: [InvokeCreateSLRFunction, InvokeCreateKMSGrantFunction]
MyAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref MyLaunchTemplate
Version: !GetAtt MyLaunchTemplate.LatestVersionNumber
MinSize: '1'
MaxSize: '3'
DesiredCapacity: '1'
AvailabilityZones:
- !Select
- '0'
- !GetAZs ''
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH and HTTP access
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Outputs:
AutoScalingGroupName:
Description: Name of the Auto Scaling Group
Value: !Ref MyAutoScalingGroup
축하합니다! 성공적으로 여러 AWS 계정에 ASG를 자동으로 배포하는 솔루션을 만들었습니다! 🔥🔥
CloudFormation StackSets 작업은 매우 신중해야 합니다. 작은 실수로도 많은 리소스가 생성되어 상당한 비용이 발생할 수 있으며, 기존 계정 환경에 문제를 일으킬 수 있으므로 변경 사항을 적용하기 전에 반드시 검토가 필요합니다.
그래도 이 글에서 본 것처럼 CloudFormation은 매우 강력한 도구입니다. 이를 잘 이해하고 사용하면 여러 계정 환경을 효율적으로 관리하는 데 매우 유용한 자원이 될 수 있습니다.
'AWS' 카테고리의 다른 글
AWS Cloud Club Hongik에서 실습 환경 구성하기 (1) | 2024.12.03 |
---|---|
[EN]Multi-account environment with CloudFormation StackSets (0) | 2024.08.16 |
AWS re:Post web crawler with AWS Serverless services (0) | 2024.08.08 |
Terraform의 aws_iam_openid_connect_provider에 관하여 (0) | 2024.07.18 |
[AWS IAM] Hands-on: Github Actions에 임시 자격 증명 사용하기 (0) | 2024.07.17 |