새로운 IAM 권한 제어 방식 – IAM Permissions Boundary 이해하기
여기서 다루는 내용
· 들어가며
· IAM Permissions Boundary의 정의
· 상황 A
· 대안 A
· 마치며
들어가며
안녕하십니까, GS네오텍 최준승입니다.
저는 수많은 AWS 서비스 중에 개인적으로 IAM 서비스에 관심이 많은 편인데요.
이유야 여러가지가 있습니다.. 개인 취향인것도 있고. 중요도에 비해 대중 관심이 떨어지기도 하고. 좀 어렵기도 하고. 그렇습니다.
그래서 저는 AWS 업데이트를 읽을때 개인적으로 IAM 서비스를 좀 주의깊게 보는 편입니다.
아마 `18년 7월쯤인가요? 관련해서 “IAM Permissions Boundary” 라는 기능이 새로 나왔습니다.
당시 한번 쭉 읽어보고 포스팅 목록에 넣어놨는데. 문제는 이 기능을 어디에 활용할지가 감이 전혀 안오더군요.
동작 방식을 이해하더라도. 결국 쓸모가 없다면 의미가 없으니까요. AWS도 누군가 쓰라고 만든거 아니겠습니까?
암튼 그렇게 3개월을 쭉 묵히다가. 어제 고객사 담당자의 멘트에서 힌트를 똭 얻었습니다.
그래서 오늘 아주 간단하게 이 내용을 다뤄볼 예정입니다.
딱 5분만 읽어보세요.
What is IAM Permissions Boundary?
AWS 공식링크의 정의부터 살펴봅시다.
IAM Permissions Boundary is..
2줄 Ver
- When you use a policy to set the permissions boundary for a user,
- it limits the user’s permissions but does not provide permissions on its own.
1줄 Ver
- The permissions boundary for a user or role limits the maximum permissions that the entity can have.
여러분들은 이미 이해가 다 가셨겠지만. 다시 한번 요약하면.
- 퍼미션 바운더리에서 정의한 권한은 실제 권한을 부여하는 것은 아니다
- 다만 연결된 IAM User나 Role에서 가질 수 있는 최대 권한을 제약?한다
여기서 핵심은 제약한다는 부분인데요.
이 부분에서 생략된 말은 “다른 IAM Policy에서 정의한 권한과 동시에 적용될때” 영향(제약을 가함)을 끼친다는 것입니다.
그래도 잘 감이 안오니. 예시를 보도록 하겠습니다.
상황 A
Jazzmaster라는 IAM User가 있습니다. 이 IAM User에는 EC2 서비스 읽기 권한만 부여하려고 합니다.
AWS가 만들어놓은 템플릿 객체(AmazonEC2ReadOnlyAccess)에는 권한이 이렇게 정의되어 있네요.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ec2:Describe*", "Resource": "*" }, { "Effect": "Allow", "Action": "elasticloadbalancing:Describe*", "Resource": "*" }, { "Effect": "Allow", "Action": [ "cloudwatch:ListMetrics", "cloudwatch:GetMetricStatistics", "cloudwatch:Describe*" ], "Resource": "*" }, { "Effect": "Allow", "Action": "autoscaling:Describe*", "Resource": "*" } ] }
이렇게 잘 쓰고 있다가.. 문득 IAM 권한을 관리하던 담당자가. 이런 생각을 하게 되었습니다.
- 우리는 어차피 tokyo region에만 리소스가 있는데. 다른 region의 권한까지 줄 필요가 있나?
- 마침 얼마전(?)에 IAM 권한을 특정 리전으로 제한하는 Condition이 새로 나왔으니 한번 써보자
그래서 Jazzmaster에게 추가로 이런 Inline Policy를 부여했습니다.
{ "Version": "2012-10-17", "Statement": { "Sid": "RegionRestricted", "Effect": "Allow", "Action": "*", "Resource": "*", "Condition": { "StringEquals": { "aws:RequestedRegion": "ap-northeast-1" } } } }
그럼 아래처럼 됩니다. 권한 2개가 붙었죠?
#1 이제 생각한대로 되는지 한번 보겠습니다.
$ aws ec2 describe-instances --region ap-northeast-1
{
"Reservations": [
{
"Instances": [
(skip)
- 도쿄 리전의 EC2 인스턴스 목록 요청 → Allow
오, 원하는대로 잘 되네요.
#2 이번엔 서울 리전의 객체를 조회해 보겠습니다. 이건 Deny가 떠야 합니다.
$ aws ec2 describe-instances --region ap-northeast-2
{
"Reservations": [
{
"Instances": [
(skip)
- 서울 리전의 EC2 인스턴스 목록 요청 → Allow
엥? 이것도 되네요? 분명히 리전 조건을 걸었는데. 왜 되는걸까요?
#3 이번엔 아무 생각없이 dynamodb 테이블도 한번 조회해 보겠습니다.
$ aws dynamodb list-tables --region ap-northeast-1
{
"TableNames": [
"test"
]
}
- 도쿄 리전의 DynamoDB 테이블 목록 요청 → Allow
이건 또 왜 조회가 될까요? 산넘어산이네요. 그 이유는 이어서 살펴보도록 하겠습니다.
상황 A가 발생한 이유
상황 A가 발생하는 이유는 하나의 객체에 여러개의 IAM Policy가 주어졌을때. Allow의 경우 OR 조건으로 해석하기 때문입니다.
그림으로 그리면 이렇습니다.
담당자가 의도한건 ②의 영역이지만, 실제 IAM에서 해석해서 부여된 권한은 ①②③이 되는 셈입니다.
상황 A에서 #2와 #3이 결국 ③의 영역에 포함되기 때문에. 의도와 다르게 허용이 된것이지요. 이해가 가시나요?
그럼 이제 우리는 어떻게 해야할까요?
대안 A – 세련되지 못한
실제 담당자의 의도대로 권한을 구성하려면. 2가지 방법이 있습니다.
첫번째는 Condition 조건을 기존 IAM Policy에 모두 병합시키는 방법입니다.
Allow 정책이 3개면. 3개 모두 끝에 Condition 조건을 추가하는 것이죠. 매우 귀찮은 일이고 사실상 사후 관리가 불가능합니다.
두번째는 Deny가 Allow에 우선으로 해석되는 것을 활용하는 방법입니다.
“O면 Allow”가 아니라 “O가 아니면 Deny”로 여집합을 정의하는 것이지요.
regionrestrict라는 Inline Policy를 아래처럼 수정하는 셈입니다. 빨간색 표시가 기존 권한에서 변경된 부분입니다.
{ "Version": "2012-10-17", "Statement": { "Sid": "RegionRestricted", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "StringNotEquals": { "aws:RequestedRegion": "ap-northeast-1" } } } }
이렇게 되면. 위 벤다이어그램처럼 되고 각 영역은 이렇게 해석이 됩니다.
- 영역 ①: AmazonEC2ReadOnlyAccess에서 Allow, regionrestrict에서 Deny → Deny가 우선이므로 Deny
- 영역 ②: AmazonEC2ReadOnlyAccess에서 Allow, regionrestrict에서 해당없음 → Allow
- 영역 ③: AmazonEC2ReadOnlyAccess에서 해당없음, regionrestrict에서 해당없음 → 암묵적 Deny
그럼 결국 ②만 허용이니 의도대로 돌아가긴 하겠네요.
하지만 가장 큰 문제는 세련된 맛이 없습니다. 관리도 좀 어려울 것 같구요.
그래서 나온 해답이 바로 오늘의 주제인 IAM Permissions Boundary입니다.
대안 A – 세련된
이번엔 IAM Permissions Boundary를 사용해 보겠습니다.
regionrestrict도 아래처럼 원래 문법으로 복원하였습니다.
{ "Version": "2012-10-17", "Statement": { "Sid": "RegionRestricted", "Effect": "Allow", "Action": "*", "Resource": "*", "Condition": { "StringEquals": { "aws:RequestedRegion": "ap-northeast-1" } } } }
그리고 Jazzmaster에 권한을 다음과 같이 설정합니다.
기존과 다른점은. regionrestrict를 Permissions policies 위치가 아니라 Permissions boundary 위치에 넣었습니다!!
이렇게 되면. 원하는 영역의 권한을 세련된 방식으로 제한할 수 있습니다.
이제 생각한대로 되는지 한번 보겠습니다.
$ aws ec2 describe-instances --region ap-northeast-1
{
"Reservations": [
{
"Instances": [
(skip)
- 도쿄 리전의 EC2 인스턴스 목록 요청 → Allow
이번엔 서울 리전의 객체를 조회해 보겠습니다. 이건 Deny가 떠야 합니다.
$ aws ec2 describe-instances --region ap-northeast-2
An error occurred (UnauthorizedOperation) when calling the (skip)
- 서울 리전의 EC2 인스턴스 목록 요청 → Deny
이제 원하는대로 동작하는군요.
마치며
이해가 되셨나요?
간단히 쓴다고 했는데 내용을 붙이고 붙이다 보니 내용이 너무 길어졌네요.
이해가 좀 어렵긴 하지만 제 생각에는 분명히 쓸모 있는 기능입니다.
특히 기존에 부여된 권한이 복잡하고 다계층일 경우 더욱 효용이 높아질 것 같구요.
아무리 쉽게 설명한다고 구성을 해도.
눈 앞에 데려다 놓고 설명하는게 아니라서. 글로 설명하는게 쉽지 않은 일인듯 합니다.
어딘가 저처럼 IAM 서비스에 관심이 많으신 분이 계셨다면..
또는 여기까지 이 글을 읽으신 분이 계시다면.. 도움이 되셨으면 좋겠습니다.
그럼 마치겠습니다. 끝!
최신 댓글