prego-docker 이미지 검증 및 취약점 대응 기획
목적: (1) Frappe·ERPNext·HRMS·custom app이 이미지에 정상 포함되었는지 검증하는 방법을 정리하고, (2) Docker Hub 등에서 보고되는 취약점을 해결하는 방향을 기획한다. 코드 생성은 하지 않고 검증 절차·취약점 대응 전략만 문서화한다.
대상 이미지: iamfork/prego-repo (prego-docker build-and-push, tag 기반 pinning).
1. 이미지 내 앱 포함 여부 검증
1.1 기대 구조
bench init --apps_path=/opt/frappe/apps.json 은 apps.json에 정의된 앱을 설치한다.
현재 apps.json: erpnext (version-15), hrms (version-15), prego-saas-app (v1.0.0).
Frappe는 bench init 시 기본으로 설치되므로, 최종 이미지의 /home/frappe/frappe-bench/apps/ 아래에는 다음이 있어야 한다.
| 앱 | 디렉터리 | 검증 포인트 |
|---|
| Frappe | frappe | bench의 코어, sites·env 공유 |
| ERPNext | erpnext | erpnext 앱 디렉터리·패키지 |
| HRMS | hrms | hrms 앱 디렉터리·패키지 |
| Custom app | prego_saas_app | prego_saas_app 앱 디렉터리·setup.py 등 |
1.2 검증 방법 (수동·로컬)
이미지 pull 후 실행 중인 컨테이너 또는 일회 실행으로 디렉터리·버전 확인.
| 단계 | 명령/확인 내용 |
|---|
| 1 | docker pull iamfork/prego-repo:latest (또는 특정 태그) |
| 2 | docker run --rm iamfork/prego-repo:latest ls -la /home/frappe/frappe-bench/apps/ → frappe, erpnext, hrms, prego_saas_app 디렉터리 존재 |
| 3 | docker run --rm iamfork/prego-repo:latest cat /home/frappe/frappe-bench/apps/prego_saas_app/setup.py → prego_saas_app 패키지 내용 확인 |
| 4 | (선택) docker run --rm iamfork/prego-repo:latest /home/frappe/frappe-bench/env/bin/pip list | grep -i frappe 등으로 설치된 앱 패키지 확인 |
정상 기준: 위 디렉터리 4개가 존재하고, 각 앱 소스(최소 디렉터리·setup.py)가 비어 있지 않음.
1.3 검증 방법 (CI·자동화)
- 시점: build-and-push 성공 후, 별도 검증 job 또는 동일 워크플로 내 후속 step.
- 방식:
- 방안 A:
docker run --rm <이미지> ls /home/frappe/frappe-bench/apps/ 실행 후 stdout에서 frappe, erpnext, hrms, prego_saas_app 포함 여부 검사.
- 방안 B: 동일 레포 또는 별도 레포에 “image verify” 워크플로를 두고, 특정 태그(예: latest 또는 빌드가 푸시한 태그)에 대해 위 명령을 실행하고 exit code·출력으로 pass/fail 판단.
- 실패 시: 이미지에 앱이 누락된 빌드로 간주하고, bench init 또는 apps.json·태그 검증 단계를 점검.
- 구현 상태: prego-docker
build.yml 에 Verify image apps 단계 적용됨. 푸시 직후 해당 태그 이미지를 pull하여 4개 앱 디렉터리 존재 여부 검사, 누락 시 job 실패.
1.4 요약
- 정상 여부: Frappe·ERPNext·HRMS·custom app 네 가지가 모두
/home/frappe/frappe-bench/apps/ 아래에 존재하면 “정상적으로 이미지 안에 들어간 것”으로 판단 가능.
- 문서화: 위 1.2를 runbook
docs/runbook/prego-docker-image-verify.md 로 정리했고, 1.3은 CI(build.yml Verify image apps)에 반영됨.
2. 취약점 해결 방향
2.1 현재 상황 (참고)
Docker Hub 스캔 결과 예: Critical 8, High 51, Medium 61, Low 76, Unknown 2 (이미지·스캔 시점에 따라 상이).
주요 발생 위치: 베이스 이미지(python:3.11-slim-bookworm), Node/프론트 빌드 의존성(npm), bench/pip 설치 패키지(pypi) 등.
예시 CVE: golang stdlib, npm loader-utils/form-data/@babel/traverse, pypi pillow 등.
2.2 대응 원칙
| 원칙 | 설명 |
|---|
| 우선순위 | Critical → High → Medium 순으로 처리. Low/Unknown은 정책에 따라 수용 또는 주기 점검. |
| 레이어 구분 | 베이스 이미지 / 시스템 패키지(apt) / Node(npm) / Python(pip) 별로 출처를 구분하고, 각 레이어에서 패치 가능한지 판단. |
| 호환성 | Frappe v15·ERPNext·HRMS 공식 요구사항과 충돌하지 않는 범위에서만 버전 상향. |
| 재현성 | Dockerfile·apps.json·태그로 빌드가 재현 가능하므로, 베이스/의존성 변경 시 빌드·검증 후 배포. |
2.3 대응 방안 (방향만)
| 구분 | 대상 | 해결 방향 (기획 수준) |
|---|
| 베이스 이미지 | python:3.11-slim-bookworm | 주기적으로 최신 digest 또는 태그로 갱신. Debian 보안 업데이트 반영 여부 확인. |
| 시스템 패키지 | Dockerfile 내 apt-get install | apt-get update 및 고정된 패키지 버전 사용 시, 보안 업데이트가 포함된 베이스 또는 패키지 버전 상향 검토. |
| Node/npm | NVM·yarn·프론트 빌드 의존성 | Node 버전 상향(현재 20 LTS 유지 시 보안 패치 버전으로), npm audit 가능 시 의존성 업데이트·교체 검토. |
| Python/pip | frappe-bench·Frappe·ERPNext·HRMS·prego_saas_app | Frappe/ERPNext/HRMS는 upstream 버전 따름. custom app(prego_saas_app)의 install_requires·requirements.txt는 최소 유지·업데이트 가능 패키지만 포함. |
| 스캔 도구 | Docker Hub / Trivy / Snyk 등 | CI에서 주기 스캔 도입 시, Critical/High만 fail로 두거나, 리포트만 수집 후 수동 대응 정책 선택. |
2.4 단계별 접근 (제안)
| 단계 | 내용 | 산출물 |
|---|
| 1 | 현황 정리 | Docker Hub(또는 Trivy) 스캔 결과에서 Critical/High 목록·영향 레이어(베이스/apt/npm/pip) 매핑. |
| 2 | 베이스·시스템 | python 이미지 최신 bookworm 태그/digest 반영, apt 패키지 필요 최소화·버전 명시. |
| 3 | Node/npm | Node 20.x 최신 패치, npm 패키지 중 알려진 CVE 있는 것만 선별 업데이트(호환성 테스트 후). |
| 4 | Python 쪽 | Frappe/ERPNext/HRMS는 upstream 의존성 유지. custom app은 stripe 등 외부 라이브러리만 버전 상향 검토. |
| 5 | 정책 | “Critical 0, High N 이하” 등 수용 기준을 정하고, CI 또는 주기 빌드에서 스캔 결과로 통과/실패 또는 경고만 출력. |
2.5 주의사항
- False positive: 스캔 도구가 “이미지에 포함된 바이너리”를 특정 패키지로 잘못 매칭할 수 있음. CVE별로 “실제 사용 코드 경로에 영향이 있는지” 확인 후 조치하는 것이 안전함.
- Upstream 의존성: Frappe/ERPNext/HRMS 내부 의존성은 우리가 직접 올리지 않으므로, 가능한 범위는 (1) 베이스·시스템·Node 버전 정리, (2) custom app 의존성 최소화·업데이트, (3) upstream 보안 릴리스 반영 시 이미지 재빌드.
3. 취약점 대응 — 어디서·어떻게 진행할지
아래는 (1)~(5) 단계를 실행 위치·도구·파일·명령 기준으로 구체화한 가이드다.
(1) Critical·High 목록·레이어 매핑
| 항목 | 어디서 | 어떻게 |
|---|
| Docker Hub | https://hub.docker.com → iamfork/prego-repo → Tags → 해당 태그(예: latest) 클릭 | Vulnerabilities 탭에서 Critical/High 개수·목록·“Present in”(레이어)·“Affected package(s)” 확인. CVE ID·패키지명·레이어 번호를 스프레드시트나 문서에 정리. |
| Trivy (로컬) | 로컬 터미널 (Trivy 설치: brew install trivy) | trivy image iamfork/prego-repo:latest 실행. CRITICAL/HIGH 행만 필터. trivy image --format table iamfork/prego-repo:latest 로 테이블 확인. 레이어는 Docker Hub Layers와 대응. |
| Trivy (CI) | prego-docker 레포 | 새 workflow: .github/workflows/trivy-scan.yml. on: workflow_dispatch 또는 schedule. Job에서 docker pull iamfork/prego-repo:latest 후 trivy image --exit-code 1 --severity CRITICAL,HIGH ... 로 스캔. 결과를 artifact 또는 job summary로 저장. |
| 매핑 정리 | Prego 문서 또는 이슈 | CVE 목록 + 해당 레이어(베이스/apt/npm/pip) + Affected package 표를 만들어 docs/planning/ 또는 GitHub Issue에 정리. (2)~(4)에서 어떤 레이어를 수정할지 결정할 때 사용. |
(2) 베이스·시스템 정리
| 항목 | 어디서 | 어떻게 |
|---|
| 베이스 이미지 | prego-docker/Dockerfile (1행 근처) | FROM python:3.11-slim-bookworm. Docker Hub → python → Tags → 3.11-slim-bookworm → Digest 복사 후 FROM python:3.11-slim-bookworm@sha256:... 로 고정. 주기적으로 최신 digest로 갱신. |
| 시스템 패키지 | prego-docker/Dockerfile (base·builder 스테이지) | apt-get install 목록 검토. 불필요 패키지 제거. 보안 업데이트 반영은 베이스 이미지 갱신으로 충분한지 먼저 확인. |
| 검증 | 로컬 또는 CI | docker build 후 Trivy/Docker Hub로 재스캔해 Critical/High 감소 여부 확인. |
(3) Node/npm
| 항목 | 어디서 | 어떻게 |
|---|
| Node 버전 | prego-docker/Dockerfile (ARG NODE_VERSION=20) | Node 20 LTS 최신 패치(예: 20.18.x)로 상향. nodejs.org 또는 nvm 문서에서 버전 확인 후 반영. |
| npm 의존성 | 이미지 내부(Frappe/ERPNext 빌드 시) | (1)에서 npm 패키지 CVE는 upstream(Frappe/ERPNext) 이슈·업데이트를 따르거나, Node 버전 상향으로 완화 가능한지 확인. custom app에 package.json이 있으면 해당 레포에서 npm audit / npm audit fix. |
(4) Python (custom app)
| 항목 | 어디서 | 어떻게 |
|---|
| custom app | prego-saas-app/setup.py | install_requires(stripe 등) 버전을 PyPI 기준 안전 버전으로 상향. |
| Frappe/ERPNext/HRMS | upstream | 직접 수정하지 않음. apps.json branch 유지, upstream 보안 릴리스 시 브랜치/태그 갱신 후 이미지 재빌드. |
(5) 정책 + CI/주기 스캔
| 항목 | 어디서 | 어떻게 |
|---|
| 정책 | 팀/문서 | ”Critical 0, High N 이하” 등 수용 기준을 docs/planning/ 또는 runbook에 명시. |
| CI 스캔 | prego-docker | .github/workflows/trivy-scan.yml 생성. trivy image --exit-code 1 --severity CRITICAL iamfork/prego-repo:$TAG 로 Critical 있으면 실패. High는 threshold 스크립트 또는 --severity CRITICAL,HIGH 로 정책에 맞게 설정. |
| 주기 스캔 | prego-docker | on: schedule: - cron: '0 9 * * 1' (매주 월요일 09:00). Trivy 결과를 artifact 또는 이슈로 저장. |
실행 순서: (1) → (2) → (3) → (4) → (5). prego-docker(Dockerfile·워크플로), prego-saas-app(setup.py), Prego 문서(정책·runbook)에 나눠 반영.
4. 정리
- 이미지 검증: Frappe·ERPNext·HRMS·custom app이
/home/frappe/frappe-bench/apps/ 아래에 모두 존재하는지 로컬 명령(§1.2) 또는 **CI 검증(§1.3)**으로 확인하면 “정상 포함” 여부를 판단할 수 있다.
- 취약점: 베이스 이미지·시스템 패키지·Node·Python(custom app) 순으로 우선순위를 두고, Critical/High 위주로 정리하며, Frappe/ERPNext/HRMS 호환성을 해치지 않는 범위에서 버전·이미지 갱신과 정책(스캔 기준·주기)을 정하는 것이 좋다.
다음 단계: 필요 시 §1.2를 runbook으로 작성하고, §2.3·2.4에 따라 “현황 정리” 단계에서 실제 CVE 목록·레이어 매핑을 한 뒤, 적용 가능한 Dockerfile·의존성 변경을 별도 작업으로 진행한다.
5. 취약점 수용 정책 (구현 반영)
| 항목 | 기준 |
|---|
| Critical | 0 — 1건이라도 있으면 CI(Trivy) 실패. |
| High | 보고만(CI는 통과). 필요 시 N 이하로 threshold 조정 가능. |
| 실행 | prego-docker .github/workflows/trivy-scan.yml: workflow_dispatch(태그 지정 가능) + 매주 월요일 09:00 UTC schedule. |
| Runbook | 이미지 앱 검증 절차: docs/runbook/prego-docker-image-verify.md. |