AWS, IAM 에 특정 TAG KEY/VALUE 조건을 사용한 리소스 제어
AWS Identity and Access Management(IAM)는 AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스다. IAM 에 대한 자세한 내용은 AWS Documents 를 참고하길 바라며, 이 글에서는 IAM 을 통한 권한 제어를 간단히 설명하고자 한다.
인프라를 설계하고, 형상을 만들어 개발자들에게 Access Key 를 제공해 직접 해당 Service/Instance에 접근하는 형태가 일반적이다. 하지만, 불가피하게 AWS Web Console 을 사용해야 하거나, AWS API 를 사용해야 하는 경우 Account 생성 및 권한을 부여해야 하는 경우가 있다. 문제는 IAM Role 설정에 문제가 있는 것. 간단한 경험을 공유하고자 한다.
내가 생각하는 조건
- 주요 서비스 목록은 확인할 수 있어야 한다.
- 자원 제어를 위해선 특정 Tag 를 생성해야 한다.
- 특정 Tag 가 있는 경우는 제어할 수 없다.
- 삭제는 할 수 없다.
AWS IAM 의 기본 권한 구조는 다음과 같다.
Step 1. IAM 정책을 생성하자. Describe* 는 기본적인 목록을 볼 수 있게 만들어준다. 이외에 ‘태그 지정’은 기본적으로 사용할 수 있도록 제한을 풀자.
Step 2. 특정 Tag 가 존재하는 경우에만 쓰기(=제어) 가 가능하다. RequestTag 로 지정하면 된다. 아래 내용은 WorkerName Tag 에 내 ID 가 있는 경우에만 제어할 수 있다는 의미다.
Step3. 특정 Tag 가 있는 경우 제어할 수 없다. 제어하지 말아야하는 서비스/인스턴스가 있는 경우에 사용한다.
Step4. 기본적으로 ‘삭제’, ‘차단(Terminate)’ 는 막는다. 참고로, 이 부분을 지정하지 않고, 위에 ‘허용/쓰기’ 부분에서 이 요소드를 제거해도 무관하다.
자, 생성된 IAM ROLE 은 다음과 같다.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "ec2:DisassociateAddress", "ec2:CopySnapshot", "ec2:ImportVolume", "ec2:UnmonitorInstances", "ec2:PurchaseReservedInstancesOffering", "ec2:ExportTransitGatewayRoutes", "ec2:MoveAddressToVpc", "ec2:DetachClassicLinkVpc", "ec2:MonitorInstances", "ec2:PurchaseHostReservation", "ec2:WithdrawByoipCidr", "ec2:CopyImage", "ec2:A*", "ec2:UpdateSecurityGroupRuleDescriptionsIngress", "ec2:StartInstances", "ec2:UnassignIpv6Addresses", "ec2:R*", "ec2:UnassignPrivateIpAddresses", "ec2:ImportImage", "ec2:EnableVpcClassicLink", "ec2:PurchaseScheduledInstances", "ec2:DetachVolume", "ec2:DisassociateTransitGatewayRouteTable", "ec2:Create*", "ec2:UpdateSecurityGroupRuleDescriptionsEgress", "ec2:Can*", "ec2:DetachNetworkInterface", "ec2:ImportInstance", "ec2:BundleInstance", "ec2:ImportKeyPair", "ec2:DisassociateClientVpnTargetNetwork", "ec2:ProvisionByoipCidr", "ec2:ImportSnapshot", "ec2:Disable*", "ec2:DetachInternetGateway", "ec2:CopyFpgaImage", "ec2:StopInstances", "ec2:DisassociateRouteTable", "ec2:DisassociateSubnetCidrBlock", "ec2:EnableVolumeIO", "ec2:DetachVpnGateway", "ec2:ImportClientVpnClientCertificateRevocationList", "ec2:Modify*", "ec2:DisassociateIamInstanceProfile", "ec2:EnableVgwRoutePropagation", "ec2:EnableVpcClassicLinkDnsSupport", "ec2:EnableTransitGatewayRouteTablePropagation", "ec2:ConfirmProductInstance" ], "Resource": "*", "Condition": { "StringEquals": { "ec2:ResourceTag/WorkerName": "${aws:username}" } } }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "ec2:Desc*", "iam:PassRole", "ec2:DeleteTags", "ec2:CreateTags", "ec2:RunInstances" ], "Resource": "*" }, { "Sid": "VisualEditor2", "Effect": "Deny", "Action": [ "ec2:Terminate*", "ec2:Delete*" ], "Resource": "*" } ] }
정책 시뮬레이터를 통해 올바르게 동작하는지 확인해보자.
- https://policysim.aws.amazon.com/home/index.jsp
문제가 없어 보인다. 그럼 정상적으로 동작할 것이고 이 글을 왜 쓰는가!?
“You are not authorized to perform this operation.”
정상적으로 Tag 가 있음에도 불구하고 제어할 수 없기 때문. 그리고 이 오류에는 별도의 메시지를 동반하기 때문에 능동적으로 조치할 수가 없다. 이상한건, RunInstance/StopInstance 등의 명령은 사용할 수 있지만, 수정(Modify), 추가(Add) 계열 기능에서 주로 오류가 발생한다. 원인은 정확하지 않다. 하지만 이래 저래 테스트 해 본 결과 Condition 부분을 수정해야 한다는 것을 찾았다.
단순히 StringEquals 만 있는 경우 특정 기능 동작 시 ResourceTag 부분이 동작하지 않는다는 걸 발견했다. 이 문제는 “ForAllValues” 를 추가해 줌으로서 해결 가능했던 것. 참고로 ForAllValue는 에디터에서 선택할 수 있는 방법이 없다.
"Condition": { "ForAllValues:StringEquals": { "ec2:ResourceTag/WorkerName": "${aws:username}" } }
이외에 AWS IAM 에 여러가지 문제를 발견했다. RDS 의 Tag 를 추가하려면 req-tag 를 사용하라 메뉴얼에 나와 있지만, 실제 IAM 해당 Key 는 찾을 수 없었다. (힘들다 ㅠㅠ)