Skip to content

필사 모드: DevSecOps 완전 가이드 2025: Shift-Left 보안, SAST/DAST/SCA, 컨테이너 보안까지

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

TL;DR

- **Shift-Left 보안**: 개발 초기에 보안을 적용하면 결함 수정 비용이 30배 절감

- **SAST**: SonarQube, Semgrep, CodeQL로 코드 레벨 취약점 탐지

- **DAST**: OWASP ZAP, Burp Suite로 런타임 취약점 발견

- **SCA**: Snyk, Dependabot로 의존성 취약점 자동 패치

- **컨테이너 보안**: Trivy, Grype로 이미지 스캔, 최소 베이스 이미지 사용

- **공급망 보안**: SBOM 생성, SLSA 레벨 달성, Sigstore 서명

- **Secret 탐지**: GitLeaks, TruffleHog로 커밋된 비밀정보 탐지

- **GitHub Actions**: 통합 보안 파이프라인으로 모든 단계 자동화

목차

1. [DevSecOps란 무엇인가](#1-devsecops란-무엇인가)

2. [Shift-Left 보안 전략](#2-shift-left-보안-전략)

3. [SAST - 정적 분석](#3-sast---정적-분석)

4. [DAST - 동적 분석](#4-dast---동적-분석)

5. [SCA - 소프트웨어 구성 분석](#5-sca---소프트웨어-구성-분석)

6. [컨테이너 보안](#6-컨테이너-보안)

7. [Secret 탐지](#7-secret-탐지)

8. [공급망 보안 - SBOM과 SLSA](#8-공급망-보안---sbom과-slsa)

9. [Policy-as-Code](#9-policy-as-code)

10. [GitHub Actions 통합 보안 파이프라인](#10-github-actions-통합-보안-파이프라인)

11. [실전 퀴즈](#11-실전-퀴즈)

12. [참고 자료](#12-참고-자료)

1. DevSecOps란 무엇인가

1.1 전통적 보안의 한계

전통적인 소프트웨어 개발에서 보안은 마지막 단계에 추가되었습니다. 개발이 끝나고 배포 직전에 보안 팀이 검토하는 방식이었죠. 이 접근법의 문제점은 명확합니다.

| 문제 | 영향 |

|------|------|

| 늦은 발견 | 수정 비용 30배 증가 |

| 병목 현상 | 보안 팀이 모든 프로젝트 검토 |

| 개발자 무관심 | "보안은 보안 팀의 일" 마인드 |

| 릴리즈 지연 | 취약점 발견 시 일정 전체 지연 |

| 컨텍스트 부족 | 보안 팀이 코드 의도를 모름 |

1.2 DevSecOps의 핵심 원칙

DevSecOps는 Development + Security + Operations의 합성어로, 보안을 소프트웨어 개발 생명 주기(SDLC) 전체에 통합하는 문화이자 실천 방법입니다.

**핵심 원칙 5가지:**

1. **모든 사람이 보안에 책임**: 보안은 보안 팀만의 일이 아님

2. **자동화 우선**: 수동 검토 대신 자동화된 도구 활용

3. **빠른 피드백**: 개발자가 코드를 작성하는 시점에 보안 피드백

4. **지속적 개선**: 보안 메트릭 측정과 지속적인 개선

5. **공유 책임**: 개발, 운영, 보안 팀 간 지식 공유

1.3 DevSecOps 도구 생태계 개요

┌─────────────────────────────────────────────────────────────┐

│ DevSecOps 파이프라인 │

├──────────┬──────────┬──────────┬──────────┬────────────────┤

│ Plan │ Code │ Build │ Test │ Deploy/Run │

├──────────┼──────────┼──────────┼──────────┼────────────────┤

│ Threat │ SAST │ SCA │ DAST │ Runtime │

│ Modeling │ Semgrep │ Snyk │ ZAP │ Protection │

│ │ CodeQL │ Trivy │ Burp │ Falco │

│ Security │ SonarQube│ OSV │ Nuclei │ Container │

│ Require │ │ │ │ Security │

│ ments │ Secret │ SBOM │ Fuzzing │ Network │

│ │ Detect │ Signing │ │ Policy │

├──────────┼──────────┼──────────┼──────────┼────────────────┤

│ Policy-as-Code (OPA / Kyverno / Conftest) │

└─────────────────────────────────────────────────────────────┘

2. Shift-Left 보안 전략

2.1 Shift-Left이란?

Shift-Left은 보안 활동을 개발 프로세스의 왼쪽(초기 단계)으로 이동시키는 전략입니다.

전통적 방식:

Plan → Code → Build → Test → Deploy → [보안 검토] → Release

↑ 여기서 발견 = 비용 높음

Shift-Left 방식:

Plan → [보안] → Code → [보안] → Build → [보안] → Test → Deploy

↑ 여기서 시작 = 비용 낮음

2.2 Shift-Left ROI 분석

IBM Systems Sciences Institute의 연구에 따르면, 결함 수정 비용은 발견 시점에 따라 기하급수적으로 증가합니다.

| 발견 단계 | 상대 비용 | 예시 |

|-----------|-----------|------|

| 요구사항 정의 | 1x | 보안 요구사항 누락 발견 |

| 설계 | 5x | 아키텍처 취약점 발견 |

| 구현 | 10x | 코드 레벨 취약점 발견 |

| 테스트 | 20x | QA 단계에서 발견 |

| 운영 | 30x | 프로덕션에서 발견 |

| 사고 발생 후 | 100x+ | 데이터 유출 사고 |

2.3 Shift-Left 구현 단계

**단계 1: 보안 챔피언 프로그램**

각 개발 팀에 보안 챔피언을 지정합니다.

security-champions.yaml

teams:

- name: "Backend Team"

champion: "alice@company.com"

responsibilities:

- "PR 보안 리뷰"

- "SAST 결과 트리아지"

- "월간 보안 교육 진행"

training:

- "OWASP Top 10"

- "Secure Coding Practices"

- "Threat Modeling 기초"

- name: "Frontend Team"

champion: "bob@company.com"

responsibilities:

- "XSS/CSRF 방지 검토"

- "의존성 취약점 관리"

- "CSP 헤더 관리"

**단계 2: 위협 모델링**

STRIDE 모델을 활용한 위협 모델링을 설계 단계에서 수행합니다.

STRIDE 위협 모델:

┌─────────────────────────────────────────┐

│ S - Spoofing (위장) │

│ T - Tampering (변조) │

│ R - Repudiation (부인) │

│ I - Information Disclosure (정보 노출) │

│ D - Denial of Service (서비스 거부) │

│ E - Elevation of Privilege (권한 상승) │

└─────────────────────────────────────────┘

**단계 3: IDE 보안 플러그인**

개발자의 IDE에서 바로 보안 피드백을 제공합니다.

// .vscode/settings.json

{

"semgrep.scan.autoScan": true,

"semgrep.scan.configuration": [

"p/owasp-top-ten",

"p/typescript",

"p/react"

],

"sonarlint.connectedMode.project": {

"connectionId": "my-sonarqube",

"projectKey": "my-project"

}

}

3. SAST - 정적 분석

3.1 SAST란?

SAST(Static Application Security Testing)는 소스 코드, 바이트코드, 바이너리를 실행하지 않고 분석하여 보안 취약점을 찾는 기법입니다.

**SAST가 탐지하는 주요 취약점:**

- SQL Injection

- Cross-Site Scripting (XSS)

- 경로 탐색(Path Traversal)

- 하드코딩된 비밀정보

- 안전하지 않은 암호화

- 버퍼 오버플로우

3.2 SonarQube 설정

docker-compose.yml - SonarQube 로컬 설정

version: "3.8"

services:

sonarqube:

image: sonarqube:community

ports:

- "9000:9000"

environment:

SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonarqube

SONAR_JDBC_USERNAME: sonar

SONAR_JDBC_PASSWORD: sonar

volumes:

- sonar_data:/opt/sonarqube/data

- sonar_logs:/opt/sonarqube/logs

- sonar_extensions:/opt/sonarqube/extensions

depends_on:

- db

db:

image: postgres:15

environment:

POSTGRES_DB: sonarqube

POSTGRES_USER: sonar

POSTGRES_PASSWORD: sonar

volumes:

- postgres_data:/var/lib/postgresql/data

volumes:

sonar_data:

sonar_logs:

sonar_extensions:

postgres_data:

sonar-project.properties

sonar.projectKey=my-app

sonar.projectName=My Application

sonar.projectVersion=1.0

sonar.sources=src

sonar.tests=tests

sonar.language=ts

sonar.sourceEncoding=UTF-8

sonar.javascript.lcov.reportPaths=coverage/lcov.info

sonar.qualitygate.wait=true

3.3 Semgrep 실전 활용

Semgrep은 가볍고 빠른 SAST 도구로, 커스텀 룰 작성이 쉽습니다.

.semgrep.yml - 커스텀 보안 룰

rules:

- id: no-eval-usage

patterns:

- pattern: eval(...)

message: "eval() 사용은 코드 인젝션 위험이 있습니다"

severity: ERROR

languages: [javascript, typescript]

metadata:

owasp: "A03:2021 Injection"

cwe: "CWE-95"

- id: no-innerHTML

patterns:

- pattern: $EL.innerHTML = $VAL

message: "innerHTML 직접 설정은 XSS 위험이 있습니다. textContent 또는 DOMPurify를 사용하세요"

severity: WARNING

languages: [javascript, typescript]

- id: sql-injection-risk

patterns:

- pattern: |

$DB.query(`... ${$VAR} ...`)

- pattern: |

$DB.query("..." + $VAR + "...")

message: "SQL 인젝션 위험! 파라미터 바인딩을 사용하세요"

severity: ERROR

languages: [javascript, typescript]

fix: |

$DB.query("... $1 ...", [$VAR])

- id: no-hardcoded-secrets

patterns:

- pattern: |

const $KEY = "AKIA..."

- pattern: |

const $KEY = "sk-..."

message: "하드코딩된 시크릿이 발견되었습니다. 환경 변수를 사용하세요"

severity: ERROR

languages: [javascript, typescript]

Semgrep 실행

semgrep --config auto --config .semgrep.yml src/

특정 룰셋만 실행

semgrep --config p/owasp-top-ten src/

semgrep --config p/typescript src/

semgrep --config p/react src/

CI용 JSON 출력

semgrep --config auto --json --output results.json src/

3.4 CodeQL 고급 쿼리

GitHub CodeQL은 코드를 데이터베이스로 변환하여 쿼리하는 강력한 도구입니다.

// codeql-queries/sql-injection.ql

/**

* @name SQL injection in query string

* @description 사용자 입력이 SQL 쿼리에 직접 포함됨

* @kind path-problem

* @problem.severity error

* @security-severity 9.8

* @precision high

* @id js/sql-injection

* @tags security

* external/cwe/cwe-089

*/

class SqlInjectionConfig extends TaintTracking::Configuration {

SqlInjectionConfig() { this = "SqlInjectionConfig" }

override predicate isSource(DataFlow::Node source) {

exists(Express::RequestInputAccess input |

source = input

)

}

override predicate isSink(DataFlow::Node sink) {

exists(DatabaseAccess query |

sink = query.getAQueryArgument()

)

}

}

from SqlInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink

where config.hasFlowPath(source, sink)

select sink.getNode(), source, sink,

"이 쿼리는 $@에서 받은 사용자 입력을 포함합니다.",

source.getNode(), "사용자 입력"

3.5 SAST 도구 비교

| 기능 | SonarQube | Semgrep | CodeQL |

|------|-----------|---------|--------|

| 가격 | Community 무료 | OSS 무료 | OSS 무료 |

| 지원 언어 | 30+ | 30+ | 10+ |

| 커스텀 룰 | Java DSL | YAML | QL Language |

| CI 통합 | 좋음 | 매우 좋음 | GitHub 최적화 |

| 속도 | 보통 | 매우 빠름 | 느림 (DB 빌드) |

| 정확도 | 높음 | 높음 | 매우 높음 |

| 학습 곡선 | 보통 | 낮음 | 높음 |

4. DAST - 동적 분석

4.1 DAST란?

DAST(Dynamic Application Security Testing)는 실행 중인 애플리케이션에 실제 공격을 시뮬레이션하여 취약점을 탐지합니다. 소스 코드가 필요 없으므로 "블랙박스 테스팅"이라고도 합니다.

4.2 OWASP ZAP 자동화

zap-automation.yaml

env:

contexts:

- name: "My Web App"

urls:

- "https://staging.example.com"

includePaths:

- "https://staging.example.com/.*"

excludePaths:

- "https://staging.example.com/logout"

authentication:

method: "form"

parameters:

loginUrl: "https://staging.example.com/login"

loginRequestData: "username=test&password=test123"

jobs:

- type: spider

parameters:

context: "My Web App"

maxDuration: 5

maxDepth: 10

- type: spiderAjax

parameters:

context: "My Web App"

maxDuration: 5

- type: passiveScan-wait

parameters:

maxDuration: 10

- type: activeScan

parameters:

context: "My Web App"

maxRuleDurationInMins: 5

policy: "API-Scan"

- type: report

parameters:

template: "modern"

reportDir: "/zap/reports"

reportFile: "zap-report"

reportTitle: "ZAP Security Report"

risks:

- high

- medium

- low

Docker로 ZAP 자동화 스캔 실행

docker run --rm -v $(pwd):/zap/wrk:rw \

-t zaproxy/zap-stable \

zap.sh -cmd -autorun /zap/wrk/zap-automation.yaml

API 스캔 (OpenAPI 스펙 기반)

docker run --rm -v $(pwd):/zap/wrk:rw \

-t zaproxy/zap-stable \

zap-api-scan.py \

-t https://staging.example.com/openapi.json \

-f openapi \

-r api-report.html

4.3 DAST와 SAST 비교

| 특성 | SAST | DAST |

|------|------|------|

| 분석 시점 | 빌드 시 | 런타임 |

| 소스 코드 필요 | 예 | 아니오 |

| 실행 환경 필요 | 아니오 | 예 |

| 오탐율 | 높음 | 낮음 |

| 커버리지 | 전체 코드 | 도달 가능한 경로 |

| 취약점 유형 | 코드 레벨 | 런타임/설정 |

| 피드백 속도 | 빠름 | 느림 |

5. SCA - 소프트웨어 구성 분석

5.1 왜 SCA가 중요한가?

현대 애플리케이션의 80% 이상이 오픈소스 코드로 구성됩니다. Log4Shell(CVE-2021-44228)은 단일 오픈소스 라이브러리의 취약점이 전 세계적 영향을 미칠 수 있음을 보여주었습니다.

5.2 Snyk 설정

.snyk - Snyk 정책 파일

version: v1.5

ignore:

SNYK-JS-LODASH-590103:

- '*':

reason: "해당 함수를 사용하지 않음"

expires: "2026-06-01T00:00:00.000Z"

patch: {}

language-settings:

javascript:

severity-threshold: high

Snyk CLI 사용법

snyk test # 취약점 검사

snyk monitor # 지속적 모니터링 등록

snyk test --severity-threshold=high # 높은 심각도만

snyk code test # SAST 스캔

snyk container test myimage:latest # 컨테이너 스캔

snyk iac test terraform/ # IaC 스캔

5.3 Dependabot 설정

.github/dependabot.yml

version: 2

updates:

- package-ecosystem: "npm"

directory: "/"

schedule:

interval: "weekly"

day: "monday"

time: "09:00"

timezone: "Asia/Seoul"

open-pull-requests-limit: 10

reviewers:

- "security-team"

labels:

- "dependencies"

- "security"

commit-message:

prefix: "deps"

include: "scope"

보안 업데이트는 자동 머지

groups:

security-patches:

patterns:

- "*"

update-types:

- "security"

- package-ecosystem: "docker"

directory: "/"

schedule:

interval: "weekly"

labels:

- "docker"

- "dependencies"

- package-ecosystem: "github-actions"

directory: "/"

schedule:

interval: "weekly"

labels:

- "ci"

- "dependencies"

5.4 Renovate 고급 설정

// renovate.json

{

"$schema": "https://docs.renovatebot.com/renovate-schema.json",

"extends": [

"config:base",

":semanticCommits",

"group:allNonMajor",

"schedule:weekends"

],

"vulnerabilityAlerts": {

"enabled": true,

"labels": ["security"],

"schedule": ["at any time"]

},

"packageRules": [

{

"matchUpdateTypes": ["patch"],

"automerge": true,

"automergeType": "pr",

"platformAutomerge": true

},

{

"matchPackagePatterns": ["eslint", "prettier"],

"groupName": "linting tools",

"automerge": true

},

{

"matchPackagePatterns": ["^@types/"],

"groupName": "type definitions",

"automerge": true

}

],

"prConcurrentLimit": 5,

"prHourlyLimit": 2

}

6. 컨테이너 보안

6.1 컨테이너 보안의 중요성

컨테이너 이미지에는 OS 패키지, 런타임, 애플리케이션 의존성이 모두 포함됩니다. 하나의 이미지에 수백 개의 취약점이 있을 수 있습니다.

6.2 Trivy 이미지 스캔

기본 이미지 스캔

trivy image myapp:latest

심각도 필터링

trivy image --severity CRITICAL,HIGH myapp:latest

수정 가능한 취약점만

trivy image --ignore-unfixed myapp:latest

SBOM 생성

trivy image --format cyclonedx --output sbom.json myapp:latest

CI용 JSON 출력과 종료 코드

trivy image --format json --output results.json \

--exit-code 1 --severity CRITICAL myapp:latest

파일시스템 스캔 (빌드 전)

trivy fs --security-checks vuln,secret,config .

Kubernetes 매니페스트 스캔

trivy config k8s/

6.3 안전한 Dockerfile 작성

BAD - 보안 안티패턴

FROM ubuntu:latest

RUN apt-get update && apt-get install -y python3

COPY . /app

RUN pip install -r requirements.txt

USER root

EXPOSE 8080

CMD ["python3", "app.py"]

GOOD - 보안 모범 사례

1. 최소 베이스 이미지 사용

FROM python:3.12-slim AS builder

2. 패키지 설치 후 캐시 정리

RUN apt-get update && \

apt-get install -y --no-install-recommends gcc && \

rm -rf /var/lib/apt/lists/*

3. 별도 빌드 스테이지

WORKDIR /build

COPY requirements.txt .

RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

4. 최종 이미지는 최소화

FROM python:3.12-slim

5. 비루트 사용자

RUN groupadd -r appuser && useradd -r -g appuser appuser

6. 빌드 아티팩트만 복사

COPY --from=builder /install /usr/local

COPY --chown=appuser:appuser . /app

WORKDIR /app

USER appuser

7. 읽기 전용 파일시스템 지원

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s \

CMD curl -f http://localhost:8080/health || exit 1

CMD ["python3", "app.py"]

6.4 Grype와 Docker Scout

Grype - 이미지 취약점 스캔

grype myapp:latest

grype myapp:latest --only-fixed

grype myapp:latest -o json > grype-results.json

Docker Scout - Docker Desktop 통합

docker scout cves myapp:latest

docker scout recommendations myapp:latest

docker scout quickview myapp:latest

6.5 컨테이너 보안 체크리스트

컨테이너 보안 체크리스트:

이미지 빌드:

[x] 최소 베이스 이미지 (distroless, alpine, slim)

[x] 멀티스테이지 빌드

[x] 비루트 사용자 실행

[x] 불필요한 패키지 제거

[x] .dockerignore 설정

[x] 이미지 서명 (cosign)

런타임:

[x] 읽기 전용 파일시스템

[x] 리소스 제한 (CPU, 메모리)

[x] capabilities 최소화

[x] seccomp/AppArmor 프로파일

[x] 네트워크 정책 적용

레지스트리:

[x] 프라이빗 레지스트리 사용

[x] 이미지 취약점 스캔

[x] 태그 불변성 설정

[x] 이미지 서명 검증

7. Secret 탐지

7.1 유출되는 Secret의 현실

GitHub에 따르면 매년 수백만 건의 시크릿이 공개 리포지토리에 커밋됩니다. API 키, 패스워드, 인증서가 유출되면 몇 분 안에 악용될 수 있습니다.

7.2 GitLeaks 설정

.gitleaks.toml

title = "Custom Gitleaks Configuration"

[extend]

useDefault = true

[[rules]]

id = "custom-api-key"

description = "Custom API Key Pattern"

regex = '''(?i)api[_-]?key\s*[:=]\s*['"][a-zA-Z0-9]{32,}['"]'''

entropy = 3.5

secretGroup = 0

tags = ["api", "key"]

[[rules]]

id = "private-key-file"

description = "Private Key File Reference"

regex = '''(?i)(private[_-]?key|ssh[_-]?key)\s*[:=]\s*['"].*\.(pem|key|p12)['"]'''

tags = ["key", "private"]

[allowlist]

description = "Global Allowlist"

paths = [

'''\.gitleaks\.toml''',

'''test/.*''',

'''.*_test\.go''',

'''.*\.test\.(ts|js)'''

]

regexes = [

'''EXAMPLE_.*''',

'''REPLACE_ME'''

]

GitLeaks 실행

gitleaks detect --source . --verbose

gitleaks detect --source . --report-format json --report-path leaks.json

Git 히스토리 전체 스캔

gitleaks detect --source . --log-opts="--all"

pre-commit hook

gitleaks protect --staged --verbose

7.3 TruffleHog 활용

리포지토리 전체 스캔

trufflehog git file://. --only-verified

GitHub 조직 전체 스캔

trufflehog github --org=my-org --only-verified

Docker 이미지 스캔

trufflehog docker --image=myapp:latest

S3 버킷 스캔

trufflehog s3 --bucket=my-bucket

7.4 pre-commit Hook 설정

.pre-commit-config.yaml

repos:

- repo: https://github.com/gitleaks/gitleaks

rev: v8.18.0

hooks:

- id: gitleaks

- repo: https://github.com/pre-commit/pre-commit-hooks

rev: v4.5.0

hooks:

- id: detect-private-key

- id: check-added-large-files

args: ['--maxkb=500']

- repo: https://github.com/returntocorp/semgrep

rev: v1.50.0

hooks:

- id: semgrep

args: ['--config', 'p/secrets', '--error']

8. 공급망 보안 - SBOM과 SLSA

8.1 공급망 공격 사례

| 사건 | 연도 | 영향 |

|------|------|------|

| SolarWinds | 2020 | 18,000+ 기관 피해 |

| Codecov | 2021 | CI 스크립트 변조 |

| ua-parser-js | 2021 | npm 패키지 하이재킹 |

| Log4Shell | 2021 | 전 세계 Java 앱 영향 |

| xz utils | 2024 | Linux 백도어 시도 |

8.2 SBOM 생성

SBOM(Software Bill of Materials)은 소프트웨어에 포함된 모든 구성요소의 목록입니다.

CycloneDX 포맷 SBOM 생성

npm 프로젝트

npx @cyclonedx/cyclonedx-npm --output-file sbom.json

Python 프로젝트

cyclonedx-py requirements requirements.txt -o sbom.json

컨테이너 이미지

trivy image --format cyclonedx -o sbom.json myapp:latest

syft myapp:latest -o cyclonedx-json > sbom.json

SPDX 포맷

syft myapp:latest -o spdx-json > sbom-spdx.json

// SBOM 예시 (CycloneDX 간략)

{

"bomFormat": "CycloneDX",

"specVersion": "1.5",

"version": 1,

"metadata": {

"component": {

"type": "application",

"name": "my-web-app",

"version": "2.1.0"

}

},

"components": [

{

"type": "library",

"name": "express",

"version": "4.18.2",

"purl": "pkg:npm/express@4.18.2",

"licenses": [{ "license": { "id": "MIT" } }]

},

{

"type": "library",

"name": "lodash",

"version": "4.17.21",

"purl": "pkg:npm/lodash@4.17.21"

}

]

}

8.3 SLSA 프레임워크

SLSA(Supply-chain Levels for Software Artifacts)는 공급망 보안의 성숙도를 측정하는 프레임워크입니다.

SLSA 레벨:

┌──────────────┬─────────────────────────────────────┐

│ SLSA Level 0 │ 보안 보장 없음 │

│ SLSA Level 1 │ 빌드 프로세스 문서화 (provenance) │

│ SLSA Level 2 │ 호스팅된 빌드, 서명된 provenance │

│ SLSA Level 3 │ 격리된 빌드, 변조 방지 │

└──────────────┴─────────────────────────────────────┘

8.4 Sigstore로 아티팩트 서명

cosign으로 컨테이너 이미지 서명

cosign sign --key cosign.key myregistry/myapp:v1.0.0

키리스 서명 (OIDC 기반)

cosign sign myregistry/myapp:v1.0.0

서명 검증

cosign verify --key cosign.pub myregistry/myapp:v1.0.0

SBOM 첨부

cosign attach sbom --sbom sbom.json myregistry/myapp:v1.0.0

아티팩트 증명 (attestation) 생성

cosign attest --predicate provenance.json \

--type slsaprovenance \

myregistry/myapp:v1.0.0

9. Policy-as-Code

9.1 OPA (Open Policy Agent)

policy/kubernetes.rego

package kubernetes.admission

루트 컨테이너 금지

deny[msg] {

input.request.kind.kind == "Pod"

container := input.request.object.spec.containers[_]

container.securityContext.runAsUser == 0

msg := sprintf("컨테이너 '%s'가 root로 실행됩니다", [container.name])

}

최신 태그 금지

deny[msg] {

input.request.kind.kind == "Pod"

container := input.request.object.spec.containers[_]

endswith(container.image, ":latest")

msg := sprintf("컨테이너 '%s'가 latest 태그를 사용합니다", [container.name])

}

리소스 제한 필수

deny[msg] {

input.request.kind.kind == "Pod"

container := input.request.object.spec.containers[_]

not container.resources.limits

msg := sprintf("컨테이너 '%s'에 리소스 제한이 없습니다", [container.name])

}

읽기 전용 루트 파일시스템 필수

deny[msg] {

input.request.kind.kind == "Pod"

container := input.request.object.spec.containers[_]

not container.securityContext.readOnlyRootFilesystem

msg := sprintf("컨테이너 '%s'가 읽기 전용 파일시스템을 사용하지 않습니다", [container.name])

}

9.2 Kyverno 정책

kyverno-policies.yaml

apiVersion: kyverno.io/v1

kind: ClusterPolicy

metadata:

name: require-labels

spec:

validationFailureAction: Enforce

rules:

- name: require-team-label

match:

any:

- resources:

kinds:

- Pod

validate:

message: "모든 Pod에는 'team' 라벨이 필요합니다"

pattern:

metadata:

labels:

team: "?*"

apiVersion: kyverno.io/v1

kind: ClusterPolicy

metadata:

name: disallow-privileged

spec:

validationFailureAction: Enforce

rules:

- name: no-privileged-containers

match:

any:

- resources:

kinds:

- Pod

validate:

message: "Privileged 컨테이너는 허용되지 않습니다"

pattern:

spec:

containers:

- securityContext:

privileged: "false"

9.3 Conftest로 IaC 검증

Conftest로 Terraform 검증

conftest test terraform/ --policy policy/

Dockerfile 검증

conftest test Dockerfile --policy policy/docker/

Kubernetes 매니페스트 검증

conftest test k8s/ --policy policy/kubernetes/

policy/docker/dockerfile.rego

package main

deny[msg] {

input[i].Cmd == "from"

val := input[i].Value

contains(val[0], ":latest")

msg := "FROM에 latest 태그 사용 금지"

}

deny[msg] {

input[i].Cmd == "user"

val := input[i].Value

val[0] == "root"

msg := "USER root 사용 금지"

}

10. GitHub Actions 통합 보안 파이프라인

10.1 종합 보안 워크플로우

.github/workflows/security.yml

name: Security Pipeline

on:

push:

branches: [main, develop]

pull_request:

branches: [main]

schedule:

- cron: '0 6 * * 1' # 매주 월요일 오전 6시

permissions:

contents: read

security-events: write

pull-requests: write

jobs:

1단계: Secret 탐지

secret-scan:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

with:

fetch-depth: 0

- name: GitLeaks Scan

uses: gitleaks/gitleaks-action@v2

env:

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2단계: SAST

sast:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Semgrep Scan

uses: returntocorp/semgrep-action@v1

with:

config: >-

p/owasp-top-ten

p/typescript

p/react

generateSarif: "1"

- name: Upload SARIF

uses: github/codeql-action/upload-sarif@v3

with:

sarif_file: semgrep.sarif

if: always()

3단계: SCA (의존성 스캔)

sca:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Snyk Security Scan

uses: snyk/actions/node@master

env:

SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

with:

args: --severity-threshold=high

4단계: 컨테이너 보안

container-security:

runs-on: ubuntu-latest

needs: [sast]

steps:

- uses: actions/checkout@v4

- name: Build Docker Image

run: docker build -t myapp:test .

- name: Trivy Image Scan

uses: aquasecurity/trivy-action@master

with:

image-ref: 'myapp:test'

format: 'sarif'

output: 'trivy-results.sarif'

severity: 'CRITICAL,HIGH'

exit-code: '1'

- name: Upload Trivy SARIF

uses: github/codeql-action/upload-sarif@v3

with:

sarif_file: 'trivy-results.sarif'

if: always()

5단계: SBOM 생성

sbom:

runs-on: ubuntu-latest

needs: [container-security]

steps:

- uses: actions/checkout@v4

- name: Generate SBOM

uses: anchore/sbom-action@v0

with:

image: myapp:test

format: cyclonedx-json

output-file: sbom.json

- name: Upload SBOM

uses: actions/upload-artifact@v4

with:

name: sbom

path: sbom.json

6단계: IaC 스캔

iac-security:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Trivy IaC Scan

uses: aquasecurity/trivy-action@master

with:

scan-type: 'config'

scan-ref: '.'

format: 'sarif'

output: 'trivy-iac.sarif'

- name: Upload IaC SARIF

uses: github/codeql-action/upload-sarif@v3

with:

sarif_file: 'trivy-iac.sarif'

if: always()

7단계: DAST (스테이징 배포 후)

dast:

runs-on: ubuntu-latest

needs: [container-security]

if: github.ref == 'refs/heads/main'

steps:

- name: ZAP Baseline Scan

uses: zaproxy/action-baseline@v0.10.0

with:

target: 'https://staging.example.com'

rules_file_name: '.zap-rules.tsv'

fail_action: 'warn'

최종: 보안 게이트

security-gate:

runs-on: ubuntu-latest

needs: [secret-scan, sast, sca, container-security, iac-security]

steps:

- name: Security Gate Check

run: |

echo "All security checks passed!"

echo "Pipeline completed at $(date)"

10.2 GitHub Advanced Security 활용

.github/workflows/codeql.yml

name: CodeQL Analysis

on:

push:

branches: [main]

pull_request:

branches: [main]

schedule:

- cron: '0 4 * * 1'

jobs:

analyze:

runs-on: ubuntu-latest

permissions:

security-events: write

strategy:

matrix:

language: ['javascript', 'typescript']

steps:

- uses: actions/checkout@v4

- name: Initialize CodeQL

uses: github/codeql-action/init@v3

with:

languages: ${{ matrix.language }}

queries: +security-extended,security-and-quality

- name: Autobuild

uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis

uses: github/codeql-action/analyze@v3

with:

category: "/language:${{ matrix.language }}"

10.3 보안 파이프라인 메트릭

성공적인 DevSecOps 프로그램에서 추적해야 하는 주요 메트릭입니다.

| 메트릭 | 설명 | 목표 |

|--------|------|------|

| MTTR | 취약점 평균 수정 시간 | Critical: 24시간 이내 |

| 취약점 밀도 | 코드 1000줄당 취약점 수 | 0.5 이하 |

| 스캔 커버리지 | 보안 스캔 적용된 리포지토리 비율 | 100% |

| 오탐율 | 전체 발견 중 오탐 비율 | 20% 이하 |

| 파이프라인 통과율 | 보안 게이트 통과 비율 | 85% 이상 |

| 의존성 최신도 | 최신 버전 의존성 비율 | 80% 이상 |

11. 실전 퀴즈

**정답:**

- **SAST**는 소스 코드를 정적으로 분석하여 취약점을 찾습니다. 빌드 단계에서 실행되며 실행 환경이 필요 없습니다.

- **DAST**는 실행 중인 애플리케이션에 공격을 시뮬레이션합니다. 런타임 환경이 필요하며 소스 코드 없이도 가능합니다.

- SAST는 오탐율이 높지만 전체 코드를 분석할 수 있고, DAST는 오탐율이 낮지만 도달 가능한 경로만 분석합니다.

- 둘 다 사용하는 것이 이상적이며, 이를 IAST(Interactive AST)라고도 합니다.

**정답:**

- 결함 수정 비용은 발견 시점이 늦을수록 기하급수적으로 증가합니다.

- 요구사항 단계에서 발견하면 1x, 설계 5x, 구현 10x, 테스트 20x, 운영 30x, 사고 후 100x+ 비용이 듭니다.

- Shift-Left은 보안을 개발 초기(왼쪽)로 이동시켜 결함을 빨리 발견하므로 비용이 절감됩니다.

- 또한 개발자가 코드를 작성하는 시점에 피드백을 받으므로 컨텍스트 전환 비용도 줄어듭니다.

**정답:**

- SBOM은 소프트웨어에 포함된 모든 구성요소(라이브러리, 프레임워크 등)의 목록입니다.

- Log4Shell 같은 취약점이 발견되면 SBOM으로 영향받는 시스템을 즉시 식별할 수 있습니다.

- 라이선스 컴플라이언스 확인에도 필수적입니다.

- 미국 행정명령(EO 14028)에서 정부 소프트웨어 공급업체에 SBOM 제출을 의무화했습니다.

- CycloneDX와 SPDX가 대표적인 SBOM 표준 포맷입니다.

**정답:**

1. **최소 베이스 이미지**: distroless, alpine, slim 이미지 사용으로 공격 표면 축소

2. **멀티스테이지 빌드**: 빌드 도구를 최종 이미지에 포함시키지 않음

3. **비루트 사용자**: USER 명령으로 루트가 아닌 사용자로 실행

4. **이미지 서명**: cosign으로 이미지 서명 및 검증

5. **정기적 스캔**: Trivy/Grype로 이미지 취약점 정기 스캔

추가 사항: 읽기 전용 파일시스템, capabilities 최소화, 불필요한 패키지 제거

**정답:**

권장 순서:

1. **Secret 탐지** (GitLeaks) - 가장 빠르고 중요

2. **SAST** (Semgrep/CodeQL) - 코드 레벨 취약점

3. **SCA** (Snyk/Dependabot) - 의존성 취약점

4. **IaC 스캔** (Trivy/Conftest) - 인프라 설정 검증

5. **컨테이너 보안** (Trivy) - 이미지 빌드 후 스캔

6. **SBOM 생성** - 아티팩트 목록 생성

7. **DAST** (ZAP) - 스테이징 배포 후 런타임 테스트

8. **보안 게이트** - 모든 결과 종합 판단

Secret 탐지와 SAST는 병렬 실행 가능하며, DAST는 배포 후에만 실행됩니다.

12. 참고 자료

1. [OWASP DevSecOps Guideline](https://owasp.org/www-project-devsecops-guideline/)

2. [NIST Secure Software Development Framework (SSDF)](https://csrc.nist.gov/Projects/ssdf)

3. [SLSA - Supply-chain Levels for Software Artifacts](https://slsa.dev/)

4. [Sigstore - Software Signing](https://www.sigstore.dev/)

5. [Semgrep Registry](https://semgrep.dev/explore)

6. [GitHub Security Lab](https://securitylab.github.com/)

7. [Trivy Documentation](https://aquasecurity.github.io/trivy/)

8. [Snyk Learn - Security Education](https://learn.snyk.io/)

9. [OWASP Top 10 (2021)](https://owasp.org/Top10/)

10. [CycloneDX SBOM Standard](https://cyclonedx.org/)

11. [OPA - Open Policy Agent](https://www.openpolicyagent.org/)

12. [Kyverno Documentation](https://kyverno.io/docs/)

13. [CISA SBOM Resources](https://www.cisa.gov/sbom)

14. [Google SLSA GitHub Generator](https://github.com/slsa-framework/slsa-github-generator)

현재 단락 (1/843)

- **Shift-Left 보안**: 개발 초기에 보안을 적용하면 결함 수정 비용이 30배 절감

작성 글자: 0원문 글자: 21,378작성 단락: 0/843