AWS CloudFormation 보안 모범 사례
이 문서는 다음의 내용을 번역한 것입니다.
AWS CloudFormation을 사용하면 개발자와 시스템 관리자가 AWS와 연관된 리소스 모음을 질서있고 예측 가능한 방식으로 프로비저닝하고 업데이트하여 쉽게 생성하고 관리 할 수 있다. 우리의 많은 고객들은 그들의 AWS 환경에서 변경사항을 간단하게 캡쳐하고 버전 제어를 실행하고 인프라에서 다른 작업 중에서도 비용을 관리하는 등에 모든 리소스를 제어하기 위해 CloudFormation 을 사용한다.
고객들은 자주 어떻게 CloudFormation 스택에 허가권을 제어하는 우리에게 묻는다. 이 글에서, 우리는 CloudFormation 에 대한 AWS Identity 와 IAM 정책을 사용, CloudFormation 에 특화된 IAM 조건 그리고 CloudFormation 스택 정책들을 포함하는 몇가지 모범사례를 공유한다. 대부분의 CloudFormation 배포는 AWS CLI 나 SDK 를 통해서 이루어지기 때문에 우리는 모범 사례를 어떻게 구현하는지 보여주기 위해서 AWS CLI 와 SDK 사용에 포커스를 둘 것이다.
IAM 을 통한 CloudFormation 스택 접근 제한
IAM 을 통해서, 여러분은 정책이나 사용자 혹은 롤(role) 을 사용함으로써 AWS 서비스나 리소스 접근을 보안적으로 통제할 수 있다. CloudFormation 은 fine-grained(세분화된) 액세스 제어를 제공하기 위해서 IAM 을 지렛대로 사용한다.
모범사례를 통해서, 우리는 최소 권한 원칙을 적용된 IAM 정책들을 통해 AWS 서비스 및 자원 접근을 제한하기 권한다. 이것을 하는 가장 단순한 방법은 CloudFormation 에 특정 API 콜을 제한하는 것이다. 예를들어, 여러분은 특정 IAM 유저나 롤이 CloudFormation 스택을 삭제하거나 업데이트하길 원하지 않을 것이다. 다음의 단수한 정책들은 모든 CloudFormation API 접근을 허용하지만 여러분의 프로덕트 스택의 UpdateStack 과 DeleteStack API 접근은 거부한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "Version":"2012-10-17", "Statement":[{ "Effect":"Allow", "Action":[ "cloudformation:*" ], "Resource":"*" }, { "Effect":"Deny", "Action":[ "cloudformation:UpdateStack", "cloudformation:DeleteStack" ], "Resource":"arn:aws:cloudformation:us-east-1:123456789012:stack/MyProductionStack/*" }] } |
IAM 정책은 종종 특정 리소스를 생성할 수 있도록 허용해야 하지만 이러한 리소스를 CloudFormation의 일부로 생성하지 않을 수 있다. 이것이 CloudFormation 의 IAM 조건 지원이 제공된다.
CloudFormation 을 위한 IAM 조건
다음은 여러분의 IAM 정책에 추가할 수 있는 세가지 CloudFormation 특화된 IAM 조건들이다.
- cloudformation:TemplateURL
- cloudformation:ResourceTypes
- cloudformation:StackPolicyURL
이러한 세가지 조건을 통해서, 여러분은 특정리소스 생성, 업데이트, 특정 템프릿 사용등과 같은 스택 작업을 API 로 가능해지거나 스택 업데이트 중에 의도하지 않게 업데이트나 삭제가 될수 있는 스택 리소스를 방지하는 스택 정책을 사용해 특정 리소스를 제한할 수 있다.
Condition: TemplateURL
첫째 조건, Condition: TemplateURL, 생성, 업데이트, reside 등과 같은 스택 작업에 대해 CloudFormation 템플릿을 지정하도록 하고 그것만 사용하도록 강제한다. IAM 정책에서, 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
{ "Version":"2012-10-17", "Statement":[{ "Effect": "Deny", "Action": [ "cloudformation:CreateStack", “cloudformation:UpdateStack” ], "Resource": "*", "Condition": { "StringNotEquals": { "cloudformation:TemplateURL": [ "https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template" ] } } }, { "Effect": "Deny", "Action": [ "cloudformation:CreateStack", "cloudformation:UpdateStack" ], "Resource": "*", "Condition": { "Null": { "cloudformation:TemplateURL": "true" } } }] } |
첫번째 구분은 지정된 템플릿에 한해서 모든 CreateStack 과 UpdateStack API 콜을 활성화 한다. 두번째 구분에서 모든 CreateStack 이나 UpdateStack API 콜들은 TemplateURL 파라메터를 반드시 포함하도록 한다. CLI 에서 여러분의 호출들은 –template-url 파라메터를 포함해야 한다.
1 |
aws cloudformation create-stack –stack-name cloudformation-demo –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template |
Condition: ResourceTypes
CloudFormation 은 IAM 정책을 통해서 템플릿 생성, 업데이트에 리소스 타입을 제어할 수 있도록 해준다. CloudFormation API는 ResourceTypes 파라메터를 받는다. API 호출에서, 생성이나 업데이트할 수 있는 리소스 유형을 지정할 수 있다. 하지만, 새로운 ResourceTypes 파라메터를 사용하기 위해서는 다음과 같이 컨디션 조건을 추가함으로서 특정한 파라메터 사용이 가능하도록 IAM 정책을 수정할 필요가 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
{ "Version":"2012-10-17", "Statement":[{ "Effect": "Deny", "Action": [ "cloudformation:CreateStack", "cloudformation:UpdateStack" ], "Resource": "*", "Condition": { "ForAllValues:StringLike": { "cloudformation:ResourceTypes": [ "AWS::IAM::*" ] } } }, { "Effect": "Deny", "Action": [ "cloudformation:CreateStack", "cloudformation:UpdateStack" ], "Resource": "*", "Condition": { "Null": { "cloudformation:ResourceTypes": "true" } } }] } |
CLI 에서, 여러분의 호출은 –resource-types 파라메터 포함할 필요가 있다. 여러분의 스택을 업데이트하기 위한 호출은 다음과 같다.
1 |
aws cloudformation create-stack –stack-name cloudformation-demo –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template –resource-types="[AWS::IAM::Group, AWS::IAM::User]" |
쉘(Shell)에 따라서 명령어는 쌍따옴표를 사용해야할 수도 있다. 그렇지 않으면 “No JSON object could be decoded” 에러를 보게 될 것이다.
1 |
aws cloudformation create-stack –stack-name cloudformation-demo –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template –resource-types='["AWS::IAM::Group", "AWS::IAM::User"]' |
ResourceTypes 조건은 CLI 나 API 호출을 통해서 CloudFormation 이 올바른 리소스 타입과 템플릿을 생성, 업데이트 하도록 합니다. 첫번째 예제에서, 우리의 IAM 정책은 AWS::IAM 리소스를 포함한 예제였기 때문에 API 호출을 차단했을 것이다. 만약 우리의 템플릿이 오직 AWS::EC2::Instance 자원만 포함한다면, CLI 명령어는 다음과 같을 것이며 성공할 것입니다.
1 |
aws cloudformation create-stack –stack-name cloudformation-demo –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template –resource-types='["AWS::EC2::Instance"]' |
세번째 조건은 StackPolicyURL 조건이다. 어떻게 동작하는지 설명하기 전에, 우리는 스택 정책에 대해 몇가지 추가적인 컨텍스트를 제공할 필요가 있다.
Stack Policies
가끔, 최악의 운영 중단은 의도되지 않은 리소스에 변경으로 발생 된다. 이 리스크를 완화하는데 도움이 되기 위해, CloudFormation 은 스택 정책들을 제공는데 이것은 스택 업데이트 중에 의도치않은 업데이트나 삭제로부터 스택 리소스들을 보호해준다. IAM 과 함께 사용할 경우, 스택 정책들은 스택 리소스에 대해 악의적이고 의도치않은 변경 모두에 대해 두번째 방어 계층을 제공 한다.
CloudFormation 스택 정책은 스택 업데이트 작업의 일부로 업데이트할 수 있는 항목을 정의하는 JSON 문서다. 정책을 지정하거나 업데이트하기 위해서, 여러분의 IAM 사용자 혹은 롤(Role)은 반드시 우선적으로 Cloudformation::SetStackPolicy 액션을 호출 할 수 있어야 한다.
여러분 스택에 직접 스택 정책을 적용한다. 주의해야할 것은 이것은 IAM 정책이 아니다. 기본적으로, 스택 정책 설정은 명시적으로 Allow 지정하지 않는 한 업데이트를 거부하기 위해 Deny 를 사용해 모든 스택 리소스들을 보호한다. 이것은 만약 오직 몇가지 리소스들만 제한 하길 원한다면, 리소스 “*” 를 사용해 Allow 를 포함으로써 모든 업데이트를 반드시 명시적으로 허용해야 하며 특정 리소스를 Deny 해야 한다.
예를들면, 스택 정책은 라이브로 진행되는 데이터를 포함하고 있기 때문에 프로덕션 데이터베이스를 보호하는 데 종종 사용된다. 변경중인 필드에 따라 업데이트중에 전체 데이터베이스를 교체할 수 있는 경우가 있다. 다음의 예제는, 스택 정책은 명시적으로 프로덕션 데이터베이스 업데이트 시도를 거부한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "Statement" : [ { "Effect" : "Deny", "Action" : "Update:*", "Principal": "*", "Resource" : "LogicalResourceId/ProductionDB_logical_ID" }, { "Effect" : "Allow", "Action" : "Update:*", "Principal": "*", "Resource" : "*" } ] } |
여러분은 모든 RDS DB 인스턴스나 주어진 ResourceType 을 포함하도록 여러분의 스택 정책을 일반화 할 수 있다. 이것을 얻기 위해서는 컨디션 사용한다. 그러나, 우리의 예제는 와일드카드를 사용했기 때문에, condition 은 반드시 “StringEquals” 이 아닌 “StringLike” condition 을 사용해야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ "Statement" : [ { "Effect" : "Deny", "Action" : "Update:*", "Principal": "*", "Resource" : "*", "Condition" : { "StringLike" : { "ResourceType" : ["AWS::RDS::DBInstance", "AWS::AutoScaling::*"] } } }, { "Effect" : "Allow", "Action" : "Update:*", "Principal": "*", "Resource" : "*" } ] } |
스택 정책에 대한 보다 많은 정보는 Prevent Updates to Stack Resources 참고하라.
마지막으로, 여러분의 모든 스택에 알맞은 미리 정의된 스택 정책을 가지고 있는지를 확인해라. 이것을 해결할려면 IAM 정책을 봐야 한다.
Condition:StackPolicyURL
여러분의 IAM 정책 내에서, 여러분은 모든 CloudFormation 스택이 StackPolicyURL 조건을 가지고 생성된 것과 연결된 스택 정책을 가지는지를 확인할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
{ "Version":"2012-10-17", "Statement":[ { "Effect": "Deny", "Action": [ "cloudformation:SetStackPolicy" ], "Resource": "*", "Condition": { "ForAnyValue:StringNotEquals": { "cloudformation:StackPolicyUrl": [ "https://s3.amazonaws.com/samplebucket/sampleallowpolicy.json" ] } } }, { "Effect": "Deny", "Action": [ "cloudformation:CreateStack", "cloudformation:UpdateStack" ], "Resource": "*", "Condition": { "ForAnyValue:StringNotEquals": { "cloudformation:StackPolicyUrl": [ “https://s3.amazonaws.com/samplebucket/sampledenypolicy.json” ] } } }, { "Effect": "Deny", "Action": [ "cloudformation:CreateStack", "cloudformation:UpdateStack", “cloudformation:SetStackPolicy” ], "Resource": "*", "Condition": { "Null": { "cloudformation:StackPolicyUrl": "true" } } }] } |
이 정책은 SetStackPolicy 가 호출될때마다 반드시 스택 정책 URL 이 지정되어 있는지 확인한다. 이 경우에, URL 은 https://s3.amazonaws.com/samplebucket/sampleallowpolicy.json 다. 유사하게, 모든 생성과 업데이트 스택 연산에서, 이 정책은 StackPolicyURL 은 S3 에 sampledenypolicy.json 문서로 지정되었고, StackPolicyURL 은 항상 지정된다. CLI 에서 create-stack 명령어는 다음과 같다.
1 |
aws cloudformation create-stack –stack-name cloudformation-demo –parameters ParameterKey=Password,ParameterValue=CloudFormationDemo –capabilities CAPABILITY_IAM –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template –stack-policy-url https://s3-us-east-1.amazonaws.com/samplebucket/sampledenypolicy.json |
주의해야 할 것은 만약 스택 업데이트에 새로운 스택 정책을 지정한다면, CloudFormation 은 이미 있는 스택 정책을 사용한다. 새로운 정책은 오직 이후 업데이트에만 새 정책을 사용한다. 예를들어, 현재 정책이 모든 업데이트를 거부하도록 지정되어 있다면, 딱 한개 업데이트를 허용하기 위해서 스택정책을 변경할려면 반드시 SetStackPolicy 명령어를 실행해야 한다. 그리고 여러분은 스택에 대해서 업데이트 명령어를 실행할 수 있다. 이미 생성된 스택 업데이트를 위해서 다음과 같이 실행 할 수 있다.
1 |
aws cloudformation set-stack-policy –stack-name cloudformation-demo –stack-policy-url https://s3-us-east-1.amazonaws.com/samplebucket/sampleallowpolicy.json |
그리고 업데이트를 실행할 수 있다.
1 |
aws cloudformation update-stack –stack-name cloudformation-demo –parameters ParameterKey=Password,ParameterValue=NewPassword –capabilities CAPABILITY_IAM –template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/IAM_Users_Groups_and_Policies.template –stack-policy-url https://s3-us-west-2.amazonaws.com/awshubfiles/sampledenypolicy.json |
우리가 사용하는 IAM 정책은 스택이 생성 혹은 업데이트 될때마다 스택에 적용되어질 특정한 스택 정책을 보장한다.
Conclusion
CloudFormation 은 연관된 AWS 리소스를 생성, 관리하는 반복적인 방법을 제공한다. IAM 정책, 사용자, 롤, CloudFormation-specific IAM condition, 스택 정책을 조합해 사용함으로써, 여러분은 CloudFormation 스택을 의도한데로 사용하고 잘못된 업데이트, 삭제를 최소할 수 있다.
You can learn more about this topic and other CloudFormation best practices in the recording of our re:Invent 2015 session, (DVO304) AWS CloudFormation Best Practices, and in our documentation.