Vault - Kulichanin/speedtest GitHub Wiki

Vault

Storing application secrets

Проблема! Есть много данных, которые необходимо передать в вертуальное окружение для работы сервиса должным образом. Секреты хроняться сейчас в Secret k8s.

Все секреты должны быть переданы зарнее и если их большой список их надо автоматизировать в helm. Также не нравится что они храняться в base64 в деплое

Лучше изменить ширование и передавать их из единой точки хранения. Подробнее

Решение! Для решения подходит vault или Helm Secrets

Install vault

install of programs74

install of dmosk

Before you start

You must have a valid Vault binary.

CentOS/RHEL

But this content is not currently available in your region!

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install vault

Download binary file

wget https://releases.hashicorp.com/vault/1.18.3/vault_1.18.3_linux_amd64.zip

install of Manually install a Vault binary

Configure the environment

export VAULT_DATA=/opt/vault/data
export VAULT_CONFIG=/etc/vault.d

Preparing binary file

sudo mv PATH/TO/VAULT/BINARY /usr/bin/
sudo setcap cap_ipc_lock=+ep $(readlink -f $(which vault))

Create directory for vault

sudo mkdir -p ${VAULT_DATA}
sudo mkdir -p ${VAULT_CONFIG}

Create user for vault

sudo useradd --system --home ${VAULT_DATA} --shell /sbin/nologin vault
sudo chown vault:vault ${VAULT_DATA}
sudo chmod -R 750 ${VAULT_DATA}

Create a basic configuration file

sudo tee ${VAULT_CONFIG}/vault.hcl <<EOF
 ui            = true
 cluster_addr  = "http://127.0.0.1:8201"
 api_addr      = "https://127.0.0.1:8200"
 disable_mlock = true

 storage "raft" {
   path    = "${VAULT_DATA}"
   node_id = "127.0.0.1"
 }

 listener "tcp" {
   address       = "0.0.0.0:8200"
   cluster_address = "0.0.0.0:8201"
   tls_disable = 1
 }
EOF

Change ownership and permissions on the Vault configuration file.

sudo chown vault:vault "${VAULT_CONFIG}/vault.hcl" && \
sudo chmod 640 "${VAULT_CONFIG}/vault.hcl"

For homelabe

Adding an option to skip certificate verification is a more acceptable option because The connection remains encrypted, but the certificate is not verified.

echo "VAULT_API_ADDR=https://127.0.0.1:8200" > /etc/vault.d/vault.env
echo "VAULT_API_SKIP_VERIFY=true" >> /etc/vault.d/vault.env
sudo chown vault:vault "${VAULT_CONFIG}/vault.env" && \
sudo chmod 640 "${VAULT_CONFIG}/vault.env"

Run Vault as a service

Confirm the path to your Vault binary: VAULT_BINARY=$(which vault)

sudo tee /lib/systemd/system/vault.service <<EOF
[Unit]
Description="HashiCorp Vault"
Documentation="https://developer.hashicorp.com/vault/docs"
ConditionFileNotEmpty="${VAULT_CONFIG}/vault.hcl"

[Service]
User=vault
Group=vault
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=${VAULT_BINARY} server -config=${VAULT_CONFIG}/vault.hcl
ExecReload=/bin/kill --signal HUP
KillMode=process
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target
EOF

Change permision

sudo chmod 644 /lib/systemd/system/vault.service

CentOS/RHEL install selinux policies

sudo sed -i "s/SELINUX=enforcing/SELINUX=permissive/" /etc/selinux/config
sudo setenforce 0
sudo systemctl daemon-reload
sudo systemctl start vault.service
sudo systemctl status vault.service

Change permission firewall

Ubuntu/Debian

sudo iptables -I INPUT -p tcp --dport 8200 -j ACCEPT

CentOS/RHEL

sudo firewall-cmd --permanent --add-port=8200/tcp
sudo firewall-cmd --reload 

Configuration vault server

После установки, сервер Vault находится в запечатанном (sealed) состоянии. То есть, он не знает, как ему расшифровывать секреты, которые будут храниться в базе.

При попытке выполнить любую операцию с хранилищем секретов мы получим ошибку: Vault is sealed

Теперь нам нужно инициировать Vault и создать мастер-ключ и секретное хранилище, для этого используется команда

vault operator init

ВАЖНО! Не вводите ключ в качестве аргумента команды vault operator unseal, т.к. он сохраниться в истории bash и это может очень негативно сказаться на безопасности!

НЕ ДЕЛАЙТЕ ТАК!

vault operator unseal 4v8A0s4aHJ9cyywmeKTJnTeS2liP3OYY/MQGPz0KGSv1

Create vault secret

Перед началом работы настройки интеграции Kubernetes с Vault необходимо создать файлы с секретом и политики работы с ним.

Создадим секрет V2 для работы с ним.

export VAULT_ADDR=http://x.x.x.x:8200/
vault login
vault secrets enable -path=kvv2 kv-v2

Vault при успехе команды вернет положительный ответ

Success! Enabled the kv-v2 secrets engine at: kvv2/

Теперь в простар секрета kvv2 можно записать секреты

Например:

vault kv put kvv2/app/config username="static-user" password="static-password"

Vault при успехе команды вернет положительный ответ

==== Secret Path ====
kvv2/data/app/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-02-10T12:58:02.143452289Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

Определим политику взаимодействия с этим секретом

В данном случае для файла config в каталоге app создадим правило для чтения и просмотра списка. Больше про политики тут

tee app.json <<EOF
path "kvv2/data/app/config" {
   capabilities = ["read", "list"]
}
EOF
vault policy write app app.json

Integration with Kubernetes

Существует 3 способа интегрировать Vault в Kubernetes

Before start Vault integration

Для того чтобы создать интеграцию любым из этих методов необходимо создать аккаунт в Kubernetes для взаимодействия с Vault

Create user for connect vault

Создайте serviceaccount vault с привязкой secret и cluster role binding в пространстве имен default.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault
  namespace: default
---
apiVersion: v1
kind: Secret
metadata:
  name: vault
  namespace: default
  annotations:
    kubernetes.io/service-account.name: vault
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: role-tokenreview-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
  - kind: ServiceAccount
    name: vault
    namespace: default

Configure Kubernetes authentication with vault

Включите метод аутентификации Kubernetes.

vault auth enable kubernetes

Получите веб-токен JSON (JWT) из секрета.

TOKEN_REVIEW_JWT=$(kubectl get secret vault --output='go-template={{ .data.token }}' | base64 --decode)

Получите сертификат CA Kubernetes.

KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)

Получите URL-адрес хоста Kubernetes.

KUBE_HOST=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')

Создайте в vault аунтефикацию и именем vault с типом kubernetes

vault auth enable -path=vault kubernetes

Настройте метод аутентификации Kubernetes для использования токена учетной записи службы, местоположения узла Kubernetes, его сертификата и имени эмитента учетной записи службы.

vault write auth/vault/config \
  token_reviewer_jwt="$TOKEN_REVIEW_JWT" \
  kubernetes_host="$KUBE_HOST" \
  kubernetes_ca_cert="$KUBE_CA_CERT" \
  disable_issuer_verification=true

Привяжем политику app, которая будет опредена для секретов, с помощью serviceaccount vault kubernetes в пространстве kubernetes default

vault write auth/vault/role/role1 \
  bound_service_account_names=vault \
  bound_service_account_namespaces=default \
  policies=app \
  audience=vault \
  ttl=24h

Vault integration via Sidecar Agent Injector

Подробная информация настройки тут

Как пользоваться тут

Install the Vault Helm chart configured to address an external Vault

Clone repo with vault helm

git clone https://github.com/hashicorp/vault-helm.git && cd vault-helm

Install the Vault Helm chart

helm install vault ./vault-helm  --set "global.externalVaultAddr=http://external-vault:8200"

Use secret with app in Kubernetes

Add metadata annotations

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        vault.hashicorp.com/agent-inject: 'true'
        vault.hashicorp.com/role: 'app'
        vault.hashicorp.com/agent-inject-secret-config.env: 'kvv2/data/app/config'
        vault.hashicorp.com/agent-inject-template-config.env: |
          {{- with secret "kvv2/data/app/config" }}
              {{- range $k, $v := .Data -}}
                  {{ $k | nindent 0}}={{ $v }}
              {{- end }}
          {{- end }}
    spec:
      serviceAccountName: vault
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

About SAI

Метод рабочий, но не умет работать с k8s Secret, а значит выдать данные в env пода не возможно! Работает только определение в файл. Надо иметь ввиду это при разработке.

Также не работают динамические секреты!

Vault integration via Vault CSI provider

Подробная доку тут

Как настраивать:

  1. Использование HashiCorp Vault для хранения секретов
  2. Секреты в kubernetes используя Hashicorp Vault + External Secrets Operator
  3. Manage your Kubernetes secrets with Hashicorp Vault
  4. Configure Hashicorp's Vault for Kubernetes Auth

About CSI provider

Он является решение, которое работает с External Secrets Operator

Vault integration via Vault Secrets Operator

Подробный гайд

Install Vault Secrets Operator with helm

Скопируем резиторий VSO

git clone https://github.com/hashicorp/vault-secrets-operator.git

Изменим vault-secrets-operator/chart/values.yaml

/:567

defaultVaultConnection:
  enabled: true
  address: "http://external-vault::8200"
  skipTLSVerify: false

Установка

helm install vault-secrets-operator vault-secrets-operator/chart -n vault-secrets-operator-system --create-namespace -f vault-secrets-operator/chart/values.yaml

Set up Kubernetes authentication for the secret

Создадим ресурсы для авторизации и взаимодействия с vault vault-auth-static.yaml

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: static-auth
  namespace: default
spec:
  method: kubernetes
  mount: vault
  kubernetes:
    role: role1
    serviceAccount: vault
    audiences:
      - vault

Применем политику

kubectl apply -f vault-auth-static.yaml

В случае успеха вывод команды вернет положительный ответ

kubectl get vaultauth static-auth -o json | jq .status
{
  "specHash": "xxxx",
  "valid": true
}

Создайте VaultStaticSecret с именем, который создаст secretkv в пространстве имен по default.

static-secret.yaml

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: vault-kv-vso
  namespace: default
spec:
  type: kv-v2

  # mount path
  mount: kvv2

  # path of the secret
  path: app/config

  # dest k8s secret
  destination:
    name: secretkv
    create: true

  # static secret refresh interval
  refreshAfter: 30s

  # Name of the CRD to authenticate to Vault
  vaultAuthRef: static-auth

Применем static-secret.yaml

kubectl apply -f static-secret.yaml 

Просмотрим секрет

kubectl describe secret secretkv
Name:         secretkv
Namespace:    default
Labels:       app.kubernetes.io/component=secret-sync
              app.kubernetes.io/managed-by=hashicorp-vso
              app.kubernetes.io/name=vault-secrets-operator
              secrets.hashicorp.com/vso-ownerRefUID=21e82006-c4cc-4b78-b486-4fb781217708
Annotations:  <none>

Type:  Opaque

Data
====
_raw:      197 bytes
password:  15 bytes
username:  11 bytes
⚠️ **GitHub.com Fallback** ⚠️