mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(matrix): gate the CA binds on the predicate that provisions them
sys-svc-compose-ca writes the CA material for exactly lookup('ca_injected', application_id), which asks three questions per application: has a domain, TLS enabled, mode self_signed. The lookup exists against this drift and says so in its own docstring: anything that reads the mounted file must ask the same three or it points at a path that was never mounted.
The matrix templates asked the global TLS_MODE instead. On an onion deployment TLS is off per application while TLS_MODE stays self_signed, so run 34653754175 logged 'CA trust N/A for web-app-matrix (TLS off/not self-signed) mark done' and the templates rendered the binds anyway.
The rest follows from the timing in that run: the matrix container was created at 05:49:35, the bundle was first written at 05:58:45 by sys-ca-selfsigned. At create time the bind pointed at a path that did not exist, which docker materialises as a directory, and the later docker restart matrix from 02_render_inventory.yml:22 failed on 'error mounting /etc/infinito.nexus/ca/ca-bundle.crt ... not a directory'.
MATRIX_CA_INJECTED holds the predicate once in vars/main.yml, beside MATRIX_CA_MOUNT_PATH, and both templates read it: the outer container bind and the synapse arguments for the nested daemon. The test pins both links of the chain, that the constant is derived from the lookup and that both if lines use the constant, so redefining it from TLS_MODE cannot pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
da09ee575b
commit
d5fc099166
4 files changed
+33
-3
No files matched your search
@@ -26,7 +26,7 @@
|
||||
- {{ lookup('volume', application_id, 'matrix_mdad_docker').name }}:{{ lookup('volume', 'web-app-matrix', 'matrix_mdad_docker').target }}
|
||||
- {{ lookup('volume', application_id, 'matrix_mdad_state').name }}:{{ lookup('volume', 'web-app-matrix', 'matrix_mdad_state').target }}
|
||||
- {{ lookup('volume', application_id, 'matrix_mdad_matrix').name }}:{{ lookup('volume', 'web-app-matrix', 'matrix_mdad_matrix').target }}
|
||||
{% if (TLS_MODE | lower) == 'self_signed' %}
|
||||
{% if MATRIX_CA_INJECTED | bool %}
|
||||
- {{ CA_TRUST.cert_host }}:{{ CA_TRUST.cert_host }}:ro
|
||||
- {{ CA_TRUST.bundle_host }}:{{ CA_TRUST.bundle_host }}:ro
|
||||
{% endif %}
|
||||
|
||||
@@ -60,7 +60,7 @@ jitsi_jicofo_container_network: host
|
||||
matrix_livekit_jwt_service_container_port: 8030
|
||||
|
||||
{% set _synapse_extra_args = [] %}
|
||||
{% if (TLS_MODE | lower) == 'self_signed' %}
|
||||
{% if MATRIX_CA_INJECTED | bool %}
|
||||
{% set _ = _synapse_extra_args.extend([
|
||||
'--mount type=bind,src=' ~ CA_TRUST.bundle_host ~ ',dst=' ~ MATRIX_CA_MOUNT_PATH ~ ',ro',
|
||||
'-e SSL_CERT_FILE=' ~ MATRIX_CA_MOUNT_PATH,
|
||||
|
||||
@@ -85,6 +85,7 @@ MATRIX_CONFERENCING_ELEMENT_CALL: "{{ lookup('config', application_id, 'services
|
||||
|
||||
MATRIX_LDAP_ENABLED: "{{ lookup('config', application_id, 'services.ldap.enabled') | bool }}"
|
||||
|
||||
MATRIX_CA_INJECTED: "{{ lookup('ca_injected', application_id) | bool }}"
|
||||
MATRIX_CA_MOUNT_PATH: "{{ CA_TRUST.cert_container }}"
|
||||
|
||||
MATRIX_POSTGRES_HOST: "{{ lookup('database', application_id, 'host') }}"
|
||||
|
||||
@@ -24,6 +24,8 @@ from utils.cache.files import read_text
|
||||
from . import PROJECT_ROOT
|
||||
|
||||
_MATRIX = PROJECT_ROOT / "roles/web-app-matrix/templates/flavor/ansible"
|
||||
_VARS = PROJECT_ROOT / "roles/web-app-matrix/vars/main.yml"
|
||||
_CA_GATE = "MATRIX_CA_INJECTED"
|
||||
|
||||
_BOUND_BY_SYNAPSE = re.compile(r"src='?\s*~?\s*CA_TRUST\.(\w+)")
|
||||
_PASSED_THROUGH = re.compile(
|
||||
@@ -64,9 +66,36 @@ class TestCaTrustPassthrough(unittest.TestCase):
|
||||
f"`- {{{{ CA_TRUST.{name} }}}}:{{{{ CA_TRUST.{name} }}}}:ro`"
|
||||
for name in missing
|
||||
)
|
||||
+ " to the self_signed block.",
|
||||
+ " to the ca_injected block.",
|
||||
)
|
||||
|
||||
def test_the_ca_blocks_are_gated_by_the_predicate_that_provisions_them(
|
||||
self,
|
||||
) -> None:
|
||||
drift = (
|
||||
"sys-svc-compose-ca provisions the CA material for exactly this "
|
||||
"predicate, while TLS_MODE is global: on an onion deployment TLS "
|
||||
"is off per app, the CA is never written, and compose bind-mounts "
|
||||
"a path docker then creates as a directory. The restart once the "
|
||||
"file appears fails with 'not a directory' (run 34653754175, "
|
||||
"Matrix#1)"
|
||||
)
|
||||
self.assertIn(
|
||||
f"{_CA_GATE}: \"{{{{ lookup('ca_injected', application_id) | bool }}}}\"",
|
||||
read_text(str(_VARS)),
|
||||
drift,
|
||||
)
|
||||
for name in ("services.yml.j2", "vars.yml.j2"):
|
||||
with self.subTest(template=name):
|
||||
template = read_text(str(_MATRIX / name))
|
||||
gate = next(
|
||||
line
|
||||
for line in template.splitlines()
|
||||
if "CA_TRUST" in template and line.strip().startswith("{% if ")
|
||||
if _CA_GATE in line or "TLS_MODE" in line
|
||||
)
|
||||
self.assertIn(_CA_GATE, gate, drift)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user