diff --git a/deployment/ansible/roles/application/tasks/sync.yml b/deployment/ansible/roles/application/tasks/sync.yml index e0b43564..077be562 100644 --- a/deployment/ansible/roles/application/tasks/sync.yml +++ b/deployment/ansible/roles/application/tasks/sync.yml @@ -44,7 +44,32 @@ - name: Determine application redis password set_fact: - application_redis_password: "{{ vault_redis_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}" + application_redis_password: "{{ redis_password | default(vault_redis_password | default('')) }}" + no_log: yes + +- name: Ensure redis password provided via vault + fail: + msg: >- + Redis credentials are missing. Define vault_redis_password in + {{ application_vault_file }} (encrypted with ansible-vault) or pass + redis_password via extra vars. + when: (application_redis_password | string | trim) == '' + +- name: Determine application app key + set_fact: + application_app_key: "{{ app_key | default(vault_app_key | default('')) }}" + no_log: yes + +- name: Ensure application app key provided via vault + fail: + msg: >- + Application key missing. Define vault_app_key in + {{ application_vault_file }} (ansible-vault) or pass app_key via extra vars. + when: (application_app_key | string | trim) == '' + +- name: Determine encryption key (optional) + set_fact: + application_encryption_key: "{{ encryption_key | default(vault_encryption_key | default('')) }}" no_log: yes - name: Check if application docker-compose source exists locally @@ -83,6 +108,8 @@ set_fact: db_password: "{{ application_db_password }}" redis_password: "{{ application_redis_password }}" + app_key: "{{ application_app_key }}" + encryption_key: "{{ application_encryption_key }}" db_username: "{{ db_user | default(db_user_default) }}" db_name: "{{ db_name | default(db_name_default) }}" no_log: yes diff --git a/deployment/ansible/secrets/production.vault.yml.example b/deployment/ansible/secrets/production.vault.yml.example index 91370bc6..ccf54281 100644 --- a/deployment/ansible/secrets/production.vault.yml.example +++ b/deployment/ansible/secrets/production.vault.yml.example @@ -8,9 +8,11 @@ vault_db_password: "change-me-secure-db-password" vault_db_root_password: "change-me-secure-root-password" # Application Stack Credentials +# Required: used for the application stack (.env) and injected into PHP containers vault_redis_password: "change-me-secure-redis-password" # Application Secrets +# Required: base64 encoded 32 byte key used for APP_KEY vault_app_key: "change-me-base64-encoded-32-byte-key" vault_jwt_secret: "change-me-jwt-signing-secret" diff --git a/deployment/ansible/templates/application.env.j2 b/deployment/ansible/templates/application.env.j2 index 47adf55f..f1aa4c22 100644 --- a/deployment/ansible/templates/application.env.j2 +++ b/deployment/ansible/templates/application.env.j2 @@ -10,15 +10,23 @@ APP_DOMAIN={{ app_domain }} # Application Settings APP_ENV={{ app_env | default('production') }} APP_DEBUG={{ app_debug | default('false') }} +APP_NAME={{ app_display_name | default(app_name | default('Framework') | replace('-', ' ') | title) }} +APP_KEY={{ app_key }} +APP_TIMEZONE={{ app_timezone | default(timezone | default('Europe/Berlin')) }} +APP_LOCALE={{ app_locale | default('de') }} APP_URL=https://{{ app_domain }} +APP_SSL_PORT={{ app_ssl_port | default('443') }} +FORCE_HTTPS={{ force_https | default('true') }} # Database Configuration # Using PostgreSQL from postgres stack -DB_HOST=postgres +DB_DRIVER={{ db_driver | default('pgsql') }} +DB_HOST={{ db_host | default('postgres') }} DB_PORT={{ db_port | default('5432') }} DB_DATABASE={{ db_name | default(db_name_default) }} DB_USERNAME={{ db_user | default(db_user_default) }} DB_PASSWORD={{ db_password }} +DB_CHARSET={{ db_charset | default('utf8') }} # Legacy variables (kept for backward compatibility) DB_NAME={{ db_name | default(db_name_default) }} DB_USER={{ db_user | default(db_user_default) }} @@ -26,15 +34,22 @@ DB_PASS={{ db_password }} # Redis Configuration # Redis runs in this stack +REDIS_HOST={{ redis_host | default('redis') }} +REDIS_PORT={{ redis_port | default('6379') }} REDIS_PASSWORD={{ redis_password }} +# Security Configuration +SECURITY_ALLOWED_HOSTS={{ security_allowed_hosts | default('localhost,' ~ app_domain ~ ',www.' ~ app_domain) }} +SECURITY_RATE_LIMIT_PER_MINUTE={{ security_rate_limit_per_minute | default('30') }} +SECURITY_RATE_LIMIT_BURST={{ security_rate_limit_burst | default('5') }} + # Cache Configuration CACHE_DRIVER={{ cache_driver | default('redis') }} CACHE_PREFIX={{ cache_prefix | default('app') }} # Session Configuration SESSION_DRIVER={{ session_driver | default('redis') }} -SESSION_LIFETIME={{ session_lifetime | default('120') }} +SESSION_LIFETIME={{ session_lifetime | default('1800') }} # Queue Worker Configuration QUEUE_DRIVER={{ queue_driver | default('redis') }} @@ -43,6 +58,9 @@ QUEUE_WORKER_SLEEP={{ queue_worker_sleep | default('3') }} QUEUE_WORKER_TRIES={{ queue_worker_tries | default('3') }} QUEUE_WORKER_TIMEOUT={{ queue_worker_timeout | default('60') }} +# Vault / Encryption +VAULT_ENCRYPTION_KEY={{ encryption_key }} + # Git Repository Configuration (optional - if set, container will clone/pull code on start) GIT_REPOSITORY_URL={{ git_repository_url | default('') }} GIT_BRANCH={{ git_branch | default('main') }} diff --git a/deployment/docs/reference/application-stack.md b/deployment/docs/reference/application-stack.md index 04ee6e15..71432b11 100644 --- a/deployment/docs/reference/application-stack.md +++ b/deployment/docs/reference/application-stack.md @@ -24,6 +24,22 @@ CI/CD Pipeline (Gitea Actions) 4. Application Stack aktualisieren ``` +### Secret Handling für Redis + +- Die Redis-Zugangsdaten liegen verschlüsselt in `deployment/ansible/secrets/production.vault.yml` + unter dem Schlüssel `vault_redis_password`. +- Die Application-Rolle (`roles/application/tasks/sync.yml`) bricht den Deploy ab, + wenn kein Passwort aus dem Vault oder via `-e redis_password=...` vorhanden ist. +- Während des Deployments wird das Passwort in `stacks/application/.env` geschrieben + und steht damit allen PHP-Containern über `REDIS_PASSWORD` zur Verfügung. +- Docker Secrets mit `REDIS_PASSWORD_FILE` werden weiterhin unterstützt, da der + Entry-Point das Secret lädt bevor PHP-FPM startet. +- Das `APP_KEY` stammt ebenfalls aus dem Vault (`vault_app_key`); der Deploy + stoppt, falls kein Schlüssel hinterlegt ist. +- Weitere sicherheitskritische Variablen (z. B. `VAULT_ENCRYPTION_KEY`) werden + aus dem Vault übernommen und in die generierte `.env` geschrieben, damit die + Container-Konfiguration 1:1 mit dem Projekt-Template übereinstimmt. + --- ## Detaillierter Ablauf diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 7eb3db42..53767f2a 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -18,6 +18,7 @@ load_secret() { load_secret "DB_PASSWORD" # Load other secrets +load_secret "REDIS_PASSWORD" load_secret "APP_KEY" load_secret "VAULT_ENCRYPTION_KEY" load_secret "SHOPIFY_WEBHOOK_SECRET"