Files
K3S/docs/security.md
Sergey Antropoff eccc1c2a01 docs: полная документация проекта — docs/ и README.md для каждого аддона
- README.md: перепиcан как компактный обзор (98 строк) с навигацией по docs/
- docs/: 13 файлов — getting-started, architecture, configuration, addons,
  storage, security, cicd, observability, networking, operations,
  make-reference, molecule-testing, troubleshooting
- addons/*/README.md: 31 новый файл — описание, параметры, примеры кода
  для каждого из 34 аддонов (vault и external-secrets уже существовали)
2026-04-26 00:22:06 +03:00

7.1 KiB
Raw Blame History

Безопасность

Стек безопасности: HashiCorp Vault, External Secrets Operator, CrowdSec, Vaultwarden.

HashiCorp Vault

Централизованное управление секретами, PKI, динамические credentials. Подробный README: addons/vault/README.md.

Быстрый старт

# group_vars/all/addons.yml
addon_vault: true

vault_mode: "standalone"            # standalone | ha
vault_auto_unseal_type: "none"      # none | k8s | aws | gcp | azure | transit
vault_injector_enabled: true        # Vault Agent Injector
vault_ingress_host: "vault-hc.example.com"
vault_ingress_tls: true
make addon-vault

Режимы auto-unseal

Тип Описание Где хранятся ключи
none Ручной unseal при каждом рестарте Нигде — только у оператора
k8s Ключи в Kubernetes Secret + unsealer Pod Secret vault-unseal-keys
aws AWS KMS AWS KMS ключ
gcp Google Cloud KMS GCP KMS ключ
azure Azure Key Vault Azure Key Vault
transit Другой Vault (transit engine) Другой Vault

Для homelab рекомендуется k8s:

vault_auto_unseal_type: "k8s"
vault_auto_unseal_k8s_shares: 5
vault_auto_unseal_k8s_threshold: 3

HA режим (3 ноды, Raft)

vault_mode: "ha"
vault_ha_replicas: 3
vault_auto_unseal_type: "k8s"   # обязателен для HA

Инициализация (первый запуск)

После установки Ansible автоматически:

  1. Инициализирует Vault (vault operator init)
  2. Сохраняет ключи unseal в Secret (при vault_auto_unseal_type: k8s)
  3. Unseals Vault
  4. Выводит root token

Vault Agent Injector — инжекция секретов в поды

# Аннотации на Pod/Deployment:
annotations:
  vault.hashicorp.com/agent-inject: "true"
  vault.hashicorp.com/role: "my-app"
  vault.hashicorp.com/agent-inject-secret-config.env: "secret/myapp/config"
  vault.hashicorp.com/agent-inject-template-config.env: |
    {{- with secret "secret/myapp/config" -}}
    DB_PASSWORD={{ .Data.data.db_password }}
    API_KEY={{ .Data.data.api_key }}
    {{- end }}

Секрет будет доступен в поде как /vault/secrets/config.env.

Kubernetes Auth Method

# Включить Kubernetes auth в Vault:
vault auth enable kubernetes

vault write auth/kubernetes/config \
  token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
  kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

# Создать роль:
vault write auth/kubernetes/role/my-app \
  bound_service_account_names=my-app \
  bound_service_account_namespaces=my-app \
  policies=my-app-policy \
  ttl=24h

Helm чарты с Vault секретами

# Chart values через External Secrets (рекомендуется)
# или через Vault Agent annotations на Pod

# Прямой pull из Vault (в init container):
initContainers:
  - name: vault-auth
    image: vault:latest
    command:
      - sh
      - -c
      - |
        vault login -method=kubernetes role=my-app
        vault kv get -field=password secret/myapp/db > /vault/secrets/db-password
    env:
      - name: VAULT_ADDR
        value: "http://vault.vault.svc.cluster.local:8200"
    volumeMounts:
      - name: vault-secrets
        mountPath: /vault/secrets

External Secrets Operator

Синхронизирует секреты из Vault в Kubernetes Secrets автоматически. Подробный README: addons/external-secrets/README.md.

Быстрый старт

addon_external_secrets: true
addon_vault: true   # рекомендуется — ESO настраивается на Vault автоматически

external_secrets_vault_url: "http://vault.vault.svc.cluster.local:8200"
external_secrets_vault_role_id: "xxx"   # после создания AppRole в Vault

Секрет в vault.yml:

vault_eso_approle_secret_id: "xxx"

Создать AppRole в Vault

vault auth enable approle

vault policy write eso-policy - <<EOF
path "secret/data/*" {
  capabilities = ["read"]
}
EOF

vault write auth/approle/role/eso-role \
  token_policies="eso-policy" \
  token_ttl=1h \
  token_max_ttl=4h

vault read auth/approle/role/eso-role/role-id
vault write -f auth/approle/role/eso-role/secret-id

ExternalSecret — синхронизировать секрет

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: my-app-secrets
  namespace: my-app
spec:
  refreshInterval: 1m
  secretStoreRef:
    name: vault-backend    # ClusterSecretStore
    kind: ClusterSecretStore
  target:
    name: my-app-secret    # имя Kubernetes Secret
    creationPolicy: Owner
  data:
    - secretKey: db-password
      remoteRef:
        key: secret/myapp
        property: db_password
    - secretKey: api-key
      remoteRef:
        key: secret/myapp
        property: api_key

Использование в Deployment:

env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-app-secret
        key: db-password

CrowdSec

IDS/IPS система обнаружения вторжений. Анализирует логи ingress-nginx. Подробнее: addons/crowdsec/README.md.

addon_crowdsec: true
crowdsec_nginx_bouncer_enabled: true   # блокировать IP через nginx

Vaultwarden

Self-hosted менеджер паролей (Bitwarden-совместимый). Подробнее: addons/vaultwarden/README.md.

addon_vaultwarden: true
vaultwarden_domain: "https://vault.example.com"
vaultwarden_signups_allowed: false

Общие рекомендации

Network Policies (Calico/Cilium)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: my-app
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-nginx
  namespace: my-app
spec:
  podSelector:
    matchLabels:
      app: my-app
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - port: 8080

Pod Security Standards

# Namespace с restricted policy:
apiVersion: v1
kind: Namespace
metadata:
  name: secure-app
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted

Non-root контейнеры

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 1000
  containers:
    - securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: [ALL]