코드부터 런타임까지, SAST·DAST·의존성 스캔을 하나의 게이트로 묶는 법
DevSecOps에서 SAST·DAST·Dependency Scanning을 SBOM·서명·정책 게이팅과 결합해 CI/CD에 내재화하는 구조와 GitHub Actions 구현 예시를 정리한다
2026-08-12 · 최초 발행 2025-12-12
개발과 운영의 속도 경쟁 속에서 보안 검증을 나중에 붙이면 항상 늦는다. DevSecOps는 개발·보안·운영이 협업한다는 전제 아래, 보안 검증을 CI/CD 파이프라인 자체에 자동화로 내재화하는 운영 모델이다. 코드 리포지토리부터 배포·운영까지 전 단계에 보안 컨트롤을 배치하고, 코드·의존성·런타임을 아우르는 자동화 스캔과 정책 기반 게이팅으로 배포 품질과 규정 준수를 동시에 잡는다.
검사는 성격이 다르다
SAST(Static Application Security Testing)는 소스 코드·IaC·구성 파일을 정적 분석해 취약점을 찾는다. 개발 초기 단계와 PR 시점에 빠른 피드백을 준다는 게 강점이다. DAST(Dynamic Application Security Testing)는 실행 중인 애플리케이션을 블랙박스 방식으로 테스트해 런타임 취약점을 검출한다. 스테이징 환경에서 실제 엔드포인트를 대상으로 돈다. Dependency Scanning은 여기서 한 걸음 더 나가 라이브러리·컨테이너 베이스 이미지·패키지 메타데이터를 분석해 CVE와 라이선스 리스크를 식별하고, SBOM 생성·서명·보존으로 무결성과 소프트웨어 공급망 추적성을 확보하는 역할까지 맡는다.
정책 게이팅과 도구체인, 시프트 레프트/라이트의 균형
파이프라인 내재화는 심각도 기반 실패 기준(예: High 이상 실패, Medium 경고)을 먼저 정의하는 데서 시작한다. Policy-as-Code(OPA/Rego)로 리포지토리·브랜치·서비스별로 차등 정책을 걸 수 있다. 도구체인 쪽에서는 SAST/DAST/Dependency 스캐너, SBOM 생성기(Syft), 이미지 스캐너(Trivy/Grype), 서명(Cosign)을 연계하고 스캔 결과를 아티팩트 저장소와 내부 취약점 DB 미러로 일원화 관리한다.
시프트 레프트와 시프트 라이트는 균형이 필요하다. IDE 플러그인·pre-commit 훅으로 조기에 잡고, 스테이징·프리프로덕션에서 동적 검증을 확장하며, 운영에서 나온 피드백(취약점 악용 지표, WAF 로그)을 다시 규칙 학습에 반영한다. 비밀관리와 공급망 보호도 빠뜨리면 안 된다. Secrets 스캐닝, 의존성 버전 고정·허용 목록, 서드파티 액션 검증(SLSA 레벨 확인)에 이미지·SBOM 서명과 배포 전 검증을 더해 무결성을 강화한다. 거버넌스는 취약점 트리아지·MTTR 대시보드, 릴리스 기준 준수 리포트, 감사 로그 완전성 확보로 마무리된다.
파이프라인이 실제로 어떻게 도는가
GitHub Actions 기반 컨테이너 애플리케이션 파이프라인은 코드/PR·Dockerfile·패키지 매니페스트·스테이징 URL을 입력받아 SAST/Secrets 스캔 → 컨테이너 빌드 → SBOM 생성/서명 → 의존성·이미지 취약점 스캔 → 스테이징 배포 후 DAST 순으로 처리하고, 취약점 리포트·SBOM 아티팩트·정책 평가 결과·게이트 승인/차단 상태를 낸다. 배포 승인은 정책 평가와 묶어 원자적으로 처리해 부분 배포를 막고, 이미지·SBOM 묶음 서명과 해시 핀닝으로 릴리스-아티팩트 일관성을 지키며, 환경 잠금(배포 락)으로 동시 배포 충돌을 방지한다.
GitLab CI 모노레포 파이프라인은 변경된 파일 목록을 입력받아 변경 영향 분석으로 서비스별 SAST 잡을 병렬 실행하고, 공통 베이스 이미지 캐시를 쓴다. 라이선스 컴플라이언스 스캔과 Rego 정책으로 자동 승인·보류를 결정하고, 서비스 수준 취약점 지표·라이선스 위반 목록·승인 파이프라인 토큰을 출력한다.
Kubernetes 배포 어드미션 게이트는 서명된 컨테이너 이미지와 SBOM/어테스테이션을 입력으로, Kyverno나 OPA Gatekeeper가 이미지 서명·프로비넌스를 검증하고 CVE 임계치를 검사한다. 불합격이면 Admission Deny로 막고, 통과하면 승인된 배포와 감사 로그, 정책 히트 리포트를 남긴다.
스캐너가 실패하면 1~2회 재시도한 뒤 Graceful Fail로 경고 전환하지만, 정책상 강제 실패 대상은 즉시 차단한다. 보고서 파싱 오류가 나면 원본 아티팩트를 보존하고 후속 파서 재실행 큐에 등록한다. 일관성·무결성 쪽에서는 SBOM·이미지 해시를 상호 참조하고 배포 시점 어테스테이션을 검증하며, 승인 기록은 변경 불가능 스토리지(WORM/S3 Object Lock)에 보관한다.
SAST, DAST, Dependency Scanning을 나란히 놓으면
| 항목 | SAST | DAST | Dependency Scanning |
|---|---|---|---|
| 성능 | 빠른 실행, PR 단위 수분 | 대상 규모·크롤 범위에 따라 수십 분까지 | 파일 시스템/이미지 스캔 수분 내 |
| 확장성 | 서비스/모노레포 병렬화 용이 | 환경 셋업·테스트 데이터 필요 | 캐시와 DB 미러로 대규모 확장 용이 |
| 일관성 | 규칙 세트 고정 시 결과 안정 | 동적 환경 영향으로 변동성 존재 | CVE DB 버전 고정 시 재현성 우수 |
| 안정성 | 코드 파싱 오류에 민감 | 네트워크/인증 실패 영향 | 패키지 메타데이터 품질에 의존 |
| 운영 편의 | IDE/PR 연동 용이 | 스테이징 유지·시드 데이터 관리 필요 | CI 통합·SBOM 연계 용이 |
GitHub Actions로 보안 검사를 한 워크플로에 묶기
전제조건은 Dockerfile을 포함한 리포지토리와 앱 기본 포트 노출, STAGING_URL 시크릿으로 제공되는 스테이징 URL, 그리고 Semgrep-action·aquasecurity/trivy-action·anchore/syft-action·zaproxy/action-baseline 버전이다.
# .github/workflows/security-ci.yml
name: security-ci
on:
pull_request:
push:
branches: [ main ]
jobs:
sast_secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep SAST
uses: returntocorp/semgrep-action@v1
with:
config: p/ci
generateSarif: true
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Secret scanning (Gitleaks)
uses: gitleaks/gitleaks-action@v2
with:
args: detect --no-banner --redact --exit-code 1
build_and_sbom:
runs-on: ubuntu-latest
needs: sast_secrets
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:ci .
- name: Create SBOM (Syft)
uses: anchore/syft-action@v1
with:
image: app:ci
format: spdx-json
output: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.spdx.json
- name: FS dependency scan (Trivy)
uses: aquasecurity/trivy-action@0.20.0
with:
scan-type: fs
format: sarif
output: trivy-fs.sarif
severity: CRITICAL,HIGH
exit-code: '1'
- name: Image scan (Trivy)
uses: aquasecurity/trivy-action@0.20.0
with:
image-ref: app:ci
format: table
severity: CRITICAL,HIGH
exit-code: '1'
dast:
runs-on: ubuntu-latest
needs: build_and_sbom
steps:
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.11.0
with:
target: ${{ secrets.STAGING_URL }}
rules_file_name: .zap/rules.tsv # 경고 임계치 조정
cmd_options: -m 5 -I
- name: Fail on High alerts
run: |
if grep -q "High" report_json.json; then
echo "High alerts found"; exit 1; fi
취약점 DB 미러(Trivy DB, NVD)를 캐시해 속도·안정성을 확보하고, SARIF를 업로드해 스캔 결과를 PR 코멘트·코드 라인에 매핑한다. 규칙 세트 버전은 고정한 뒤 주간 단위로 갱신 배치를 돌려 재현성을 유지한다.
얼마나 줄어드는가
릴리스 후 High/Critical 취약점 유출률은 5080% 줄고, 규칙이 성숙하면 1% 미만까지 유지할 수 있다. PR 시점 피드백 덕에 보안 이슈 MTTR은 3060% 단축되며 트리아지 자동화로 재현·분류 시간도 함께 준다. SBOM·어테스테이션·서명 체계는 라이선스·공급망 규정 대응 시간을 70% 이상 줄이고 감사 로그 완결성을 확보한다. 정책 기반 게이팅은 품질 저하 배포를 막고 개발자는 IDE/PR 피드백으로 반복 비용을 줄이지만, 그 대가로 빌드 시간이 3~8분 범위에서 늘어난다.
DevSecOps는 결국 보안을 속도에 맞춰 자동화·정책화하는 문제다. SAST/DAST/Dependency Scanning을 SBOM·서명·게이팅과 통합하면 취약점 유출과 규정 위반 리스크를 동시에 줄일 수 있다. 모노레포·멀티서비스 환경에서는 병렬화·캐시·정책 분리로 성능·재현성·운영 편의를 맞추는 게 관건이고, 단일 서비스 파일럿에서 시작해 조직 표준 파이프라인으로 확장하는 순서를 권한다.