-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yaml
More file actions
180 lines (173 loc) · 7.13 KB
/
docker-compose.yaml
File metadata and controls
180 lines (173 loc) · 7.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# =============================================================================
# HashiCorp Vault — Docker Compose Stack
# Prerequisites: Docker >= 24, Docker Compose >= 2.20
#
# Usage:
# cp .env.example .env # Edit .env to match your environment
# docker compose up -d # Prepares volumes, validates/generates certs
# docker compose logs -f vault # Follow logs
#
# After first start you MUST initialise Vault (see README / workflow guide).
# =============================================================================
name: vault-internal
# ---------------------------------------------------------------------------
# Custom network — isolates Vault from the default bridge network.
# Only containers explicitly attached to this network can reach Vault
# by container name. The published port (VAULT_PORT) is the only external
# exposure point.
# ---------------------------------------------------------------------------
networks:
vault-net:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/24
# ---------------------------------------------------------------------------
# Volumes — all data lives here, persisted on the host.
# ---------------------------------------------------------------------------
volumes:
# Writable volume for the rendered vault.hcl (substituted by entrypoint.sh).
vault-config-rendered:
services:
# ---------------------------------------------------------------------------
# init-volumes: Ensures bind-mounted host directories exist with
# permissions that allow the Vault container (UID/GID 100) to use them.
# Runs once and exits before cert generation or Vault startup.
# ---------------------------------------------------------------------------
init-volumes:
image: alpine:3.21
container_name: vault-init-volumes
restart: "no"
networks:
- vault-net
environment:
VAULT_UID: ${VAULT_UID:-100}
VAULT_GID: ${VAULT_GID:-100}
volumes:
- ${VAULT_DATA_DIR:-./vault-data}:/vault/data
- ${VAULT_LOGS_DIR:-./vault-logs}:/vault/logs
- ${VAULT_CERTS_DIR:-./vault-certs}:/certs
- ./vault/scripts/prepare-volumes.sh:/prepare-volumes.sh:ro
entrypoint: ["sh", "/prepare-volumes.sh"]
# ---------------------------------------------------------------------------
# cert-gen: Runs once to either generate self-signed TLS certs or validate
# externally provided certificate files. Uses the standard Alpine OpenSSL
# image — no custom image required.
# Container exits with code 0 after success; Docker will not restart it.
# ---------------------------------------------------------------------------
cert-gen:
image: alpine/openssl:latest
container_name: vault-cert-gen
restart: "no"
depends_on:
init-volumes:
condition: service_completed_successfully
networks:
- vault-net
environment:
TLS_MODE: ${TLS_MODE:-generate}
VAULT_HOSTNAME: ${VAULT_HOSTNAME:-vault.internal}
TLS_COUNTRY: ${TLS_COUNTRY:-US}
TLS_STATE: ${TLS_STATE:-New York}
TLS_CITY: ${TLS_CITY:-Albany}
TLS_ORG: ${TLS_ORG:-IT Company}
TLS_OU: ${TLS_OU:-IT}
TLS_DAYS: ${TLS_DAYS:-3650}
TLS_EXTRA_SANS: ${TLS_EXTRA_SANS:-}
VAULT_UID: ${VAULT_UID:-100}
VAULT_GID: ${VAULT_GID:-100}
volumes:
- ${VAULT_CERTS_DIR:-./vault-certs}:/certs
- ./vault/scripts/generate-certs.sh:/generate-certs.sh:ro
entrypoint: ["sh", "/generate-certs.sh"]
# ---------------------------------------------------------------------------
# vault: The Vault server itself.
# Depends on both volume prep and TLS materials being ready.
# ---------------------------------------------------------------------------
vault:
image: ${VAULT_IMAGE:-hashicorp/vault:1.18}
container_name: vault-server
restart: unless-stopped
depends_on:
init-volumes:
condition: service_completed_successfully
cert-gen:
condition: service_completed_successfully
networks:
- vault-net
ports:
# Expose HTTPS API + UI on the configured host port.
- "${VAULT_PORT:-8200}:8200"
environment:
# Vault reads these environment variables directly at runtime.
VAULT_ADDR: "https://127.0.0.1:8200"
VAULT_CACERT: "/vault/certs/ca.crt"
VAULT_LOG_LEVEL: "${VAULT_LOG_LEVEL:-info}"
VAULT_UI: "${VAULT_UI:-true}"
VAULT_DEFAULT_LEASE_TTL: "${VAULT_DEFAULT_LEASE_TTL:-768h}"
VAULT_MAX_LEASE_TTL: "${VAULT_MAX_LEASE_TTL:-8760h}"
# Passed to entrypoint script for rendered HCL values
VAULT_HOSTNAME: "${VAULT_HOSTNAME:-vault.internal}"
VAULT_API_ADDR: "${VAULT_API_ADDR:-}"
VAULT_CLUSTER_ADDR: "${VAULT_CLUSTER_ADDR:-}"
VAULT_NODE_ID: "${VAULT_NODE_ID:-vault-node-1}"
# Disable coloured log output — cleaner for log aggregators
NO_COLOR: "true"
volumes:
# Writable volume for rendered vault.hcl (entrypoint writes here)
- vault-config-rendered:/vault/config-rendered
# Integrated storage (raft)
- ${VAULT_DATA_DIR:-./vault-data}:/vault/data
# Audit logs
- ${VAULT_LOGS_DIR:-./vault-logs}:/vault/logs
# TLS certificates (generated or externally provided)
- ${VAULT_CERTS_DIR:-./vault-certs}:/vault/certs:ro
# HCL config template (read-only source; entrypoint writes rendered copy)
- ./vault/config/vault.hcl:/vault/config-template/vault.hcl:ro
# Entrypoint script
- ./vault/scripts/entrypoint.sh:/entrypoint.sh:ro
entrypoint: ["sh", "/entrypoint.sh"]
cap_add:
# Required for mlock — prevents Vault secrets from being swapped to disk.
# This is a CRITICAL security control for production use.
- IPC_LOCK
cap_drop:
# Drop all other capabilities not needed by Vault.
- ALL
security_opt:
# Prevent privilege escalation inside the container.
- no-new-privileges:true
# Read-only root filesystem — Vault only writes to mounted volumes.
# Uncomment after verifying your setup works correctly.
# read_only: true
# tmpfs:
# - /tmp
ulimits:
# Increase open file descriptors for high-throughput environments.
nofile:
soft: 65536
hard: 65536
# memlock unlimited — required for mlock to function correctly.
memlock:
soft: -1
hard: -1
healthcheck:
# Vault returns HTTP 200 (initialized+unsealed), 429 (standby), or
# 501/503 (sealed/uninitialised). We treat all of these as "alive"
# because a sealed/uninitialised Vault is still a running container.
# This is suitable for single-node raft because the service is still
# "running" before initialization/unseal is complete.
test: >
wget --no-verbose --tries=1 --spider
--no-check-certificate
https://127.0.0.1:8200/v1/sys/health?standbyok=true&uninitcode=200&sealedcode=200
|| exit 1
interval: 30s
timeout: 10s
retries: 5
start_period: 10s
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"