CI 연동
코드를 푸시하거나 병합 요청(PR/MR)을 올릴 때마다 보안 스캔이 자동으로 돌게 하려면 CI 파이프라인에 스캔 트리거 단계를 추가합니다. 소스코드뿐 아니라 컨테이너 이미지, 웹 서비스도 같은 방식으로 연동됩니다.
어떤 유형이 지원되나
CI 트리거는 서비스별로 설정합니다. 서비스 유형에 따라 실행할 수 있는 스캔과 스캔 대상이 다릅니다.
| 서비스 유형 | 실행 가능한 스캔 | 스캔 대상 |
|---|---|---|
| 소스코드 (Git) | SAST, SCA, SBOM, IaC, Secret | 요청에 담긴 브랜치/커밋의 Git 소스 |
| 컨테이너 이미지 | 이미지 SCA, SBOM, 이미지 하드닝 | 레지스트리 이미지(지정 이미지 또는 최신 이미지 자동) |
| 웹 서비스 (DAST) | DAST | 소유권이 검증된 도메인 |
실제로 노출되는 스캔 종류는 그 서비스에서 켜 둔 분석으로 제한됩니다.
서버/호스트와 SBOM 업로드는 CI 대상이 아닙니다
설정 절차
서비스 스코프의 [CI 트리거] 메뉴에서 진행합니다.
- 토큰 발급 : 인증 토큰을 발급합니다. 토큰은 발급 시 한 번만 표시되므로 즉시 복사해 둡니다. 재발급하면 기존 토큰은 즉시 무효화됩니다.
- 트리거 활성화 + 스캔 종류 선택 : 트리거를 켜고, 푸시 때 실행할 스캔 종류를 고릅니다. 컨테이너 이미지 유형은 스캔 대상 이미지를 지정하거나 최신 이미지(자동) 를 선택할 수 있습니다. 최신 이미지를 선택하면 CI 가 방금 빌드/푸시한 이미지를 매번 스캔합니다.
- CI 비밀변수로 저장 : 발급한 토큰을 CI 도구의 비밀변수 VULINDER_CI_TOKEN 으로 등록합니다. 토큰을 코드에 평문으로 넣지 마세요.
- 파이프라인에 스니펫 추가 : 아래 도구별 스니펫을 저장소에 추가합니다. [CI 트리거] 화면에는 서비스에 맞는 정확한 인바운드 웹훅 URL 과 스니펫이 함께 표시됩니다.
- 커밋/푸시 : 파이프라인이 실행되며 해당 단계에서 스캔이 자동으로 큐에 등록됩니다.
호출 규격
파이프라인 단계에서 인바운드 웹훅을 호출하는 구조입니다. 요청에는 서비스 ID 를 담지 않습니다. 토큰이 어떤 서비스인지 식별합니다.
- 메서드/주소 :
POST <인바운드 웹훅 URL>(형식:.../api/v1/webhook/ci/scan). 정확한 주소는 [CI 트리거] 화면에 표시됩니다. - 헤더 :
X-CI-Token: <발급받은 토큰> - 본문(JSON, 선택) :
{ "branch": "...", "commit": "..." }. 생략하면 서비스에 설정된 기본 브랜치를 씁니다. - 응답(200) :
{ "queued": [...], "failed": [...] }. 큐에 등록된 스캔과 실패한 항목을 함께 돌려줍니다.
도구별 스니펫
토큰은 각 도구의 비밀변수(VULINDER_CI_TOKEN)로 참조하고, 아래 <인바운드 웹훅 URL> 은 [CI 트리거] 화면에 표시된 주소로 바꿉니다.
GitLab CI
CI/CD 설정의 Variables 에 VULINDER_CI_TOKEN 을 (Masked) 변수로 등록한 뒤 .gitlab-ci.yml 에 추가합니다.
vulinder-security-scan:
stage: test
image: curlimages/curl:latest
script:
- >
curl -fsS -X POST "<인바운드 웹훅 URL>"
-H "X-CI-Token: $VULINDER_CI_TOKEN"
-H "Content-Type: application/json"
-d "{\"branch\":\"$CI_COMMIT_REF_NAME\",\"commit\":\"$CI_COMMIT_SHA\"}"
GitHub Actions
저장소 Settings 의 Secrets and variables > Actions 에 VULINDER_CI_TOKEN 을 등록한 뒤 .github/workflows/vulinder-security.yml 로 추가합니다.
name: Vulinder Security Scan
on: [push, pull_request]
jobs:
trigger-scan:
runs-on: ubuntu-latest
steps:
- name: Trigger Vulinder scan
run: |
curl -fsS -X POST "<인바운드 웹훅 URL>" \
-H "X-CI-Token: ${{ secrets.VULINDER_CI_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"branch\":\"${{ github.ref_name }}\",\"commit\":\"${{ github.sha }}\"}"
Jenkins
Manage Jenkins 의 Credentials 에 VULINDER_CI_TOKEN 을 Secret text 자격증명으로 등록한 뒤 Jenkinsfile 에 추가합니다.
pipeline {
agent any
stages {
stage('Vulinder Security Scan') {
steps {
withCredentials([string(credentialsId: 'VULINDER_CI_TOKEN', variable: 'VULINDER_CI_TOKEN')]) {
sh '''
curl -fsS -X POST "<인바운드 웹훅 URL>" \
-H "X-CI-Token: $VULINDER_CI_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"branch\":\"${GIT_BRANCH}\",\"commit\":\"${GIT_COMMIT}\"}"
'''
}
}
}
}
}
동작과 제한
- 인증 실패 : 토큰이 없거나 틀리거나, 트리거가 비활성이면 요청은 거부됩니다(401). 비활성화하면 토큰이 유효해도 인바운드 요청이 막힙니다.
- 호출 빈도 제한 : 무효 토큰 스팸을 막기 위해 IP 당 분당 30회로 제한합니다.
- 진행 중 스캔 상한 : 한 서비스에 진행 중인 스캔이 너무 많으면 잠시 거부됩니다(429). CI 는 잠시 후 다시 시도하면 됩니다. 같은 브랜치를 짧은 간격으로 다시 호출하면 중복 스캔은 자동으로 합쳐집니다.
- 네이티브 저장소 웹훅 : 현재는 CI 파이프라인 연동 방식만 지원합니다. 저장소 Settings 의 네이티브 웹훅 연동은 준비 중입니다.