Terraform에서 AWS Provider를 사용할 때 AWS 자격 증명 정보를 하드 코딩하는 것은 보안에 매우 취약하다.
Vault에서는 해당 문제를 해결하기 위해 AWS Secrets Engine 기능을 제공한다.
AWS Secrets Engine은 동적으로 AWS 자격 증명을 생성하고 관리하는 데 사용된다. 이를 통해, Terraform 코드에 자격 증명 정보를 저장하지 않고도 AWS 리소스를 관리할 수 있다.
Vault의 AppRole은 Vault에서 생성된 role_id와 secret_id를 통해 동적으로 자격 증명을 생성하여 인증하는 방식이다. Vault의 AWS STS Assume Role은 Vault에서 AWS STS API를 사용하여 AWS iam role을 통해 일회성 자격 증명을 생성한다. 이러한 방식으로 생성된 자격 증명은 일정 기간이 지나면 자동으로 만료되므로 보안성이 높아진다.
동작 절차는 아래와 같다.
이번 글에서는 AppRole 인증 방식과 AWS Secrets Engine의 AWS STS AssumeRole을 사용하여 테라폼에서 자격증명을 얻어 리소스를 생성하는 실습을 다룰 것이다.
실습은 Vault 설정이 필요하므로 Vault가 구성되어 있지 않다면, [HashiCorp Vault 설치] 글을 참고하여 설치하고 진행하면 된다.
실습 절차
1. Vault aws secrets engine(sts assumed_role) 구성2. Vault approle 구성
3. Terraform 파일 설정
4. 이슈 해결
실습 환경
- Terraform 버전 : v1.2.1
- Vault provider 버전 : v2.24.1
- Vault APP 버전: 1.12.1
- Vault Helm Chart 버전 : 0.23.0
실습
1. Vault aws secrets engine(sts assumed_role) 구성
Vault에서 사용할 role을 만든다.
## trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{account_id}:user/{user_name}"
},
"Action": "sts:AssumeRole"
}
]
}
$ aws iam create-role \
--role-name my-role \
--assume-role-policy-document file://trust-policy.json \
--description "my role for AssumeRole"
만든 iam role에 알맞은 정책을 넣어준다.
다른 Account에 대한 role은 아래와 같이 정책을 추가하면 된다.
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:role/RoleNameToAssume"
}
}
root token으로 Vault에 로그인한다.
$ kubectl exec -it -n vault sts/vault -- /bin/sh
/ $ vault login hvs.XXXXXXXXXX
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token hvs.XXXXXXXXXXXX
token_accessor 8mPHZDIUmjluDM2sI3koW1bj
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
aws secrets을 활성화한다.
$ vault secrets enable aws
Success! Enabled the aws secrets engine at: aws/
AWS 자격 증명에 필요한 aws_access_key_id, aws_secret_access_key를 알맞게 넣어준다.
아래 credentials 권한을 이용하여 aws role에 접근한다.
$ vault write aws/config/root \
access_key={aws_access_key_id} \ ## 알맞게 aws credentials 입력
secret_key={aws_secret_access_key} \ ## 알맞게 aws credentials 입력
region=ap-northeast-2
Success! Data written to: aws/config/root
위에서 만든 aws iam role의 arn을 입력하고 assumed_role type의 role을 만든다.
$ vault write aws/roles/my-role \
role_arns={aws_role_arn} \
credential_type=assumed_role
Success! Data written to: aws/roles/my-role
2. Vault approle 구성
approle Auth Methods를 활성화한다.
$ vault auth enable approle
Success! Enabled approle auth method at: approle/
approle에서 사용할 policy를 생성한다.
$ vault policy write aws_policy -<<EOF
path "aws/sts/my-role" {
capabilities = ["read","update"]
}
path "aws/creds/my-role" {
capabilities = ["read","update"]
}
path "auth/token/create" {
capabilities = ["create", "read", "update", "delete", "list"]
}
EOF
위에서 만든 aws_policy를 지정하여 approle을 생성한다.
$ vault write auth/approle/role/aws_role token_policies="aws_policy" \
token_ttl=1h token_max_ttl=4h
Success! Data written to: auth/approle/role/aws_role
## 생성 확인
$ vault read auth/approle/role/aws_role
Key Value
--- -----
bind_secret_id true
local_secret_ids false
secret_id_bound_cidrs <nil>
secret_id_num_uses 0
secret_id_ttl 0s
token_bound_cidrs []
token_explicit_max_ttl 0s
token_max_ttl 4h
token_no_default_policy false
token_num_uses 0
token_period 0s
token_policies [aws_policy]
token_ttl 1h
token_type default
approle의 role_id, secret_id를 가져온다. 해당 값은 Terraform tf파일에 넣어줘야 하니 기억해 두자.
$ vault read auth/approle/role/aws_role/role-id
Key Value
--- -----
role_id {approle role_id}
$ vault write -force auth/approle/role/aws_role/secret-id
Key Value
--- -----
secret_id {approle secret id}
secret_id_accessor 10e457d1-f96b-c306-faf7-ca26db9481cb
secret_id_num_uses 0
secret_id_ttl 0s
approle로 로그인하여 assumed_role을 통한 token 정보를 잘 가져오는지 확인한다.
$ vault write auth/approle/login role_id="{approle role_id}" secret_id="{approle secret_id}"
Key Value
--- -----
token hvs.xxxxxxxxxxx3cxxxxU1MR1k ## 해당 값으로 로그인
token_accessor Ym18YCNx86HqDyGxye50f4U1
token_duration 1h
token_renewable true
token_policies ["aws_policy" "default"]
identity_policies []
policies ["aws_policy" "default"]
token_meta_role_name aws_role
위 token값으로 로그인
## approle 로그인
$ vault login hvs.xxxxxxxxxxx3cxxxxU1MR1k
Key Value
--- -----
token hvs.xxxxxxxxxxx3cxxxxU1MR1k
token_accessor Ym18YCNx86HqDyGxye50f4U1
token_duration 59m53s
token_renewable true
token_policies ["aws_policy" "default"]
identity_policies []
policies ["aws_policy" "default"]
token_meta_role_name aws_role
## sts 조회
$ vault read aws/sts/my-role
Key Value
--- -----
lease_id aws/sts/my-role/nmoyR2muYPi4bNQr9SifNoLa
lease_duration 1h
lease_renewable false
access_key AXXXXXXXXXXXX
arn arn:aws:sts::xxxxxxxxxx:assumed-role/my-role/vault-approle-my-role-1682401311-3UFyrfLQeNDhtGflrOB4
secret_key PxxxxmRxxxxxxxx
security_token Ixxxxxxxxxxxxxxxxxxx
3. Terraform 파일 설정
아래는 테라폼 코드이다.
## vault.tf
terraform {
#...
vault = {
source = "hashicorp/vault"
version = "~> 2.0"
}
}
}
## vault provider
provider "vault" {
address = "{vault ipaddr}"
auth_login {
path = "auth/approle/login"
parameters = {
role_id = "{approle role_id}" ## 위 approle role_id 정보를 넣어준다
secret_id = "{approle secret_id}" ## 위 approle secret_id 정보를 넣어준다
}
}
}
## vault access credentials
data "vault_aws_access_credentials" "iam" {
region = "ap-northeast-2"
backend = "aws"
role = "my-role"
type = "sts"
}
## aws provider
provider "aws" {
access_key = data.vault_aws_access_credentials.iam.access_key
secret_key = data.vault_aws_access_credentials.iam.secret_key
token = data.vault_aws_access_credentials.iam.security_token
}
## output
output "token" {
value = data.vault_aws_access_credentials.iam
# sensitive = true ## vault provider version 3.0 이상부터 필수로 적용해야 한다.
}
terraform apply 하면 data.vault_aws_access_credentials 블록에서 정보를 읽어오는 것을 확인할 수 있다.
$ terraform apply
data.vault_aws_access_credentials.cred: Reading...
data.vault_aws_access_credentials.cred: Read complete after 0s [id=aws/sts/my-role/QdAK2e70AQg1o9Ha1DK4d382]
output 내용
Outputs:
token = {
"access_key" = "ASIXXXXXXXXX"
"backend" = "aws"
"id" = "aws/sts/my-role/QdAK2e70AQg1o9Ha1DK4d382"
"lease_duration" = 7200
"lease_id" = "aws/sts/my-role/QdAK2e70AQg1o9Ha1DK4d382"
"lease_renewable" = false
"lease_start_time" = "2023-04-25T05:18:52Z"
"region" = "ap-northeast-2"
"role" = "my-role"
"role_arn" = tostring(null)
"secret_key" = "PXXXXXXXXXXXXXXFV"
"security_token" = "IQoJb3JpZ2luXXXXXXXXXXXXXXjV12HWz42yEINSQxjbQVWXXXXXXXXXXXXXX5eZZWvPkD8RNaxZmLBtYc8ofmEo1jKnayGQ9uak6irSAgj+//////////8BEAMaDDAwMDk4MjE5MTIxOCIMyyWAwWTwUY49GCylKqYCOQwWZIgyWszlR9Rrt4IhQUnECRJ22nN+p12ranr/BGvW+mJif1M0MnoAyPkrU5uYKpdbspz7EF4cojxq3S0+VQVxiqsZVazAcGAI5HwUBzS9hnAQNzxf0noDort18pNf+pSbHChbiKoTn8/JJG21eu/80pNrjiXgb+56u6V3F8sXquscdgN1fHPMwzbtXkljenStTs+SVFkB0cEzUWaJRyEHTf6k7Oom9y2nmJyeVP4BJuYWUvQhd2sMcB46hBaH2rn+fVoQMMjxrlssNQEzNVeTkleHvgrc3e4utqDigvij63boQvIx6kNw+ueIFwZLtJbP3simW3yUekGMLVZMcdeYK+E/M2FSKDF2p2iodAnflaeR6E+E/RxuHzzMsV6718yquumUMLzFnaIGOp4BjZwiJxfr9RgqanErhShOTqpVE3ReyawucVADMkvsE8sld1WtN36GjeevmeKVi/cjDHv2GTXIyEt01qh8OXgU0tVMjVrktyq7gAjkdLm9epV391gpGCXwq+BQ9slecUiKaWxarl0EFbksO+URdRQJ2C6CnmXPcvcFrkZF9sKIzMlhEIFDVsBb7cc6ve3J0sNQHxHvGfzCNbbq7u1/NZ0="
"ttl" = "7200"
"type" = "sts"
}
approle을 통한 로그인 이력 및 token 정보를 확인한다.
[Vault 대시보드]
[AWS Console Cloud Trail]
4. 이슈 해결
[참고]
테라폼에서 helm, kubectl, kubernetes provider를 사용할 경우 "error: Unauthorized"와 같은 에러가 나올 수 있다.
이는 vault assumed_role을 통해 토큰을 받아 terraform을 사용하려는데, 만료된 경우이거나, 권한이 없어 EKS에 접근할 수 없는 경우 발생할 수 있다.
체크 1.
aws-auth configMap에 aws iam role이 잘 들어가 있는지 확인한다.
$ kubectl get cm -n kube-system aws-auth -oyaml
mapRoles: |
- rolearn: arn:aws:iam::{account_id}:role/my-role ## aws role arn
username: testuser
groups:
- system:masters
체크 2.
assumed_role을 용하여 토큰을 다시 받아오도록 Terraform retry 시도.
토큰이 만료되지 않게 aws iam role의 최대 세션 지속시간과 token ttl 시간을 적절하게 설정한다.
[참고]
aws iam role의 MaxSessionDuration 시간 이하로 설정해야 한다
## vault.tf
data "vault_aws_access_credentials" "cred" {
region = "ap-northeast-2"
backend = "aws"
role = "my-role"
type = "sts"
ttl = "7200" ## ttl 시간을 늘린다.
}
마치며
이번 포스팅에서는 Terraform + Vault approle + Vault aws secrets engine 연동 실습을 통해 AWS 자격 증명을 동적으로 생성하고, Terraform에서 안전하게 사용하는 방법을 알아보았다. 이를 통해 AWS 자격 증명을 효율적으로 안전하게 관리할 수 있다.
현재 Vault 최신 버전인 1.13.1에서 위와 같이 구성하면 Vault aws secrets engine의 iam_user 방식은 정상 동작하지만 Assumed_role 방식을 사용하면, Terraform에서 vault_aws_access_credentials 값들을 전부 null로 가져오는 이슈가 있다. 해당 문제는 추 후 해결하면 내용을 추가할 예정이다.
'IaC > Terraform' 카테고리의 다른 글
Terraform Cloud Drift Detection이란? (0) | 2024.03.05 |
---|---|
Terraform Cloud Agent 개념 및 사용 방법 (0) | 2024.02.29 |
Terraform Cloud를 활용한 Kubernetes Provider 동적 자격 증명 구성(Dynamic Provider Credentials) (0) | 2024.01.09 |
Terraform Cloud를 활용한 AWS Provider 동적 자격 증명 구성(Dynamic Provider Credentials) (0) | 2024.01.09 |
Terraform Local -> Terraform Cloud로 마이그레이션 (0) | 2023.04.06 |
댓글