version: '3.8' services: # ------------------------------------------------------------------------- # 1. PRIMARY VAULT CLUSTER (3 NODES - RAFT HIGH AVAILABILITY) # ------------------------------------------------------------------------- # before deloy ## echo "kendi_urettigin_guclu_token" | docker secret create transit_master_token - # after deploy ## docker exec -it $(docker ps -q -f name=iklimco_vault.1) vault operator init vault: image: hashicorp/vault:2.0.1 cap_add: - IPC_LOCK # Overriding the default entrypoint to manipulate configuration strictly in RAM memory entrypoint: ["sh", "-c"] # 1. Reads the transit token from Docker Secret into RAM # 2. Substitutes TRANSIT_TOKEN_PLACEHOLDER and HOSTNAME_PLACEHOLDER via sed entirely in RAM # 3. Writes the resolved config to /dev/shm (RAM-backed tmpfs) — no secret ever touches disk # 4. Purges token variable, then execs vault as PID 1 with the resolved config command: > "export MASTER_TOKEN=$$(cat /run/secrets/transit_master_token); cat /vault/config/vault.json | sed \"s/TRANSIT_TOKEN_PLACEHOLDER/$$MASTER_TOKEN/g\" | sed \"s/HOSTNAME_PLACEHOLDER/$$HOSTNAME/g\" > /dev/shm/vault.json; unset MASTER_TOKEN; exec vault server -config=/dev/shm/vault.json" networks: iklimco-net: aliases: - vault.iklim.co environment: # NOTE: VAULT_LOCAL_API_ADDR is intentionally omitted. # Vault automatically discovers its own container IP and port (8200) from the listener block below. VAULT_ADDR: "https://127.0.0.1:8200" # PHASE 1 (Bootstrap): Keep it "true" so Vault CLI can operate on self-signed/temporary certificates. # PHASE 2 (Strict SSL): set this 'false' once you switch your configuration to v2. VAULT_SKIP_VERIFY: "true" volumes: # Persistent volume for primary Raft storage - vault-data-vl:/vault/file # Persistent volume for audit and operational logs - vault-logs-vl:/vault/logs # Read-only mount of the host directory where the real wildcard certificates are managed - /opt/iklimco/ssl:/vault/certs:ro configs: # PHASE 1: Deploy with 'vault_template_v1' (TLS validation skipped for easy initialization) # PHASE 2: Update this source to 'vault_template_v2' to enforce strict wildcard SSL verification - source: vault_template_v2 target: /vault/config/vault.json mode: 0444 secrets: - transit_master_token deploy: mode: replicated replicas: 3 placement: # High Availability rule: Ensures Vault nodes are strictly scheduled across different physical Swarm workers max_replicas_per_node: 1 constraints: - node.labels.type == service restart_policy: condition: any delay: 5s # ------------------------------------------------------------------------- # 2. AUTO-UNSEAL HELPER (1 NODE - PERSISTENT ON-PREMISE KMS) # ------------------------------------------------------------------------- # BOOTSTRAP (first deploy only — run these steps in order): # Step 1: echo "bootstrap" | docker secret create vault_transit_unseal_key - # Step 2: docker stack deploy ... (transit starts sealed and uninitialized) # Step 3: docker exec -it $(docker ps -q -f name=iklimco_vault-transit) \ # vault operator init -key-shares=1 -key-threshold=1 # -> note the Unseal Key and Root Token from the output # Step 4: docker service update --secret-rm vault_transit_unseal_key iklimco_vault-transit # docker secret rm vault_transit_unseal_key # echo "" | docker secret create vault_transit_unseal_key - # docker service update --secret-add vault_transit_unseal_key iklimco_vault-transit # Step 5: (exec into container) unseal, enable transit engine, create autounseal key, # create a dedicated policy token, then update the transit_master_token secret: # vault operator unseal # vault login # vault secrets enable transit # vault write -f transit/keys/autounseal # vault policy write autounseal - < docker secret rm transit_master_token # -> echo "" | docker secret create transit_master_token - # NORMAL OPERATION: auto-unseals on restart using vault_transit_unseal_key # NODE PINNING (recommended): pin to one node to prevent volume data loss on rescheduling # docker node update --label-add vault_transit=true vault-transit: image: hashicorp/vault:2.0.1 cap_add: - IPC_LOCK entrypoint: ["sh", "-c"] # 1. Starts vault in background with persistent file storage config # 2. Registers SIGTERM/SIGINT trap so Docker stop triggers graceful vault shutdown # 3. Polls vault status; exit 1 = not ready yet, exit 0/2 = vault is responding # 4. Auto-unseals using vault_transit_unseal_key secret (no-op when uninitialized) # 5. Waits for vault to exit and propagates its exit code to Docker command: > "vault server -config=/vault/config/transit.json & VAULT_PID=$$!; trap 'kill -TERM $$VAULT_PID; wait $$VAULT_PID' TERM INT; export VAULT_ADDR='http://127.0.0.1:8200'; for i in 1 2 3 4 5 6 7 8 9 10; do vault status > /dev/null 2>&1; [ $$? -ne 1 ] && break; sleep 2; done; vault operator unseal $$(cat /run/secrets/vault_transit_unseal_key) > /dev/null 2>&1 || true; wait $$VAULT_PID" networks: - iklimco-net secrets: - vault_transit_unseal_key volumes: - vault-transit-data-vl:/vault/file configs: - source: vault_transit_config target: /vault/config/transit.json mode: 0444 deploy: mode: replicated replicas: 1 placement: constraints: - node.labels.type == service - node.labels.vault_transit == true restart_policy: condition: any delay: 5s configs: # ========================================================================= # CONFIG TEMPLATE PHASE 1: Bootstrap / Initial Discovery (No Verification) # ========================================================================= vault_template_v1: file: ./vault-template-v1.json # ========================================================================= # CONFIG TEMPLATE PHASE 2: Production Safe (Strict Wildcard SSL Enforcement) # ========================================================================= vault_template_v2: file: ./vault-template-v2.json # ========================================================================= # TRANSIT VAULT CONFIG: Persistent file storage, TLS disabled (internal only) # ========================================================================= vault_transit_config: file: ./vault-template-transit.json volumes: vault-data-vl: vault-logs-vl: vault-transit-data-vl: secrets: # Must be provisioned via 'docker secret create transit_master_token -' before deployment transit_master_token: external: true # First deploy: echo "bootstrap" | docker secret create vault_transit_unseal_key - # After init: replace with the real unseal key from 'vault operator init' output vault_transit_unseal_key: external: true networks: iklimco-net: external: true