# Checkov로 Terraform 설정 오류를 찾고 고치기

> 연습용 main.tf를 apply 없이 Checkov로 점검해 실패 항목 표를 읽고, 설정을 고쳐 통과시킵니다. 사유를 남기는 skip 주석, soft-fail과 종료 코드로 만드는 CI 게이트, json과 sarif 출력, Trivy config와의 결과 비교까지 다룹니다.

- 주소: https://copyandrun.com/blog/checkov-terraform-misconfig/
- 분야: DevSecOps
- 발행일: 2026-10-16
- 태그: Checkov, Terraform, IaC, Trivy

Terraform 파일을 `apply` 하지 않고 파일 내용만 읽어서 설정 오류를 찾는 정적 점검을 Checkov로 해 봅니다. 열린 S3 버킷, 전 세계에 열린 SSH, 암호화하지 않은 EBS 볼륨을 일부러 넣은 연습용 `main.tf`를 점검하고 고친 뒤, 같은 파일을 Trivy로도 점검해 결과를 비교합니다. 이 글의 취약한 설정은 직접 만든 연습용이며 실제 서비스에 쓰면 안 됩니다. 이 파일은 점검용이며 `terraform init`, `plan`, `apply`를 실행하지 않습니다. AWS 계정이나 자격 증명은 필요하지 않고 클라우드 호출도 하지 않습니다.

## 준비물

| 항목 | 내용 |
| --- | --- |
| Checkov | 3.3.29 (`pip install checkov==3.3.29`로 고정) |
| Python | 3.12.10 (가상환경에 pip로 설치) |
| Docker | Docker Desktop (Trivy 실행용) |
| Trivy | 0.76.0 (이미지 `aquasec/trivy:0.76.0`) |
| 실행 환경 | Windows Git Bash |
| 예상 소요 시간 | 약 25분 |

명령은 Windows의 Git Bash 기준입니다. 가상환경 활성화는 Linux와 macOS에서 `source .venv/bin/activate`입니다. 가상환경 크기는 약 260MB입니다. 이 글의 건수(12/20, 36/8 등)는 Checkov 3.3.29 기준이며 버전이 다르면 달라질 수 있습니다. 한글이 든 파일을 읽을 때 생기는 인코딩 문제는 4절과 아래 자주 막히는 곳에 적었습니다.

```bash
mkdir cr-checkov-lab && cd cr-checkov-lab
python -m venv .venv
source .venv/Scripts/activate
pip install checkov==3.3.29
checkov --version
mkdir bad fixed
```

기대 출력의 마지막 줄입니다.

```text
3.3.29
```

## 1. 설정 오류가 든 main.tf 만들기

퍼블릭 읽기 ACL이 있는 버킷, 암호화와 버전 관리가 없는 버킷, 0.0.0.0/0에 SSH가 열린 보안 그룹, 암호화하지 않은 EBS 볼륨을 한 파일에 넣습니다. 이 파일은 점검용이며 `terraform init`, `plan`, `apply`를 실행하지 않습니다.

```bash
cat > bad/main.tf <<'EOF'
resource "aws_s3_bucket" "assets" {
  bucket = "cr-checkov-demo-assets"
  acl    = "public-read"
}

resource "aws_s3_bucket" "logs" {
  bucket = "cr-checkov-demo-logs"
}

resource "aws_security_group" "ssh" {
  name        = "cr-checkov-demo-ssh"
  description = "ssh access"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_ebs_volume" "data" {
  availability_zone = "ap-northeast-2a"
  size              = 20
}
EOF
```

## 2. 점검하고 실패 항목 읽기

`-d`는 점검할 폴더입니다. `--compact`는 코드 블록을 빼고, `--quiet`는 실패 항목만 보여 줍니다. 출력이 길어 앞부분만 봅니다.

```bash
checkov -d bad --compact --quiet | head -28
```

기대 출력입니다. 항목 순서는 실행마다 다를 수 있습니다.

```text
terraform scan results:

Passed checks: 12, Failed checks: 20, Skipped checks: 0

Check: CKV_AWS_23: "Ensure every security group and rule has a description"
	FAILED for resource: aws_security_group.ssh
	File: \main.tf:10-20
	Guide: https://docs.prismacloud.io/...
```

한 건은 네 줄로 읽습니다.

| 줄 | 읽는 법 |
| --- | --- |
| `Check: CKV_AWS_23` | 검사 ID와 설명입니다. skip 주석과 `--check` 옵션에 이 ID를 씁니다. |
| `FAILED for resource` | 문제가 있는 리소스 `종류.이름`입니다. |
| `File: \main.tf:10-20` | 파일과 리소스가 차지한 줄 범위입니다. Windows에서는 역슬래시로 나옵니다. |
| `Guide` | 이유와 수정 방법을 적은 문서 주소입니다. |

같은 검사가 버킷마다 한 번씩 반복되므로 건수(20)는 문제 종류보다 많습니다. 실패한 검사 ID가 몇 가지인지는 5절의 json 출력으로 세어 보며, 13가지입니다.

![Passed 12, Failed 20 요약 아래에 검사 ID, 리소스, 파일과 줄 범위, 가이드 주소가 건마다 나오는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/01-checkov-bad-scan.png)

## 3. 설정 고치기

핵심 오류는 `CKV_AWS_20`(퍼블릭 읽기 ACL), `CKV_AWS_24`(SSH 전체 개방), `CKV_AWS_3`(EBS 암호화 없음)입니다. 이들과 함께 버전 관리, 암호화, 퍼블릭 액세스 차단, 접근 로그까지 고친 파일입니다. S3 설정은 별도 리소스로 분리해 적었고 SSH 대역은 연습용 사설 대역 `10.0.0.0/24`입니다.

```bash
cat > fixed/main.tf <<'EOF'
resource "aws_kms_key" "data" {
  description         = "cr-checkov-demo data key"
  enable_key_rotation = true
}

resource "aws_s3_bucket" "assets" {
  bucket = "cr-checkov-demo-assets"
}

resource "aws_s3_bucket_public_access_block" "assets" {
  bucket                  = aws_s3_bucket.assets.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_versioning" "assets" {
  bucket = aws_s3_bucket.assets.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "assets" {
  bucket = aws_s3_bucket.assets.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.data.arn
    }
  }
}

resource "aws_s3_bucket_logging" "assets" {
  bucket        = aws_s3_bucket.assets.id
  target_bucket = aws_s3_bucket.logs.id
  target_prefix = "assets/"
}

resource "aws_s3_bucket" "logs" {
  bucket = "cr-checkov-demo-logs"
}

resource "aws_s3_bucket_public_access_block" "logs" {
  bucket                  = aws_s3_bucket.logs.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_versioning" "logs" {
  bucket = aws_s3_bucket.logs.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
  bucket = aws_s3_bucket.logs.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.data.arn
    }
  }
}

resource "aws_security_group" "ssh" {
  name        = "cr-checkov-demo-ssh"
  description = "ssh access from the office network only"

  ingress {
    description = "ssh from office"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/24"]
  }
}

resource "aws_ebs_volume" "data" {
  availability_zone = "ap-northeast-2a"
  size              = 20
  encrypted         = true
  kms_key_id        = aws_kms_key.data.arn
}
EOF

checkov -d fixed --compact --quiet | grep -E "Passed checks|Check:"
```

기대 출력입니다.

```text
Passed checks: 36, Failed checks: 8, Skipped checks: 0
Check: CKV2_AWS_64: "Ensure KMS key Policy is defined"
Check: CKV2_AWS_62: "Ensure S3 buckets should have event notifications enabled"
Check: CKV2_AWS_62: "Ensure S3 buckets should have event notifications enabled"
Check: CKV2_AWS_61: "Ensure that an S3 bucket has a lifecycle configuration"
...
```

20건이 8건으로 줄었습니다. 남은 것은 KMS 키 정책, 이벤트 알림, 수명 주기, 교차 리전 복제, 보안 그룹 연결 여부입니다. 이 연습 환경에는 해당하지 않는 항목이라 다음 절에서 사유를 남기고 넘깁니다.

![고친 뒤 Passed 36, Failed 8로 줄고 남은 검사 ID가 나열되는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/02-checkov-fixed-remaining.png)

## 4. 사유를 남기고 검사 예외 처리하기

리소스 블록 안에 `#checkov:skip=<검사 ID>:<사유>` 형식으로 적습니다. 공식 문서의 Suppressing and Skipping Policies 형식이며 사유는 선택이지만 출력에 그대로 남으므로 적어 둡니다. 사유에 한글을 쓰므로 먼저 `PYTHONUTF8=1`을 지정합니다. 지정하지 않으면 Windows에서 Checkov가 `UnicodeDecodeError`로 종료합니다(아래 자주 막히는 곳). 아래 `awk`는 리소스 시작 줄 바로 아래에 주석을 넣으며 GNU `sed`와 달리 macOS에서도 같게 동작합니다. 두 번째 보안 그룹 사유는 연습용 예시 문구입니다. 실제로는 근거가 있을 때만 사유를 적습니다.

```bash
export PYTHONUTF8=1
awk '
{ print }
/^resource "aws_kms_key" "data"/ { print "  #checkov:skip=CKV2_AWS_64:연습용 키라 기본 키 정책을 사용합니다" }
/^resource "aws_s3_bucket" "/ {
  print "  #checkov:skip=CKV2_AWS_62:연습용 버킷이라 이벤트 알림을 쓰지 않습니다"
  print "  #checkov:skip=CKV_AWS_144:단일 리전 연습용이라 교차 리전 복제를 쓰지 않습니다"
  print "  #checkov:skip=CKV2_AWS_61:연습용 버킷이라 수명 주기 규칙을 두지 않습니다" }
/^resource "aws_security_group" "ssh"/ { print "  #checkov:skip=CKV2_AWS_5:연습용 예시 사유입니다. 실제로는 근거가 있을 때만 적습니다" }
' fixed/main.tf > fixed/main.tf.new && mv fixed/main.tf.new fixed/main.tf

checkov -d fixed --compact --quiet; echo "exit=$?"
checkov -d fixed --compact | grep -A3 SKIPPED | head -9
```

기대 출력입니다.

```text
Passed checks: 36, Failed checks: 0, Skipped checks: 8

exit=0
	SKIPPED for resource: aws_s3_bucket.assets
	Suppress comment: 연습용 버킷이라 이벤트 알림을 쓰지 않습니다
	File: \main.tf:7-12
```

실패 0건에 종료 코드 0입니다. 예외 처리한 항목은 사라지지 않고 `SKIPPED`와 `Suppress comment`로 남아서 나중에 사유를 검토할 수 있습니다. 반대로 `--skip-check`는 해당 검사를 실행하지 않아 출력에도 남지 않으므로, 리소스 단위의 예외는 주석으로 적는 편이 기록에 유리합니다.

![Skipped 8, 종료 코드 0이고 SKIPPED 항목마다 Suppress comment에 사유가 나오는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/03-checkov-skip-comments.png)

## 5. 종료 코드와 출력 형식으로 CI 게이트 만들기

Checkov는 실패가 있으면 종료 코드 1로 끝납니다. 이 값이 CI의 통과와 실패가 됩니다. 아래는 `bad` 폴더에 옵션별 동작을 확인한 것입니다.

```bash
checkov -d bad --quiet --compact --soft-fail > /dev/null; echo "soft-fail exit=$?"
checkov -d bad --check CKV_AWS_20,CKV_AWS_24,CKV_AWS_3 --quiet --compact; echo "gate exit=$?"
checkov -d bad -o json --quiet > report.json; echo "json exit=$?"
python -c "import json; d=json.load(open('report.json')); print(d['summary'])"
python -c "import json; d=json.load(open('report.json')); print(len({c['check_id'] for c in d['results']['failed_checks']}))"
checkov -d bad -o sarif --output-file-path . --quiet > /dev/null; ls -l results_sarif.sarif
```

마지막 줄 `python -c`는 실패한 검사 ID의 종류를 세며 `13`이 출력됩니다. 앞의 `summary` 줄은 아래 그림에서 확인합니다.

| 옵션 | 동작 |
| --- | --- |
| `--soft-fail` | 점검은 하되 종료 코드를 0으로 합니다. 도입 초기에 보고만 할 때 씁니다. |
| `--check ID,ID` | 지정한 검사만 실행하고 나머지는 건너뜁니다. 꼭 막을 항목만 게이트로 거는 데 씁니다. 위 결과는 3건 실패에 종료 코드 1이었습니다. |
| `-o json` / `-o sarif` | 결과를 json 또는 sarif로 냅니다. json의 `summary`에는 passed, failed, 버전이 들어 있고, sarif는 `--output-file-path`로 지정한 폴더에 `results_sarif.sarif`로 저장됩니다. |
| `--hard-fail-on ID` | 공식 문서는 "Exits with a non-zero exit code for specified checks"라고 설명합니다. `--soft-fail`과 함께 쓰면 지정한 검사만 실패로 처리하며, 이 글에서는 `CKV_AWS_20`으로 종료 코드 1이 나오는 것을 확인했습니다. |

CI에는 다음처럼 옮깁니다. 알려진 항목을 한꺼번에 막지 않고 핵심 오류가 새로 들어오지 않게 하려면 `--check`로 시작해 범위를 넓혀 갑니다. 공식 문서(https://www.checkov.io/2.Basics/CLI%20Command%20Reference.html)는 `--check`를 "Checks to run; any other checks will be skipped"라고 설명합니다. 즉 `--check`로 고른 검사 외의 나머지 검사는 실행되지 않습니다.

```bash
checkov -d . --framework terraform --quiet --compact --check CKV_AWS_20,CKV_AWS_24,CKV_AWS_3
```

이 게이트는 연습 파일의 모양만 잡습니다. 다른 형태로 쓴 리소스나 다른 포트는 지나갈 수 있어서 게이트 통과가 안전하다는 증거는 아닙니다. 아래 `weak` 폴더는 22번이 아닌 2222번 포트를 `0.0.0.0/0`에 연 보안 그룹 규칙과 설정이 빈 버킷입니다.

```bash
mkdir weak && cat > weak/main.tf <<'EOF'
resource "aws_s3_bucket" "open" {
  bucket = "cr-checkov-demo-open"
}

resource "aws_security_group_rule" "ssh_alt" {
  type              = "ingress"
  security_group_id = "sg-0123456789abcdef0"
  from_port         = 2222
  to_port           = 2222
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}
EOF
checkov -d weak --check CKV_AWS_20,CKV_AWS_24,CKV_AWS_3 --quiet --compact; echo "gate exit=$?"
checkov -d weak --quiet --compact | grep -c "FAILED for"
```

```text
terraform scan results:

Passed checks: 2, Failed checks: 0, Skipped checks: 0

gate exit=0
8
```

세 항목만 거는 게이트는 종료 코드 0으로 통과하지만, 같은 폴더를 모든 검사로 돌리면 8건이 실패합니다.

![soft-fail은 종료 코드 0, check로 고른 세 항목은 3건 실패와 종료 코드 1, json 요약과 sarif 파일 생성이 나오는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/04-checkov-exit-formats.png)

## 6. Trivy config로 같은 파일 교차 점검하기

Trivy도 `trivy config`로 Terraform을 정적 점검합니다. 이미지 스캔과 빌드 게이트는 [Trivy로 컨테이너 이미지 취약점을 스캔하고 빌드 게이트 만들기](/blog/trivy-image-scan-gate/)에서 다뤘으므로 여기서는 설정 점검만 봅니다. 현재 폴더를 컨테이너에 연결하는 함수를 먼저 등록합니다. 점검 규칙은 실행할 때 내려받아 캐시 볼륨에 보관합니다.

```bash
trivy() { MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd -W):/work" -w /work -v cr-checkov-trivy-cache:/root/.cache/ aquasec/trivy:0.76.0 "$@"; }
trivy config -q bad | head -16
```

Linux와 macOS에서는 `MSYS_NO_PATHCONV=1`을 빼고 `$(pwd -W)` 대신 `$PWD`를 씁니다. 첫 줄 요약에서 `main.tf`에 21건이 나옵니다.

![Report Summary에서 main.tf 한 파일에 21건의 설정 오류가 나오는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/05-trivy-config-bad.png)

```bash
trivy config -q --exit-code 1 bad > trivy-bad.txt; echo "bad exit=$?"
trivy config -q --exit-code 1 fixed > trivy-fixed.txt; echo "fixed exit=$?"
grep -E "^AWS-|Failures" trivy-bad.txt | cut -c1-90 | sort | uniq -c
grep -E "^AWS-|Failures" trivy-fixed.txt
```

Trivy는 `--exit-code`를 주지 않으면 실패가 있어도 종료 코드 0입니다. Checkov는 기본값이 1이라 이 점이 다릅니다. 고친 파일은 LOW 한 건(`AWS-0089`, 로그 버킷에 접근 로그 없음)만 남았습니다. `--exit-code`의 공식 설명은 "specify exit code when any security issues are found"이고, `--severity`로 거른 결과만 판정에 쓰입니다. `--severity HIGH,CRITICAL`을 더해 실제로 실행한 결과입니다.

```bash
trivy config -q --exit-code 1 --severity HIGH,CRITICAL fixed > /dev/null; echo "severity exit=$?"
```

```text
severity exit=0
```

LOW 한 건만 남은 고친 파일이 HIGH, CRITICAL 기준에서는 통과합니다. 같은 파일을 `--severity` 없이 `--exit-code 1`로 돌리면 종료 코드 1입니다(위 `fixed exit=1`).

![bad는 21건과 종료 코드 1, fixed는 AWS-0089 LOW 한 건이 남는 것을 확인합니다.](https://copyandrun.com/img/checkov-terraform-misconfig/06-trivy-compare.png)

같은 `bad`에 대한 두 도구의 결과를 비교하면 다음과 같습니다.

| 항목 | Checkov 3.3.29 | Trivy 0.76.0 |
| --- | --- | --- |
| 건수 | 20건 (검사 ID 13가지) | 21건 (ID 13가지) |
| 퍼블릭 ACL | `CKV_AWS_20` | `AWS-0092` |
| SSH 전체 개방 | `CKV_AWS_24` | `AWS-0107` |
| EBS 암호화 없음 | `CKV_AWS_3` | `AWS-0026` |
| 퍼블릭 액세스 차단 없음 | `CKV2_AWS_6` 한 건 | `AWS-0086`, `0087`, `0091`, `0093`, `0094`로 나뉨 |
| 이벤트 알림, 수명 주기, 교차 리전 복제 | 지적함 | 지적하지 않음 |
| 로그 버킷의 접근 로그 (고친 뒤) | 통과 | `AWS-0089` 지적 |
| 예외 처리 주석 | `#checkov:skip=ID:사유` | `#trivy:ignore:AWS-0089` |
| 실패 시 기본 종료 코드 | 1 | 0 (`--exit-code 1` 필요) |

핵심 세 오류는 둘 다 잡았습니다. 갈리는 부분은 도구마다 가진 검사 목록의 폭과 묶는 방식입니다. Trivy 공식 문서(https://trivy.dev/docs/latest/guide/coverage/iac/terraform/)는 인라인 `# trivy:ignore` 주석으로 예외 처리할 수 있다고만 안내하고 상세 문법은 싣지 않습니다. 그래서 `#trivy:ignore:<ID>` 형식은 직접 실행으로 확인했습니다. 로그 버킷 리소스 바로 윗줄에 `#trivy:ignore:AWS-0089`를 적었더니 `--exit-code 1`에서도 종료 코드 0이 되었습니다. 어느 쪽이 맞는지는 팀이 정한 기준으로 판단하고, 한 도구의 검사 목록이 닿지 않는 곳을 다른 도구가 메우는 용도로 함께 쓸 수 있습니다. 시크릿 점검은 [gitleaks 글](/blog/gitleaks-secret-scan/)에서 따로 다룹니다.

## 자주 막히는 곳

**한글이 든 skip 주석을 넣었더니 Checkov가 `UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d`로 종료됩니다.** Windows의 기본 인코딩(cp1252)으로 `.tf` 파일을 읽다가 생깁니다. 이 환경(Windows Git Bash, Python 3.12, Checkov 3.3.29)에서 종료 코드는 2였고 환경에 따라 다를 수 있습니다. Checkov 공식 문서의 종료 코드 2는 `--no-fail-on-crash` 설명에 나오는 플랫폼 연동 실패이며 이 오류와는 다른 것입니다. 4절처럼 `export PYTHONUTF8=1`을 지정하면 정상 점검되며(종료 코드 0), 영문 사유만 쓰는 방법도 있습니다. 점검 실패(종료 코드 1)와 구분해서 봅니다.

**`File: \main.tf:10-20`처럼 경로가 역슬래시로 나오고 폴더 이름이 보이지 않습니다.** `-d`에 지정한 폴더를 기준으로 한 상대 경로이고 Windows에서는 구분자가 역슬래시입니다. 폴더가 여럿이면 어느 폴더인지 구분이 어려우니 폴더마다 따로 실행합니다.

**항목 순서가 실행할 때마다 달라서 결과를 비교하기 어렵습니다.** 같은 파일을 반복해 실행하면 순서가 바뀌는 것을 확인했습니다. 비교는 순서 대신 검사 ID로 하고, 자동화에는 `-o json`을 씁니다.

**Trivy `config`가 처음 실행할 때 느립니다.** 규칙을 내려받으므로 네트워크가 필요하고, 캐시 볼륨을 같이 마운트하면 다음부터는 받지 않습니다.

## 이어서 해 볼 것

- **Docker 이미지로 실행하기**: 가상환경 대신 Checkov 공식 이미지로 같은 점검을 돌려 CI 러너에 맞는 방식을 고릅니다. 이미지 이름과 태그는 공식 문서에서 확인합니다.
- **새 리소스 추가해 보기**: `aws_instance`에 보안 그룹을 연결하면 `CKV2_AWS_5` 예외 처리가 필요 없어지는지 확인합니다.
- **sarif를 code scanning에 올리기**: `results_sarif.sarif`를 `github/codeql-action/upload-sarif` 단계로 GitHub에 올려 PR에 표시하는 구성을 시도해 봅니다.

## 확인 범위

직접 실행한 부분은 1절부터 6절까지입니다. 환경은 Windows의 Git Bash, Python 3.12.10 가상환경, Checkov 3.3.29, Docker Desktop과 `aquasec/trivy:0.76.0`입니다. 한글 skip 주석에서 `PYTHONUTF8=1`을 지정하지 않았을 때의 인코딩 오류도 재현했습니다. 모두 파일을 읽기만 했고 `terraform init`, `plan`, `apply`는 하지 않았으며 AWS를 호출하지 않았습니다.

설치는 pip만 확인했습니다. Checkov의 Docker 이미지와 Linux, macOS 명령(`source .venv/bin/activate`, `awk`의 macOS 동작), GitHub Actions 연동은 실행하지 못했습니다. Checkov 옵션은 공식 문서 https://www.checkov.io/2.Basics/CLI%20Command%20Reference.html 과 https://www.checkov.io/2.Basics/Suppressing%20and%20Skipping%20Policies.html 을 읽고 `checkov --help`로 대조했습니다. `--hard-fail-on`은 검사 ID 지정의 종료 코드 확인까지만 했고, 심각도로 지정하는 방식은 API 키가 필요하다고 안내되어 실행하지 않았습니다. Trivy는 https://trivy.dev/docs/latest/guide/coverage/iac/terraform/ 에서 인라인 `# trivy:ignore` 언급을, https://trivy.dev/docs/latest/references/configuration/cli/trivy_config/ 에서 `--exit-code` 설명을, https://trivy.dev/docs/latest/guide/configuration/filtering/ 에서 `--severity` 설명을 확인했고 `#trivy:ignore:<ID>` 상세 문법은 공식 문서에서 찾지 못해 실행 결과만 적었습니다. 검사 목록과 건수는 도구 버전에 따라 달라집니다.
