6.2 Безопасность в CI/CD #
🎯 Цель изучения #
Научиться интегрировать security проверки в CI/CD pipeline так, чтобы каждый коммит и деплой проходил через автоматизированные security gates.
🔒 Security Gates в Pipeline #
Традиционный vs DevSecOps Pipeline #
❌ Традиционный:
Code → Build → Test → Deploy → Security Check (optional)
✅ DevSecOps:
Code → SAST → Build → SCA → DAST → Deploy → Runtime Security
↓ ↓ ↓ ↓ ↓ ↓ ↓
Secret Static Image Deps Dynamic Deploy Monitor
Scan Analysis Scan Check Test Security Threats
🚧 Security Gates по этапам #
# .github/workflows/devsecops-pipeline.yml
name: DevSecOps Pipeline
on: [push, pull_request]
jobs:
# Gate 1: Secret Detection
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
head: HEAD
# Gate 2: Static Analysis Security Testing (SAST)
sast:
runs-on: ubuntu-latest
needs: secrets-scan
steps:
- uses: actions/checkout@v3
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: p/security-audit p/secrets
# Gate 3: Software Composition Analysis (SCA)
sca:
runs-on: ubuntu-latest
needs: sast
steps:
- uses: actions/checkout@v3
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# Gate 4: Container Image Scanning
container-scan:
runs-on: ubuntu-latest
needs: sca
steps:
- uses: actions/checkout@v3
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
# Gate 5: Infrastructure as Code Scanning
iac-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Checkov action
uses: bridgecrewio/checkov-action@master
with:
directory: .
framework: terraform,kubernetes,dockerfile
🔍 SAST (Static Application Security Testing) #
Что такое SAST? #
SAST анализирует исходный код без его выполнения
Source Code → SAST Tool → Security Issues Report
↓ ↓ ↓
.js, .py Rules Vulnerabilities
.java Patterns Best practices
.go, .rb Configs Code quality
🛠️ Популярные SAST инструменты #
SonarQube #
# SonarQube в GitHub Actions
- name: SonarQube Scan
uses: sonarqube-quality-gate-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
scanMetadataReportFile: target/sonar/report-task.txt
# sonar-project.properties
sonar.projectKey=my-project
sonar.organization=my-org
sonar.sources=src
sonar.tests=tests
sonar.javascript.lcov.reportPaths=coverage/lcov.info
# Security rules
sonar.security.hotspots.inherited=true
sonar.security.review.inherited=true
Semgrep #
# Semgrep configuration
- name: Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/secrets
p/owasp-top-ten
p/cwe-top-25
# Custom Semgrep rules (.semgrep.yml)
rules:
- id: hardcoded-password
patterns:
- pattern: password = "..."
- pattern: PASSWORD = "..."
message: Hardcoded password detected
languages: [python, javascript]
severity: ERROR
- id: sql-injection
patterns:
- pattern: cursor.execute("SELECT * FROM users WHERE id = " + $VAR)
message: Possible SQL injection
languages: [python]
severity: WARNING
CodeQL #
# GitHub Advanced Security
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
analyze:
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript, python
queries: security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
📦 SCA (Software Composition Analysis) #
Что такое SCA? #
SCA (Анализ компонентов программного обеспечения) проверяет зависимости и третьесторонние компоненты
Процесс работы: файлы зависимостей (package.json, requirements.txt, go.mod) анализируются SCA инструментом, который сравнивает их с базами данных CVE, рекомендациями по безопасности и SBOM (списком материалов ПО), чтобы выявить известные уязвимости, проблемы с лицензиями и устаревшие зависимости. Результатом является отчет о уязвимостях.
🛠️ SCA инструменты и практики #
Snyk #
Для работы с Snyk необходимо установить CLI через npm, пройти аутентификацию и затем сканировать проект на уязвимости. Можно задавать порог критичности (high) для отфильтровывания результатов и настроить непрерывный мониторинг проекта на новые уязвимости.
Интеграция Snyk в CI/CD осуществляется через специальное действие для Node.js, которое использует токен из секретов и может быть настроено на определенный порог критичности (medium) и провал на любых проблемах. Результаты могут быть загружены в GitHub Code Scanning в формате SARIF.
OWASP Dependency Check #
OWASP Dependency Check интегрируется в Maven проекты через плагин, который может быть настроен на провал сборки при обнаружении уязвимостей с оценкой CVSS выше 7. Можно настроить файлы подавления (suppression) для исключения ложных срабатываний.
Для GitHub Actions существует готовое действие, которое можно настроить на сканирование конкретного проекта с выводом в HTML формате и дополнительными параметрами для включения проверок устаревших и экспериментальных правил.
🐳 Container Image Scanning #
Зачем сканировать образы? #
Образы контейнеров содержат множество компонентов, каждый из которых может содержать уязвимости. Например, базовый образ ubuntu:18.04 может содержать свыше 100 известных CVE. К этому добавляются уязвимости в коде приложения, зависимостях (npm/pip пакеты) и системных пакетах (apt/yum). Поэтому критично важно сканировать образы перед использованием в production.
🛠️ Инструменты для сканирования #
Trivy #
Trivy можно использовать локально для быстрого сканирования образов контейнеров. В CI/CD пиплайне можно запустить через Docker контейнер с монтированием Docker socket и рабочей директории. Результаты могут быть сохранены в формате SARIF для интеграции с GitHub Security.
В GitHub Actions Trivy интегрируется через специальное действие для сканирования указанного образа с выводом в формате SARIF и фильтрацией по критичности (CRITICAL, HIGH). Результаты автоматически загружаются на вкладку GitHub Security для дальнейшего анализа.
Grype #
Grype устанавливается через специальный скрипт с GitHub и может сканировать как образы контейнеров, так и файловую систему напрямую. Можно настроить провал сканирования при обнаружении уязвимостей высокой критичности.
🏗️ Secure Container Practices #
Пример настроек для безопасного контейнера:
Небезопасные практики:
- Использование устаревших базовых образов (ubuntu:18.04)
- Обновление пакетов без очистки кэша
- Копирование всего контекста в контейнер
- Установка чрезмерных разрешений (777)
- Использование root пользователя
Безопасные практики:
- Многоэтапная сборка с отдельным builder этапом
- Использование обновленных alpine образов
- Установка только production зависимостей с очисткой кэша
- Создание непривилегированного пользователя
- Правильная настройка владельца файлов через –chown
🌐 DAST (Dynamic Application Security Testing) #
Что такое DAST? #
DAST (Динамическое тестирование безопасности приложений) тестирует запущенное приложение как “черный ящик”
Процесс работы: работающее приложение (через HTTP/HTTPS, WebSockets, API) сканируется DAST сканером, который сочетает web crawler для обхода сайта, векторы атак и тестирование аутентификации. Результатом является отчет о проблемах безопасности, включая OWASP Top 10, runtime уязвимости и проблемы бизнес-логики.
🛠️ DAST инструменты #
OWASP ZAP #
OWASP ZAP интегрируется в GitHub Actions через специальное действие baseline scan, которое можно настроить на сканирование конкретного URL с настраиваемыми правилами и дополнительными параметрами командной строки.
Для Docker можно запустить ZAP через официальный stable образ с монтированием рабочей директории, указанием целевого URL, конфигурационного файла и выводом отчета в HTML формате.
Nuclei #
Nuclei устанавливается через Go и позволяет сканировать как отдельные URL, так и списки целей из файла. Можно указывать конкретные шаблоны (vulnerabilities/, cves/) и фильтровать по уровню критичности (critical, high).
В CI/CD Nuclei интегрируется через официальное действие, которое можно настроить на сканирование конкретного домена с определенными шаблонами и автоматическим созданием отчета в GitHub с использованием токена.
🚨 Security Policy Enforcement #
Policy as Code с OPA Gatekeeper #
# Constraint Template
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredsecuritycontext
spec:
crd:
spec:
names:
kind: K8sRequiredSecurityContext
validation:
type: object
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredsecuritycontext
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.runAsNonRoot
msg := "Container must run as non-root user"
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem
msg := "Root filesystem must be read-only"
}
# Constraint Instance
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredSecurityContext
metadata:
name: must-have-security-context
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters: {}
Quality Gates в Pipeline #
# SonarQube Quality Gate
- name: SonarQube Quality Gate check
uses: sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
scanMetadataReportFile: target/sonar/report-task.txt
# Custom Security Gate
- name: Security Gate
run: |
#!/bin/bash
# Check SAST results
if [ $(jq '.runs[0].results | length' sast-results.sarif) -gt 0 ]; then
echo "❌ SAST findings detected"
exit 1
fi
# Check container scan results
CRITICAL_VULNS=$(jq '.runs[0].results[] | select(.level=="error") | length' trivy-results.sarif)
if [ $CRITICAL_VULNS -gt 0 ]; then
echo "❌ Critical vulnerabilities found: $CRITICAL_VULNS"
exit 1
fi
echo "✅ All security gates passed"
🔐 Secrets Management в CI/CD #
Проблемы с секретами #
# ❌ Плохие практики
export DATABASE_PASSWORD="super_secret_123"
docker run -e DB_PASS=password123 myapp
kubectl create secret generic mysecret --from-literal=password=abc123
# История Git с секретами
git log --grep="password" --all
git log -p | grep -i "api.key\|password\|secret"
✅ Правильное управление секретами #
GitHub Secrets #
# Использование GitHub Secrets
- name: Deploy to production
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
run: |
echo "Deploying with secure credentials"
# Secrets не попадают в логи
HashiCorp Vault #
# Vault в CI/CD
- name: Import Secrets
uses: hashicorp/vault-action@v2.4.0
with:
url: https://vault.example.com:8200
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/prod database_password | DATABASE_PASSWORD ;
secret/data/prod api_key | API_KEY
External Secrets Operator #
# Kubernetes External Secrets
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "example-role"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
data:
- secretKey: database-password
remoteRef:
key: secret/app
property: database_password
📊 Security Metrics и Reporting #
Dashboard для Security в CI/CD #
{
"security_pipeline_metrics": {
"last_24h": {
"total_builds": 45,
"security_gate_failures": 3,
"avg_scan_time": "2m 34s",
"critical_vulns_found": 2,
"critical_vulns_fixed": 2
},
"trending": {
"false_positive_rate": "8%",
"security_debt": "12 hours",
"compliance_score": "94%"
}
}
}
Alerting и Notifications #
# Slack уведомления
- name: Notify Security Team
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
channel: '#security-alerts'
text: |
🚨 Security gate failure in ${{ github.repository }}
Branch: ${{ github.ref }}
Commit: ${{ github.sha }}
Failed step: ${{ github.job }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
🎯 Практические задания #
🟢 Задание 1: Настройка SAST #
# 1. Создать проект с уязвимостями
mkdir vulnerable-app && cd vulnerable-app
npm init -y
npm install express@4.16.0 # старая версия с CVE
cat > app.js << 'EOF'
const express = require('express');
const app = express();
// SQL Injection vulnerability
app.get('/user', (req, res) => {
const query = `SELECT * FROM users WHERE id = ${req.query.id}`;
// Выполнение query...
});
// XSS vulnerability
app.get('/search', (req, res) => {
res.send(`<h1>Results for: ${req.query.q}</h1>`);
});
app.listen(3000);
EOF
# 2. Настроить Semgrep
semgrep --config=p/security-audit .
🟡 Задание 2: Container Scanning #
# 1. Создать уязвимый Dockerfile
cat > Dockerfile << 'EOF'
FROM ubuntu:18.04
RUN apt-get update
COPY . /app
RUN chmod 777 /app
USER root
CMD ["node", "app.js"]
EOF
# 2. Сканирование
docker build -t vulnerable-app .
trivy image vulnerable-app:latest
# 3. Исправить проблемы
cat > Dockerfile.secure << 'EOF'
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
COPY --chown=nextjs:nodejs . .
USER nextjs
CMD ["node", "app.js"]
EOF
🟠 Задание 3: Pipeline Integration #
# Создать .github/workflows/security.yml
name: Security Pipeline
on: [push, pull_request]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Secret scanning
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
# SAST
- name: Semgrep
uses: returntocorp/semgrep-action@v1
# SCA
- name: Snyk scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# Container scan
- name: Build and scan image
run: |
docker build -t myapp:${{ github.sha }} .
trivy image myapp:${{ github.sha }}
📚 Полезные ресурсы #
🛠️ Инструменты #
- SAST: SonarQube, Semgrep, CodeQL, Checkmarx
- SCA: Snyk, WhiteSource, OWASP Dependency Check
- DAST: OWASP ZAP, Burp Suite, Nuclei
- Container: Trivy, Twistlock, Aqua Security
📖 Стандарты #
- OWASP SAMM - Software Assurance Maturity Model
- NIST SSDF - Secure Software Development Framework
- BSIMM - Building Security In Maturity Model
🎯 Результаты изучения #
После изучения этого раздела вы:
- ✅ Умеете настраивать security gates в CI/CD
- ✅ Знаете как интегрировать SAST/SCA/DAST инструменты
- ✅ Можете сканировать container images на уязвимости
- ✅ Понимаете как управлять секретами в pipeline
- ✅ Умеете настраивать security policy enforcement
Следующий раздел: 6.3 Infrastructure Security