From 3b1e0efa1928f8db5dd8ab6b6926bd6a12b1c6f0 Mon Sep 17 00:00:00 2001 From: git Date: Tue, 7 Apr 2026 19:38:51 +1000 Subject: [PATCH] modified: .gitignore modified: apps/gramps/docker-compose.yml modified: apps/nextcloud/docker-compose.yml modified: apps/passbolt/docker-compose.yml modified: core/docker-compose.yml modified: monitoring/gotify/docker-compose.yml modified: monitoring/prometheus/docker-compose.yml modified: monitoring/prometheus/prometheus.yml .env.example DEPLOYMENT.md SECURITY_SECRETS_INVENTORY.md secrets/ --- .gitignore | 4 +- apps/gramps/docker-compose.yml | 26 +++---- apps/nextcloud/docker-compose.yml | 92 +++++++++++++----------- apps/passbolt/docker-compose.yml | 44 ++++++------ core/docker-compose.yml | 7 +- monitoring/gotify/docker-compose.yml | 10 +-- monitoring/prometheus/docker-compose.yml | 24 +++++-- monitoring/prometheus/prometheus.yml | 4 +- 8 files changed, 121 insertions(+), 90 deletions(-) diff --git a/.gitignore b/.gitignore index d1efebd..4cf1b7d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,6 @@ apps/searxng/* venv/ core/authelia/users_database.yml monitoring/influxdb/* - +secrets/* +!secrets/.env.secrets.example +!.env.example diff --git a/apps/gramps/docker-compose.yml b/apps/gramps/docker-compose.yml index 65b4bc1..54c69f7 100644 --- a/apps/gramps/docker-compose.yml +++ b/apps/gramps/docker-compose.yml @@ -4,22 +4,25 @@ services: image: postgres:13 container_name: gramps-db restart: always + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env environment: - POSTGRES_USER: ${GRAMPS_POSTGRES_USER} - POSTGRES_PASSWORD: ${GRAMPS_POSTGRES_PASSWORD} - POSTGRES_DB: ${GRAMPS_POSTGRES_DB} + POSTGRES_USER: ${GRAMPS_DB_USER} + POSTGRES_PASSWORD_FILE: /run/secrets/gramps_db_password + POSTGRES_DB: ${GRAMPS_DB_NAME} + secrets: + - gramps_db_password volumes: - ${PROJECT_ROOT}/apps/gramps/db:/var/lib/postgresql networks: - gramps healthcheck: - test: ["CMD-SHELL", "pg_isready -h db -p 5432 -U gramps -d gramps"] + test: ["CMD-SHELL", "pg_isready -h gramps-db -p 5432 -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 10s timeout: 5s retries: 12 start_period: 30s - grampsweb: profiles: ["apps","all","gramps"] image: ghcr.io/gramps-project/grampsweb:latest @@ -27,8 +30,8 @@ services: depends_on: - gramps-db restart: always -# ports: -# - "5000:5000" # access via http://localhost:5000 + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env environment: DB_URI: ${GRAMPS_DB_URI} GRAMPSWEB_LOGLEVEL: ${GRAMPSWEB_LOGLEVEL} @@ -62,10 +65,9 @@ services: retries: 6 start_period: 60s - - networks: -# traefik_reverse_proxy: -# external: true gramps: -# driver: bridge + +secrets: + gramps_db_password: + file: ${PROJECT_ROOT}/secrets/gramps_db_password.txt diff --git a/apps/nextcloud/docker-compose.yml b/apps/nextcloud/docker-compose.yml index fe7ffed..b9203ea 100644 --- a/apps/nextcloud/docker-compose.yml +++ b/apps/nextcloud/docker-compose.yml @@ -1,12 +1,13 @@ services: nextcloud-webapp: -# image: nextcloud:production profiles: ["apps","all","nextcloud"] build: context: ${PROJECT_ROOT}/apps/nextcloud container_name: nextcloud-webapp restart: always hostname: nextcloud.lan.ddnsgeek.com + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - ${PROJECT_ROOT}/apps/nextcloud/data:/var/www/html/data:rw - ${PROJECT_ROOT}/apps/nextcloud/config:/var/www/html/config:rw @@ -16,26 +17,28 @@ services: - nextcloud-db - nextcloud-redis environment: - - MYSQL_PASSWORD=${NEXTCLOUD_MYSQL_PASSWORD} - - MYSQL_DATABASE=${NEXTCLOUD_MYSQL_DATABASE} - - MYSQL_USER=${NEXTCLOUD_MYSQL_USER} - - MYSQL_HOST=${NEXTCLOUD_MYSQL_HOST} - - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_TRUSTED_DOMAINS} - - OVERWRITEPROTOCOL=${NEXTCLOUD_OVERWRITEPROTOCOL} - - OVERWRITECLIURL=${NEXTCLOUD_OVERWRITECLIURL} - - - SMTP_HOST=${NEXTCLOUD_SMTP_HOST} - - SMTP_SECURE=${NEXTCLOUD_SMTP_SECURE} - - SMTP_PORT=${NEXTCLOUD_SMTP_PORT} - - SMTP_AUTHTYPE=${NEXTCLOUD_SMTP_AUTHTYPE} - - MAIL_FROM_ADDRESS=${NEXTCLOUD_MAIL_FROM_ADDRESS} - - MAIL_DOMAIN=${NEXTCLOUD_MAIL_DOMAIN} + - MYSQL_PASSWORD_FILE=/run/secrets/nextcloud_db_password + - MYSQL_DATABASE=${NEXTCLOUD_DB_NAME} + - MYSQL_USER=${NEXTCLOUD_DB_USER} + - MYSQL_HOST=nextcloud_db:3306 + - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.lan.ddnsgeek.com + - OVERWRITEPROTOCOL=https + - OVERWRITECLIURL=https://nextcloud.lan.ddnsgeek.com + - SMTP_HOST=smtp.gmail.com + - SMTP_SECURE=tls + - SMTP_PORT=587 + - SMTP_AUTHTYPE=login + - MAIL_FROM_ADDRESS=${NEXTCLOUD_SMTP_FROM_ADDRESS} + - MAIL_DOMAIN=${NEXTCLOUD_SMTP_DOMAIN} - SMTP_NAME=${NEXTCLOUD_SMTP_NAME} - - SMTP_PASSWORD=${NEXTCLOUD_SMTP_PASSWORD} - - - REDIS_HOST=${NEXTCLOUD_REDIS_HOST} - - REDIS_HOST_PORT=${NEXTCLOUD_REDIS_HOST_PORT} - - REDIS_HOST_PASSWORD=${NEXTCLOUD_REDIS_HOST_PASSWORD} + - SMTP_PASSWORD_FILE=/run/secrets/nextcloud_smtp_password + - REDIS_HOST=redis + - REDIS_HOST_PORT=6379 + - REDIS_HOST_PASSWORD_FILE=/run/secrets/nextcloud_redis_password + secrets: + - nextcloud_db_password + - nextcloud_smtp_password + - nextcloud_redis_password networks: - traefik - nextcloud @@ -54,7 +57,6 @@ services: - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.regex=https://(.*)/.well-known/webfinger" - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.replacement=https://$${1}/nextcloud/index.php/.well-known/webfinger" - "traefik.docker.network=core_traefik" - healthcheck: test: - CMD-SHELL @@ -68,9 +70,6 @@ services: retries: 6 start_period: 180s - - - nextcloud-db: image: mariadb:11.4 restart: always @@ -78,36 +77,41 @@ services: container_name: nextcloud-db hostname: nextcloud_db command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - ${PROJECT_ROOT}/apps/nextcloud/database:/var/lib/mysql:rw environment: - - MYSQL_ROOT_PASSWORD=${NEXTCLOUD_MYSQL_ROOT_PASSWORD} - - MYSQL_PASSWORD=${NEXTCLOUD_MYSQL_PASSWORD} - - MYSQL_DATABASE=${NEXTCLOUD_MYSQL_DATABASE} - - MYSQL_USER=${NEXTCLOUD_MYSQL_USER} - - MARIADB_AUTO_UPGRADE=${NEXTCLOUD_MARIADB_AUTO_UPGRADE} + - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/nextcloud_db_root_password + - MYSQL_PASSWORD_FILE=/run/secrets/nextcloud_db_password + - MYSQL_DATABASE=${NEXTCLOUD_DB_NAME} + - MYSQL_USER=${NEXTCLOUD_DB_USER} + - MARIADB_AUTO_UPGRADE=1 - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} - - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} + - NEXTCLOUD_ADMIN_PASSWORD_FILE=/run/secrets/nextcloud_admin_password + secrets: + - nextcloud_db_root_password + - nextcloud_db_password + - nextcloud_admin_password networks: - nextcloud labels: - "io.portainer.accesscontrol.public" healthcheck: - test: ["CMD-SHELL", "mariadb-admin ping -u ${NEXTCLOUD_MYSQL_USER} --password=${NEXTCLOUD_MYSQL_PASSWORD} --silent"] + test: ["CMD-SHELL", "mariadb-admin ping -u $$MYSQL_USER --password=$$(cat /run/secrets/nextcloud_db_password) --silent"] interval: 10s timeout: 5s retries: 12 start_period: 60s - nextcloud-redis: image: "redis" profiles: ["apps","all","nextcloud"] - command: ["redis-server", "--requirepass", "${NEXTCLOUD_REDIS_HOST_PASSWORD}", "--appendonly", "yes", "--save", "60", "1000"] + command: ["sh", "-c", "redis-server --requirepass \"$$(cat /run/secrets/nextcloud_redis_password)\" --appendonly yes --save 60 1000"] hostname: redis container_name: nextcloud-redis - environment: - - REDIS_HOST_PASSWORD=${NEXTCLOUD_REDIS_HOST_PASSWORD} + secrets: + - nextcloud_redis_password volumes: - ${PROJECT_ROOT}/apps/nextcloud/data/redis:/data:rw restart: always @@ -116,15 +120,23 @@ services: labels: - "io.portainer.accesscontrol.public" healthcheck: - test: ["CMD-SHELL", "redis-cli -a ${NEXTCLOUD_REDIS_HOST_PASSWORD} PING | grep -q PONG"] + test: ["CMD-SHELL", "redis-cli -a \"$$(cat /run/secrets/nextcloud_redis_password)\" PING | grep -q PONG"] interval: 10s timeout: 5s retries: 6 start_period: 10s - networks: -# traefik_reverse_proxy: -# external: true nextcloud: -# driver: bridge + +secrets: + nextcloud_db_root_password: + file: ${PROJECT_ROOT}/secrets/nextcloud_db_root_password.txt + nextcloud_db_password: + file: ${PROJECT_ROOT}/secrets/nextcloud_db_password.txt + nextcloud_admin_password: + file: ${PROJECT_ROOT}/secrets/nextcloud_admin_password.txt + nextcloud_smtp_password: + file: ${PROJECT_ROOT}/secrets/nextcloud_smtp_password.txt + nextcloud_redis_password: + file: ${PROJECT_ROOT}/secrets/nextcloud_redis_password.txt diff --git a/apps/passbolt/docker-compose.yml b/apps/passbolt/docker-compose.yml index a0bcc89..e92cea2 100644 --- a/apps/passbolt/docker-compose.yml +++ b/apps/passbolt/docker-compose.yml @@ -4,17 +4,21 @@ services: container_name: passbolt-db image: mariadb:12 restart: always + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env environment: - MYSQL_RANDOM_ROOT_PASSWORD: "${PASSBOLT_MYSQL_RANDOM_ROOT_PASSWORD}" - MYSQL_DATABASE: "${PASSBOLT_MYSQL_DATABASE}" - MYSQL_USER: "${PASSBOLT_MYSQL_USER}" - MYSQL_PASSWORD: "${PASSBOLT_MYSQL_PASSWORD}" + MYSQL_RANDOM_ROOT_PASSWORD: "true" + MYSQL_DATABASE: ${PASSBOLT_DB_NAME} + MYSQL_USER: ${PASSBOLT_DB_USER} + MYSQL_PASSWORD_FILE: /run/secrets/passbolt_db_password + secrets: + - passbolt_db_password volumes: - ${PROJECT_ROOT}/apps/passbolt/data/database:/var/lib/mysql networks: - passbolt healthcheck: - test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u\"$$MARIADB_USER\" -p\"$$MARIADB_PASSWORD\" --silent"] + test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u\"$$MYSQL_USER\" -p\"$$(cat /run/secrets/passbolt_db_password)\" --silent"] interval: 10s timeout: 5s retries: 12 @@ -22,22 +26,24 @@ services: labels: - "io.portainer.accesscontrol.public" - passbolt-webapp: image: passbolt/passbolt:latest-ce profiles: ["apps","all","passbolt"] container_name: passbolt-webapp - #Alternatively you can use rootless: restart: always depends_on: - passbolt-db + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env environment: - APP_FULL_BASE_URL: ${PASSBOLT_APP_FULL_BASE_URL} - DATASOURCES_DEFAULT_HOST: "${PASSBOLT_DATASOURCES_DEFAULT_HOST}" - DATASOURCES_DEFAULT_USERNAME: "${PASSBOLT_DATASOURCES_DEFAULT_USERNAME}" - DATASOURCES_DEFAULT_PASSWORD: "${PASSBOLT_DATASOURCES_DEFAULT_PASSWORD}" - DATASOURCES_DEFAULT_DATABASE: "${PASSBOLT_DATASOURCES_DEFAULT_DATABASE}" - PASSBOLT_GPG_SERVER_KEY_FINGERPRINT: "${PASSBOLT_GPG_SERVER_KEY_FINGERPRINT}" + APP_FULL_BASE_URL: https://passbolt.lan.ddnsgeek.com + DATASOURCES_DEFAULT_HOST: "passbolt-db" + DATASOURCES_DEFAULT_USERNAME: ${PASSBOLT_DB_USER} + DATASOURCES_DEFAULT_PASSWORD_FILE: /run/secrets/passbolt_db_password + DATASOURCES_DEFAULT_DATABASE: ${PASSBOLT_DB_NAME} + PASSBOLT_GPG_SERVER_KEY_FINGERPRINT: "CBBB2B8F3E9FACA114537ACB8965B750F7363586" + secrets: + - passbolt_db_password volumes: - ${PROJECT_ROOT}/apps/passbolt/data/gpg:/etc/passbolt/gpg - ${PROJECT_ROOT}/apps/passbolt/data/jwt:/etc/passbolt/jwt @@ -60,20 +66,16 @@ services: - "traefik.http.routers.passbolt.tls.certresolver=myresolver" - "io.portainer.accesscontrol.public" - "traefik.docker.network=core_traefik" - healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost/healthcheck/status | grep -qx OK"] -# su -s /bin/sh -c "/usr/share/php/passbolt/bin/cake passbolt healthcheck" www-data -# | grep -q "No error found" interval: 30s timeout: 10s retries: 6 start_period: 120s - networks: -# traefik_reverse_proxy: -# external: true -# internal: -# driver: bridge passbolt: + +secrets: + passbolt_db_password: + file: ${PROJECT_ROOT}/secrets/passbolt_db_password.txt diff --git a/core/docker-compose.yml b/core/docker-compose.yml index 145ae00..fad817e 100644 --- a/core/docker-compose.yml +++ b/core/docker-compose.yml @@ -17,6 +17,8 @@ services: build: context: ${PROJECT_ROOT}/core + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - /var/run/docker.sock:/var/run/docker.sock:ro @@ -51,7 +53,8 @@ services: container_name: crowdsec restart: always environment: - - COLLECTIONS=${CROWDSEC_COLLECTIONS} + - COLLECTIONS=crowdsecurity/traefik + - CROWDSEC_LAPI_KEY=${CROWDSEC_LAPI_KEY} volumes: - ${PROJECT_ROOT}/core/crowdsec/logs:/logs:ro - ${PROJECT_ROOT}/core/crowdsec/data:/var/lib/crowdsec/data @@ -99,6 +102,8 @@ services: restart: always build: context: ${PROJECT_ROOT}/core/authelia + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - ${PROJECT_ROOT}/core/authelia:/config networks: diff --git a/monitoring/gotify/docker-compose.yml b/monitoring/gotify/docker-compose.yml index e8927ed..ebaee66 100644 --- a/monitoring/gotify/docker-compose.yml +++ b/monitoring/gotify/docker-compose.yml @@ -4,10 +4,10 @@ services: image: gotify/server:latest container_name: gotify restart: always - + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - ${PROJECT_ROOT}/monitoring/gotify/data:/app/data - environment: - TZ=${TZ} - GOTIFY_DEFAULTUSER_NAME=${GOTIFY_DEFAULTUSER_NAME} @@ -15,9 +15,7 @@ services: - GOTIFY_REGISTRATION=${GOTIFY_REGISTRATION} networks: -# - traefik_reverse_proxy - traefik - labels: - "traefik.enable=true" - "traefik.docker.network=core_traefik" @@ -26,7 +24,3 @@ services: - "traefik.http.routers.gotify.entrypoints=websecure" - "traefik.http.routers.gotify.tls.certresolver=myresolver" - "traefik.http.services.gotify.loadbalancer.server.port=80" - -#networks: -# traefik_reverse_proxy: -# external: true diff --git a/monitoring/prometheus/docker-compose.yml b/monitoring/prometheus/docker-compose.yml index d54f917..f95401e 100644 --- a/monitoring/prometheus/docker-compose.yml +++ b/monitoring/prometheus/docker-compose.yml @@ -4,6 +4,8 @@ services: prometheus: profiles: ["monitoring","all","prometheus"] image: prom/prometheus:latest + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env container_name: prometheus depends_on: # - alertmanager @@ -22,6 +24,7 @@ services: - ${PROJECT_ROOT}/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ${PROJECT_ROOT}/monitoring/prometheus/data:/prometheus - ${PROJECT_ROOT}/monitoring/prometheus/rules:/etc/prometheus/rules:ro + - ${PROJECT_ROOT}/secrets/prometheus_kuma_basic_auth_password.txt:/run/secrets/prometheus_kuma_basic_auth_password:ro restart: unless-stopped labels: @@ -53,7 +56,7 @@ services: # volumes: # - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro # restart: unless-stopped -# networks: +# secrets: # - edge # - traefik_reverse_proxy # healthcheck: @@ -101,14 +104,18 @@ services: image: influxdb:2.7 container_name: influxdb restart: unless-stopped + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env volumes: - ${PROJECT_ROOT}/monitoring/influxdb:/var/lib/influxdb2 environment: - DOCKER_INFLUXDB_INIT_MODE: ${INFLUXDB_INIT_MODE} + DOCKER_INFLUXDB_INIT_MODE: setup DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_INIT_USERNAME} - DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_INIT_PASSWORD} + DOCKER_INFLUXDB_INIT_PASSWORD_FILE: /run/secrets/influxdb_init_password DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_INIT_ORG} DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_INIT_BUCKET} + secrets: + - influxdb_init_password networks: # - edge # - traefik_reverse_proxy @@ -205,10 +212,12 @@ services: profiles: ["monitoring","all","prometheus-exporters"] image: ekofr/pihole-exporter:latest container_name: pihole-exporter + env_file: + - ${PROJECT_ROOT}/secrets/stack-secrets.env environment: PIHOLE_HOSTNAME: ${PIHOLE_HOSTNAME} - PIHOLE_PASSWORD: "${PIHOLE_PASSWORD}" - PORT: ${PIHOLE_EXPORTER_PORT} + PIHOLE_PASSWORD: ${PIHOLE_PASSWORD} + PORT: 9617 ports: - "9617:9617" restart: unless-stopped @@ -228,3 +237,8 @@ services: # external: true + + +secrets: + influxdb_init_password: + file: ${PROJECT_ROOT}/secrets/influxdb_init_password.txt diff --git a/monitoring/prometheus/prometheus.yml b/monitoring/prometheus/prometheus.yml index 00ff587..d4db4d4 100644 --- a/monitoring/prometheus/prometheus.yml +++ b/monitoring/prometheus/prometheus.yml @@ -96,8 +96,8 @@ scrape_configs: scrape_interval: 30s basic_auth: - username: wayne.bennett@live.com - password: '4vjCco?[%{=+,t`):C' + username: ${PROMETHEUS_KUMA_BASIC_AUTH_USERNAME} + password_file: /run/secrets/prometheus_kuma_basic_auth_password static_configs: - targets: