#!/usr/bin/env sh set -eu log() { echo "[vault-k8s-auth] $*"; } ensure_token() { if [ -n "${VAULT_TOKEN:-}" ]; then return fi role="${VAULT_K8S_ROLE:-vault}" jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" if ! VAULT_TOKEN="$(vault write -field=token auth/kubernetes/login role="${role}" jwt="${jwt}")"; then log "kubernetes auth login failed; set VAULT_TOKEN or fix role ${role}" exit 1 fi export VAULT_TOKEN } status_json="$(vault status -format=json || true)" if [ -z "${status_json}" ]; then log "vault status failed; check VAULT_ADDR and VAULT_TOKEN" exit 1 fi if ! printf '%s' "${status_json}" | grep -q '"initialized":[[:space:]]*true'; then log "vault not initialized; skipping" exit 0 fi if printf '%s' "${status_json}" | grep -q '"sealed":[[:space:]]*true'; then log "vault sealed; skipping" exit 0 fi ensure_token k8s_host="https://${KUBERNETES_SERVICE_HOST}:443" k8s_ca="$(cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt)" k8s_token="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" role_ttl="${VAULT_K8S_ROLE_TTL:-1h}" token_reviewer_jwt="${VAULT_K8S_TOKEN_REVIEWER_JWT:-}" if [ -z "${token_reviewer_jwt}" ] && [ -n "${VAULT_K8S_TOKEN_REVIEWER_JWT_FILE:-}" ] && [ -r "${VAULT_K8S_TOKEN_REVIEWER_JWT_FILE}" ]; then token_reviewer_jwt="$(cat "${VAULT_K8S_TOKEN_REVIEWER_JWT_FILE}")" fi if [ -z "${token_reviewer_jwt}" ]; then token_reviewer_jwt="${k8s_token}" fi if ! vault auth list -format=json | grep -q '"kubernetes/"'; then log "enabling kubernetes auth" vault auth enable kubernetes fi log "configuring kubernetes auth" vault write auth/kubernetes/config \ token_reviewer_jwt="${token_reviewer_jwt}" \ kubernetes_host="${k8s_host}" \ kubernetes_ca_cert="${k8s_ca}" write_raw_policy() { name="$1" body="$2" log "writing policy ${name}" printf '%s\n' "${body}" | vault policy write "${name}" - } write_policy_and_role() { role="$1" namespace="$2" service_accounts="$3" read_paths="$4" write_paths="$5" policy_body="" for path in ${read_paths}; do policy_body="${policy_body} path \"kv/data/atlas/${path}\" { capabilities = [\"read\"] } path \"kv/metadata/atlas/${path}\" { capabilities = [\"list\"] } " done for path in ${write_paths}; do policy_body="${policy_body} path \"kv/data/atlas/${path}\" { capabilities = [\"create\", \"update\", \"read\"] } path \"kv/metadata/atlas/${path}\" { capabilities = [\"list\"] } " done log "writing policy ${role}" printf '%s\n' "${policy_body}" | vault policy write "${role}" - log "writing role ${role}" vault write "auth/kubernetes/role/${role}" \ bound_service_account_names="${service_accounts}" \ bound_service_account_namespaces="${namespace}" \ policies="${role}" \ ttl="${role_ttl}" } vault_admin_policy=' path "sys/auth" { capabilities = ["read"] } path "sys/auth/*" { capabilities = ["create", "update", "delete", "sudo", "read"] } path "auth/kubernetes/*" { capabilities = ["create", "update", "read"] } path "auth/oidc/*" { capabilities = ["create", "update", "read"] } path "sys/policies/acl" { capabilities = ["list"] } path "sys/policies/acl/*" { capabilities = ["create", "update", "read"] } path "sys/internal/ui/mounts" { capabilities = ["read"] } path "sys/mounts" { capabilities = ["read"] } path "sys/mounts/auth/*" { capabilities = ["read", "update", "sudo"] } path "kv/data/atlas/vault/*" { capabilities = ["read"] } path "kv/metadata/atlas/vault/*" { capabilities = ["list"] } path "kv/data/*" { capabilities = ["create", "update", "read", "delete", "patch"] } path "kv/metadata" { capabilities = ["list"] } path "kv/metadata/*" { capabilities = ["read", "list", "delete"] } path "kv/data/atlas/shared/*" { capabilities = ["create", "update", "read", "patch"] } path "kv/metadata/atlas/shared/*" { capabilities = ["list"] } ' write_raw_policy "vault-admin" "${vault_admin_policy}" dev_kv_policy=' path "kv/metadata" { capabilities = ["list"] } path "kv/metadata/atlas" { capabilities = ["list"] } path "kv/metadata/atlas/shared" { capabilities = ["list"] } path "kv/metadata/atlas/shared/*" { capabilities = ["list"] } path "kv/data/atlas/shared/*" { capabilities = ["read"] } ' write_raw_policy "dev-kv" "${dev_kv_policy}" log "writing role vault-admin" vault write "auth/kubernetes/role/vault-admin" \ bound_service_account_names="vault-admin" \ bound_service_account_namespaces="vault" \ policies="vault-admin" \ ttl="${role_ttl}" write_policy_and_role "outline" "outline" "outline-vault" \ "outline/* shared/postmark-relay" "" write_policy_and_role "planka" "planka" "planka-vault" \ "planka/* shared/postmark-relay" "" write_policy_and_role "bstein-dev-home" "bstein-dev-home" "bstein-dev-home,bstein-dev-home-vault-sync" \ "portal/* shared/chat-ai-keys-runtime shared/portal-e2e-client harbor-pull/bstein-dev-home" "" write_policy_and_role "gitea" "gitea" "gitea-vault" \ "gitea/*" "" write_policy_and_role "vaultwarden" "vaultwarden" "vaultwarden-vault" \ "vaultwarden/* shared/postmark-relay" "" write_policy_and_role "sso" "sso" "sso-vault,sso-vault-sync,mas-secrets-ensure" \ "sso/* portal/bstein-dev-home-keycloak-admin shared/keycloak-admin shared/portal-e2e-client shared/postmark-relay harbor-pull/sso" "" write_policy_and_role "mailu-mailserver" "mailu-mailserver" "mailu-vault-sync" \ "mailu/* shared/postmark-relay harbor-pull/mailu-mailserver" "" write_policy_and_role "harbor" "harbor" "harbor-vault-sync" \ "harbor/* harbor-pull/harbor" "" write_policy_and_role "nextcloud" "nextcloud" "nextcloud-vault" \ "nextcloud/* shared/keycloak-admin shared/postmark-relay" "" write_policy_and_role "comms" "comms" "comms-vault,atlasbot" \ "comms/* shared/chat-ai-keys-runtime harbor-pull/comms" "" write_policy_and_role "jenkins" "jenkins" "jenkins" \ "jenkins/*" "" write_policy_and_role "monitoring" "monitoring" "monitoring-vault-sync" \ "monitoring/* shared/postmark-relay harbor-pull/monitoring" "" write_policy_and_role "logging" "logging" "logging-vault-sync" \ "logging/* harbor-pull/logging" "" write_policy_and_role "pegasus" "jellyfin" "pegasus-vault-sync" \ "pegasus/* harbor-pull/jellyfin" "" write_policy_and_role "crypto" "crypto" "crypto-vault-sync" \ "crypto/* harbor-pull/crypto" "" write_policy_and_role "health" "health" "health-vault-sync" \ "health/*" "" write_policy_and_role "longhorn" "longhorn-system" "longhorn-vault" \ "longhorn/*" "" write_policy_and_role "postgres" "postgres" "postgres-vault" \ "postgres/postgres-db" "" write_policy_and_role "vault" "vault" "vault" \ "vault/*" "" write_policy_and_role "sso-secrets" "sso" "mas-secrets-ensure" \ "shared/keycloak-admin" \ "harbor/harbor-oidc vault/vault-oidc-config comms/synapse-oidc logging/oauth2-proxy-logs-oidc" write_policy_and_role "crypto-secrets" "crypto" "crypto-secrets-ensure" \ "" \ "crypto/wallet-monero-temp-rpc-auth" write_policy_and_role "comms-secrets" "comms" \ "comms-secrets-ensure,mas-db-ensure,mas-admin-client-secret-writer,othrys-synapse-signingkey-job" \ "" \ "comms/turn-shared-secret comms/livekit-api comms/synapse-redis comms/synapse-macaroon comms/atlasbot-credentials-runtime comms/synapse-db comms/mas-db comms/mas-admin-client-runtime comms/mas-secrets-runtime comms/othrys-synapse-signingkey"