AWS 노트

AWS 특정 IAM 역할로 S3 버킷에 대한 접근을 제한하기 (적당히 해석)

Jonchann 2020. 4. 10. 12:19

원문: How to Restrict Amazon S3 Bucket Access to a Specific IAM Role

 

나는 AWS의 클라우드 서포트 엔지니어인데 고객들이 종종 어떻게 아마존 S3 버킷에 대한 접근을 특정 AWS IAM 역할로 제한하느냐 묻곤 한다. 일반적으로 그들은 IAM 사용자와 같은 방식으로 이것을 시도한다: 접근 승인을 하고 싶지 않은 Principals(정책에서 자원에 대한 접근이 호용되거나 거부되는 보안 주체를 지정하는 요소)를 모두 거부(Deny)한다. 이 방식의 문제점은 버킷 정책 유지가 요구된다는 점이다. 만약 모든 작업(Action)에 대해 "s3:\*"가 적용된 새로운 IAM 사용자는 버킷에 접근할 수 있을 것이다. 접근을 차단하고 싶은 사용자 목록을 특정시키기 보다 logic을 반전시키고 NotPrincipal 요소를 버킷 정책의 Deny 명령문에 추가하는 방법을 사용할 수 있다. 이 요소는 목록에 들어가 있지 않은 어떤 사용자도 명시적으로 Deny한다.

 

하지만 이런 반전 논리 접근법은 IAM 역할에 관한 문제를 갖고 있다. 역할의 Principal역할(role)ARN(아마존 리소스 네임)과 수행자 역할(assumed-role)ARN이라는 두 ARN으로 구성되어있기 때문이다. 역할 ARNIAM 역할 그 자체의 식별자이고 수행자 역할 ARN은 로그에서 무엇이 역할 세션을 식별하는지를 알려준다. NotPrincipal 요소를 사용할 때 두 ARN을 포함시켜야만 실패하지 않고 두 번째 ARN(수행자 역할 ARN)을 변수 이름에 포함시켜야한다. 보통 변수 문자열이 가는 곳에 와일드카드(\*)를 명시할텐데 이는 Principal 요소 혹은 NotPrincipal 요소에서도 허용되지 않는다. 이 포스팅에서 나는어떻게 IAM 역할 혹은 사용자의 S3 버킷에 대한 접근을 NotPrincipal 요소 대신 Conditions를 사용해 제한할 수 있는지 설명할 것이다. Admin 정책을 소유하는 계정과 같은 계정을 갖는 사용자 혹은 "s3:\*" 정책이 적용된 사용자라 하더라도 목록에 명시되어있지 않는 한 접근이 거부될 것이다. 이러한 방법을 사용해 예를 들어, Auto Scaling group에 있는 인스턴스의 버킷에 대한 접근을 설정할 수도 있다. 또한, 높은 보안 수준을 요구하는 버킷에 대한 접근도 제한할 수 있다.

솔루션 개요

이 포스트에서 제안하는 해결법은 S3의 모든 API에 대한 접근 권한을 가지고 있는 경우에도 S3 버킷에 대한 접근을 통제하기 위해 버킷 정책을 사용한다. 아래 그림은 같은 계정 안에서 어떤 식으로 동작하는지 묘사하고 있다.

1. IAM 사용자의 정책과 역할의 사용자 정책이 "s3:*"로의 접근을 승인한다.

2. S3 버킷 정책은 오직 역할만으로 접근을 제한한다.

3. IAM 사용자와 역할은 계정이 소유하는 버킷에 접근할 수 있다. 역할은 두 버킷에 전부 접근할 수 있지만 사용자는 버킷 정책이 적용되지 않은 버킷에만 접근할 수 있다. 역할과 사용자 둘 다 "s3:*" 허가를 갖고 있다 할지라도 버킷 정책은 역할이 부여되지 않은 모든 사람들의 버킷에 대한 접근을 무효화한다.

앞서 말한 경우와 교차 계정의 경우의 가장 큰 차이점으로 모든 버킷이 반드시 버킷 정책을 가지고 있어야 한다는 것을 꼽을 수 있다. 아래 그림은 교차 계정의 경우에 어떻게 동작하는지 보여준다.

1. 버킷 계정의 IAM 역할의 사용자 정책과 IAM 사용자의 정책은 "s3:*"로의 접근을 승인한다.

2. 버킷 정책은 만약 user:id가 역할과 일치하지 않는 모두의 접근을 거부하고 정책은 역할이 버킷으로 무엇을 할 수 있는지 정의한다.

3. 버킷 정책은 다른 계정에서의 역할에 대한 접근을 허가한다.

NotPrincipal 요소와 사용법을 이해하기

IAM 혹은 S3 버킷 정책NotPrincipal 요소를 특정 사용자 집단의 자원에 대한 접근을 제한하기 위해 사용할 수 있다. 이 요소는 값 배열에 정의되지 않은 모든 사용자를 차단한다. 그들의 IAM 사용자 정책에서 Allow가 적혀있다고 해도 말이다. 결과적으로 S3에 있는 특정 버킷을 제외한 모든 버킷에 접근해야하는 사용자가 있다면 사용자의 IAM 정책 스택을 수정하지 않고 이를 버킷에 정의할 수 있다.

 

IAM 역할에 있어서, Principal이 두개 ARN으로 역할이 정의되어 있기 때문에 사실 더 복잡하다: 역할 ARN수행자 역할 ARN. 역할 ARN(arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME)은 정적이고 역할 세션을 사용하기 시작한 사람과는 별개이다. (이 포스트 전체에 적혀있는 모든 빨간색 대문자 대신 본인의 정보를 기입해야 한다는 사실을 기억하기 바란다). 수행자 역할 ARN(arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME)은 역할 세션 이름이 어떻게 정의되어 있느냐에 따라 달라진다. 역할을 수행한 사용자가 API를 호출하기 위해 만든 아래 AWS CloudTrailIdentity 요소를 보면 이를 확인할 수 있다.

{
"type": "AssumedRole",
"principalId": "AROAJI4AVVEXAMPLE:ROLE-SESSION-NAME",
"arn": "arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME",
"accountId": "ACCOUNTNUMBER",
"accessKeyId": "ASIAEXAMPLEKEY",
"sessionContext": {
 "attributes": {
   "mfaAuthenticated": "false",
   "creationDate": "XXXX-XX-XXTXX:XX:XXZ"
 },
 "sessionIssuer": {
   "type": "Role",
   "principalId": "AROAJI4AVV3EXAMPLEID",
   "arn": "arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME",
   "accountId": "ACCOUNTNUBMER",
   "userName": "ROLE-SESSION-NAME"
 }
}
}

위의 자격증명(Identity) 요소 내에 역할 ARN수행자 역할 ARN이 들어있는 것이 보일 것이다. ROLE-SESSION-NAME 은 잠재적으로 누가 역할을 수행하는지에 따라 변경된다. principalID 값은 이 정보를 포함하지만 버킷 정책의 Principal요소 밖에서 사용되는 형식으로 포맷된다. 나는 버킷 정책을 기술할 때 이 정보를 사용할 것이다.

특정 역할에 같은 계정 버킷 접근을 승인하기

같은 계정에서 버킷에 접근할 때 대부분의 경우에는 버킷 정책을 사용하지 않아도 된다. 사용자의 IAM 정책에서 이미 버킷 정책이 접근을 정의하고 있기 때문이다. S3 버킷 정책은 보통 교차 계정이 접근할 때 사용되지만 버킷처럼 같은 계정에 속해있든 다른 계정에 속해있든 모든 Principal에 적용될 명시적인 Deny를 통해 접근을 제한할 때에도 사용할 수 있다.

IAM 엔티티(사용자, 그룹 혹은 역할)는 aws:userid 값이 정의되어있다. 버킷 정책에서 조건적으로 역할 혹은 사용자를 특정해 제외하려면 이 값이 필요할 것이다. 수행자 역할의 aws:userId 값은 UNIQUE-ROLE-ID:ROLE-SESSIOM-NAME (예를 들어, AROAEXAMPLEID:userdefinedsessionname)와 같이 정의된다.

IAM 역할을 위해 AROAEXAMPLEID를 얻기 위해 아래를 따라하면 된다.

1. AWS CLI를 설치하고 커맨드 프롬프트 혹은 셸을 연다.

2. aws iam get-role --role-name ROLE-NAME을 실행한다.

3. 출력값으로 RoleID 문자열이 나올 것이다. AROA로 시작한다. 이 역할만이 버킷에 접근하도록 버킷 정책에서 이를 사용면 된다.

앞서 보여준 CloudTrail 코드 예시에서 이 ID는 principalId 요소이다. 이 요소의 값은 중요한데 AWS 정책 값이 IAM 정책에서도 문자열로 확인되기 때문이다. NotPrincipal요소에 있는 역할과 수행자 역할 ARN을 명시하는 대신 와일드카드 문자열과 함께 StringNotLike 조건 속에 있는 aws:userId 값을 사용할 수도 있다. aws:userId 값에 루트 사용자(처음 계정을 만든 사용자)를 정의된 역할이 삭제되어 아무도 접근하지 못하게 될 때에 대비해 추가해야 한다. 루트 계정의 userId는 계정 숫자이다.

AWS CLI를 통해 얻은 AROAEXAMPLEID를 사용하는 것은 이 역할을 사용하는 사용자들을 위해서만 작동하는 버킷에 접근하는 버킷 정책의 조건 로직을 만들 수 있다. 조건 로직을 사용하는 것은 NotPrincipal요소가 어떠한 역할 세션 이름이라도 승인되는 와일드카드 문자열을 허용하는 것 보다 낫다.

접근을 허가하기 위한 ID를 이제는 갖고 있으니 같은 계정의 버킷에 다른 사용자들이 접근하지 못하도록 해야 한다. 버킷에의 접근을 차단하는 정책과 IAM 역할 혹은 루트 계정을 사용하지 않는 사용자들의 객체는 아래와 같은 자격증을 발급한다.

{
"Version": "2012-10-17",
"Statement": [
 {
   "Effect": "Deny",
   "Principal": "*",
   "Action": "s3:*",
   "Resource": [
     "arn:aws:s3:::MyExampleBucket",
     "arn:aws:s3:::MyExampleBucket/*"
   ],
   "Condition": {
     "StringNotLike": {
       "aws:userId": [
         "AROAEXAMPLEID:*",
         "111111111111"
       ]
     }
   }
 }
]
}

IAM 사용자들을 위한 같은 정책에 사용해도 된다. IAM 사용자는 AIDA로 시작하는 특이한 ID를 갖고 있는데 이 목적으로 사용할 수 있다. AIDA로 시작하는 특이한 ID를 얻기 위해서:

1. AWS CLI가 설치된 상태에서 커맨드 프롬프트나 셸을 기동시킨다.

2. aws iam get-user --user-name (USER-NAME)을 실행한다.

3. 출력값으로 userId 문자열을 얻고 이는 AIDAEXAMPLEID와 같은 형식일 것이다.

식별된 userId를 얻었으면 아래 예시와 같이 "aws:userId" 조건 배열에 대입하면 된다.

{
"Version": "2012-10-17",
"Statement": [
 {
   "Effect": "Deny",
   "Principal": "*",
   "Action": "s3:*",
   "Resource": [
     "arn:aws:s3:::MyExampleBucket",
     "arn:aws:s3:::MyExampleBucket/*"
   ],
   "Condition": {
     "StringNotLike": {
       "aws:userId": [
         "AROAEXAMPLEID:*",
         "AIDAEXAMPLEID",
         "111111111111"
       ]
     }
   }
 }
]
}

특정 IAM 역할을 통한 교차 계정 버킷 접근 승인하기

앞에서 같은 계정 IAM 역할 혹은 사용자의 S3 버킷에의 접근 제한 방법을 서술했다. 지금부터 교차 계정의 경우를 설명할 것이다. IAM 사용자 혹은 역할을 통한 교차 계정 버킷 접근을 승인할 때 IAM 사용자 혹은 역할이 무엇을 위해 접근이 허용된 것인지 정의해야 한다. 앞서 올라온 AWS 보안 블로그에서 Jim Scharf는 CLI/API와 콘솔을 통한 버킷 접근을 위한 IAM 엔티티를 허용하는 법에 대해 적었다. 이 정보를 활용하면 CLI/API 차원의 접근을 서술한 버킷 정책은 아래와 같다.

{
 "Version": "2012-10-17",
 "Statement": [
     {
         "Effect": "Allow",
         "Principal": {
             "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
         },
         "Action": "s3:ListBucket",
         "Resource": "arn:aws:s3:::MyExampleBucket"
     },
     {
         "Effect": "Allow",
         "Principal": {
             "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
         },
         "Action": [
             "s3:GetObject",
             "s3:PutObject",
             "s3:DeleteObject"
         ],
         "Resource": "arn:aws:s3:::MyExampleBucket/*"
     },
     {
         "Effect": "Deny",
         "Principal": "*",
         "Action": "s3:*",
         "Resource": [
             "arn:aws:s3:::MyExampleBucket",
             "arn:aws:s3:::MyExampleBucket/*"
         ],
         "Condition": {
             "StringNotLike": {
                 "aws:userId": [
                     "AROAEXAMPLEID:*",
                     "111111111111"
                 ]
             }
         }
     }
 ]
}

작업을 수행하기 위해서는 아래와 같은 콘솔에서의 IAM 역할 전환 기능을 동반한 콘솔 차원의 접근이 요구된다.

{
 "Version": "2012-10-17",
 "Statement": [
     {
         "Effect": "Allow",
         "Principal": {
             "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
         },
         "Action": [
             "s3:ListAllMyBuckets",
             "s3:GetBucketLocation"
         ],
         "Resource": "*"
     },
     {
         "Effect": "Allow",
         "Principal": {
             "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
         },
         "Action": "s3:ListBucket",
         "Resource": "arn:aws:s3:::MyExampleBucket"
     },
     {
         "Effect": "Allow",
         "Principal": {
             "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
         },
         "Action": [
             "s3:GetObject",
             "s3:PutObject",
             "s3:DeleteObject"
         ],
         "Resource": "arn:aws:s3:::MyExampleBucket/*"
     },
     {
         "Effect": "Deny",
         "Principal": "*",
         "Action": "s3:*",
         "Resource": [
             "arn:aws:s3:::MyExampleBucket",
             "arn:aws:s3:::MyExampleBucket/*"
         ],
         "Condition": {
             "StringNotLike": {
                 "aws:userId": [
                     "AROAEXAMPLEID:*",
                     "111111111111"
                 ]
             }
         }
     }
 ]
}

다른 계정의 IAM 사용자에게 API/CLI 접근 승인을 하기 위해서는 IAM 사용자를 위해 앞서 했던 것과 같이 "aws:userId"AIDAEXAMPLEID를 대입해야 한다. "aws:userId" 조건에 IAM 사용자의 이러한 정책의 Principal요소에 대한 모든 ARN을 추가해야 한다. IAM 사용자에 교차 계정 콘솔을 승인할 수 없다는 것을 기억해야 한다. 왜냐 하면, 사용자는 목적 계정에서 역할을 수행해야 하기 때문이다. 하지만 API/CLI를 통해 버킷에의 접근을 승인할 수 있다. 아래와 같이.

{
 "Version": "2012-10-17",
 "Statement": [
     {
         "Effect": "Allow",
         "Principal": [
             {
                 "AWS": [
                     "arn:aws:iam::222222222222:role/ROLENAME",
                     "arn:aws:iam::222222222222:user/USERNAME"
                 ]
             }
         ],
         "Action": "s3:ListBucket",
         "Resource": "arn:aws:s3:::MyExampleBucket"
     },
     {
         "Effect": "Allow",
         "Principal": [
             {
                 "AWS": [
                     "arn:aws:iam::222222222222:role/ROLENAME",
                     "arn:aws:iam::222222222222:user/USERNAME"
                 ]
             }
         ],
         "Action": [
             "s3:GetObject",
             "s3:PutObject",
             "s3:DeleteObject"
         ],
         "Resource": "arn:aws:s3:::MyExampleBucket/*"
     },
     {
         "Effect": "Deny",
         "Principal": "*",
         "Action": "s3:*",
         "Resource": [
             "arn:aws:s3:::MyExampleBucket",
             "arn:aws:s3:::MyExampleBucket/*"
         ],
         "Condition": {
             "StringNotLike": {
                 "aws:userId": [
                     "AROAEXAMPLEID:*",
                     "AIDAEXAMPLEID",
                     "111111111111"
                 ]
             }
         }
     }
 ]
}

게다가 버킷 정책에 역할 허가를 포함하려면 IAM 사용자 혹은 역할 사용자의 정책에 이러한 허가를 정의해야 한다. 허가는 직접 관리하는 정책에 추가될 수 있고 IAM 콘솔의 역할 혹은 사용자에 적용할 수 있다:

{
"Version": "2012-10-17",
"Statement": [
 {
   "Effect": "Allow",
   "Action": [
     "s3:ListAllMyBuckets",
     "s3:GetBucketLocation"
   ],
   "Resource": "*"
 },
 {
   "Effect": "Allow",
   "Action": "s3:ListBucket",
   "Resource": "arn:aws:s3:::MyExampleBucket"
 },
 {
   "Effect": "Allow",
   "Action": [
     "s3:GetObject",
     "s3:PutObject",
     "s3:DeleteObject"
   ],
   "Resource": "arn:aws:s3:::MyExampleBucket/*"
 }
]
}

이 포스팅을 따라하면 Admin 정책을 가진 사용자 혹은 "s3:*"가 적용된 로컬 계정 혹은 교차 계정의 특정 IAM 역할 혹은 사용자를 S3 버킷에 제한 할 수 있게 된다. (이하생략)