infra: relocate docker-30 compose stack under vms-home/, add garage and frisbee-drills

Move the docker-30 service definitions (gitea, kanidm, vault, zot,
nginx, lab-proxy, maru-hleda-byt, fuj-management) into vms-home/ to
match the naming convention used for other hosts, and add the new
garage object-storage and frisbee-drills services alongside it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 00:05:30 +02:00
parent d43ffd488e
commit d541f2e1d2
32 changed files with 157 additions and 17 deletions

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

View File

@@ -0,0 +1,10 @@
## 1. Enable & configure JWT auth in Vault
```bash
vault auth enable jwt
vault write auth/jwt/config \
bound_issuer="https://gitea.home.hrajfrisbee.cz" \
jwks_url="https://gitea.home.hrajfrisbee.cz/login/oauth/keys"
```

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,115 @@
resource "vault_mount" "kv" {
path = "secret"
type = "kv-v2"
description = "KV v2 secrets engine"
}
resource "vault_jwt_auth_backend" "gitea" {
path = "jwt"
type = "jwt"
bound_issuer = "https://gitea.home.hrajfrisbee.cz"
jwks_url = "https://gitea.home.hrajfrisbee.cz/login/oauth/keys"
}
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
}
# for now i allow my gitea to read everything in /v1/secret/data/gitea
resource "vault_policy" "gitea_ci_read" {
name = "gitea-ci-read"
policy = <<-EOT
path "${vault_mount.kv.path}/data/gitea/*" {
capabilities = ["read"]
}
path "${vault_mount.kv.path}/metadata/gitea/*" {
capabilities = ["read", "list"]
}
EOT
}
resource "vault_jwt_auth_backend_role" "gitea_ci" {
backend = vault_jwt_auth_backend.gitea.path
role_name = "gitea-ci"
role_type = "jwt"
token_policies = [vault_policy.gitea_ci_read.name]
user_claim = "sub"
bound_audiences = ["https://gitea.home.hrajfrisbee.cz"]
# allow any valid jwt token when commented out
# bound_claims = {
# repository = "myorg/repo1,myorg/repo3"
# }
token_ttl = 600
token_max_ttl = 1200
}
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
}
resource "vault_approle_auth_backend_role" "gitea_ci" {
backend = vault_auth_backend.approle.path
role_name = "gitea-ci"
token_policies = [vault_policy.gitea_ci_read.name]
token_ttl = 600
token_max_ttl = 1200
}
data "vault_approle_auth_backend_role_id" "gitea_ci" {
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.gitea_ci.role_name
}
resource "vault_approle_auth_backend_role_secret_id" "gitea_ci" {
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.gitea_ci.role_name
}
output "gitea_ci_role_id" {
value = data.vault_approle_auth_backend_role_id.gitea_ci.role_id
sensitive = true
}
output "gitea_ci_secret_id" {
value = vault_approle_auth_backend_role_secret_id.gitea_ci.secret_id
sensitive = true
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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
minio-cli cp --quiet "${BACKUP_FILE}" "${MC_ALIAS}/${S3_BUCKET}/vault-backup-${TIMESTAMP}.tar.gz"
# --- Prune old backups ---
log "Pruning backups older than ${RETENTION_DAYS} days..."
minio-cli rm --quiet --recursive --force --older-than "${RETENTION_DAYS}d" "${MC_ALIAS}/${S3_BUCKET}/"
log "Backup complete: vault-backup-${TIMESTAMP}.tar.gz"