Files
K3S/docs/security.md
Sergey Antropoff 38aaadbfb1 docs: sync addon docs with explicit external/internal service modes
Обновлена документация под новые аддоны (gitlab, redis, mongodb, kafka, kafka-ui, rabbitmq) и новую модель явного выбора зависимостей. Добавлены и унифицированы описания переключателей *_database_mode и *_redis_mode, обновлена таблица зависимостей аддонов, примеры конфигурации и список vault-секретов.
2026-04-29 23:21:04 +03:00

383 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Безопасность
Стек безопасности: HashiCorp Vault, External Secrets Operator, CrowdSec, Vaultwarden.
## HashiCorp Vault
Централизованное управление секретами, PKI, динамические credentials. Подробный README: [addons/vault/README.md](../addons/vault/README.md).
### Быстрый старт
```yaml
# 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
```
```bash
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`:
```yaml
vault_auto_unseal_type: "k8s"
vault_auto_unseal_k8s_shares: 5
vault_auto_unseal_k8s_threshold: 3
```
### HA режим (3 ноды, Raft)
```yaml
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 — инжекция секретов в поды
```yaml
# Аннотации на 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`.
### Примеры: как подключать env в манифесты из HashiCorp Vault
#### Вариант 1 — Vault Agent Injector + `source /vault/secrets/*.env`
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-injector
namespace: my-app
spec:
replicas: 1
selector:
matchLabels:
app: app-with-injector
template:
metadata:
labels:
app: app-with-injector
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "my-app"
vault.hashicorp.com/agent-inject-secret-app.env: "secret/data/myapp/config"
vault.hashicorp.com/agent-inject-template-app.env: |
{{- with secret "secret/data/myapp/config" -}}
DB_PASSWORD={{ .Data.data.db_password }}
API_KEY={{ .Data.data.api_key }}
{{- end }}
spec:
serviceAccountName: my-app
containers:
- name: app
image: ghcr.io/example/app:latest
command: ["/bin/sh", "-c"]
args:
- |
set -a
. /vault/secrets/app.env
set +a
exec /app/start
```
#### Вариант 2 — Vault → ExternalSecret → `envFrom.secretRef`
```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-env
namespace: my-app
spec:
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: app-env
data:
- secretKey: DB_PASSWORD
remoteRef:
key: secret/myapp
property: db_password
- secretKey: API_KEY
remoteRef:
key: secret/myapp
property: api_key
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-envfrom
namespace: my-app
spec:
template:
spec:
containers:
- name: app
image: ghcr.io/example/app:latest
envFrom:
- secretRef:
name: app-env
```
#### Вариант 3 — отдельные env-переменные через `secretKeyRef`
```yaml
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-env
key: DB_PASSWORD
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-env
key: API_KEY
```
### Kubernetes Auth Method
```bash
# Включить 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 секретами
```yaml
# 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](../addons/external-secrets/README.md).
### Быстрый старт
```yaml
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`:
```yaml
vault_eso_approle_secret_id: "xxx"
```
### Создать AppRole в Vault
```bash
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 — синхронизировать секрет
```yaml
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:
```yaml
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secret
key: db-password
```
---
## CrowdSec
IDS/IPS система обнаружения вторжений. Анализирует логи ingress-nginx. Подробнее: [addons/crowdsec/README.md](../addons/crowdsec/README.md).
```yaml
addon_crowdsec: true
crowdsec_nginx_bouncer_enabled: true # блокировать IP через nginx
```
---
## Vaultwarden
Self-hosted менеджер паролей (Bitwarden-совместимый). Подробнее: [addons/vaultwarden/README.md](../addons/vaultwarden/README.md).
```yaml
addon_vaultwarden: true
vaultwarden_domain: "https://vault.example.com"
vaultwarden_signups_allowed: false
```
---
## Общие рекомендации
### Network Policies (Calico/Cilium)
```yaml
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
```yaml
# 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 контейнеры
```yaml
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]
```