6.2 Безопасность в CI/CD

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