다음은 주말 CloudNet 테라폼 스터디 내용 참고하여 정리한 부분입니다.
https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
리소스와 데이터 소스 관리
보완 방법 :
Environment variables 환경 변수로 관리
Encrypted files 암복호화로 관리
Secret stores로 관리
기본 서울리전에서 작업하자.
KMS가 리전 서비스 이다.
KMS를 이용하는 예가 있다.
aws configure
ap-northeast-2
디폴트 네트워크가 있어야한다.
mkdir test
cd test
<1> 리소스와 데이터 소스 -Environment variables 환경 변수로 관리
<2> 리소스와 데이터 소스 -Encrypted files 암복호화로 관리
<3> 리소스와 데이터 소스 -Secret stores로 관리
<4> 상태 파일과 planfile 관리
<1> 리소스와 데이터 소스 -Environment variables 환경 변수로 관리
1
리소스와 데이터 소스에 민감 정보 노출 - 예) 데이터베이스 암호 등
[Resources and data sources]Environment variables 환경 변수
2
환경 변수 Environment variables
아래 처럼 DB 계정 정보를 변수로 사용 설정
variable "db_username" {
description = "The username for the database"
type = string
sensitive = true
}
variable "db_password" {
description = "The password for the database"
type = string
sensitive = true
}
3
위 정보를 리소스에 전달
resource "aws_db_instance" "example" {
identifier_prefix = "terraform-up-and-running"
engine = "mysql"
allocated_storage = 10
instance_class = "db.t2.micro"
skip_final_snapshot = true
db_name = var.db_name
# Pass the secrets to the resource
username = var.db_username
password = var.db_password
}
4
환경 변수로 전달 : TF_VAR_<변수이름>
export TF_VAR_db_username=(DB_USERNAME)
export TF_VAR_db_password=(DB_PASSWORD)
5
장점 : 모든 언어에서 환경 변수를 설정 및 쉽게 쓸 수 있고, 추가 비용이 들지 않음
단점: 팀원 모두 환경 변수 수동 사용 관리가 필요, (테라폼 외부) 비밀 번호 관리 표준화가 어려움, 각 환경에서 버저닝/패키징/테스트 시 암호 환경 변수 지정 시 설정 오류 발생 가능
<2> 리소스와 데이터 소스 -Encrypted files 암복호화로 관리
# 사전 작업
# aws cli v2 install
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
aws-cli/2.0.30
1
암호를 파일에 저장 후 버전 관리 → 암호화 키를 클라우드 공급자 KMS를 통해 안전하게 저장 혹은 PGP 키 사용
Resources and data sources]Encrypted files
2
cli로 kms 키 만들고 사용해보자.
3
# 키 생성(기본값) - 키 생성하고 변수로 등록하자.
# aws kms create-key --description "my text encrypt descript demo"
CREATE_KEY_JSON=$(aws kms create-key --description "my text encrypt descript demo")
echo $CREATE_KEY_JSON | jq
[root@ip-172-31-61-209 ~]# echo $CREATE_KEY_JSON | jq
{
"KeyMetadata": {
"Origin": "AWS_KMS",
"KeyId": "b44d1",
"Description": "my text encrypt descript demo",
"KeyManager": "CUSTOMER",
"EncryptionAlgorithms": [
"SYMMETRIC_DEFAULT"
],
"Enabled": true,
"CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
콘솔에서 확인
해당 리전으로 이동 > KMS로 이동 >고객 관리형키가 만들어져 있다.
4
# 키 ID를 뽑아낸다.
KEY_ID=$(echo $CREATE_KEY_JSON | jq -r ".KeyMetadata.KeyId")
echo $KEY_ID
5
# 키 alias 생성
export ALIAS_SUFFIX=<각자 닉네임>
export ALIAS_SUFFIX=masterseo
aws kms create-alias --alias-name alias/$ALIAS_SUFFIX --target-key-id $KEY_ID
aws kms list-aliases
# 별칭 확인
"AliasName": "alias/masterseo",
# 콘솔에서 별칭 확인
6
CMK 평문 실습해보기 !!!
# CMK로 평문을 암호화해보기, 파일로 만들기
echo "Hello 123123" > secrect.txt
aws kms encrypt --key-id alias/$ALIAS_SUFFIX --cli-binary-format raw-in-base64-out --plaintext file://secrect.txt --output text --query CiphertextBlob | base64 --decode > secrect.txt.encrypted
# 파일 암호문 확인
cat secrect.txt.encrypted
# 파일 복호화
aws kms decrypt --ciphertext-blob fileb://secrect.txt.encrypted --output text --query Plaintext | base64 --decode
Hello 123123
7
AWS CMK(KMS Key) 생성을 위해 Key policy 생성
현재 사용자가 CMK 권한을 가질 수 있게 코드 설정해보자~~~
# aws cli 로 현재 사용자 정보 확인
aws sts get-caller-identity | jq
{
"Account": "45xxxxxxxxxxx83",
"UserId": "AIxxxxxxxxxxxxxxUYL",
"Arn": "arn:aws:iam::45xxxxxxx83:user/aws111"
}
8
# 테라폼에서 aws_caller_identity 데이터소스로 사용자 정보 확인
provider "aws" {
region = "ap-northeast-2"
}
# Look up the details of the current user
data "aws_caller_identity" "self" {}
9
현재 사용자에 KMS 권한 부여 정책 생성한다.
data "aws_iam_policy_document" "cmk_admin_policy" {
statement {
effect = "Allow"
resources = ["*"]
actions = ["kms:*"]
principals {
type = "AWS"
identifiers = [data.aws_caller_identity.self.arn]
}
}
}
10
resource "aws_kms_key" "cmk" {
policy = data.aws_iam_policy_document.cmk_admin_policy.json
}
11
kms는 id로 된 긴숫자 대신 , alias로 사용하자.
resource "aws_kms_alias" "cmk" {
name = "alias/kms-cmk-example"
target_key_id = aws_kms_key.cmk.id
}
12
cmk 생성완료
13
실습
DB계정 정보가 포함된 db-creds.yml 파일을 생성
cat <<EOT > db-creds.yml
username: admin
password: password
EOT
14
암호화
aws kms encrypt --key-id alias/$ALIAS_SUFFIX --cli-binary-format raw-in-base64-out --plaintext file://db-creds.yml --output text --query CiphertextBlob | base64 --decode | tee db-creds.yml.encrypted
u0s0nۺ▒`▒He.0▒M?e_▒7▒7FH▒3▒4U▒B(@'(▒j▒▒[▒▒
aws kms encrypt --key-id alias/$ALIAS_SUFFIX --cli-binary-format raw-in-base64-out --plaintext file://db-creds.yml --output text --query CiphertextBlob | tee db-creds.yml.encrypted2
AQICAHgSmCTHsrGP27rx/drzj4pFwzYY7U0/Z
// 이 타입만 됨
# 암호문 확인
cat db-creds.yml.encrypted
cat db-creds.yml.encrypted2
# 복호화해보기
cat db-creds.yml.encrypted = 복호화 됨
cat db-creds.yml.encrypted2 = 복호화 안됨
aws kms decrypt --ciphertext-blob fileb://db-creds.yml.encrypted --output text --query Plaintext | base64 --decode
username: admin
password: password
15
테라폼 코드에서 암호화(파일) 활용 할 수 있게 설정
data "aws_kms_secrets" "creds" {
secret {
name = "db"
payload = file("${path.module}/db-creds.yml.encrypted")
}
}
16
복호화된 값을 로컬 변수로 지정
locals {
db_creds = yamldecode(data.aws_kms_secrets.creds.plaintext["db"])
}
17
DB 계정과 암호를 aws_kms_secrets 의 복호화된 로컬 변수를 전달
resource "aws_db_instance" "example" {
identifier_prefix = "terraform-up-and-running"
engine = "mysql"
allocated_storage = 10
instance_class = "db.t2.micro"
skip_final_snapshot = true
db_name = var.db_name
# Pass the secrets to the resource
username = local.db_creds.username
password = local.db_creds.password
}
18
이제 안전하게 암호를 저장할 수 있고, 암호화된 파일은 버전 관리를 할 수 있습니다.
테라폼 코드에서 암호를 다시 읽을 수 있습니다.
19
cat <<EOT > rds.tf
provider "aws" {
region = "ap-northeast-2"
}
data "aws_kms_secrets" "creds" {
secret {
name = "db"
payload = file("\${path.module}/db-creds.yml.encrypted2")
}
}
locals {
db_creds = yamldecode(data.aws_kms_secrets.creds.plaintext["db"])
}
resource "aws_db_instance" "example" {
identifier_prefix = "terraform-up-and-running"
engine = "mysql"
allocated_storage = 10
instance_class = "db.t2.micro"
skip_final_snapshot = true
db_name = var.db_name
# Pass the secrets to the resource
username = local.db_creds.username
password = local.db_creds.password
}
EOT
20
cat <<EOT > variables.tf
variable "db_name" {
description = "The name to use for the database"
type = string
default = "example"
}
EOT
21
cat <<EOT > outputs.tf
output "address" {
value = aws_db_instance.example.address
description = "Connect to the database at this endpoint"
}
output "port" {
value = aws_db_instance.example.port
description = "The port the database is listening on"
}
EOT
cat db-creds.yml.encrypted2
AQICApFwzYY7U0/ZV+JN2TJ/WrPQJntcHP3CEQjAAAAgTB/BgkqhkiG9w0BBwa
22
확인
terraform init
terraform plan
terraform apply -auto-approve
실습을 위해 내용 다운로드
23
확인
aws rds describe-db-instances --query "*[].[DBInstanceIdentifier,MasterUsername,Endpoint.Address,Endpoint.Port]" --output text
24
삭제
terraform destroy -auto-approve
25
# 생성한 키 ID 변수 지정
KEY_ID=$(echo $CREATE_KEY_JSON | jq -r ".KeyMetadata.KeyId")
# 키 비활성화
aws kms disable-key --key-id $KEY_ID
# 키 삭제 예약 : 대기 기간(7일)
aws kms schedule-key-deletion --key-id $KEY_ID --pending-window-in-days 7
26
장점 : 암호를 평문 사용 절대 금지, 클라우드 KMS 활용
단점 : 도구 학습 필요, 자동화 환경에 적용 시 어려움, 여전히 암호 변경 어려움, 감사 로그 취약, 비밀 번호 관리 표준화 어려움
<3> 리소스와 데이터 소스 -Secret stores로 관리
1
중앙 집중식 비밀 저장소 서비스 사용 - AWS Secrets Manager, Google Secret Manager 등
[Resources and data sources]Secret stores
<4> 상태파일과 planfile 관리
상태 파일과 플랜 파일에 민감 정보 노출
State files : 테라폼 리소스와 데이터 소스에 전달되는 모든 민감정보는 테라폼 상태 파일에 평문으로 저장됨
백엔드 저장소에 저장 시 암호화 Store Terraform state in a backend that supports encryption
백엔드 액세스에 대한 접근 통제 Strictly control who can access your Terraform backend
다음 과정
https://brunch.co.kr/@topasvga/2844
https://brunch.co.kr/@topasvga/2421
감사합니다.