이번 세션에서는 안전한 파이프라인 구축을 위해 HashiCorp Vault와 GitHub Actions를 사용하여 최신 GitOps Workflow 적용방안을 알아봅니다.
- Github 계정
- Terraform Cloud 계정
- Vault 서버
- AWS 계정 (free tier로 테스트 가능)
- Terraform Helper
이미 Github 계정과 AWS 계정 (Free Tier도 가능)은 있다는 가정 하에 다음 순서로 데모 환경을 구성.
아래 작업 전, 다음 Repo를 Fork 할 것
https://github.com/jsp-hashicorp/vault-gh-actions
- 테라폼 클라우드 가입하기
다음 링크 상의 정보를 확인하여 Terraform Cloud에 가입하여 계정을 생성한다.
Sign up for Terraform Cloud
Start from scratch를 선택하여 Organization을 생성.
- Workspace 생성
다음 링크 상의 정보를 참고하여, Workspace를 생성
Create a Workspace
CLI Driven Run Workflow
Workspace 생성 시 CLI Driven Workflow를 선택하여 하여 구성.
Workspace > Settings > General Settings에서 다음 내용 설정
Executio Mode: Remote, Apply Method: Auto Apply
- Terraform API 토큰 생성
다음 명령어를 수행하여 Terraform API 토큰을 생성, 로컬 파일에 저장.
이 단계에서 생성된 토큰 값을 Vault Terraform Cloud 시크릿 엔진에서 사용하여 필요 시 동적으로 생성 예정.
terraform login
- Fork한 Repo상의 remote_backend.tf 수정
다음과 같이 파일 수정
terraform {
cloud {
organization = "단계 1에서 만든 Organization 이름"
workspaces {
name = "단계 2에서 만든 Workspace 이름"
}
}
}
- Terraform Cloud 환경 변수 설정
Variables 탭에서 아래 변수값 설정. 우선 임의의 값으로 설정.
Vault와 연계하여, 파이프 라인 동작 시 자동으로 설정.
환경 변수로 설정
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY (SENSITIVE 설정)
Terraform 변수로 설정
region
placeholder
width
height
prefix
-
Vault Enterprise Trial 라이센스 신청
다음 링크에 접속하여 Vault Enterprise 30일 Trial 라이센스 신청
Vault Enterprise Trial 라이센스 신청 -
Vault 서버 구성
다음 링크 상의 내용을 참고하여 Vault 서버를 구성하고 잠금 해제할 것.
이 때 Unseal Key와 Initial Root Token을 잘 보관할 것.
Deploy Vault
Enterprise License를 적용은 아래와 같이 환경 변수나 설정 파일로 적용.
환경 변수로 적용하는 경우 : $ export VAULT_LICENSE_PATH=/etc/vault.d/license.hclic
설정파일로 적용하는 경우 : license_path = "/etc/vault.d/license.hclic" (서버 구성 파일 하단에 추가)
- 시크릿 엔진 구성
AWS 시크릿 엔진, Key/Value 시크릿 엔진 그리고 Terraform Cloud 시크릿 엔진을 구성
AWS Secret Engine - 사용 중인 방식(iam_user, assumed_role, federation_token)을 선택하여 구성
AWS Dynmacic Secrets
Versioned Key/Value Secrets Engine
Terraform Cloud Secrets Engine
위에서 구성한 시크릿 엔진을 사용하여 계정 생성 및 조회가 정상적으로 진행되는 경우, 다음 단계를 수행.
- Vault Token 생성 위에서 생성된 시크릿 엔진에 접속 가능한 정책을 설정. 역할 명이나 Path는 단계 3에서 설정한 경로와 역할명을 사용하여 생성할 것
# file name : readonly_policy.hcl
# sts AssumeRole 사용 시
path "aws/sts/{생성할 Role 이름}" {
capabilities = [ "create","update" ]
}
# key/value 값 조회
path "secret/data/tfvars/*" {
capabilities = ["read"]
}
# Get credentials from the terraform secrets engine
path "terraform/creds/my-user" {
capabilities = [ "read" ]
}
위 정책 파일을 사용하여 정책 생성 및 Token 생성
$ vault policy write ro readonly_policy.hcl
$ vault token create -policy=ro
Key Value
--- -----
token s.iyNUhq8Ov4hIAx6snw5mB2nL <-- 해당 값을 VAULT_TOKEN이란 이름으로 Github secret으로 저장.
token_accessor maMfHsZfwLB6fi18Zenj3qh6
token_duration 768
token_renewable true
token_policies ["default","ro"]
identity_policies []
policies ["default","ro"]
다음 Repo를 참고하여 Terraform Helper를 구성하여, Terraform Cloud 상의 변수 설정 시 사용.
The Terraform Helper
사용법 또한 위 링크 상의 문서 참고. 금번 데모의 경우 pushvar 기능 사용
다음 링크 상에 Vault Github Actions 사용 방법을 확인하고, 사전 작업 단계에서 Fork한 Repo 상의 Secret으로 VAULT_TOKEN 값을 설정. (이 예제에서는 s.iyNUhq8Ov4hIAx6snw5mB2nL)
Vault Github Actions
GitHub Actions 구동 시 Self-hosted Runner를 사용.
Vault를 HCP Vault 또는 Public IP로 접근 가능한 곳에 구성한 경우, GitHub Hosted Runner 사용 가능.
Github Actions는 다음과 같은 3개의 Job으로 구성
- 시크릿 조회 및 TFC 변수 설정
- EC2 배포
- 시크릿 회수 및 TFC 변수 설정 초기화
주요 내용
pre-vault:
name: 1. 시크릿 조회 및 TFC 변수 설정
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: 1.1 시크릿 조회 및 생성
id: import
uses: hashicorp/vault-action@v2.4.0
with:
url: {{VAULT_ADDR}} --> 로컬 구동 시 http://127.0.0.1:8200, Vault 구성 환경에 따라 상이.
tlsSkipVerify: true
token: ${{ secrets.VAULT_TOKEN }} --> GitHub 시크릿으로 설정된 VAULT_TOKEN값
secrets: |
secrets/data/tfvar prefix | prefix ; --> Terraform Cloud에서 사용할 변수 값 조회
(( 중략 ))
terraform/creds/my-user token | TF_API_TOKEN ; --> Terraform Cloud에 접근 가능한 API 토큰 생성
aws/sts/vault-demo-jsp access_key | AWS_ACCESS_KEY_ID ; --> AWS Access Key 생성
aws/sts/vault-demo-jsp secret_key | AWS_SECRET_ACCESS_KEY ; --> AWS Secret key 생성
- name: 1.2 TFC Workspace 변수 설정
id: set_var
run: |
cd {Terraform Helper 설치 경로}
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -var 'prefix=${{ env.prefix }}' -overwrite prefix
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -var 'height=${{ env.height }}' -overwrite height
(( 중략 ))
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -env-var 'AWS_ACCESS_KEY_ID=${{ env.AWS_ACCESS_KEY_ID }}' -overwrite-env AWS_ACCESS_KEY_ID --> 환경 변수로 설정
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -senv-var 'AWS_SECRET_ACCESS_KEY=${{ env.AWS_SECRET_ACCESS_KEY }}' -overwrite-env AWS_SECRET_ACCESS_KEY --> 환경 변수를 Sensitive로 설정
(( 생략 ))
대부분의 내용은 Terraform Github Actions의 내용을 대부분 사용.
다음 부분을 먼저 수행 후 Terraform GitHub Actions 내용 수행.
terraform:
name: 2. EC2 인스턴스 배포
runs-on: self-hosted
needs: pre-vault
steps:
- name: Checkout
uses: actions/checkout@v2
- name: 2.1 임시 작업 토큰 생성
id: import
uses: hashicorp/vault-action@v2.4.0
with:
url: {{VAULT_ADDR}} --> 로컬 구동 시 http://127.0.0.1:8200, Vault 구성 환경에 따라 상이.
tlsSkipVerify: true
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
terraform/creds/my-user token | TF_API_TOKEN
작업을 위한 시크릿을 생성 조회하는 부부은 1. 시크릿 조회 및 TFC 변수 설정
단계와 동일
변수 설정을 초기화 하고, 시크릿을 삭제하는 부분만 아래와 같이 다르게 동작함.
- name: 3.2 임시 계정 회수 (TF API TOKEN, AWS access key) 및 TFC 환경 변수 초기화
id: unset_var
run: |
cd cd {Terraform Helper 설치 경로}
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -var 'prefix=env.prefix' -overwrite prefix
(( 중략 ))
./tfh pushvars -org ${{ env.TF_ORGANIZATION }} -name 'vault-gh-actions' -token ${{ env.TF_API_TOKEN }} -env-var 'AWS_ACCESS_KEY_ID=AWS_ACCESS_KEY_ID' -overwrite-env AWS_ACCESS_KEY_ID
(( 중략 ))
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=${{ secrets.VAULT_TOKEN }}
vault lease revoke -sync -prefix ${{ env.STS_PREFIX }} --> AWS 접속 정보 폐기
vault lease revoke -sync -prefix terraform/creds/my-user --> Terraform API 토큰 페기
Terraform Configuration Template을 수정하고 push 하게 되면, GitHub Actions가 동작하면서 다음과 같이 동작한다.
시연 시 main.tf상의 aws_vpc
리소스에 다음과 같이 Tag값을 추가 후 Commit & Push 할 것.
resource "aws_vpc" "snapshot" {
cidr_block = var.address_space
enable_dns_hostnames = true
tags = {
name = "${var.prefix}-vpc-${var.region}"
environment = "snapshot"
owner = "test"
ttl = "48"
}
}
- 시크릿 조회 및 TFC 변수 설정
- Terraform Cloud 상의 Workspace 접속을 위한 Terraform API Token을 생성
- 해당 Token을 사용하여 각종 변수 설정
- EC2 배포
단계 1에서 설정한 변수값을 사용하여 AWS EC2 인스턴스 및 Application 배포 - 시크릿 회수 및 TFC 변수 설정 초기화
- 작업용 Terraform API 토큰 생성 및 AWS access_key, secret_key 폐기
- Terraform Cloud 상 모든 환경 변수 초기화
- 전체 과정에서 생성된 Terraform API 토큰 삭제
파이프 파인 각 단계에서 필요한 각종 시크릿을 최소 권한의 원칙과 필요 시 사용 후 폐기하는 방식으로 보다 안전하게 사용할 수 있는 방법을 확인