[AWS] AWS IAM Roles Anywhere 적용하기

rex.chun
28 min readJul 17, 2022

--

AWS IAM Roles Anywhere 라는 기능이 출시됐다.

일전에도 다양한 방법을 통해 엑세스키의 발급없이도 사용이 가능했고, 실제로 해당 아이디어를 통해 구현한 블로그도 있었다.

다만, 지속적으로 사용해야하는 경우 안정성에 대한 보장을 해당 회사의 엔지니어들이 보장해야된다는 것과 뭔가 강제로 만든 것 같은 찝찝함이 있었기에 보통은 엑세스키를 발급받아 사용했었다.

하지만 이제는 그럴 필요가 없어졌다. 새롭게 출시된 기능을 통해 온프레미스에서도 키가 아닌 역할을 사용할 수 있게 됐다.

참고한 사이트는 맨 아래에 첨부해놓았다.

1. Root CA 생성

$ openssl genrsa -aes256 -out rexchun-rootca.key 2048Generating RSA private key, 2048 bit long modulus
.....+++
..........+++
e is 65537 (0x10001)
Enter pass phrase for rexchun-rootca.key:
Verifying - Enter pass phrase for rexchun-rootca.key:

Root CA 개인키의 안전한 보관을 위해 암호를 설정한다.

2. CSR(Certificate Signing Request) 요청 파일 생성

[ req ]
default_bits = 2048
default_md = sha256
default_keyfile = rexchun-rootca.key
distinguished_name = req_distinguished_name
extensions = v3_ca
req_extensions = v3_ca
[ v3_ca ]
basicConstraints = critical, CA:TRUE, pathlen:0
subjectKeyIdentifier = hash
##authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = keyCertSign, cRLSign
nsCertType = sslCA, emailCA, objCA
[req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = KR
countryName_min = 2
countryName_max = 2
organizationName = Organization Name (eg, company)
organizationName_default = rexchun Inc.
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Rexchun Project
commonName = Common Name (eg, your name or your server's hostname)
commonName_default = rexchun's Self Signed CA
commonName_max = 64

rexchun_rootca_openssl.conf 파일에 위 내용을 저장 후, 아래 명령어를 입력하여 결과를 확인한다.

$ openssl req -new -key rexchun-rootca.key -out rexchun-rootca.csr -config rexchun_rootca_openssl.confEnter pass phrase for rexchun-rootca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [KR]:
Organization Name (eg, company) [rexchun Inc.]:
Organizational Unit Name (eg, section) [Rexchun Project]:
Common Name (eg, your name or your servers hostname) [rexchuns Self Signed CA]:

3. CRT(Certificate) 파일 생성(인증서)

openssl x509 -req -days 3650 \
-extensions v3_ca \
-set_serial 1 \
-in rexchun-rootca.csr \
-signkey rexchun-rootca.key \
-out rexchun-rootca.crt \
-extfile rexchun_rootca_openssl.conf \
-sha256

파일 생성이 완료되면 아래 명령을 입력하여 결과를 확인한다.

$ openssl x509 -text -in rexchun-rootca.crtCertificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=KR, O=rexchun Inc., OU=Rexchun Project, CN=rexchuns Self Signed CA
Validity
Not Before: Jul 17 02:25:21 2022 GMT
Not After : Jul 14 02:25:21 2032 GMT
Subject: C=KR, O=rexchun Inc., OU=Rexchun Project, CN=rexchuns Self Signed CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:9f:17:21:65:2e:f3:f7:00:ac:ad:5a:f6:e0:b7:
...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier: 52:5E:05:6C:...
X509v3 Key Usage:
Certificate Sign, CRL Sign
Netscape Cert Type:
SSL CA, S/MIME CA, Object Signing CA
Signature Algorithm: sha256WithRSAEncryption
8d:c2:83:74:15:05:cc:27:47:15:6f:83:e2:f7:d2:60:aa:f0:
...
-----BEGIN CERTIFICATE-----
MIIDkDCCAn...
-----END CERTIFICATE-----

굵게 표시한 부분을 꼭 확인한다. IAM Roles Anywhere를 사용하기 위해서는 몇 가지 규칙을 준수해야한다. 링크를 참고하자.

루트인증서를 Trust Anchor에 등록하기 위해서는 아래 조건이 충족되어야한다.

Certificates used as trust anchors must satisfy the same requirements for signature algorithm, but with the following differences:1. The key usage must include Digital Signature, Certificate Sign, and CRL Sign.
2. Basic constraints must include CA: true.

4. Trust Anchor 등록

‘역할’ 메뉴에 접근 후 아래로 내리면 Roles Anywhere가 나온다. ‘관리' 버튼을 누른 후, ‘트러스트 앵커 생성’을 클릭한다.

일전에 생성한 rexchun-rootca.crt의 내용을 복사하여 ‘외부 인증서 번들'에 등록하고 ‘트러스트 앵커 생성'을 클릭한다.(이때, 외부 인증서 번들을 통해 등록을 진행해야 한다.)

성공적으로 완료됐다면, 목록에서 생성된 트러스트 앵커 링크를 클릭하여 ARN을 복사해둔다.

5. IAM Roles Anywhere 전용 역할 생성

Roles Anywhere를 신뢰할 수 있는 엔터티로 선택하고 ‘ReadOnlyAccess’ 권한을 선택 후 원하는 역할명을 입력하여 역할을 생성한다.(이때 역할의 ARN은 따로 복사해둔다.)

6. 프로파일 생성

역할 생성이 완료됐다면 프로파일을 생성해준다. 이때, 생성한 역할을 등록하고 아무것도 건드리지 않고 바로 생성한다.

프로파일까지 모두 생성했다면 AWS에서 할 수 있는 모든 준비는 끝이났다.

7. Roles Anywhere 사용을 위한 인증서 발급

이제 서버에서 사용할 인증서를 생성해보자.

$ openssl genrsa -aes256 -out rexchun.com.key 2048Generating RSA private key, 2048 bit long modulus
.................................................+++
..............+++
e is 65537 (0x10001)
Enter pass phrase for rexchun.com.key:
Verifying - Enter pass phrase for rexchun.com.key:
$ cp rexchun.com.key rexchun.com.key.enc
$ openssl rsa -in rexchun.com.key.enc -out rexchun.com.key
Enter pass phrase for rexchun.com.key.enc:
writing RSA key

신규 인증서를 위한 개인키를 생성하고, 암호화를 해제해준다.

이때 생성된 rexchun.com.key 파일의 상단에 아래와 같이 내용이 출력되는지 확인한다.

[성공]
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA3hjh7bUGud8+AMmK2GwMFXLUivpOoAWmKMM55zmPor9pO2N0
[실패]
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED

8. CSR(Certificate Signing Request) 요청 파일 생성

[req]
default_bits = 2048
default_md = sha256
default_keyfile = rexchun-rootca.key
distinguished_name = req_distinguished_name
extensions = v3_user
[v3_user]
basicConstraints = CA:FALSE
authorityKeyIdentifier = keyid,issuer
subjectKeyIdentifier = hash
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth,clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.rexchun.com
DNS.2 = rexchun.com
DNS.3 = *.rexchun.com
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = KR
countryName_min = 2
countryName_max = 2
organizationName = Organization Name (eg, company)
organizationName_default = rexchun Inc.
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Rexchun Project
commonName = Common Name (eg, your name or your server's hostname)
commonName_default = rexchun.com
commonName_max = 64

rexchun_host_openssl.conf 파일에 위 내용을 저장 후, 아래 명령어를 입력하여 결과를 확인한다.

$ openssl req -new -key rexchun.com.key -out rexchun.com.csr -config rexchun_host_openssl.confYou are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [KR]:
Organization Name (eg, company) [rexchun Inc.]:
Organizational Unit Name (eg, section) [Rexchun Project]:
Common Name (eg, your name or your servers hostname) [rexchun.com]:

9. CRT(Certificate) 파일 생성(인증서)

$ openssl x509 -req -days 1825 -extensions v3_user -in rexchun.com.csr \
-CA rexchun-rootca.crt -CAcreateserial \
-CAkey rexchun-rootca.key \
-out rexchun.com.crt \
-extfile rexchun_host_openssl.conf \
-sha256
Signature ok
subject=/C=KR/O=rexchun Inc./OU=Rexchun Project/CN=rexchun.com
Getting CA Private Key
Enter pass phrase for rexchun-rootca.key:

파일 생성이 완료되면 아래 명령을 입력하여 내용을 확인한다.

$ openssl x509 -text -in rexchun.com.crtCertificate:
Data:
Version: 3 (0x2)
Serial Number: 15481608681461087905 (0xd6d9b9121a177ea1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=KR, O=rexchun Inc., OU=Rexchun Project, CN=rexchuns Self Signed CA
Validity
Not Before: Jul 17 02:58:19 2022 GMT
Not After : Jul 16 02:58:19 2027 GMT
Subject: C=KR, O=rexchun Inc., OU=Rexchun Project, CN=rexchun.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:de:18:e1:ed:b5:06:b9:df:3e:00:c9:8a:d8:6c:
...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Authority Key Identifier:
keyid:52:5E:05:6C:29:A2:5F:6A:E3:88:C3:2A:89:D7:CC:18:FA:33:DC:E3
X509v3 Subject Key Identifier:
A8:EF:02:30:6C:1D:69:7B:80:78:4E:80:28:B8:B1:D3:47:8E:73:21
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Alternative Name:
DNS:www.rexchun.com, DNS:rexchun.com, DNS:*.rexchun.com
Signature Algorithm: sha256WithRSAEncryption
9b:58:72:c0:ee:10:aa:7e:29:09:2d:60:5b:23:a5:a7:c9:f1:
...
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIJANbZuRIaF36hMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
...
-----END CERTIFICATE-----

발급된 인증서를 사용하기 위해서는 아래 조건이 충족되어야 한다.

End entity certificates must satisfy the following constraints to be used for authentication:1. The certificates must be X.509v3.
2. Basic constraints must include CA: false.
3. The key usage must include Digital Signature.
4. The signing algorithm must include SHA256 or stronger. MD5 and SHA1 signing algorithms are rejected.

10. 인증서와 개인키를 사용하여 인증정보 획득하기

먼저 링크에 접속하여 사용 환경에 맞는 바이너리 파일을 다운로드한다.

이후, chmod와 같은 명령을 활용하여 실행권한을 부여하고 실행해본다.

$ ./aws_signing_helper 
2022/07/17 12:03:23 No command provided

명령이 정상적으로 수행됨을 확인했다면, 아래 형식으로 다시 한 번 명령어를 입력한다.

./aws_signing_helper credential-process \
--certificate /path/to/certificate \
--private-key /path/to/private-key \
--trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID \
--profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID \
--role-arn arn:aws:iam::account:role/role-name-with-path

예시는 여기서 볼 수 있다.

./aws_signing_helper credential-process \
--certificate rexchun.com.crt \
--private-key rexchun.com.key \
--trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-2:ACCOUNT_ID:trust-anchor/a68e4021-0efd-45c2-bc51-d0a6537b6639 \
--profile-arn arn:aws:rolesanywhere:ap-northeast-2:ACCOUNT_ID:profile/7d2acc38-0dfb-450e-ac0d-86c322e24b17 \
--role-arn arn:aws:iam::ACCOUNT_ID:role/rexchun-iam-roles-anywhere-test-role
{"Version":1,"AccessKeyId":"ACCESS_KEY_ID","SecretAccessKey":"SECRET_ACCESS_KEY","SessionToken":"SESSION_TOKEN","Expiration":"2022-07-17T04:06:22Z"}

여기까지 모두 완료했다면 이제 시스템에 등록하여 사용하는 방법을 살펴보자.

11. ~/.aws/config 파일에 등록하여 사용하기

적용 전 credential_process에 대한 내용은 링크를 참고하자.(환경변수를 활용할 수 없는 등 제한되는 내용에 대해 숙지하자.)

아래 명령을 입력하여 ~/.aws 경로에 인증서와 키를 복사한다.

$ cp rexchun.com.crt rexchun.com.key ~/.aws/

config 파일에 프로파일을 등록한 후 저장한다.(이때, ACCOUNT_ID 부분을 자신의 계정번호로 변경해준다.

[profile roles-anywhere]
credential_process = ./aws_signing_helper credential-process --certificate rexchun.com.crt --private-key rexchun.com.key --trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-2:ACCOUNT_ID:trust-anchor/a68e4021-0efd-45c2-bc51-d0a6537b6639 --profile-arn arn:aws:rolesanywhere:ap-northeast-2:ACCOUNT_ID:profile/7d2acc38-0dfb-450e-ac0d-86c322e24b17 --role-arn arn:aws:iam::ACCOUNT_ID:role/rexchun-iam-roles-anywhere-test-role
region=ap-northeast-2

region을 입력하지 않을 시 오류가 발생할 수 있음에 주의하고, 내부 환경에서 사용해야한다면 rolesanywhere 엔드포인트를 생성한 후, --endpoint 옵션을 추가로 사용한다.(온프레미스 서버의 경우 DNS를 해석하지 못할 수 있으므로 DNS 서버에 엔드포인트 IP를 등록해주거나, /etc/hosts에 등록하여 사용한다.)

추가로 절대경로로 등록하지 않으면 내가 입력하고 있는 경로를 기준으로 동작하기 때문에 어디서든 사용하고 싶다면 절대경로로 입력해야한다.

2022. 7. 17.(일) 19:08 수정

config 파일에 설정된 credential_process에 상대경로로 넣으면 현재 내가 쉘에서 위치하고 있는 경로의 영향을 받게된다. 그러므로 위와 같이 ./ 으로 설정을 부여했다면 현재 위치한 경로에 해당 파일들이 존재해야 한다.

완료됐으면 명령을 입력하여 확인한다.

$ aws sts get-caller-identity --profile roles-anywhere"UserId": "ROLE_ID:SESSION_NAME",
"Account": "ACCOUNT_ID",
"Arn": "arn:aws:sts::ACCOUNT_ID:assumed-role/rexchun-iam-roles-anywhere-test-role/SESSION_NAME"
}

여기까지 모두 된다면 성공적으로 적용이 완료된 것이다.

12. 세션정책(Session Policy) 적용하기

세션정책과 관련된 정보는 링크를 참고하자.

세션을 생성할 때 사용하는 API 중 GetFederationToken, AssumeRole류는 적용되는 방법은 조금 다르지만 여기서는 해당 내용은 설명하지 않도록 한다.

어쨋든 간단히 말해서 세션정책은 실제로 적용되는 정책은 아니지만 IAM의 Permission Boundaries와 비슷하게 최대로 보유할 수 있는 정책에 대한 제한과 여러 조건(Condition)을 설정할 수 있다.

여기서는 IP에 대한 제한과, CN(Common Name)을 통한 제한을 살펴본다.

IP 제한(IP Restriction)

프로파일에서 인라인 정책을 위와 같이 변경해준다. 당연히 1.1.1.1/32 를 사용하진 않을 것이므로 오류가 나야한다. 확인해보자.(프로파일 페이지 최상단의 ‘편집' 버튼을 누르면 수정이 가능하다.)

$ aws sts get-caller-identity --profile roles-anywhere{
"UserId": "ROLE_ID:SESSION_NAME",
"Account": "ACCOUNT_ID",
"Arn": "arn:aws:sts::ACCOUNT_ID:assumed-role/rexchun-iam-roles-anywhere-test-role/SESSION_NAME"
}

??? 정상적으로 출력된다. 뭔가 이상하다고 생각할 수 있지만 이는 의도된 동작이다. 링크를 참고하자.

그렇다면 다른 API를 호출하여 확인해보자.

$ aws ec2 describe-instances --profile roles-anywhereAn error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.

의도한대로 동작함을 확인할 수 있다. IP를 본인의 IP로 변경한 후에 시도해보면 결과가 오류없이 나오는 것을 확인할 수 있을 것이다.

CN(Common Name) 제한

주체 활동(Subject Activity)에 들어가보면 우리가 생성한 인증서를 통해 인증되고 있는 현황을 볼 수 있다. 여기서 rexchun 이라는 CN으로 요청오는 경우만 허용하도록 제한해보자.

$ aws ec2 describe-instances --profile roles-anywhereAn error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.

의도한대로 요청이 거부된다. 해당 값을 rexchun.com 으로 변경해본다.

$ aws ec2 describe-instances --profile roles-anywhere
{
"Reservations": []
}

성공이다.

13. CloudTrail 로그 확인하기

Roles Anywhere 동작방식에 대한 설명은 링크를 참고하자.

간단히 말해 “AssumeRole -> RolesAnywhere -> CreateSession -> 키수령 -> 실제API 수행” 의 순서라고 보면 될 것 같다.(혹시 틀린 부분이 있다면 댓글 부탁한다.)

실제로 EC2 DescribeInstances API를 호출했을 때 아래와 같이 남게된다.

AssumeRole

CreateSession

DescribeInstances

요청을 받은 RolesAnywhere가 AssumeRole 호출 -> CreateSession 호출(이때 사용자 IP로 요청 들어감) -> 키값반환 -> DescribeInstances 호출

결론적으로 정책을 준수하지 않으면 실제 호출하는 API에서 오류가 발생한다.(물론 이건 이미 확인한 내용이긴 하다.)

14. 주의사항

CN(Common Name)에는 특수문자(* 등)가 포함되면 안된다.

15. 결론

매우 좋은 기능이다. 앞에서 살펴본 세션 정책 외에도 신뢰관계(Trust Relationship)을 통한 추가적인 제한도 가능할 것으로 보이고(아마 세션 정책은 큰 그림, 신뢰관계는 작은 그림의 개념으로 정책을 수립하지 않을까?), 키 로테이션 90일 이라는(하지만 지키기는 쉽지 않은..) 취약점 점검 항목에 대해서도 해결가능한 기능이다. 처음 출시됐을 때는 오류가 너무 불친절해서 사용하기 너무 힘들었는데 불평을 많이 들었는지 빠르게 패치한 것 같다.

물론 AWS에서 제공하는 PCA(Private Certificate Authority)를 활용하면 훨씬 쉽게 인증서와 키를 만들고 추출(export)할 수 있다.(이때 키는 암호화돼서 나오므로 복호화 과정이 필요하다.)

하지만, 알다시피 PCA는 키는 순간 한달 400불이라는 어마어마한 과금이 들기때문에 자체 Root CA를 통해 기능을 활용하는 글을 작성했다.

이제 회사에서 적용해보자!

참고링크

  1. 실무에서 사용중인 AWS 클라우드 IAM 이해와 보안
  2. OpenSSL 로 ROOT CA 생성 및 SSL 인증서 발급 : https://www.lesstif.com/system-admin/openssl-root-ca-ssl-6979614.html
  3. Setup AWS “Instance Profile” for on-prem servers : https://jackiechen.blog/2020/12/11/setup-instance-profile-for-on-prem-servers/
  4. https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html#credential-helper-examples
  5. https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html
  6. https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policy-types
  7. https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
  8. https://aws.amazon.com/ko/blogs/security/extend-aws-iam-roles-to-workloads-outside-of-aws-with-iam-roles-anywhere/

--

--