vault: deployment manifest, some docs, backup script - expected to run

on docker host
This commit is contained in:
Jan Novak
2026-01-14 14:48:09 +01:00
parent b5e1f4b737
commit 90a44bd59f
9 changed files with 214 additions and 0 deletions

35
docker-30/vault/backup.md Normal file
View File

@@ -0,0 +1,35 @@
## vault-cli install
```bash
VAULT_VERSION="1.21.2"
wget https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
unzip vault_${VAULT_VERSION}_linux_amd64.zip
sudo mv vault /usr/local/bin/
```
## minio-cli
```bash
wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /tmp/minio-cli
chmod +x /tmp/minio-cli
sudo mv /tmp/minio-cli /usr/local/bin/minio-cli
minio-cli alias set synology http://192.168.0.2:9000 k8s ----proper secret here----
```
## backup token
```bash
mkdir -p /etc/vault.d/
vault policy write backup - <<EOF
path "sys/storage/raft/snapshot" {
capabilities = ["read"]
}
EOF
vault token create -policy=backup -period=8760h -orphan > /etc/vault.d/backup-token
chmod 600 /etc/vault.d/backup-token
```

View File

@@ -0,0 +1,20 @@
{
"ui": true,
"listener": {
"tcp": {
"address": "0.0.0.0:8200",
"tls_disable": "1",
"tls_cert_file": "/vault/certs/fullchain.pem",
"tls_key_file": "/vault/certs/privkey.pem"
}
},
"backend": {
"file": {
"path": "/vault/data/file"
}
},
"default_lease_ttl": "168h",
"max_lease_ttl": "0h",
"api_addr": "https://vault.hrajfrisbee.cz"
// "api_addr": "http://0.0.0.0:8200"
}

View File

@@ -0,0 +1,20 @@
services:
vault:
image: hashicorp/vault:1.21.1
container_name: vault
restart: unless-stopped
cap_add:
- IPC_LOCK
ports:
- 8200:8200
environment:
- VAULT_ADDR=http://0.0.0.0:8200
- VAULT_API_ADDR=http://0.0.0.0:8200
- VAULT_ADDRESS=http://0.0.0.0:8200
volumes:
- ./data:/vault/data
- ./config:/vault/config
- ./logs:/vault/logs
- ./certs:/vault/certs
entrypoint: vault
command: server -config=/vault/config/vault.json -log-level=debug

38
docker-30/vault/readme.md Normal file
View File

@@ -0,0 +1,38 @@
## deployment notes
There was a problem with "production" deployment of Vault through docker container, because default `docker-entrypoint.sh` adds argument saying where dev instance is supposed to listen and then vault crashes because it tries to listen on same port twice.
Solution: override default entrypoint
```bash
# vault helpers
alias set-vault="export VAULT_ADDR=https://docker-30:8200"
alias set-vault-ignore-tls="export VAULT_ADDR=https://docker-30:8200; export VAULT_SKIP_VERIFY=true"
export VAULT_ADDR="https://vault.hrajfrisbee.cz"
export VAULT_SKIP_VERIFY=true
```
## backup
Simple file copy initiated by cron, backend storage is minio (s3) running on synology
```bash
echo '30 2 * * * root /root/bin/vault-backup.sh >> /var/log/vault-backup.log 2>&1' > /etc/cron.d/vault-backup
```
```bash
# output role info
tofu output -raw role_id
tofu output -raw secret_id
```
## vault initialization
```bash
vault operator init -key-shares=1 -key-threshold=1
```

View File

@@ -0,0 +1,49 @@
resource "vault_mount" "kv" {
path = "secret"
type = "kv-v2"
description = "KV v2 secrets engine"
}
resource "vault_policy" "eso_read" {
name = "external-secrets-read"
policy = <<-EOT
path "${vault_mount.kv.path}/data/*" {
capabilities = ["read"]
}
path "${vault_mount.kv.path}/metadata/*" {
capabilities = ["read", "list"]
}
EOT
}
resource "vault_auth_backend" "approle" {
type = "approle"
}
resource "vault_approle_auth_backend_role" "eso" {
backend = vault_auth_backend.approle.path
role_name = "external-secrets"
token_policies = [vault_policy.eso_read.name]
token_ttl = 3600
token_max_ttl = 14400
}
data "vault_approle_auth_backend_role_id" "eso" {
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.eso.role_name
}
resource "vault_approle_auth_backend_role_secret_id" "eso" {
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.eso.role_name
}
output "role_id" {
value = data.vault_approle_auth_backend_role_id.eso.role_id
sensitive = true
}
output "secret_id" {
value = vault_approle_auth_backend_role_secret_id.eso.secret_id
sensitive = true
}

View File

@@ -0,0 +1 @@
{"version":4,"terraform_version":"1.11.2","serial":2,"lineage":"88d0da45-267c-24b8-34e1-c9a1c58ab70f","outputs":{"role_id":{"value":"864e352d-2064-2bf9-2c73-dbd676a95368","type":"string","sensitive":true},"secret_id":{"value":"8dd0e675-f4dc-50ba-6665-3db5ae423702","type":"string","sensitive":true}},"resources":[{"mode":"data","type":"vault_approle_auth_backend_role_id","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"backend":"approle","id":"auth/approle/role/external-secrets/role-id","namespace":null,"role_id":"864e352d-2064-2bf9-2c73-dbd676a95368","role_name":"external-secrets"},"sensitive_attributes":[]}]},{"mode":"managed","type":"vault_approle_auth_backend_role","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"backend":"approle","bind_secret_id":true,"id":"auth/approle/role/external-secrets","namespace":null,"role_id":"864e352d-2064-2bf9-2c73-dbd676a95368","role_name":"external-secrets","secret_id_bound_cidrs":null,"secret_id_num_uses":0,"secret_id_ttl":0,"token_bound_cidrs":null,"token_explicit_max_ttl":0,"token_max_ttl":14400,"token_no_default_policy":false,"token_num_uses":0,"token_period":0,"token_policies":["external-secrets-read"],"token_ttl":3600,"token_type":"default"},"sensitive_attributes":[],"private":"bnVsbA==","dependencies":["vault_auth_backend.approle","vault_mount.kv","vault_policy.eso_read"]}]},{"mode":"managed","type":"vault_approle_auth_backend_role_secret_id","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"accessor":"f20ef8a0-f21f-8c9b-fc38-887a005af763","backend":"approle","cidr_list":null,"id":"backend=approle::role=external-secrets::accessor=f20ef8a0-f21f-8c9b-fc38-887a005af763","metadata":"{}","namespace":null,"num_uses":0,"role_name":"external-secrets","secret_id":"8dd0e675-f4dc-50ba-6665-3db5ae423702","ttl":0,"with_wrapped_accessor":null,"wrapping_accessor":null,"wrapping_token":null,"wrapping_ttl":null},"sensitive_attributes":[[{"type":"get_attr","value":"secret_id"}],[{"type":"get_attr","value":"wrapping_token"}]],"private":"bnVsbA==","dependencies":["vault_approle_auth_backend_role.eso","vault_auth_backend.approle","vault_mount.kv","vault_policy.eso_read"]}]},{"mode":"managed","type":"vault_auth_backend","name":"approle","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":1,"attributes":{"accessor":"auth_approle_409190cb","description":"","disable_remount":false,"id":"approle","identity_token_key":null,"local":false,"namespace":null,"path":"approle","tune":[],"type":"approle"},"sensitive_attributes":[],"private":"eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="}]},{"mode":"managed","type":"vault_mount","name":"kv","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"accessor":"kv_d207dd40","allowed_managed_keys":null,"allowed_response_headers":null,"audit_non_hmac_request_keys":[],"audit_non_hmac_response_keys":[],"default_lease_ttl_seconds":0,"delegated_auth_accessors":null,"description":"KV v2 secrets engine","external_entropy_access":false,"id":"secret","identity_token_key":"","listing_visibility":"","local":false,"max_lease_ttl_seconds":0,"namespace":null,"options":null,"passthrough_request_headers":null,"path":"secret","plugin_version":null,"seal_wrap":false,"type":"kv-v2"},"sensitive_attributes":[],"private":"bnVsbA=="}]},{"mode":"managed","type":"vault_policy","name":"eso_read","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"id":"external-secrets-read","name":"external-secrets-read","namespace":null,"policy":"path \"secret/data/*\" {\n capabilities = [\"read\"]\n}\npath \"secret/metadata/*\" {\n capabilities = [\"read\", \"list\"]\n}\n"},"sensitive_attributes":[],"private":"bnVsbA==","dependencies":["vault_mount.kv"]}]}],"check_results":null}

View File

@@ -0,0 +1 @@
{"version":4,"terraform_version":"1.11.2","serial":1,"lineage":"88d0da45-267c-24b8-34e1-c9a1c58ab70f","outputs":{"role_id":{"value":"8833d0f8-d35d-d7ea-658b-c27837d121ab","type":"string","sensitive":true},"secret_id":{"value":"1791bfd9-5dc6-406a-3960-ba8fcad4a5a9","type":"string","sensitive":true}},"resources":[{"mode":"data","type":"vault_approle_auth_backend_role_id","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"backend":"approle","id":"auth/approle/role/external-secrets/role-id","namespace":null,"role_id":"8833d0f8-d35d-d7ea-658b-c27837d121ab","role_name":"external-secrets"},"sensitive_attributes":[]}]},{"mode":"managed","type":"vault_approle_auth_backend_role","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"backend":"approle","bind_secret_id":true,"id":"auth/approle/role/external-secrets","namespace":null,"role_id":"8833d0f8-d35d-d7ea-658b-c27837d121ab","role_name":"external-secrets","secret_id_bound_cidrs":null,"secret_id_num_uses":0,"secret_id_ttl":0,"token_bound_cidrs":null,"token_explicit_max_ttl":0,"token_max_ttl":14400,"token_no_default_policy":false,"token_num_uses":0,"token_period":0,"token_policies":["external-secrets-read"],"token_ttl":3600,"token_type":"default"},"sensitive_attributes":[],"private":"bnVsbA==","dependencies":["vault_auth_backend.approle","vault_mount.kv","vault_policy.eso_read"]}]},{"mode":"managed","type":"vault_approle_auth_backend_role_secret_id","name":"eso","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"accessor":"bcc08746-6bea-8df2-02da-f6a697bceb59","backend":"approle","cidr_list":null,"id":"backend=approle::role=external-secrets::accessor=bcc08746-6bea-8df2-02da-f6a697bceb59","metadata":"{}","namespace":null,"num_uses":0,"role_name":"external-secrets","secret_id":"1791bfd9-5dc6-406a-3960-ba8fcad4a5a9","ttl":0,"with_wrapped_accessor":null,"wrapping_accessor":null,"wrapping_token":null,"wrapping_ttl":null},"sensitive_attributes":[[{"type":"get_attr","value":"secret_id"}],[{"type":"get_attr","value":"wrapping_token"}]],"private":"bnVsbA==","dependencies":["vault_approle_auth_backend_role.eso","vault_auth_backend.approle","vault_mount.kv","vault_policy.eso_read"]}]},{"mode":"managed","type":"vault_auth_backend","name":"approle","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":1,"attributes":{"accessor":"auth_approle_c6cd7bc1","description":"","disable_remount":false,"id":"approle","identity_token_key":null,"local":false,"namespace":null,"path":"approle","tune":[],"type":"approle"},"sensitive_attributes":[],"private":"eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="}]},{"mode":"managed","type":"vault_mount","name":"kv","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"accessor":"kv_8285fbfc","allowed_managed_keys":null,"allowed_response_headers":null,"audit_non_hmac_request_keys":[],"audit_non_hmac_response_keys":[],"default_lease_ttl_seconds":0,"delegated_auth_accessors":null,"description":"KV v2 secrets engine","external_entropy_access":false,"id":"secret","identity_token_key":"","listing_visibility":"","local":false,"max_lease_ttl_seconds":0,"namespace":null,"options":null,"passthrough_request_headers":null,"path":"secret","plugin_version":null,"seal_wrap":false,"type":"kv-v2"},"sensitive_attributes":[],"private":"bnVsbA=="}]},{"mode":"managed","type":"vault_policy","name":"eso_read","provider":"provider[\"registry.opentofu.org/hashicorp/vault\"]","instances":[{"schema_version":0,"attributes":{"id":"external-secrets-read","name":"external-secrets-read","namespace":null,"policy":"path \"secret/data/*\" {\n capabilities = [\"read\"]\n}\npath \"secret/metadata/*\" {\n capabilities = [\"read\", \"list\"]\n}\n"},"sensitive_attributes":[],"private":"bnVsbA==","dependencies":["vault_mount.kv"]}]}],"check_results":null}

View File

@@ -0,0 +1,12 @@
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
version = "~> 4.0"
}
}
}
provider "vault" {
# Uses VAULT_ADDR and VAULT_TOKEN from env
}

View File

@@ -0,0 +1,38 @@
#!/bin/bash
set -euo pipefail
# set -x # Enable debug output
# --- Configuration ---
VAULT_DATA_DIR="${VAULT_DATA_DIR:-/srv/docker/vault/data/}"
S3_BUCKET="${S3_BUCKET:-vault-backup}"
MC_ALIAS="${MC_ALIAS:-synology}" # Pre-configured mc alias
RETENTION_DAYS="${RETENTION_DAYS:-60}"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="/tmp/vault-backup-${TIMESTAMP}.tar.gz"
log() { echo "[$(date -Iseconds)] $*"; }
cleanup() {
rm -f "${BACKUP_FILE}"
}
trap cleanup EXIT
# --- Create backup ---
log "Backing up ${VAULT_DATA_DIR}..."
tar -czf "${BACKUP_FILE}" -C "$(dirname "${VAULT_DATA_DIR}")" "$(basename "${VAULT_DATA_DIR}")"
BACKUP_SIZE=$(stat -c%s "${BACKUP_FILE}")
log "Backup size: ${BACKUP_SIZE} bytes"
# --- Upload to MinIO ---
log "Uploading to ${MC_ALIAS}/${S3_BUCKET}..."
set -x
mc cp --quiet "${BACKUP_FILE}" "${MC_ALIAS}/${S3_BUCKET}/vault-backup-${TIMESTAMP}.tar.gz"
# --- Prune old backups ---
log "Pruning backups older than ${RETENTION_DAYS} days..."
mc rm --quiet --recursive --force --older-than "${RETENTION_DAYS}d" "${MC_ALIAS}/${S3_BUCKET}/"
log "Backup complete: vault-backup-${TIMESTAMP}.tar.gz"