Модуль 11: DevSecOps — Безопасность в DevOps
🔒 Что такое DevSecOps?
DevSecOps — это эволюция DevOps, которая интегрирует безопасность на каждом этапе разработки и эксплуатации. Вместо того чтобы думать о безопасности в конце, DevSecOps делает её частью повседневного процесса разработки.
По данным исследований 2025 года, более 85% инцидентов безопасности связаны с неправильной конфигурацией компонентов и недостаточной защитой в CI/CD пайплайнах. DevSecOps решает эти проблемы через автоматизацию проверок безопасности.
🎯 Принцип "Shift Left Security"
Shift Left означает перенос проверок безопасности как можно раньше в цикле разработки:
- Анализ кода на этапе написания
- Автоматические проверки при commit
- Сканирование зависимостей при сборке
- Тестирование безопасности в CI/CD
- Мониторинг безопасности в продакшне
Преимущества Shift Left
Снижение затрат — исправление уязвимостей на раннем этапе в 100 раз дешевле
Быстрая обратная связь — разработчики получают уведомления о проблемах сразу
Повышение качества — безопасность становится частью культуры разработки
⚠️ Основные угрозы безопасности
OWASP Top 10 — критичные уязвимости 2025
- Broken Access Control — нарушения контроля доступа
- Cryptographic Failures — криптографические сбои
- Injection — SQL, NoSQL, OS injection атаки
- Insecure Design — небезопасный дизайн приложения
- Security Misconfiguration — неправильная конфигурация
- Vulnerable Components — уязвимые компоненты
- Authentication Failures — сбои аутентификации
- Software Integrity Failures — нарушения целостности ПО
- Logging Failures — недостаточное логирование
- Server-Side Request Forgery — SSRF атаки
🔐 Безопасность в CI/CD пайплайне
Многоуровневая защита пайплайна
# .github/workflows/security.yml
name: Security Checks
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# 1. Сканирование секретов в коде
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
# 2. Статический анализ кода (SAST)
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v2
with:
languages: javascript, python
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
# 3. Сканирование зависимостей (SCA)
- name: Run Snyk to check vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# 4. Проверка Docker образа
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# 5. Проверка Infrastructure as Code
- name: Run Checkov on Terraform
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
output_file_path: checkov-report.sarif
- name: Upload Checkov results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: checkov-report.sarif
🔑 Управление секретами
Никогда не храните секреты в коде!
Проблемы хранения секретов в коде:
- Утечка через публичные репозитории
- Доступ к секретам всех разработчиков
- Сложность ротации паролей
- Отсутствие аудита доступа
HashiCorp Vault — централизованное управление
# Установка Vault
wget https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip
unzip vault_1.15.0_linux_amd64.zip
sudo mv vault /usr/local/bin/
# Запуск Vault в dev режиме (только для обучения!)
vault server -dev
# Сохранение секрета
vault kv put secret/myapp/db \
password="super-secret-password" \
username="dbuser"
# Получение секрета
vault kv get secret/myapp/db
# Получение только пароля
vault kv get -field=password secret/myapp/db
Интеграция Vault с приложениями
# Python приложение с Vault
import hvac
import os
def get_db_credentials():
# Подключение к Vault
client = hvac.Client(
url=os.getenv('VAULT_URL', 'http://localhost:8200'),
token=os.getenv('VAULT_TOKEN')
)
# Получение секретов
response = client.secrets.kv.v2.read_secret_version(
path='myapp/db'
)
credentials = response['data']['data']
return credentials['username'], credentials['password']
# Использование в приложении
username, password = get_db_credentials()
db_url = f"postgresql://{username}:{password}@localhost:5432/myapp"
Kubernetes Secrets
# k8s-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
database-password: <base64-encoded-password>
api-key: <base64-encoded-api-key>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: database-password
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secrets
key: api-key
🛡️ Сканирование контейнеров
Безопасный Dockerfile
# Используем минимальный базовый образ
FROM node:18-alpine
# Обновляем пакеты для устранения уязвимостей
RUN apk update && apk upgrade && \
apk add --no-cache dumb-init && \
rm -rf /var/cache/apk/*
# Создаем непривилегированного пользователя
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
# Устанавливаем рабочую директорию
WORKDIR /app
# Копируем только файлы зависимостей для кэширования
COPY package*.json ./
# Устанавливаем только production зависимости
RUN npm ci --only=production && \
npm cache clean --force && \
npm audit fix
# Копируем исходный код
COPY --chown=nextjs:nodejs . .
# Удаляем ненужные файлы
RUN rm -rf .git .gitignore README.md
# Переключаемся на непривилегированного пользователя
USER nextjs
# Используем init процесс для правильной обработки сигналов
ENTRYPOINT ["dumb-init", "--"]
# Указываем команду запуска
CMD ["npm", "start"]
# Открываем только необходимый порт
EXPOSE 3000
# Добавляем health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Добавляем метки для трекинга
LABEL org.opencontainers.image.source="https://github.com/user/repo"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.created="2025-06-11"
Автоматическое сканирование с Trivy
# Сканирование локального образа trivy image myapp:latest # Сканирование с выводом только критических уязвимостей trivy image --severity HIGH,CRITICAL myapp:latest # Сканирование с сохранением в файл trivy image --format json --output results.json myapp:latest # Сканирование файловой системы trivy fs . # Сканирование Kubernetes манифестов trivy config k8s/ # Сканирование Terraform файлов trivy config terraform/
🛠️ Практические задания
Задание 11.1: Настройка security scanning в CI/CD
# 1. Создание проекта с уязвимостями для демонстрации
mkdir devsecops-demo
cd devsecops-demo
# 2. Создание package.json с уязвимыми зависимостями
cat > package.json << 'EOF'
{
"name": "devsecops-demo",
"version": "1.0.0",
"dependencies": {
"express": "4.16.0",
"lodash": "4.17.4",
"moment": "2.19.0"
}
}
EOF
# 3. Создание простого приложения
cat > app.js << 'EOF'
const express = require('express');
const _ = require('lodash');
const moment = require('moment');
const app = express();
app.use(express.json());
// Уязвимый endpoint (SQL injection)
app.get('/user/:id', (req, res) => {
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
// Это уязвимо к SQL injection!
res.json({ query, message: 'This is vulnerable!' });
});
// Секрет в коде (плохая практика)
const API_KEY = "sk-1234567890abcdef";
const DB_PASSWORD = "password123";
app.listen(3000, () => {
console.log('Server running on port 3000');
});
EOF
# 4. Создание GitHub Actions workflow (используйте пример выше)
mkdir -p .github/workflows
# Скопируйте security.yml из примера выше
Задание 11.2: Установка и настройка Vault
# 1. Установка Vault
wget https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip
unzip vault_1.15.0_linux_amd64.zip
sudo mv vault /usr/local/bin/
# 2. Создание конфигурации Vault
cat > vault-config.hcl << 'EOF'
storage "file" {
path = "./vault-data"
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = true
}
ui = true
EOF
# 3. Инициализация Vault
vault server -config=vault-config.hcl &
export VAULT_ADDR='http://127.0.0.1:8200'
# Инициализация (сохраните ключи!)
vault operator init
# Разблокировка Vault (используйте 3 ключа из вывода init)
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>
# 4. Настройка секретов приложения
vault auth <root-token>
# Включение KV секретов
vault secrets enable -path=secret kv-v2
# Сохранение секретов
vault kv put secret/myapp/database \
username="dbuser" \
password="secure-password-123"
vault kv put secret/myapp/api \
key="sk-secure-api-key-456" \
url="https://api.example.com"
Задание 11.3: Сканирование безопасности
# 1. Установка инструментов сканирования # Trivy curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # TruffleHog для поиска секретов pip install truffleHog # 2. Сканирование проекта # Поиск секретов в Git истории truffleHog --regex --entropy=False . # Сканирование зависимостей npm audit # Сканирование Docker образа docker build -t vulnerable-app . trivy image vulnerable-app # 3. Создание отчета безопасности cat > security-scan.sh << 'EOF' #!/bin/bash echo "=== Security Scan Report ===" echo "Date: $(date)" echo echo "=== Dependency Vulnerabilities ===" npm audit --json > npm-audit.json cat npm-audit.json | jq '.vulnerabilities | length' echo "=== Secret Scanning ===" truffleHog --regex --entropy=False . > secrets-report.txt cat secrets-report.txt echo "=== Container Scanning ===" trivy image --format json vulnerable-app > container-scan.json cat container-scan.json | jq '.Results[].Vulnerabilities | length' EOF chmod +x security-scan.sh ./security-scan.sh
Задание 11.4: Network Security в Kubernetes
# network-policies.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
- to: [] # DNS разрешение
ports:
- protocol: UDP
port: 53
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
🔍 Мониторинг безопасности
Falco для обнаружения аномалий
# falco-deployment.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: falco
namespace: falco-system
spec:
selector:
matchLabels:
app: falco
template:
metadata:
labels:
app: falco
spec:
serviceAccount: falco
hostNetwork: true
hostPID: true
containers:
- name: falco
image: falcosecurity/falco:latest
securityContext:
privileged: true
args:
- /usr/bin/falco
- --cri=/run/containerd/containerd.sock
- --k8s-api=https://kubernetes.default:443
volumeMounts:
- name: dev
mountPath: /host/dev
- name: proc
mountPath: /host/proc
- name: boot
mountPath: /host/boot
- name: lib-modules
mountPath: /host/lib/modules
- name: usr
mountPath: /host/usr
- name: etc
mountPath: /host/etc
volumes:
- name: dev
hostPath:
path: /dev
- name: proc
hostPath:
path: /proc
- name: boot
hostPath:
path: /boot
- name: lib-modules
hostPath:
path: /lib/modules
- name: usr
hostPath:
path: /usr
- name: etc
hostPath:
path: /etc
Пользовательские правила Falco
# custom-rules.yaml
- rule: Suspicious Network Activity
desc: Detect suspicious network connections
condition: >
spawned_process and
proc.name in (nc, ncat, netcat) and
not proc.args contains "-l"
output: >
Suspicious network activity detected
(user=%user.name command=%proc.cmdline container=%container.name)
priority: WARNING
- rule: Unauthorized File Access
desc: Detect access to sensitive files
condition: >
open_read and
fd.name in (/etc/passwd, /etc/shadow, /etc/hosts) and
not proc.name in (systemd, sshd)
output: >
Unauthorized access to sensitive file
(user=%user.name file=%fd.name proc=%proc.name container=%container.name)
priority: CRITICAL
📊 Compliance и аудит
CIS Kubernetes Benchmark
# Установка kube-bench kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml # Просмотр результатов kubectl logs job.batch/kube-bench # Сохранение отчета kubectl logs job.batch/kube-bench > cis-benchmark-report.txt # Проверка соответствия с kube-score kubectl score deployment.yaml
Policy as Code с Open Policy Agent
# security-policies.rego
package kubernetes.security
# Запрет запуска контейнеров от root
deny[msg] {
input.kind == "Pod"
input.spec.securityContext.runAsUser == 0
msg := "Containers must not run as root user"
}
# Обязательное использование read-only root filesystem
deny[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem
msg := sprintf("Container %s must have read-only root filesystem", [container.name])
}
# Запрет privileged контейнеров
deny[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Container %s cannot run in privileged mode", [container.name])
}
# Обязательные resource limits
deny[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container %s must have memory limits", [container.name])
}
# Запрет использования latest тегов
deny[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Container %s must not use 'latest' tag", [container.name])
}
📖 Полезные ресурсы
- OWASP DevSecOps Guideline — практики безопасности в DevOps
- NIST Cybersecurity Framework — стандарты кибербезопасности
- CIS Controls — критичные контроли безопасности
- YouTube: "DevSecOps: безопасность в CI/CD" — практические видеоуроки
- Awesome DevSecOps — коллекция инструментов и ресурсов
✅ Чек-лист модуля
- Понимаю принципы DevSecOps и Shift Left Security
- Настроил автоматическое сканирование безопасности в CI/CD
- Интегрировал проверку секретов с TruffleHog
- Добавил сканирование зависимостей с Snyk
- Настроил сканирование Docker образов с Trivy
- Установил и настроил HashiCorp Vault
- Создал безопасные Dockerfile согласно best practices
- Настроил Network Policies в Kubernetes
- Изучил мониторинг безопасности с Falco
- Понимаю основы compliance и Policy as Code
🚀 Что дальше?
После освоения DevSecOps переходите к Финальному проекту, где объедините все изученные навыки для создания полноценной DevOps инфраструктуры с интегрированной безопасностью.