diff --git a/infra/ansible/roles/deploy/templates/root.env.j2 b/infra/ansible/roles/deploy/templates/root.env.j2 index d71cefb..b8c307a 100644 --- a/infra/ansible/roles/deploy/templates/root.env.j2 +++ b/infra/ansible/roles/deploy/templates/root.env.j2 @@ -1,10 +1,19 @@ # Top-level docker-compose environment — MQTT credentials and registry prefix. # Managed by Ansible. Do not edit manually. +# +# The passwords are $-escaped ($ -> $$). Compose INTERPOLATES this file, so a +# raw "$fP" in a password is read as the variable $fP, warned about, and +# replaced with an empty string. The env_file templates (c2-core.env.j2 etc.) +# are NOT interpolated, so they keep the literal value — which means an +# unescaped $ here silently gives mosquitto and c2-core two different +# passwords and MQTT auth fails. Compose collapses $$ back to a single $, so +# both sides end up with the real password. +# Do not add the same escaping to the env_file templates; it would be literal. MQTT_C2_USER={{ vault_mqtt_c2_user }} -MQTT_C2_PASS={{ vault_mqtt_c2_pass }} +MQTT_C2_PASS={{ vault_mqtt_c2_pass | replace('$', '$$') }} MQTT_NODE_USER={{ vault_mqtt_node_user }} -MQTT_NODE_PASS={{ vault_mqtt_node_pass }} +MQTT_NODE_PASS={{ vault_mqtt_node_pass | replace('$', '$$') }} # Container registry prefix — docker compose uses this for image: ${REGISTRY}/name:latest REGISTRY={{ vault_registry }}