Post

Terraform Study #5

โ€˜ํ…Œ๋ผํผ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” IaCโ€™ ์ฑ…์œผ๋กœ ์ง„ํ–‰ํ•˜๋Š” Terraform ์Šคํ„ฐ๋””[T101] 5์ฃผ์ฐจ ์ •๋ฆฌ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

5์ฃผ์ฐจ

์›Œํฌํ”Œ๋กœ

Terraform_remote_state

๋ฐ์ดํ„ฐ ์†Œ์Šค ์ค‘ ํ•˜๋‚˜๋กœ, ๋‹ค๋ฅธ Terraform state ํŒŒ์ผ์˜ ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ํ•œ Terraform ํ”„๋กœ์ ํŠธ์˜ ์ถœ๋ ฅ ๋ณ€์ˆ˜๋ฅผ ๋‹ค๋ฅธ Terraform ํ”„๋กœ์ ํŠธ์—์„œ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ํ”„๋กœ์ ํŠธ๋‚˜ ํ™˜๊ฒฝ ๊ฐ„์˜ ์ข…์†์„ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ network ์ฝ”๋“œ์™€ ec2์˜ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•œ ๋’ค, ๊ฐ๊ฐ terraform cloud์— ์˜ฌ๋ฆฌ๊ณ  ์ด๋ฅผ terraform_remote_state์„ ํ†ตํ•ด ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•ด๋ณธ๋‹ค.

  • network
    • backend.tf

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
        terraform {
          cloud {
            organization = "kane-org"         # ์ƒ์„ฑํ•œ ORG ์ด๋ฆ„ ์ง€์ •
            hostname     = "app.terraform.io" # default
              
            workspaces {
              name = "network" # ์—†์œผ๋ฉด ์ƒ์„ฑ๋จ
            }
          }
          required_providers {
            aws = {
              source  = "hashicorp/aws"
              version = ">= 4.58"
            }
          }
          required_version = ">= 0.13"
        }
      
    • main.tf

      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
      
        locals {
          additional_tags = {
            Terraform   = "true"
            Environment = "Network"
          }
        }
              
        resource "aws_vpc" "kane_vpc" {
          cidr_block           = "10.10.0.0/16"
          enable_dns_support   = true
          enable_dns_hostnames = true
              
          tags = {
            Name = "t101-study"
          }
        }
              
        resource "aws_subnet" "kane_subnet" {
          vpc_id            = aws_vpc.kane_vpc.id
          cidr_block        = "10.10.1.0/24"
          availability_zone = "ap-northeast-2a"
          tags = {
            Name = "t101-subnet"
          }
        }
              
        resource "aws_internet_gateway" "kane_igw" {
          vpc_id = aws_vpc.kane_vpc.id
              
          tags = {
            Name = "t101-igw"
          }
        }
              
        resource "aws_route_table" "kane_rt" {
          vpc_id = aws_vpc.kane_vpc.id
              
          tags = {
            Name = "t101-rt"
          }
        }
              
        resource "aws_route_table_association" "kane_rtassociation1" {
          subnet_id      = aws_subnet.kane_subnet.id
          route_table_id = aws_route_table.kane_rt.id
        }
              
        resource "aws_route" "kane_defaultroute" {
          route_table_id         = aws_route_table.kane_rt.id
          destination_cidr_block = "0.0.0.0/0"
          gateway_id             = aws_internet_gateway.kane_igw.id
        }
              
        resource "aws_security_group" "kane_sg" {
          vpc_id      = aws_vpc.kane_vpc.id
          name        = "T101 SG"
          description = "T101 Study SG"
        }
              
        resource "aws_security_group_rule" "kane_sginbound" {
          type              = "ingress"
          from_port         = 80
          to_port           = 80
          protocol          = "tcp"
          cidr_blocks       = ["0.0.0.0/0"]
          security_group_id = aws_security_group.kane_sg.id
        }
              
        resource "aws_security_group_rule" "kane_sgoutbound" {
          type              = "egress"
          from_port         = 0
          to_port           = 0
          protocol          = "-1"
          cidr_blocks       = ["0.0.0.0/0"]
          security_group_id = aws_security_group.kane_sg.id
        }
      
    • output.tf

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
        output "aws_vpc_id" {
          value = aws_vpc.kane_vpc.id
        }
        output "aws_subnet_id" {
          value = aws_subnet.kane_subnet.id
        }
        output "aws_security_group_id" {
          value = aws_security_group.kane_sg.id
        }
      
  • ec2
    • backend.tf

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
        terraform {
          cloud {
            organization = "kane-org"         # ์ƒ์„ฑํ•œ ORG ์ด๋ฆ„ ์ง€์ •
            hostname     = "app.terraform.io" # default
              
            workspaces {
              name = "ec2" # ์—†์œผ๋ฉด ์ƒ์„ฑ๋จ
            }
          }
          required_providers {
            aws = {
              source  = "hashicorp/aws"
              version = ">= 4.58"
            }
          }
          required_version = ">= 0.13"
        }
      
    • main.tf

      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
      
        locals {
          additional_tags = {
            Terraform   = "true"
            Environment = "EC2"
          }
        }
        data "aws_ami" "amazonlinux2" {
          most_recent = true
          filter {
            name   = "owner-alias"
            values = ["amazon"]
          }
              
          filter {
            name   = "name"
            values = ["amzn2-ami-hvm-*-x86_64-ebs"]
          }
              
          owners = ["amazon"]
        }
              
        data "tfe_outputs" "network" {
          organization = "kane-org"
          workspace    = "network"
        }
        resource "aws_instance" "kane_ec2" {
          ami                         = data.aws_ami.amazonlinux2.id
          associate_public_ip_address = true
          instance_type               = "t2.micro"
          vpc_security_group_ids      = ["${data.tfe_outputs.network.values.aws_security_group_id}"]
          subnet_id                   = data.tfe_outputs.network.values.aws_subnet_id
              
          user_data_replace_on_change = true
        }
      
    • output.tf

      1
      2
      3
      4
      5
      6
      7
      8
      
        output "instance_id" {
          value       = aws_instance.kane_ec2.id
          description = "The ID of the App instance"
        }
        output "instance_public_ip" {
          value       = aws_instance.kane_ec2.public_ip
          description = "The public IP address of the App instance"
        }
      

๋จผ์ € network ๋ชจ๋“ˆ์„ ์‹คํ–‰ํ•œ๋‹ค. network ๋ชจ๋“ˆ์„ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด vpc, subnet, ๋ณด์•ˆ๊ทธ๋ฃน, igw ๋“ฑ์ด ์ƒ์„ฑ๋˜๊ณ  state ํŒŒ์ผ์€ terraform cloud๋กœ ์—…๋กœ๋“œ๋œ๋‹ค.

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
...
aws_vpc.kane_vpc: Creating...
aws_vpc.kane_vpc: Still creating... [10s elapsed]
aws_vpc.kane_vpc: Creation complete after 11s [id=vpc-0611bde7af568db76]
aws_internet_gateway.kane_igw: Creating...
aws_subnet.kane_subnet: Creating...
aws_security_group.kane_sg: Creating...
aws_route_table.kane_rt: Creating...
aws_internet_gateway.kane_igw: Creation complete after 0s [id=igw-0a40a4d39738b4bf1]
aws_route_table.kane_rt: Creation complete after 0s [id=rtb-07685b8b451a260ed]
aws_route.kane_defaultroute: Creating...
aws_subnet.kane_subnet: Creation complete after 0s [id=subnet-08e6ad517434f1842]
aws_route_table_association.kane_rtassociation1: Creating...
aws_route_table_association.kane_rtassociation1: Creation complete after 0s [id=rtbassoc-0994211199a244a68]
aws_route.kane_defaultroute: Creation complete after 0s [id=r-rtb-07685b8b451a260ed1080289494]
aws_security_group.kane_sg: Creation complete after 1s [id=sg-0002c365bfa9ad634]
aws_security_group_rule.kane_sgoutbound: Creating...
aws_security_group_rule.kane_sginbound: Creating...
aws_security_group_rule.kane_sgoutbound: Creation complete after 0s [id=sgrule-1882620294]
aws_security_group_rule.kane_sginbound: Creation complete after 1s [id=sgrule-1795632479]

Apply complete! Resources: 9 added, 0 changed, 0 destroyed.

Outputs:

aws_security_group_id = "sg-0002c365bfa9ad634"
aws_subnet_id = "subnet-08e6ad517434f1842"
aws_vpc_id = "vpc-0611bde7af568db76"

์ดํ›„ ec2 ๋ชจ๋“ˆ์„ ์‹คํ–‰ํ•œ๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์œ„์—์„œ ์‹คํ–‰๋œ network ๋ชจ๋“ˆ์˜ state ํŒŒ์ผ์„ ์ฝ์–ด ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
data "tfe_outputs" "network" {
  organization = "kane-org"
  workspace    = "network"
}

๋ฐ์ดํ„ฐ์†Œ์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ EC2์˜ ๋„คํŠธ์›Œํฌ ๊ด€๋ จ ์‚ฌํ•ญ์ด ์„ค์ •๋œ๋‹ค. ์ƒ์„ฑ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ๋ฐ์ดํ„ฐ์†Œ์Šค๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋Š” ๊ฐ’๋“ค์€ sensitive value๋กœ ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

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
...
	  + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (sensitive value)
      + tags_all                             = (known after apply)
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = true
      + vpc_security_group_ids               = (sensitive value)
...
Changes to Outputs:
  + instance_id        = (known after apply)
  + instance_public_ip = (known after apply)
aws_instance.kane_ec2: Creating...
aws_instance.kane_ec2: Still creating... [10s elapsed]
aws_instance.kane_ec2: Still creating... [20s elapsed]
aws_instance.kane_ec2: Still creating... [30s elapsed]
aws_instance.kane_ec2: Still creating... [40s elapsed]
aws_instance.kane_ec2: Creation complete after 41s [id=i-052c74426b547ab75]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

instance_id = "i-052c74426b547ab75"
instance_public_ip = "3.34.94.79"

AWS ์ฝ˜์†”์—์„œ ํ™•์ธํ•ด๋ณด๋ฉด VPC,Subnet ๋ชจ๋‘ ์ •์ƒ์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ๋ชจ๋“ˆ์—์„œ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ๊ฐ€์ ธ์™”๋‹ค.

๊ทœ๋ชจ์— ๋”ฐ๋ฅธ ์›Œํฌํ”Œ๋กœ

  1. ๊ฐœ์ธ: ํ˜ผ์ž์„œ ํ…Œ๋ผํผ์œผ๋กœ ์ž‘์—…ํ•  ๋•Œ๋Š” ๊ธฐ์กด๊ณผ ๊ฐ™์ด 3๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ž‘์—…ํ•œ๋‹ค.
    1. write: ํ…Œ๋ผํผ ์ฝ”๋“œ ์ž‘์„ฑ
    2. plan: ๋ฆฌ๋ทฐ
    3. apply: ํ”„๋กœ๋น„์ €๋‹, ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ VCS์— ์ฝ”๋“œ๋ฅผ ๋ณ‘ํ•ฉํ•œ๋‹ค.
  2. ๋‹จ์ผ ํŒ€:
    1. write: ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜ ํ˜น์€ ๋‹ค๋ฅธ ์ž‘์—…ํ™˜๊ฒฝ์—์„œ ํ˜ผ์ž ํ…Œ๋ผํผ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
    2. plan(review): ํ…Œ์ŠคํŠธ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด, plan์„ ํ†ตํ•ด ๋‹ค๋ฅธ ํŒ€์›์—๊ฒŒ ๋ฆฌ๋ทฐ๋ฐ›๋Š”๋‹ค.
    3. apply(merge): ๋ฆฌ๋ทฐ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ณ  ์ธํ”„๋ผ๋ฅผ ํ”„๋กœ๋น„์ €๋‹ํ•œ๋‹ค.
  3. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒ€

    ํŒ€ ๋ณ„๋กœ (2)๋ฒˆ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ดํ›„ terraform_remote_state๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ํŒ€์˜ state ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์—ฌ ์ธํ”„๋ผ๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค.

MSA

๋ฆฌ์†Œ์Šค๊ฐ€ ์ ๋‹ค๋ฉด ๋ชจ๋†€๋ฆฌ์‹ ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์„ฑํ•ด๋„ ์ข‹์ง€๋งŒ ์œ ์ง€๋ณด์ˆ˜, ์šด์˜์„ ์ƒ๊ฐํ•˜๋ฉด ํ”„๋กœ๋น„์ €๋‹ ๋‹จ์œ„๋ณ„๋กœ ๋ถ„๋ฅ˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ •๋ณด๋Š” ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฐ ์ง‘ํ•ฉ์€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ ๋‹ค๋ฅธ ์ง‘ํ•ฉ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ๊ฒฉ๋ฆฌ๋œ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์ถœ์ฒ˜: https://medium.com/@dudwls96/terraform-%ED%86%B5%ED%95%9C-iac-infrastructure-as-code-365%EC%9D%BC%EA%B0%84-%EC%9A%B4%EC%98%81-%ED%9B%84%EA%B8%B0-500737e6c1e6

CI/CD

์ œ๊ณตํ•ด์ฃผ์‹  ์ž๋ฃŒ๋ฅผ ํ†ตํ•ด GitHub Actions ์‹ค์Šต์„ ์ง„ํ–‰ํ–ˆ๋‹ค.

https://github.com/terraform101/terraform-aws-github-action

actions.yaml ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์š”์•ฝํ•ด๋ณด๋ฉด

  1. TerraScan์„ ํ†ตํ•ด ์Šค์บ” ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ณ , ์—…๋กœ๋“œํ•œ๋‹ค.
  2. Terraform ์›Œํฌํ”Œ๋กœ ์‹คํ–‰: ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•˜๊ณ , fmt โ†’ init โ†’ validate โ†’ plan โ†’ apply ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.
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
106
107
108
109
110
111
112
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: $

      - 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: $

      - 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:
          AWS_ACCESS_KEY_ID: $
          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$"
        with:
          github-token: $
          script: |
            const output = `#### Terraform Format and Style ๐Ÿ–Œ\`$\`
            #### Terraform Initialization โš™๏ธ\`$\`
            #### Terraform Plan ๐Ÿ“–\`$\`
            <details><summary>Show Plan</summary>
            \`\`\`hcl
            ${process.env.PLAN}
            \`\`\`
            </details>
            **Pusher**: @$
            **Action**: $
            `;
            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: $
          AWS_SECRET_ACCESS_KEY: $

๊ฒฐ๊ณผ

GitHub Actions, AWS, Terraform Cloud์— ๋ชจ๋‘ ์ •์ƒ์ ์œผ๋กœ ๋ฐ˜์˜๋˜์—ˆ๋‹ค. Terrascan์ด ์ˆ˜ํ–‰๋˜๊ณ  ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋ผ ํ”„๋กœ๋น„์ €๋‹๋˜์—ˆ๊ณ , ๊ฒฐ๊ณผ๋ฅผ AWS ์ฝ˜์†”๊ณผ ํ…Œ๋ผํผ ํด๋ผ์šฐ๋“œ์—์„œ ๋ชจ๋‘ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  • GitHub Actions

  • AWS ์ฝ˜์†”

  • Terraform Cloud

์ด์ œ ๋กœ์ปฌ์—์„œ terraform plan -destroy -out=destroy.tfplan ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋ฐฑ์—”๋“œ์˜ state๊ฐ’์„ ์ฝ์–ด์™€ ์ธํ”„๋ผ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

๋„์ „๊ณผ์ œ: Terrascan ์„ค์น˜ ํ›„ ์ง์ ‘ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ธฐ

๊ณต์‹์‚ฌ์ดํŠธ์—์„œ ์ง์ ‘ ์„ค์น˜ํ•œ ํ›„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณธ๋‹ค. ์•„๋ž˜๋Š” macOS, ๋ฆฌ๋ˆ…์Šค ์ „์šฉ ์„ค์น˜๋ช…๋ น์–ด๋‹ค.

1
2
3
4
5
$ curl -L "$(curl -s https://api.github.com/repos/tenable/terrascan/releases/latest | grep -o -E "https://.+?_Darwin_x86_64.tar.gz")" > terrascan.tar.gz
$ tar -xf terrascan.tar.gz terrascan && rm terrascan.tar.gz
$ install terrascan /usr/local/bin && rm terrascan
$ terrascan version
version: v1.18.3

docker image๋„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด, gitlab ๋“ฑ ๋‹ค๋ฅธ ํ”Œ๋žซํผ ํŒŒ์ดํ”„๋ผ์ธ์— ์ ์šฉํ•  ๋•Œ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

1
docker run --rm tenable/terrascan version

์ด์ œ ํ…Œ๋ผํผ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•˜์—ฌ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ terrascan init
$ terrascan scan
...
Scan Summary -

        File/Folder         :   ...
        IaC Type            :   terraform
        Scanned At          :   2023-09-30 02:36:12.552512 +0000 UTC
        Policies Validated  :   144
        Violated Policies   :   6
        Low                 :   2
        Medium              :   1
        High                :   3

๋ณด์•ˆ ๊ทธ๋ฃน๊ณผ ๊ด€๋ จํ•˜์—ฌ High์ด 3๊ฐœ ์žˆ๋‹ค. 3๊ฐœ์˜ ํฌํŠธ๋ฅผ ์—ด์—ˆ๋Š”๋ฐ ๊ฐ๊ฐ ์ทจ์•ฝ์ ์œผ๋กœ ๊ฒ€์‚ฌ๋˜์—ˆ๋‹ค.

scan์˜ exit ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ด 5๊ฐœ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค. GitHub ์ฐธ๊ณ . Terraform Cloud Run task, CI/CD๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ์ฐธ๊ณ ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

ScenarioExit Code
scan summary has errors and violations5
scan summary has errors but no violations4
scan summary has violations but no errors3
scan summary has no violations or errors0
scan command errors out due to invalid inputs1
This post is licensed under CC BY 4.0 by the author.