들어가며
“이제와서 시작하는 GitHub 마스터하기” 시리즈의 열여섯 번째 시간입니다. 이번에는 GitHub의 강력한 보안 기능들을 활용하여 코드베이스를 안전하게 보호하는 방법을 알아보겠습니다. 보안은 개발의 선택이 아닌 필수입니다.
1. GitHub Security 개요
보안 기능 전체 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| GitHub Security Features:
Supply Chain:
- Dependency graph: 의존성 시각화
- Dependabot alerts: 취약점 알림
- Dependabot updates: 자동 업데이트
Code Security:
- Code scanning: 정적 분석
- Secret scanning: 비밀 정보 탐지
- Push protection: 푸시 차단
Access Control:
- 2FA: 이중 인증
- SSO: 단일 로그인
- IP allowlist: IP 제한
Audit & Compliance:
- Audit log: 감사 로그
- Security policy: 보안 정책
- Advisory database: 취약점 DB
|
Security Overview 대시보드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| 저장소 → Security 탭에서 확인 가능:
1. Security Policy
- 보안 정책 문서
- 취약점 보고 방법
2. Advisories
- 보안 권고 사항
- CVE 발행
3. Dependabot
- 의존성 업데이트
- 취약점 알림
4. Code scanning
- 코드 취약점 분석
- SAST 결과
5. Secret scanning
- 노출된 시크릿
- 토큰 알림
|
2. Dependabot 설정과 활용
Dependabot 활성화
.github/dependabot.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
| version: 2
updates:
# JavaScript 의존성
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
time: "09:00"
timezone: "Asia/Seoul"
open-pull-requests-limit: 10
reviewers:
- "security-team"
- "lead-developer"
assignees:
- "dependency-manager"
labels:
- "dependencies"
- "security"
commit-message:
prefix: "chore"
prefix-development: "chore"
include: "scope"
milestone: 4
ignore:
# 특정 의존성 무시
- dependency-name: "lodash"
versions: ["4.x"]
# 메이저 버전 업데이트 무시
- dependency-name: "*"
update-types: ["version-update:semver-major"]
allow:
# 직접 의존성만
- dependency-type: "direct"
# 그룹화
groups:
development-dependencies:
dependency-type: "development"
update-types:
- "minor"
- "patch"
# Python 의존성
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
labels:
- "python"
- "dependencies"
# Docker 이미지
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "devops-team"
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci/cd"
# Go modules
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "deps"
# Terraform
- package-ecosystem: "terraform"
directory: "/infrastructure"
schedule:
interval: "daily"
reviewers:
- "infrastructure-team"
|
Dependabot 보안 업데이트 자동화
.github/workflows/auto-merge-dependabot.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| name: Auto-merge Dependabot PRs
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: write
pull-requests: write
jobs:
auto-merge:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1
with:
github-token: "$"
- name: Auto-merge patch updates
if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: $
GITHUB_TOKEN: $
- name: Auto-merge minor updates for dev dependencies
if: |
steps.metadata.outputs.update-type == 'version-update:semver-minor' &&
steps.metadata.outputs.dependency-type == 'direct:development'
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: $
GITHUB_TOKEN: $
- name: Comment on major updates
if: steps.metadata.outputs.update-type == 'version-update:semver-major'
run: |
gh pr comment "$PR_URL" --body "
⚠️ **Major version update detected!**
This PR updates $ from $ to $.
Please review carefully:
- [ ] Check breaking changes
- [ ] Update code if necessary
- [ ] Test thoroughly
"
env:
PR_URL: $
GITHUB_TOKEN: $
|
커스텀 Dependabot 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| # .github/dependabot.yml - 고급 설정
version: 2
registries:
npm-private:
type: npm-registry
url: https://npm.company.com
username: $
password: $
docker-private:
type: docker-registry
url: registry.company.com
username: $
password: $
updates:
- package-ecosystem: "npm"
directory: "/"
registries:
- npm-private
schedule:
interval: "daily"
# 버전 요구사항 증가 전략
versioning-strategy: increase
# 또는: increase-if-necessary, lockfile-only, widen
- package-ecosystem: "docker"
directory: "/"
registries:
- docker-private
schedule:
interval: "weekly"
|
3. Secret Scanning 설정
Secret Scanning 활성화 및 설정
1
2
3
4
5
6
7
| # Repository Settings → Security & analysis
# Enable:
- Dependency graph ✓
- Dependabot alerts ✓
- Dependabot security updates ✓
- Secret scanning ✓
- Push protection ✓
|
커스텀 패턴 정의
.github/secret-scanning.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # 커스텀 시크릿 패턴
patterns:
- name: Company API Key
pattern: |
COMP_API_[A-Z0-9]{32}
- name: Internal Token
pattern: |
(internal|int)_token[\s]*=[\s]*["']?[a-zA-Z0-9]{40}["']?
- name: Database Connection String
pattern: |
(postgres|mysql|mongodb):\/\/[^:]+:[^@]+@[^/]+\/\w+
- name: JWT Secret
pattern: |
JWT_SECRET[\s]*=[\s]*["']?[a-zA-Z0-9+/]{32,}={0,2}["']?
- name: Slack Webhook
pattern: |
https://hooks\.slack\.com/services/T[A-Z0-9]{8}/B[A-Z0-9]{8}/[a-zA-Z0-9]{24}
# 제외 경로
paths-ignore:
- "**/*.test.js"
- "**/test/**"
- "docs/**"
- "*.md"
|
Push Protection 우회 처리
.github/workflows/handle-blocked-push.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| name: Handle Blocked Push
on:
workflow_dispatch:
inputs:
reason:
description: 'Reason for bypassing'
required: true
type: choice
options:
- 'False positive'
- 'Test data'
- 'Already rotated'
- 'Public information'
jobs:
document-bypass:
runs-on: ubuntu-latest
steps:
- name: Log bypass reason
uses: actions/github-script@v6
with:
script: |
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Secret Scanning Bypass: ${new Date().toISOString()}`,
body: `
## Bypass Information
**User**: $
**Reason**: $
**Time**: ${new Date().toISOString()}
**Commit**: $
### Justification
Please provide detailed justification in comments.
`,
labels: ['security', 'bypass', 'audit']
});
console.log(`Created issue #${issue.data.number}`);
|
4. Code Scanning과 CodeQL
CodeQL 기본 설정
.github/workflows/codeql.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| name: "CodeQL"
on:
push:
branches: [ "main", "develop" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '0 0 * * 0' # 매주 일요일
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript', 'python', 'java' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: $
queries: security-and-quality
# 추가 쿼리 팩
# queries: security-extended,security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# 또는 수동 빌드
# - name: Build Java
# if: matrix.language == 'java'
# run: |
# ./gradlew build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:$"
|
커스텀 CodeQL 쿼리
.github/codeql/custom-queries.ql:
/**
* @name Hardcoded credentials
* @description Finds hardcoded credentials in code
* @kind problem
* @problem.severity error
* @security-severity 8.0
* @precision high
* @id custom/hardcoded-credentials
* @tags security
* external/cwe/cwe-798
*/
import javascript
import semmle.javascript.security.dataflow.HardcodedCredentials
from DataFlow::Node source, DataFlow::Node sink, string value
where
HardcodedCredentials::flow(source, sink) and
source.asExpr().(StringLiteral).getValue() = value and
value.regexpMatch(".*[pP]assword.*|.*[sS]ecret.*|.*[kK]ey.*") and
value.length() > 8
select sink, "Hardcoded credential: " + value
서드파티 도구 통합
.github/workflows/security-scan.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| name: Security Scanning
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
snyk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: $
with:
args: --severity-threshold=high
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: $
SONAR_TOKEN: $
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
|
5. Security Policy 작성
SECURITY.md
SECURITY.md:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| # Security Policy
## Supported Versions
현재 다음 버전들에 대해 보안 업데이트를 제공합니다:
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :white_check_mark: |
| 4.0.x | :x: |
| < 4.0 | :x: |
## Reporting a Vulnerability
보안 취약점을 발견하셨다면 책임감 있는 공개를 부탁드립니다.
### 보고 방법
1. **GitHub Security Advisory 사용** (권장)
- [Security 탭 → Report a vulnerability](https://github.com/username/repo/security/advisories/new)
- 비공개로 안전하게 보고 가능
2. **이메일**
- security@example.com
- PGP 키: [링크]
3. **보고 시 포함사항**
- 취약점 설명
- 재현 단계
- 영향 범위
- 가능한 해결 방법
### 대응 절차
1. **접수 확인**: 24시간 이내
2. **초기 평가**: 72시간 이내
3. **상세 대응**: 7일 이내
4. **패치 릴리즈**: 심각도에 따라 결정
5. **공개**: CVE 발행 및 공지
### 보상 프로그램
현재 버그 바운티 프로그램은 운영하지 않지만,
기여자는 SECURITY.md에 크레딧을 받습니다.
### 제외 사항
다음은 보안 취약점으로 간주하지 않습니다:
- 서비스 거부 공격 (DoS)
- 스팸
- 소셜 엔지니어링
- 물리적 공격
## Security Features
### 구현된 보안 기능
- [x] 입력 검증
- [x] SQL 인젝션 방지
- [x] XSS 방지
- [x] CSRF 토큰
- [x] Rate limiting
- [x] 암호화된 통신
### 보안 헤더
|
Content-Security-Policy: default-src ‘self’ X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000; includeSubDomains
1
2
3
4
5
|
## Contact
보안팀: security@example.com
긴급 연락처: +1-234-567-8900
|
6. 브랜치 보호와 서명
커밋 서명 강제
1
2
3
4
5
6
7
8
9
10
11
12
13
| # GPG 키 생성
gpg --full-generate-key
# GPG 키 목록 확인
gpg --list-secret-keys --keyid-format=long
# Git에 GPG 키 설정
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
# GPG 키 GitHub에 추가
gpg --armor --export YOUR_KEY_ID
# GitHub Settings → SSH and GPG keys → New GPG key
|
브랜치 보호 규칙 자동화
.github/workflows/branch-protection.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| name: Enforce Branch Protection
on:
repository_dispatch:
types: [created]
workflow_dispatch:
jobs:
protect-branches:
runs-on: ubuntu-latest
steps:
- name: Configure branch protection
uses: actions/github-script@v6
with:
github-token: $
script: |
const branches = ['main', 'develop', 'release/*'];
for (const branch of branches) {
await github.rest.repos.updateBranchProtection({
owner: context.repo.owner,
repo: context.repo.repo,
branch,
required_status_checks: {
strict: true,
contexts: ['continuous-integration', 'code-review']
},
enforce_admins: true,
required_pull_request_reviews: {
required_approving_review_count: 2,
dismiss_stale_reviews: true,
require_code_owner_reviews: true,
require_last_push_approval: true
},
restrictions: null,
allow_force_pushes: false,
allow_deletions: false,
required_conversation_resolution: true,
lock_branch: false,
allow_fork_syncing: false,
required_signatures: true
});
}
|
7. 컨테이너 보안
Dockerfile 보안 스캔
.github/workflows/container-security.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| name: Container Security
on:
push:
paths:
- 'Dockerfile*'
- '.dockerignore'
pull_request:
paths:
- 'Dockerfile*'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
- name: Build image
run: docker build -t $:$ .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: $:$
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
- name: Run Grype vulnerability scanner
uses: anchore/scan-action@v3
with:
image: $:$
fail-build: true
severity-cutoff: high
- name: Container structure test
run: |
wget https://storage.googleapis.com/container-structure-test/latest/container-structure-test-linux-amd64 -O container-structure-test
chmod +x container-structure-test
./container-structure-test test \
--image $:$ \
--config container-test.yaml
|
안전한 Dockerfile 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| # 보안 강화 Dockerfile 예제
FROM node:18-alpine@sha256:abc123... AS builder
# 보안 업데이트
RUN apk update && apk upgrade && apk add --no-cache \
ca-certificates \
&& rm -rf /var/cache/apk/*
# 비root 사용자 생성
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 작업 디렉토리
WORKDIR /app
# 의존성 먼저 복사 (캐시 활용)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 소스 코드 복사
COPY --chown=nodejs:nodejs . .
# 빌드
RUN npm run build
# Production 이미지
FROM node:18-alpine@sha256:abc123...
# 보안 업데이트
RUN apk update && apk upgrade && apk add --no-cache \
ca-certificates \
dumb-init \
&& rm -rf /var/cache/apk/*
# 비root 사용자
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# 빌드된 파일만 복사
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
# 보안 설정
USER nodejs
EXPOSE 3000
# 헬스체크
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
# dumb-init으로 시그널 처리
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]
|
8. Supply Chain 보안
SBOM 생성과 관리
.github/workflows/sbom.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| name: Generate SBOM
on:
release:
types: [published]
workflow_dispatch:
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate SBOM with Syft
uses: anchore/sbom-action@v0
with:
format: spdx-json
output-file: sbom.spdx.json
- name: Generate CycloneDX SBOM
run: |
npm install -g @cyclonedx/cyclonedx-npm
cyclonedx-npm --output-format json --output-file sbom.cyclonedx.json
- name: Sign SBOM
env:
COSIGN_PASSWORD: $
run: |
cosign sign-blob \
--key cosign.key \
sbom.spdx.json > sbom.spdx.json.sig
- name: Upload SBOM
uses: actions/upload-artifact@v3
with:
name: sbom
path: |
sbom.*.json
sbom.*.json.sig
- name: Attach SBOM to release
uses: softprops/action-gh-release@v1
with:
files: |
sbom.*.json
sbom.*.json.sig
|
License 검사
.github/workflows/license-check.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| name: License Check
on:
pull_request:
schedule:
- cron: '0 0 * * 1' # 매주 월요일
jobs:
license-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check licenses with license-checker
run: |
npm install -g license-checker
license-checker --summary --excludePrivatePackages \
--onlyAllow 'MIT;Apache-2.0;BSD-3-Clause;BSD-2-Clause;ISC;CC0-1.0' \
--out licenses.json
- name: FOSSA scan
uses: fossas/fossa-action@main
with:
api-key: $
- name: Check for copyleft licenses
run: |
if grep -E "GPL|LGPL|AGPL" licenses.json; then
echo "::error::Copyleft licenses found!"
exit 1
fi
|
9. 보안 자동화
Security Scoreboard
.github/workflows/security-scorecard.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| name: Security Scorecard
on:
schedule:
- cron: '0 0 * * 0'
push:
branches: [ main ]
permissions:
security-events: write
contents: read
actions: read
jobs:
analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@v2
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif
|
보안 메트릭 수집
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| // security-metrics.js
const { Octokit } = require('@octokit/rest');
async function collectSecurityMetrics(owner, repo) {
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const metrics = {
timestamp: new Date().toISOString(),
vulnerabilities: {
critical: 0,
high: 0,
medium: 0,
low: 0
},
codeScanning: {
openAlerts: 0,
closedAlerts: 0
},
secretScanning: {
openAlerts: 0,
closedAlerts: 0
},
dependencies: {
total: 0,
outdated: 0,
vulnerable: 0
}
};
// Dependabot alerts
const { data: vulnAlerts } = await octokit.dependabot.listAlertsForRepo({
owner,
repo,
state: 'open'
});
vulnAlerts.forEach(alert => {
metrics.vulnerabilities[alert.security_vulnerability.severity]++;
});
// Code scanning alerts
const { data: codeAlerts } = await octokit.codeScanning.listAlertsForRepo({
owner,
repo
});
metrics.codeScanning.openAlerts = codeAlerts.filter(a => a.state === 'open').length;
metrics.codeScanning.closedAlerts = codeAlerts.filter(a => a.state === 'closed').length;
// Secret scanning alerts
const { data: secretAlerts } = await octokit.secretScanning.listAlertsForRepo({
owner,
repo
});
metrics.secretScanning.openAlerts = secretAlerts.filter(a => a.state === 'open').length;
return metrics;
}
// 대시보드용 데이터 생성
async function generateSecurityDashboard() {
const metrics = await collectSecurityMetrics('org', 'repo');
const dashboard = {
title: 'Security Dashboard',
lastUpdated: metrics.timestamp,
summary: {
totalVulnerabilities: Object.values(metrics.vulnerabilities).reduce((a, b) => a + b, 0),
criticalIssues: metrics.vulnerabilities.critical,
openAlerts: metrics.codeScanning.openAlerts + metrics.secretScanning.openAlerts
},
charts: {
vulnerabilitiesBySeverity: metrics.vulnerabilities,
alertsTrend: await getAlertsTrend(),
dependencyHealth: metrics.dependencies
}
};
return dashboard;
}
|
10. 인시던트 대응
보안 인시던트 대응 워크플로우
.github/workflows/incident-response.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
| name: Security Incident Response
on:
workflow_dispatch:
inputs:
incident_type:
description: 'Type of incident'
required: true
type: choice
options:
- 'credential-leak'
- 'vulnerability-exploit'
- 'dependency-compromise'
- 'unauthorized-access'
severity:
description: 'Severity level'
required: true
type: choice
options:
- 'critical'
- 'high'
- 'medium'
- 'low'
jobs:
respond:
runs-on: ubuntu-latest
steps:
- name: Create incident issue
uses: actions/github-script@v6
with:
script: |
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[SECURITY] ${context.payload.inputs.incident_type} - ${new Date().toISOString()}`,
body: `
## Security Incident Report
**Type**: ${context.payload.inputs.incident_type}
**Severity**: ${context.payload.inputs.severity}
**Reported by**: @${context.actor}
**Time**: ${new Date().toISOString()}
### Incident Response Checklist
- [ ] Assess impact
- [ ] Contain incident
- [ ] Collect evidence
- [ ] Eradicate threat
- [ ] Recover systems
- [ ] Document lessons learned
### Actions Taken
<!-- Document all actions here -->
### Timeline
<!-- Document timeline of events -->
`,
labels: ['security', 'incident', context.payload.inputs.severity],
assignees: ['security-team']
});
- name: Notify security team
if: inputs.severity == 'critical' || inputs.severity == 'high'
run: |
# Send notifications via multiple channels
# Slack, email, PagerDuty, etc.
- name: Enable additional monitoring
run: |
# Enable enhanced logging
# Increase security scanning frequency
# Deploy additional security controls
- name: Generate incident report
run: |
# Create detailed incident report
# Include all relevant logs and evidence
|
마무리
GitHub의 보안 기능들은 현대적인 DevSecOps 파이프라인의 핵심입니다.
핵심 포인트:
- Dependabot으로 의존성 취약점 자동 관리
- Secret scanning으로 민감 정보 노출 방지
- Code scanning으로 코드 취약점 조기 발견
- 포괄적인 보안 정책 수립
- 자동화를 통한 지속적인 보안 강화
보안은 한 번 설정하고 끝나는 것이 아닌 지속적인 프로세스입니다. GitHub의 보안 기능들을 적극 활용하여 안전한 코드베이스를 유지하세요.
다음 편에서는 GitHub Packages를 활용한 패키지 관리에 대해 알아보겠습니다.
📚 GitHub 마스터하기 시리즈
🌱 기초편 (입문자)
- GitHub 시작하기
- Repository 기초
- Git 기본 명령어
- Branch와 Merge
- Fork와 Pull Request
💼 실전편 (중급자)
- Issues 활용법
- Projects로 프로젝트 관리
- Code Review 잘하기
- GitHub Discussions
- Team 협업 설정
- GitHub Pages
🚀 고급편 (전문가)
- GitHub Actions 입문
- Actions 고급 활용
- Webhooks와 API
- GitHub Apps 개발
- [보안 기능] (현재 글)(/posts/github-advanced-05-security-features/)
- GitHub Packages
- Codespaces
- GitHub CLI
- 통계와 인사이트
🏆 심화편 (전문가+)
- Git Submodules & Subtree
- Git 내부 동작 원리
- 고급 브랜치 전략과 릴리스 관리
- GitHub GraphQL API
-