본 포스팅은 "Tekton 사용해보기" 시리즈의 네 번째 글입니다.
해당 시리즈의 첫 번째 글은 Tekton 사용해보기 (1) Tekton으로 쿠버네티스 CI/CD 파이프라인을 구성해보자 에서 볼 수 있습니다.
해당 시리즈의 두 번째 글은 Tekton 사용해보기 (2) Tekton으로 인프라를 자동 배포하는 Terraform Pipeline을 만들어보자 에서 볼 수 있습니다.
해당 시리즈의 세 번째 글은 Tekton 사용해보기 (3) Tekton Dashboard에 OIDC를 기반으로 RBAC 적용하기 에서 볼 수 있습니다.
이번 포스팅에서는 Tekton에서 Google Cloud Platform의 인프라를 Terraform으로 배포할 시 배포 코드에 대한 정책 검사, 즉 Validation을 수행하는 파이프라인을 구성해보겠습니다.
Terraform 코드에 대한 Validation이란 테라폼 코드로 인프라를 배포하기 전 단계에서 코드가 정책을 준수하는지 검사한 후에 배포를 진행하는 것을 말합니다.
Validation을 배포 프로세스에 포함시키면 Terrform 코드로 인해 배포되는 인프라가 조직이 세운 정책을 준수하게 할 수 있기 때문에 일종의 정책 가드레일을 세울 수 있다는 이점이 존재합니다.
정책 가드레일을 세워놓으면 인프라 배포 조직원이 정책을 위반할 수 있는 리소스를 배포하고자 해도 이를 자동적으로 방지하기 때문에 정책 위반의 사전 예방책으로써 기능을 할 수 있습니다.
이러한 이점이 존재하는 Validation 프로세스를 Tekton 파이프라인 내부에 포함시켜 자동으로 Terraform 정책 가드레일을 세울 수 있는 GCP 테라폼 배포 파이프라인을 구축해보겠습니다.
1. gcloud terraform vet?
gcloud terraform vet은 Terraform을 사용한 인프라 배포 및 기존 인프라 파이프라인 정책 검사를 수행할 수 있는 CLI 도구입니다.
gcloud terraform vet을 이용해 정책 가드레일을 세울 수 있어 조직이 규정한 컴플라이언스 혹은 정책을 자동화해서 검사할 수 있습니.
이로써 감사를 통해 문제가 드러날 위험이 줄어들며 조직의 규모가 커질수록 위험에 노출되는 인프라가 줄어들 수 있습니다.
gcloud terraform vet 사용시 다음과 같은 이점이 있습니다.
- 애플리케이션 개발의 어느 단계에서나 조직의 정책 시행
- 정책 검사 자동화로 수동 오류 방지
- 배포 전 확인을 통한 빠른 실패
1-1. gcloud terraform vet 구성
gcloud terraform vet을 사용하기 위해서는 다음과 같은 Requirements들이 요구됩니다.
- "resourcemanager.projects.getIamPolicy" Permission : Organization의 Security Reviewer Role을 통해 획득 가능
- "resourcemanager.projects.get" Permission : Organization의 Project Viewer Role을 통해 획득 가능
- Cloud SDK
gcloud terraform vet은 Terraform plan 명세서를 Constraint라고 하는 정책과 비교하는 방식으로 정책 위반 여부를 검사하는 프로세스로 진행합니다.
Constraint들은 Policy Library 디렉토리 내부에 존재해야 하며 gcloud terraform vet은 Policy Library 디렉토리를 참조해 정책들을 인지하게 됩니다.
gcloud terraform vet은 제출한 Terraform plan 명세서가 Policy Library의 Constraints를 위반할 경우 에러를 출력하며(code 1), 위반하지 않을 경우 에러를 출력하지 않습니다(code 0)
1-2. gcloud terraform vet 사용해보기
간단한 사례로 gcloud terraform vet을 직접 사용해보며 이해도를 높여보겠습니다.
1.아래 명령어로 Google Cloud에서 제공하는 Sample Policy library를 clone 합니다.
1
|
git clone https://github.com/GoogleCloudPlatform/policy-library.git
|
cs |
2. Policy library에서 Sample network_enable_firewall_logs constraint 파일을 policies/constrains 디렉토리로 복사합니다.
1
|
cp samples/network_enable_firewall_logs.yaml policies/constraints/
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPNetworkEnableFirewallLogsConstraintV1
metadata:
name: enable-network-firewall-logs
annotations:
description: Ensure Firewall logs is enabled for every firewall in VPC Network
bundles.validator.forsetisecurity.org/healthcare-baseline-v1: security
spec:
severity: high
match:
ancestries:
- "organizations/**"
parameters: {}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
resource "google_compute_firewall" "rules" {
name = "test-firewall"
network = "default"
direction = "INGRESS"
priority = 1000
source_ranges = [
"0.0.0.0/0"
]
source_tags = [
"some-tag"
]
allow {
protocol = "tcp"
ports = ["80", "8080", "1000-2000"]
}
}
|
cs |
1
|
terraform init
|
cs |
1
|
terraform plan -out=test.tfplan
|
cs |
1
|
terraform show -json ./test.tfplan > ./tfplan.json
|
cs |
1
|
sudo apt-get install google-cloud-sdk-terraform-tools
|
cs |
1
|
gcloud beta terraform vet tfplan.json --policy-library=. --format=json
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
[
{
"constraint": "GCPNetworkEnableFirewallLogsConstraintV1.enable-network-firewall-logs",
"constraint_config": {
"api_version": "constraints.gatekeeper.sh/v1alpha1",
"kind": "GCPNetworkEnableFirewallLogsConstraintV1",
"metadata": {
"annotations": {
"bundles.validator.forsetisecurity.org/healthcare-baseline-v1": "security",
"description": "Ensure Firewall logs is enabled for every firewall in VPC Network",
"validation.gcp.forsetisecurity.org/yamlpath": "policies/constraints/network_enable_firewall_logs.yaml"
},
"name": "enable-network-firewall-logs"
},
"spec": {
"match": {
"ancestries": [
"organizations/**"
]
},
"parameters": {},
"severity": "high"
}
},
"message": "Firewall logs are disabled in firewall //compute.googleapis.com/projects/prj-sandbox-devops-9999/global/firewalls/test-firewall.",
"metadata": {
"ancestry_path": "organizations/1085400699340/folders/599651043362/projects/prj-sandbox-devops-9999",
"constraint": {
"annotations": {
"bundles.validator.forsetisecurity.org/healthcare-baseline-v1": "security",
"description": "Ensure Firewall logs is enabled for every firewall in VPC Network",
"validation.gcp.forsetisecurity.org/yamlpath": "policies/constraints/network_enable_firewall_logs.yaml"
},
"labels": {},
"parameters": {}
},
"details": {
"resource": "//compute.googleapis.com/projects/prj-sandbox-devops-9999/global/firewalls/test-firewall"
}
},
"resource": "//compute.googleapis.com/projects/prj-sandbox-devops-9999/global/firewalls/test-firewall",
"severity": "high"
}
]
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
resource "google_compute_firewall" "rules" {
name = "test-firewall"
network = "default"
direction = "INGRESS"
priority = 1000
source_ranges = [
"0.0.0.0/0"
]
source_tags = [
"some-tag"
]
allow {
protocol = "tcp"
ports = ["80", "8080", "1000-2000"]
}
log_config {
metadata = "INCLUDE_ALL_METADATA"
}
}
|
cs |
1
2
|
Validating resources...done.
[]
|
cs |
2. Tekton으로 gcloud terraform vet을 이용한 validation 파이프라인 구성하기
gcloud terraform vet을 이용한 validation을 Tekton Pipeline의 일부로 포함시켜 자동화된 검증을 수행할 수 있습니다.
Tekton을 활용한 Terraform CI/CD Pipeline에 대한 정보는 이번 시리즈의 두 번째 글 Tekton 사용해보기 (2) Tekton으로 인프라를 자동 배포하는 Terraform Pipeline을 만들어보자 포스팅을 참고하세요.
위 다이어그램은 gcloud terraform vet을 포함한 Tekton Terraform CI/CD Pipeline의 리소스 구성도입니다.
Pipeline의 작업들을 순차적으로 나열하면 다음과 같습니다.
- git clone 명령어를 통해 terraform configuration이 존재하는 Source repository를 클론합니다.
- terraform init, terraform plan -out=.. 명령어로 Terraform initializing 후 plan 파일을 저장합니다.
- terraform show 명령어로 저장된 plan 파일을 json 포맷으로 변경해 저장합니다.
- git clone 명령어를 통해 terraform policy가 존재하는 Source repository를 클론합니다.
- gcloud beta terraform vet 명령어를 통해 json 포맷의 plan 파일을 policy 디렉토리의 constraints 파일로 검증합니다.
- 검증이 통과되면 terraform apply 명령어로 인프라 배포를, 검증을 통과하지 못하면 원인이 포함된 Error 메세지를 출력하고 작업을 종료합니다.
2-1. Tekton 파이프라인 구성 코드
위에서 소개한 파이프라인의 컴포넌트 중 중요한 부분만 함께 보도록 하겠습니다.
1. pipeline.yaml
pipeline.yaml은 Tekton pipeline을 정의하는 yaml 매니페스트입니다.
아래와 같은 구성으로 이루어져 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-terraform-cli
spec:
description: |
This pipeline clones a git repo, run "terraform plan" command based on .tf config file
params:
- name: source-repo-url
type: string
- name: policy-repo-url
type: string
workspaces:
- name: shared-data
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.source-repo-url)
- name: terraform-plan
runAfter: ["fetch-source"]
taskRef:
name: terraform-cli
workspaces:
- name: source
workspace: shared-data
params:
- name: terraform-secret
value: "terraform-secret"
- name: ARGS
value:
- plan
- "-out=tfplan.tfplan"
- name: terraform-show
runAfter: ["terraform-plan"]
taskRef:
name: terraform-script
workspaces:
- name: source
workspace: shared-data
params:
- name: terraform-secret
value: "terraform-secret"
- name: SCRIPT
value: |-
#!/usr/bin/env sh
set -e
terraform show -json ./tfplan.tfplan
terraform show -json ./tfplan.tfplan > ./tfplan.json
- name: fetch-policy
runAfter: ["terraform-show"]
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.policy-repo-url)
- name: subdirectory
value: policy-library
- name: gcloud-terraform-vet
runAfter: ["fetch-policy"]
taskRef:
name: gcloud
workspaces:
- name: source
workspace: shared-data
params:
- name: SCRIPT
value: |-
#!/usr/bin/env sh
apt-get install google-cloud-sdk-terraform-tools
VIOLATIONS=$(gcloud beta terraform vet tfplan.json --policy-library=./policy-library/ --format=json)
retVal=$?
if [ $retVal -eq 2 ]; then
# Optional: parse the VIOLATIONS variable as json and check the severity level
echo "$VIOLATIONS"
echo "Violations found; not proceeding with terraform apply"
exit 1
fi
if [ $retVal -ne 0 ]; then
echo "Error during gcloud beta terraform vet; not proceeding with terraform apply"
exit 1
fi
echo "No policy violations detected; proceeding with terraform apply"
- name: terraform-apply
runAfter: ["gcloud-terraform-vet"]
taskRef:
name: terraform-cli
workspaces:
- name: source
workspace: shared-data
params:
- name: terraform-secret
value: "terraform-secret"
- name: ARGS
value:
- apply
- "-auto-approve"
|
cs |
2. gcloud-terraform-vet
위 매니페스트에서 중요한 부분은 아래의 "gcloud-terraform-vet" Task를 실행하는 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
- name: gcloud-terraform-vet
runAfter: ["fetch-policy"]
taskRef:
name: gcloud
workspaces:
- name: source
workspace: shared-data
params:
- name: SCRIPT
value: |-
#!/usr/bin/env sh
apt-get install google-cloud-sdk-terraform-tools
VIOLATIONS=$(gcloud beta terraform vet tfplan.json --policy-library=./policy-library/ --format=json)
retVal=$?
if [ $retVal -eq 2 ]; then
# Optional: parse the VIOLATIONS variable as json and check the severity level
echo "$VIOLATIONS"
echo "Violations found; not proceeding with terraform apply"
exit 1
fi
if [ $retVal -ne 0 ]; then
echo "Error during gcloud beta terraform vet; not proceeding with terraform apply"
exit 1
fi
echo "No policy violations detected; proceeding with terraform apply"
|
cs |
"gcloud-terraform-vet"은 gcloud beta terraform vet 명령어를 수행하여 Error가 발생하면 Status code 1을 반환해 Task를 종료, 검증이 통과되어 Error가 발생하지 않으면 다음 Task로 계속 진행하는 Script를 실행합니다.
Tekton hub에서 제공하는 "gcloud" Task를 이용했으며 해당 Task는 아직 beta 버전인 gcloud terraform vet이 설치되어 있지 않으므로 "apt-get install google-cloud-sdk-terraform-tools" 라인을 넣어 해당 도구를 설치해야 함에 유의합니다.
2-2. Tekton validation 파이프라인 DEMO
1. firewall log가 enable되어 있어야 한다는 Constraint가 포함된 Policy library 레포지토리를 준비
2. terraform configuration이 포함된 레포지토리를 준비, firewall_log가 disable된 firewall rule 리소스를 Commit & Push
3. Tekton Pipeline이 자동으로 실행되나 Policy validation에 실패해 Pipeline이 중단되는 모습
4. terraform configuration에서 firewall_log을 enable하는 변경사항을 Commit & Push.
5. Tekton Pipeline이 자동으로 실행되고 Policy validation이 성공해 Firewall이 배포되는 모습
3. 마무리
지금까지 gcloud terraform vet을 이용해서 Tekton validation 파이프라인을 구성하는 방법에 대해서 알아봤습니다.
gcloud terraform vet과 같이 Terraform 코드에 대해서 정책을 검사할 수 있는 도구를 사용한다면 정책 가드레일을 세울 수 있기 때문에 조직 내 정책 위반을 사전에 예방할 수 있다는 이점이 존재합니다.
이같은 도구를 Tekton Terraform 배포 파이프라인에 포함한다면 배포 프로세스 내에서 정책을 검사해 자동적으로 정책을 검사할 수 있는 Validation 프로세스를 정착시킬 수도 있습니다.
그래서 이번 포스팅을 통해 Tekton 파이프라인에서 성공적으로 Validation 파이프라인을 구축할 수 있는 것을 확인할 수 있었습니다.
포스팅을 보시는 분들이 많은 도움을 얻으셨기를 바랍니다.
'Devops' 카테고리의 다른 글
Tekton 사용해보기 (5) Tekton에 Human Approval 기능을 추가해보자 (0) | 2023.03.18 |
---|---|
Terraform으로 Replace없는 GCP Compute Instance 부트 디스크를 구성하는 방법 (0) | 2023.01.29 |
Tekton 사용해보기 (3) Tekton Dashboard에 OIDC를 기반으로 RBAC 적용하기 (0) | 2022.11.13 |
Tekton 사용해보기 (2) Tekton으로 인프라를 자동 배포하는 Terraform Pipeline을 만들어보자 (2) | 2022.11.06 |
Tekton 사용해보기 (1) Tekton으로 쿠버네티스에서 CI/CD 파이프라인을 구성해보자 (1) | 2022.10.03 |