사전 준비
aws로그인 https://console.aws.amazon.com/
명령서버에서 사용할 pem키 필요
access-key 필요
secret-key 필요
cloudformation으로 명령 서버 1대를 만든다.
1
프로비저닝 파이프라인 + Github Action 준비
실습 실패~
작업 순서는 확인하자.
2
실제 서비스가 실행되는 대상을 프로비저닝하면 테라폼의 Plan과 Apply 과정상에 추가로 코드 검증, 실행 계획 검증, 실행 후 결과 확인과 같은 추가 동작을 자동화.
도구 : 젠킨스, Github Action, TFC/TFE
3
저장소 포크 : https://github.com/terraform101/terraform-aws-github-action
topasvga@naver.com
4
Github Action은 별도의 State 저장소를 제공하지 않기 때문에 테라폼 실행으로 생성되는 State가 항상 초기화되어 프로비저닝 결과를 유지할 수 없다.
백엔드를 활성화 하자.
1
리모트 저장소를 로컬 환경에 복제
MyGit=<각자 자신의 깃허브 계정>
MyGit=topasvga
git clone https://github.com/$MyGit/terraform-aws-github-action
# 확인
tree terraform-aws-github-action
terraform-aws-github-action
├── files
│ └── deploy_app.sh
├── LICENSE
├── main.tf
├── outputs.tf
├── README.md
└── variables.tf
cd terraform-aws-github-action
git remote get-url origin
2
토큰 정보 확인
gb1!
설정 토큰 확인
오른쪽위 개인 아이콘 > Setting > 왼쪽 맨 아래 Developer settings > Personal access tokens Tockens(classic) > Generate new token 클릭 > 맨 아래 Generate new token (classic)
test-seo1
repo체크
Generate token
(Personal access tokens (classic) 을 복사해두자)
깃헙 액션 파이프라인 에러가 발생하시는 분은
레포지토리 Settings -> Actions -> General -> 최하단 Workflow permissions을 read and write permissions로 변경해보시고 재실행 해보세요.
3
push test?
#
echo "T101 Study" >> test.txt
git add test.txt
git commit -m "first commit"
git push
(정보를 넣어야 하는데 정보를 모른다)
# 우선 Git 자격 증명 설정이 필요하다.
git config --global user.name $MyGit
git config --global user.email <깃허브 가입 이메일주소>
git config --global user.email topasvga@naver.com
cat ~/.gitconfig
# push 실행을 위해서 로그인 정보 입력
git push
Username for 'https://github.com': <깃허브 계정 정보>
Password for 'https://topasvga@github.com': <토큰 정보>
Username for 'https://github.com': topasvga
Password for 'https://topasvga@github.com': <토큰 정보>
4
콘솔에서 확인
https://github.com/topasvga/terraform-aws-github-action
5
테라폼 클라우드를 사용할수 있도록 하자~
main.tf의 terraform 블록에서 사용자의 TFC 설정 organization으로 변경
확인 ?
cat ~/.terraform.d/credentials.tfrc.json | jq
참고
테라폼 클라우드 토큰 받기
https://brunch.co.kr/@topasvga/3395
3
main.tf 내용 수정
terraform {
cloud {
organization = "<MY_ORG_NAME>" # 생성한 ORG 이름 지정 topasvga-org
hostname = "app.terraform.io" # default
workspaces {
name = "terraform-aws-github-action"
}
}
...
4
.github/workflow/action.yml 내용 수정
vi /root/terraform-aws-github-action/.github/workflows/action.yml
env:
MY_PREFIX: DEV
TF_VERSION: 1.2.6 # 1.2.5에서 변경
// 테라폼이 로컬에서 실행되는건 아니고, 깃허브 액션에서 실행된다.
5
push
git add main.tf
git add .github/workflow/action.yml
git commit -m "init"
git push
.github/workflow/action.yml 파일 push 시 에러 발생 시
→ 깃허브 콘솔 > 세팅 > 해당 토큰에 workflow 권한 추가 후 다시 push 할 것 .
6
지정된 Terraform Cloud 백엔드 활성화를 위해 terraform init을 수행
cd /root/terraform-aws-github-action
terraform init
tree .terraform
7
생성된 TFC 간다.
워크스페이스 > 실행 모드 Execution mode를 Local로 수정 (저장소만 동기화해 사용함) > 저장
terraform-aws-github-action 워크스페이스(State 백엔드 역할만 수행) 확인 →
선택 후 좌측에 Settings 클릭 → General -> Local로 수정 > 저장
8
동작의 설명 ?
github에서 풀리퀘스트 PR 하면 깃허브 액션이 돌아간다.
SCAN - 테라폼 ---- Main 브랜치에서 PR 승인 ---- SCAN --테라폼- APPLY--- AWS 리소스 생성
9
action.yml 파일 내용을 보라.
jobs ?
SCAN 실행됨. 검증하는 부분임.
Terrafrom 테라폼.
- Job
Scan : 테라폼 코드 검증
- Check out code : 검증을 위해 저장소의 코드를 체크아웃
- Run terrascan : 테라폼 코드 검증 도구인 Terrascan을 실행
https://runterrascan.io/
https://runterrascan.io/docs/getting-started/
https://runterrascan.io/docs/integrations/cicd/
- Upload SARIF file : 검증의 결과(정적 분석 결과 표준 포맷)을 업로드
- Job ‘Terraform’ : 테라폼 실행 ← Job ‘Scan’ 이후 실행
- Check out code : 검증을 위해 저장소의 코드를 체크아웃
- Configure AWS credentials : AWS 환경을 프로비저닝하기 위한 Credential 설정
- Terraform Fmt : 표준 스타일 수정 대상 확인
- Terraform init : 테라폼 실행을 위한 init 수행
- Terraform validate : 코드 문법 오류 검사
- Terraform plan : 실행 계획 확인
- env.TF_LOG: info : 로그 수즌을 info로 출력해 실행 디버깅
- Plan output : 풀 리퀘스트인 경우 실행 계획을 정리해 출력
- Terraform apply : 메인 브랜치 변경 시에만 Apply 수행
- 예시의 동작 외에도 프로비저닝 이후의 테스트를 위한 terratest 도구와 비용 예측을 위한 terracost, infracost 도구들도 추가해볼 수 있다.
- 코드 내용 설명
10
action.yml : Github Action의 구성은 .github/workflows의 yml 파일 형태로 작성
name: Terraform DEV
on:
push:
branches:
- main
pull_request:
env:
MY_PREFIX: DEV
TF_VERSION: 1.2.5
jobs:
SCAN:
name: SCAN
runs-on: ubuntu-latest
# env:
# working-directory: terraform
# TF_WORKSPACE: my-workspace
steps:
# - name: Configure AWS credentials
# uses: aws-actions/configure-aws-credentials@v1
# with:
# aws-region: eu-west-1
- name: Check out code
uses: actions/checkout@v3
- name: Run Terrascan
id: terrascan
uses: tenable/terrascan-action@main
with:
iac_type: 'terraform'
iac_version: 'v14'
policy_type: 'aws'
only_warn: true
sarif_upload: true
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: terrascan.sarif
Terraform:
needs: SCAN
name: Terraform
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: $TF_VERSION
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
- name: Terraform Fmt
id: fmt
run: terraform fmt -recursive -check
continue-on-error: true
- name: Terraform init
id: init
run: terraform init -upgrade
# working-directory: ${{ env.working-directory }}
- name: Terraform validate
id: validate
run: terraform validate -no-color
- name: Terraform plan
id: plan
run: terraform plan -no-color -var=prefix="$MY_PREFIX"
# working-directory: ${{ env.working-directory }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
TF_LOG: info
- name: Plan output
id: output
uses: actions/github-script@v3
if: github.event_name == 'pull_request'
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform Format and Style �\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Terraform Plan �\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`hcl
${process.env.PLAN}
\`\`\`
</details>
**Pusher**: @${{ github.actor }}
**Action**: ${{ github.event_name }}
`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
- name: Terraform apply
id: apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -var=prefix="$MY_PREFIX" -input=false
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
10.
main.tf
: 프로비저닝의 실행은 작업자나 Github Action에서 발생하더라도 동일한 State유지를 위해 백엔드 구성 추가
11
Github Action 과정에서 필요로 하는 State 공유를 위한 Terraform Cloud의 토큰, AWS 프로비저닝을 위한 AWS Credential과 같은 민감 데이터를 저장소에서 민감 변수로 처리할 수 있다.
(옵션) AWS IAM 계정 생성 및 자격증명 획득
aws iam create-user --user-name testuser
aws iam create-access-key --user-name testuser
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser
"AccessKeyId": "AKIWPLWXCWW",
"SecretAccessKey": "1K/h1h231kGQBDs+PHhxF/M"
12
깃허브 액션 에서
해당 repository 저장소의 [Setting] → [Secrets and variables - Actions] 선택 ⇒ 3가지 새로운 민감 변수 등록
[New repository secret]
Name :
TF_API_TOKEN
Secret : <각자 자신의 TFC Token>
AWS_ACCESS_KEY_ID
: AWS Access Key 입력
AWS_SECRET_ACCESS_KEY
: AWS Secret Access Key 입력
13
깃허브 액션이 기본 비활성화이다.
본인 깃허브 계정것을 활성화 하자.
포크되어 비활성화되어 있는 저장소의 [Actions] 탭으로 이동해
[I understand my workflows, go ahead and enable them] 버튼을 클릭, 활성화한다
1
Automate Terraform with GitHub Actions 가이드 참고해서 토큰 생성 하고 실습 진행
2
브렌치 하나 따서 작업한다.
- 브랜치 이름 : add-env-variable
테라폼 입력 변수 추가
- 이름 : environment
- 설명 : Define infrastructure’s environment
- 타입 : string
- 기본값 : dev
- 변수 확인
- 조건 : dev, qa, prod 인 경우 허용
- 에러 메시지 : The environment value must be dev, qa, or prod.
- **aws_vpc**의 **tags.environment**를 입력 변수 **environment** 값으로 선언
- 새로운 브랜치의 변경 내용을 커밋, 푸시하고 깃허브 웹페이지에서 **풀 리퀘스트**를 생성한다 ← 주의: 자신의 저장소로 요청하는지 꼭 확인
- Github Action의 동작 조건은 메인 브랜치에 푸시가 발생하거나 풀 리퀘스트가 발생하는 경우로 정의되어 있다.
3
# Github Action의 실행 조건 : ./github/workflows/action.yml
on:
push:
branches:
- main
pull_request:
// main 프렌치에 push 되거나 pull_request 될때 , Github Action이 실행된다.
4
해결 ?
브랜치 생성 : add-env-variable
cd /root/terraform-aws-github-action
git branch
git branch -M add-env-variable
vi main.tf
내용 수정
resource "aws_vpc" "hashicat" {
cidr_block = var.address_space
enable_dns_hostnames = true
tags = {
name = "${var.prefix}-vpc-${var.region}"
environment = var.environment # 원래 값 Production
}
}
// variable "environment 정보 가져온다.
사용을 위해서는 아래 variable 만들어 줘야 한다!!
5
vi variables.tf
내용 추가
variable "environment" {
type = string
description = "Define infrastructure’s environment"
default = "dev"
validation {
condition = contains(["dev", "qa", "prod"], var.environment)
error_message = "The environment value must be dev, qa, or prod."
}
}
6
push
terraform fmt
git add .
git commit -m "add env variable"
git push origin HEAD
7
아래 링크로 간다~
remote:
remote: Create a pull request for 'add-env-variable' on GitHub by visiting:
remote: https://github.com/topasvga/terraform-aws-github-action/pull/new/add-env-variable
remote:
To https://github.com/topasvga/terraform-aws-github-action
* [new branch] HEAD -> add-env-variable
8
반드시 본인의 저장소로 변경해야 한다.
// 본인 레파지토리 저장소로 하자.
9
PR을 만들자.
create pr
Create pull request
7
Github에 Action 에 가서 확인하자
콘솔에서 action을 보자~~
scan 보자.
깃허브 action에 있는 sandbox 환경에서 돌아가고 있는것이다.
Terraform plan에서 에러가 난다.
# error 메시지
Terraform Unhandled error: HttpError: Resource not accessible by integration
Terraform The following actions uses node12 which is deprecated and will be forced to run on node16: actions/github-script@v3. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
9
동작 성공 시 → Main RP 병합 수행 ⇒ Github Action 에서 Apply 수행
- AWS 서울 리전에 리소스 생성 확인
- Github Action 확인
- Github Security 에 정적 코드 분석 내용 확인 : [runterrascan.io](http://runterrascan.io)
동작 실패로 관련 리소스 삭제
1. Github Repo 삭제 ?
레파지토리 https://github.com/topasvga/terraform-aws-github-action > 세팅 > 맨아래 > 삭제
2. TFC Workspace 삭제 ?
workspace > 해당 워크스페이스 terraform-aws-github-action > Destruction and Deletion > terraform-aws-github-action
3. 로컬에 코드 폴더 삭제
rm -rf terraform-aws-collaboration
rm -rf terraform-aws-github-action
4
추가 자료
악분님 자료 참고
https://github.com/sungwook-practice/intergreation_TFC
깃헙 액션 파이프라인 에러가 발생하시는 분은
레포지토리 Settings -> Actions -> General -> 최하단 Workflow permissions을 read and write permissions로 변경해보시고 재실행 해보세요.
다음과정
https://brunch.co.kr/@topasvga/3409
감사합니다.