Ssoon

[6주차] 06 Terraform으로 Secret 관리 - Resources & Data Sources 본문

Terraform 101 Study

[6주차] 06 Terraform으로 Secret 관리 - Resources & Data Sources

구구달스 2022. 11. 27. 01:19
CloudNet@ 팀의 가시다님이 진행하는 Terraform 101 Study 06주차 정리입니다.

 

 

GitHub - kschoi728/T101: Terraform 101 Study

Terraform 101 Study. Contribute to kschoi728/T101 development by creating an account on GitHub.

github.com

✅ 환경 변수 - Environment variables

 💠 전달하려는 secret 에 대한 변수를 선언합니다.

   ✔ sensitiev = true 👉 terrform 을 실행할 때 값을 기록하지 않습니다.

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
}

 💠 해당 secret 가 필요한 Terraform 리소스에 변수를 전달합니다.

  username = var.db_username
  password = var.db_password

resource "aws_db_instance" "ssoon_ec2" {
  identifier_prefix   = "Ssoon"
  engine              = "mysql"
  allocated_storage   = 10
  instance_class      = "db.t2.micro"
  skip_final_snapshot = true
  db_name             = var.db_name

  #! secrets 를 리소스에 전달
  username = var.db_username
  password = var.db_password

  tags = {
    Name = "Ssoon-EC2"
  }
}

 💠 환경 변수 TF_VAR_foo를 설정하여 각 변수 foo에 대한 값을 전달합니다.

$ export TF_VAR_db_username=(DB_USERNAME)
$ export TF_VAR_db_password=(DB_PASSWORD)

🚩 Console 확인

 

📌 환경 변수를 통해 secrets 을 전달하면 코드에 일반 텍스트로 secrets 을 저장하는 것을 방지할 수 있지만 secrets 을 안전하게 저장하는 방법과 같은 중요한 질문에 대답하지는 않습니다.

 

환경 변수를 사용 장점

  • 코드 및 버전 제어 시스템에서 일반 텍스트 secrets 을 유지합니다.
  • 거의 모든 다른 secrets 관리 솔루션을 사용할 수 있으므로 secrets 을 저장하는 것이 쉽습니다
  • 모든 언어에서 환경 변수 읽기가 간단하므로 secrets 검색이 쉽습니다.
  • 환경 변수를 모의 값으로 쉽게 설정할 수 있으므로 자동화된 테스트와의 통합이 쉽습니다.
  • 다른 비밀 관리 솔루션과 달리 환경 변수를 사용하면 비용이 들지 않습니다

환경 변수를 사용 단점

  • 모든 것이 Terraform 코드 자체에 정의되어 있는 것은 아닙니다. 이것은 코드를 이해하고 유지하기 어렵게 만듭니다. 코드를 사용하는 모든 사용자는 이러한 환경 변수를 수동으로 설정하거나 wrapper scrip 를 실행하기 위해 추가 단계를 수행해야 함을 알아야 합니다
  • secrets 관리 관행을 표준화하는 것은 더 어렵습니다. secrets 의 모든 관리는 Terraform 외부에서 발생하므로 코드는 보안 속성을 적용하지 않으며 누군가가 여전히 안전하지 않은 방식으로 비밀을 관리하고 있을 수 있습니다(예: 비밀을 일반 텍스트로 저장).
  • secrets 는 코드와 함께 버전 지정, 패키징 및 테스트되지 않기 때문에 한 환경(예:스테이징)에 새 secrets 를 추가했지만 다른 환경(예: 프로덕션)에 추가하는 것을 잊는 것과 같은 구성 오류가 발생할 가능성이 큽니다.

 

✅ 암호화된 파일 - Encrypted files

파일의 일부 비밀과 같은 일부 데이터를 암호화하려면 암호화 키가 필요합니다. 암호화 키는 그 자체로 비밀이므로 안전하게 저장할 수 있는 방법이 필요합니다. 일반적인 솔루션은 클라우드 공급자의 KMS(예:AWS KMS, Google KMS, Azure Key Vault)를 사용하거나 팀에서 한 명 이상의 개
발자의 PGP 키를 사용하는 것입니다.

  • AWS에서 관리하는 암호화 키인 KMS 고객 관리형 키(CMK)를 생성해야 합니다
  • CMK를 생성하려면 먼저 IAM 정책인 키 정책을 정의해야 합니다.
  • 해당 CMK를 사용할 수 있는 사람을 정의합니다.
  • 현재사용자에게 CMK에 대한 관리자 권한을 부여하는 키 정책을 생성합니다.

 

💠 현재 사용자의 정보(사용자 이름, ARN 등)를 가져옵니다.

#! 현재 사용자의 세부 정보 조회
data "aws_caller_identity" "self" {}

💠 aws_iam_policy_document 을 사용하여 현재 사용자에게 CMK에 대한 관리 권한을 부여하는 정책을 생성합니다.

#! 현재 IAM 사용자를 CMK의 관리자로 만드는 정책
data "aws_iam_policy_document" "cmk_admin_policy" {
  statement {
    effect    = "Allow"
    resources = ["*"]
    actions   = ["kms:*"]
    principals {
      type        = "AWS"
      identifiers = [data.aws_caller_identity.self.arn]
    }
  }
}

💠 aws_kms_key 리소스를 사용하여 CMK를 생성합니다.

#! KMS Customer Managed Key (CMK) 생성
resource "aws_kms_key" "cmk" {
  policy = data.aws_iam_policy_document.cmk_admin_policy.json

  #! 테스트를 위해 짧은 삭제 기간을 설정
  deletion_window_in_days = 7
}

💠 기본적으로 KMS CMK는 긴 숫자 식별자(예: b7670b0eed67-28e4-9b15-0d61e1485be3)로만 식별되므로 aws_kms_alias 리소스를 사용하여 CMK에 대해 alias 을 생성합니다.

#! CMK에 대한 alias 생성
resource "aws_kms_alias" "cmk" {
  name          = "alias/${kms-cmk-ssoon}"
  target_key_id = aws_kms_key.cmk.id
}

 

위에 설정으로 terraform apply을 해보았지만 아래와 같이 error가 발생하여 IAM CONSOLE에서 "cmk_admin_policy" 을 수동으로 추가 하였습니다.

📢 CLI 확인

🚩 Console 확인

AWS만이 해당 암호화 키에 액세스할 수 있지만 AWS API 및 CLI를 사용하여 사용할 수 있습니다

💠 데이터베이스 자격 증명과 같은 몇 가지 비밀이 포함된 "db-creds.yml"이라는 파일을 생성합니다.

#! 암호화에 대한 일반 텍스트 입력의 예로 사용
username: admin
password: password

💠 AWS CLI을 통해 "aws kms encrypt" 명령을 사용하고 결과 암호 텍스트를 새 파일에 쓸 수 있는 " encrypt.sh" BASH Script 를 생성합니다.

#!/bin/bash

set -e

if [[ "$#" -ne 4 ]]; then
  echo "Usage: encrypt.sh <CMK_ID> <AWS_REGION> <INPUT_FILE> <OUTPUT_FILE>"
  exit
fi

CMK_ID="$1"
AWS_REGION="$2"
INPUT_FILE="$3"
OUTPUT_FILE="$4"

echo "Encrypting contents of $INPUT_FILE using CMK $CMK_ID..."
ciphertext=$(aws kms encrypt \
  --key-id "$CMK_ID" \
  --region "$AWS_REGION" \
  --plaintext "fileb://$INPUT_FILE" \
  --output text \
  --query CiphertextBlob)

echo "Writing result to $OUTPUT_FILE..."
echo "$ciphertext" > "$OUTPUT_FILE"

echo "Done!"

💠 "encrypt.sh" 를 사용하여 이전에 생성한 KMS CMK 로 "db-creds.yml" 파일을 암호화하고 결과 암호문을 "dbcreds.yml.encrypted" 라는 새 파일에 저장합니다.

./encrypt.sh \
alias/kms-cmk-ssoon \
ap-northeast-2 \
db-creds.yml \
db-creds.yml.encrypted

📢 CLI 확인

db-creds.yml(일반 텍스트 파일)을 삭제하고 dbcreds.yml.encrypted(암호화된 파일)를 버전 제어에 안전하게 체크인할 수 있습니다
Terraform 코드에서 해당 파일을 어떻게 사용할 수 있을까요?

 

💠 "aws_kms_secrets" date source을 사용하여 이 파일의 암호를 해독합니다.

file helper 기능을 사용하여 디스크에서 dbcreds.yml.encrypted를 읽고 KMS에서 해당 키에 액세스할 수 있는 권한이 있다고 가정하고 내용을 해독하고 원본 dbcreds.yml 파일의 내용을 다시 제공합니다.

data "aws_kms_secrets" "creds" {
  secret {
    name    = "db"
    payload = file("../kms-cmk/db-creds.yml.encrypted")
  }
}

💠 "aws_kms_secrets" date source 에서 데이터베이스 암호를 추출하고 YAML을 구문 분석한 다음 결과를 db_creds라는 로컬 변수에 저장합니다.

#! YAML 구문 분석
locals {
  db_creds = yamldecode(data.aws_kms_secrets.creds.plaintext["db"])
}

💠 db_creds 에서 사용자 이름과 암호를 읽고 해당 자격 증명을 aws_db_instance 리소스에 전달합니다.

resource "aws_db_instance" "ssoon_db" {
  identifier_prefix   = "ssoon"
  engine              = "mysql"
  allocated_storage   = 10
  instance_class      = "db.t2.micro"
  skip_final_snapshot = true
  db_name             = "ssoon"

  # Pass the secrets to the resource
  username = local.db_creds.username
  password = local.db_creds.password
}

🚩 Console 확인

환경 변수를 사용 장점

  • 코드 및 버전 제어 시스템에서 일반 텍스트 secrets 을 유지합니다.
  • secrets 은 버전 제어에서 암호화된 형식으로 저장되므로 나머지 코드와 함께 버전이 지정되고 패키징되고 테스트됩니다. 하나의 환경(예: 스테이징)에 새암호를 추가했지만 다른 환경(예: 프로덕션)에 추가하는 것을 잊는 것과 같은 구성 오류를 줄이는 데 도움이 됩니다.
  • 사용 중인 암호화 형식이 기본적으로 Terraform 또는 타사 플러그인에서 지원된다고 가정하면secrets 검색이 쉽습니다.
  • AWS KMS, GCP KMS, PGP 등 다양한 암호화 옵션과 함께 작동합니다.
  • 모든 것은 코드에 정의되어 있습니다.

환경 변수를 사용 단점

  • secrets 을 저장하는 것은 더 어렵습니다. 많은 명령을 실행해야 합니다(예: aws kms 암호화)
  • 테스트 환경에서 암호화 키와 암호화된 테스트 데이터를 사용할 수 있도록 추가 작업을 수행해야 하므로 자동화된 테스트와 통합하는 것이 더 어렵습니다.
  • secrets 은 암호화되지만 여전히 버전 제어에 저장되어 있기 때문에 secrets 을 교체하고 취소하는 것은 어렵습니다.
  • secrets 에 액세스한 사람을 감사하는 기능은 최소한입니다. 클라우드 키 관리 시스템(예: AWS KMS)을 사용하는 경우 누가 암호화 키를 사용했는지에 대한 감사 로그를 유지할 가능성이 높지만 키가 실제로 무엇에 사용되었는지 알 수 없습니다(예: 어떤 비밀에 액세스했는지).
  • 대부분의 관리형 키 서비스는 약간의 비용이 듭니다.
  • secrets 관리 관행을 표준화하는 것은 더 어렵습니다.




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

✅ 비밀 저장소 - Secret stores

 
Comments