Trivy: 컨테이너 이미지 취약성 검사 스캐너
이번 포스팅에서는 Trivy를 사용하여 도커 및 기타 컨테이너 이미지의 취약성을 검사하는 방법을 공유해보려고 합니다.
개요
도커 컨테이너 이미지 스캔
- 컨테이너를 프로덕션 환경에 배포하기 전에 취약점을 사전에 해결
- 컨테이너화된 애플리케이션의 보안을 향상
Tools
- Clair
- Anchore Engine
- Trivy
이 중 먼저, Aqura Security에서 만든 오픈소스 툴인 Trivy를 사용하여, 여러 대상 중 Container Image 관련 취약섬 검사에 대해서 공유
Trivy
Target (스캔할 수 있는 대상)
- Container Image (해당 포스팅에서는 이 부분을 공유)
- Filesystem
- Rootfs
- Git Repo (remote)
- Virtual Machine Image
- Kubernetes
- AWS
- SBOM
Scanner (찾을 수 있는 문제)
- 사용 중인 OS 패키지와 소프트웨어 종속성 (SBOM)
- 알려진 취약점 (CVE)
- IaC 문제 및 구성오류
- 민감 정보 및 비밀
- 소프트웨어 라이선스
Mode
- Standalone
-
Client/Server
- Client
- 독립 실행형으로 실행됨
- 사용자가 명령어를 실행하면 로컬에서 바로 취약점 검사 수행
- Server
- 서버로 실행됨
- 여러 클라이언트가 동시에 사용 가능하며, 중앙에서 취약점 DB를 관리할 수 있게 됨
- 클라이언트는 이 서버에 요청을 보내 취약점 검사를 수행
- 클라이언트는 취약점 DB를 다운받을 필요가 없어짐
- Client
Container Image
2가지 지원
- 컨테이너 이미지 내부의 파일들
- 컨테이너 이미지 내의 파일들을 스캔
- 컨테이너 이미지의 메타데이터
컨테이너 이미지 내부의 파일 항목
- Vulnerabilities (취약점)
- Misconfigurations (구성 오류)
- Secrets
- Licenses
-- 해당 이미지에서 발견된 모든 취약점에 대한 보고서 생성
-- (Vulnerabilities + Secrets 은 디폴트로 활성화)
$ trivy image [IMAGE_NAME]
Vulnerabilities
- Severity(심각도)
- LOW : 0.1~3.9
- MEDIUM : 4.0~6.9
- HIGH : 7.0~8.9
- CRITICAL : 9.0~10.0
-- 해당 옵션은 디폴트로 활성화된 상태
-- 스캔 범위를 취약점만으로 제한하는 등의 역할을 수행
$ trivy image --scanners vuln [IMAGE_NAME]
Misconfiguration
Infrastructure as Code(IaC) 파일들에 대한 구성 오류 검사
- ex. Kubernetes Yaml
- ex. Terraform 파일
$ trivy image --scanners misconfig [IMAGE_NAME]
Secrets
컨테이너 이미지 내부에서 민감한 정보나 비밀 데이터 탐지
- 하드코딩된 비밀 정보
- ex. API키, 패스워드, 데이터베이스 연결정보
- 보안에 취약한 설정을 가진 파일이나 구성
- ex. SSH 개인키가 포함된 경우, 파일 권한 설정 취약
- 기타 민감한 데이터
$ trivy image [IMAGE_NAME]
Licenses
이미지에 포함된 패키지들의 라이선스 정보 검사 및 보고
- 사용자가 해당 패키지를 사용할 때, 어떤 조건을 준수해야 하는지
$ trivy image --scanners license [IMAGE_NAME]
이미지 소스 검색 방식
저장된 이미지를 여러 위치에서 검색
- 로컬 Docker Engine
- $ docker images
- 로컬 도커 환경에서 저장된 이미지
- Containerd
- $ nerdctl images
- $ ctr image ls
- 컨테이너 런타임에서 관리하는 이미지
- Podman
- $ podman images
- 도커와 유사한 컨테이너 관리 도구에서의 이미지
- 컨테이너 레지스트리
- $ trivy image –remote docker.io/library/alpine:3.7.3
- DockerHub, Github Container Registry 등 외부 레지스트
- private Registry 포함한 Public/Private
- Tar Files
- $ trivy image –input /path/to/image.tar
- 로컬에 Tar로 저장된 이미지
- OCI(Open Container Initiative) Layout
- $ trivy image –input /path/to/oci-layout
- OCI는 컨테이너 포맷/런타임에 대한 오픈 스펙과 표준을 제공함으로써 컨테이너 생태계의 호환성을 강화하는 것
- 이미지 스펙과 런타임스펙
-- 기본 동작 변경 시, --image-src 플래그 사용
-- 예시
$ trivy image --image-src podman,containerd [IMAGE_NAME]
테스트
1. Standalone Mode
- command를 통해, python:3.4-alpine 이미지를 스캔
- Standalone 모드이기에, 로컬에서 바로 취약점 검사 수행
docker-compose.yml
# https://aquasecurity.github.io/trivy/v0.53/getting-started/installation/
version: '3.3'
services:
trivy:
image: aquasec/trivy:0.53.0
container_name: trivy
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
# - '$HOME/Library/Caches:/root/.cache/'
command: ["image", "python:3.4-alpine"]
-- 4가지 모두 다 확인
command: ["image", "--scanners", "vuln,secret,misconfig,license", "python:3.4-alpine"]
-
실행 과정
-
이 콘솔로그는 vuln과 secret에 대한 로그
- secret 에 문제가 되는 코드는 없어서 로그가 안 뜨는 것으로 보임
-
1. 취약점 DB 업데이트 필요 확인
trivy | 2024-07-18T06:44:32Z INFO Need to update DB
2. ghcr.io/aquasecurity/trivy-db:2 라는 취약점 DB 다운로드
trivy | 2024-07-18T06:44:32Z INFO Downloading DB... repository="ghcr.io/aquasecurity/trivy-db:2"
3. 취약점 스캐닝 활성화 확인
trivy | 2024-07-18T06:44:36Z INFO Vulnerability scanning is enabled
4. 비밀 정보 스캐닝 활성화 확인
trivy | 2024-07-18T06:44:36Z INFO Secret scanning is enabled
5. 스캐닝 속도 향상 권장사항 제공 (느리면, 비밀정보 비활성화해라 등)
trivy | 2024-07-18T06:44:36Z INFO If your scanning is slow, please try '--scanners vuln' to disable secret scanning
trivy | 2024-07-18T06:44:36Z INFO Please see also https://aquasecurity.github.io/trivy/v0.53/docs/scanner/secret#recommendation for faster secret detection
6. OS 감지 (컨테이너 이미지에서 사용된 OS와 버전 감지)
trivy | 2024-07-18T06:44:38Z INFO Detected OS family="alpine" version="3.9.2"
7. 취약점 감지
trivy | 2024-07-18T06:44:38Z INFO [alpine] Detecting vulnerabilities... os_version="3.9" repository="3.9" pkg_num=28
8. 언어별 파일 수 감지 (여기서는 파이썬 파일 하나있음을 감지)
trivy | 2024-07-18T06:44:38Z INFO Number of language-specific files num=1
9. 언어별 패키지(Bundler, npm, yarn ) 취약점 감지
trivy | 2024-07-18T06:44:38Z INFO [python-pkg] Detecting vulnerabilities...
10. OS 지원 종료 경고
trivy | 2024-07-18T06:44:38Z WARN This OS version is no longer supported by the distribution family="alpine" version="3.9.2"
trivy | 2024-07-18T06:44:38Z WARN The vulnerability detection may be insufficient because security updates are not provided
11. 결과 출력 형식 정보 제공 (디폴트 : 테이블 형식)
trivy | 2024-07-18T06:44:38Z INFO Table result includes only package filenames. Use '--format json' option to get the full path to the package file.
12. 최종 스캔 결과 출력 (일부 출력)
(총 37개 중 4개가 낮은 심각도/16개의 중간심각도/13개의 높은 심각도/4개의 치명적 취약점 분류)
trivy |
trivy | python:3.4-alpine (alpine 3.9.2)
trivy | ================================
trivy | Total: 37 (UNKNOWN: 0, LOW: 4, MEDIUM: 16, HIGH: 13, CRITICAL: 4)
trivy |
trivy | ┌──────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
trivy | │ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
trivy | ├──────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
trivy | │ expat │ CVE-2018-20843 │ HIGH │ fixed │ 2.2.6-r0 │ 2.2.7-r0 │ expat: large number of colons in input makes parser consume │
trivy | │ │ │ │ │ │ │ high amount... │
-
Status
- fixed : 취약점이 패치된 버전이 존재하는 상태
- not fixed : 취약점이 해결되지 않은 상태
- unknown : 취약점 상태가 알려지지않은 상태
-
Fixed Version : 취약점이 패치된 버전
-- Lincense 보고서
-- 여기서는, OS 패키지 라이선스와 파이썬 패키지 라이선스 보고서
trivy | OS Packages (license)
trivy | =====================
trivy | Total: 32 (UNKNOWN: 4, LOW: 15, MEDIUM: 2, HIGH: 11, CRITICAL: 0)
trivy |
trivy | ┌────────────────────────┬───────────────┬────────────────┬──────────┐
trivy | │ Package │ License │ Classification │ Severity │
trivy | ├────────────────────────┼───────────────┼────────────────┼──────────┤
trivy | │ alpine-baselayout │ GPL-2.0 │ restricted │ HIGH │
trivy | ├────────────────────────┼───────────────┼────────────────┼──────────┤
trivy | │ alpine-keys │ MIT │ notice │ LOW │
...
trivy | Python (license)
trivy | ================
trivy | Total: 3 (UNKNOWN: 3, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
trivy |
trivy | ┌────────────┬─────────────┬────────────────┬──────────┐
trivy | │ Package │ License │ Classification │ Severity │
trivy | ├────────────┼─────────────┼────────────────┼──────────┤
trivy | │ pip │ MIT License │ unknown │ UNKNOWN │
trivy | ├────────────┤ │ │ │
trivy | │ setuptools │ │ │ │
trivy | ├────────────┤ │ │ │
trivy | │ wheel │ │ │ │
trivy | └────────────┴─────────────┴────────────────┴──────────┘
-
옵션
- timeout : 작업의 타임아웃
- format : 출력형식
- dependency-tree : 의존성 트리 포함여부
- JSON 형식에서는 작동 X (JSON형식에서는 비활성화)
- 출력을 table로 하면 가능함
- list-all-pkgs : 모든 패키지 나열 설정
- exit-code : 1 취약점이 발견되면 Trivy가 종료 코드를 1로 반환하도록 하는 설정
- CI/CD 파이프라인에서 사용
- output : 결과를 파일에 저장
- scan : skip-dirs 특정 디렉토리를 스캔하지 않도록 설정
- vulnerability: type : OS 및 라이브러리 취약점을 스캔하도록 설정
- vulnerability: ignore-unfixed : 수정되지 않은 취약점을 무시하도록 설정
- false : 모든 취약점 확인
- db: skip-update 데이터베이스 업데이트를 건너뛰지 않도록 설정
2. Client/Server Mode
version: '3.3'
services:
trivy-server:
image: aquasec/trivy:0.53.0
container_name: trivy-server
command: ["server", "--listen", "0.0.0.0:8080"]
ports:
- "8081:8080" # 외부포트 8081로 변경
trivy-client:
image: aquasec/trivy:0.53.0
container_name: trivy-client
depends_on:
- trivy-server
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
command: ["image", "--server", "http://trivy-server:8080", "python:3.4-alpine"]
3. Tar 파일로 이미지 스캔
$ docker images
$ docker save -o google_cadvisor.tar google/cadvisor:latest
$ vi docker-compose.yml
version: '3.3'
services:
trivy:
image: aquasec/trivy:0.53.0
container_name: trivy
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
- './volume/Library/Caches:/root/.cache/'
- './google_cadvisor.tar:/google_cadvisor.tar'
command: ["image", "--input", "/google_cadvisor.tar"]
4. 서비스를 올리면서, 올리는 서비스에 대한 이미지 분석 수행
version: '3.3'
services:
app:
image: alpine:latest
container_name: alpine
command: ["sh", "-c", "while true; do echo 'Hello from Alpine'; sleep 3600; done"]
trivy:
image: aquasec/trivy:0.53.0
container_name: trivy
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
entrypoint: ["sh", "-c", "trivy image alpine:latest"]
depends_on:
- app
실행 중인 컨테이너에 대한 실시간 스캔 X
참고