Los comandos de ejemplo "podman inspect ... --format '{{range
.Config.Env}}{{println .}}{{end}}'" son sintaxis de Go templates, no de
Tera, pero Zola igual intenta interpretarlos como expresiones Tera al
renderizar la página — zola check fallaba con "Found `}}` but expected
identifier". Encontrado por la propia CI al validar --require-zola tras
la conversión a instancia (antes nunca se había corrido zola check
sobre este contenido en CI con la ruta real). Envueltos en {% raw %}.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
71 lines
7.5 KiB
Markdown
71 lines
7.5 KiB
Markdown
+++
|
|
title = "Configurar correo saliente para recuperación de contraseña en Zammad y Grafana"
|
|
description = "Zammad tenía la credencial SMTP de salida desincronizada del buzón real (los resets de contraseña fallaban silenciosamente); Grafana no tenía SMTP configurado en absoluto. Se creó una cuenta dedicada de solo-salida y se configuró en ambos servicios, sin tocar el buzón soporte@ que Zammad usa para recibir tickets."
|
|
date = 2026-08-24T20:49:04Z
|
|
authors = ["gen"]
|
|
slug = "mem-20260824-254312-configurar-correo-saliente-para-recuperacion-de-contrasena-en-zammad-y-grafana"
|
|
template = "memory.html"
|
|
|
|
[taxonomies]
|
|
categories = ["memorias"]
|
|
tags = ["correo", "docker-mailserver", "grafana", "smtp", "zammad"]
|
|
systems = ["grafana", "mail-server", "mcps-hpc-01", "mcps-vpn-server", "zammad"]
|
|
|
|
[extra]
|
|
id = "MEM-20260824-254312"
|
|
kind = "memory"
|
|
author_id = "gen"
|
|
author_fingerprint = "SHA256:JhN1Tt4jYqWoJIznDJ6QkMAiOR6HFHr3xLz9aBJqmPg"
|
|
risk = "medium"
|
|
ticket = ""
|
|
review_required = true
|
|
review_policy = "all-active"
|
|
reviewer_snapshot = true
|
|
reviewers = ["gen"]
|
|
started_at = ""
|
|
finished_at = ""
|
|
duration_minutes = 0
|
|
agent = "claude-code"
|
|
+++
|
|
|
|
## Contexto
|
|
|
|
El usuario pidió configurar correo saliente en mail.mcps-epcm.org (10.8.0.1, mcps-vpn-server) para que soporte.mcps-epcm.org (Zammad) y grafana.mcps-epcm.org (Grafana, ambos en mcps-hpc-01) puedan mandar el correo de 'olvidé mi contraseña'. Diagnóstico: el contenedor zammad-railsserver tenía SMTP_USER_NAME=soporte@mcps-epcm.org y un SMTP_PASSWORD que ya NO coincidía con la contraseña real del buzón (confirmado con un intento swaks que produjo 'Password mismatch' / 'SASL LOGIN authentication failed' en el log de postfix). Ese mismo buzón soporte@ es el canal de ENTRADA real de Zammad (Channel id=1, área Email::Notification para el saliente; hay además un Channel id=5 de tipo IMAP que zammad-fetch-mail.timer sondea cada 60s para crear tickets desde correos entrantes — ese canal sí tiene la contraseña correcta, guardada en la base de datos de Zammad, no accesible desde fuera). Rotar la contraseña de soporte@ habría arreglado el saliente pero roto el sondeo IMAP de entrada (Channel 5), que sigue funcionando con normalidad. Por eso se optó por crear una cuenta nueva dedicada solo a notificaciones automáticas salientes (notificaciones@mcps-epcm.org), dejando soporte@ intacto. Grafana no tenía ninguna sección [smtp] activa (todo comentado/default) ni SSO configurado (auth local activa por default), así que hoy era literalmente imposible que mandara cualquier correo. Se creó la cuenta en docker-mailserver, se verificó por SMTP con swaks (auth+entrega limpia confirmada en el log de postfix/amavis). Se actualizó el Channel id=1 de Zammad (área Email::Notification) por rails runner dentro del contenedor zammad-railsserver, apuntando host/user/password/domain a la cuenta nueva, dejando notification_sender ('Soporte MCPS <soporte@mcps-epcm.org>') sin cambios para que el remitente visible siga siendo reconocible aunque la autenticación SMTP real sea con notificaciones@. Se probó un envío real de extremo a extremo replicando el pipeline de entrega de Zammad (Mail.new + delivery_method :smtp con las mismas opciones ya guardadas en el Channel) y llegó limpio. Para Grafana, no había compose file ni bind-mount de config: el contenedor se recrea vía un unit de systemd propio (/etc/systemd/system/container-grafana.service, patrón 'podman run' directo, igual que el de Caddy documentado en el manual RUN-20260819-A3B63B). Se agregó GF_SMTP_* al ExecStart, con GF_SMTP_PASSWORD inyectado en forma 'bare' desde un EnvironmentFile dedicado (/etc/grafana-smtp.env, 600 root:root) — mismo patrón de manejo de secretos que ya usa Caddy con las credenciales de Route53. Se respaldó la unit original antes de editar (container-grafana.service.bak-2026-08-24). Tras systemctl daemon-reload + restart, el contenedor recreado ya expone las variables GF_SMTP_* correctas. No se pudo verificar el flujo completo de 'olvidé mi contraseña' de Grafana desde este entorno (no hay acceso a navegador ni sesión admin de Grafana para disparar su endpoint de test email) — queda pendiente un clic de prueba real por parte de un administrador.
|
|
|
|
## Cambios realizados
|
|
|
|
- Creada la cuenta notificaciones@mcps-epcm.org en docker-mailserver (mcps-vpn-server), verificada por SMTP con swaks
|
|
- Actualizado Channel id=1 (Email::Notification, saliente) de Zammad para autenticar con notificaciones@mcps-epcm.org en vez de la contraseña vieja de soporte@; notification_sender se dejó igual
|
|
- Probado un envío real desde Zammad usando el canal actualizado, confirmado entregado limpio en el log de postfix/amavis
|
|
- Agregada configuración SMTP a Grafana: nuevo /etc/grafana-smtp.env (600, root:root) con la contraseña, y variables GF_SMTP_ENABLED/HOST/USER/PASSWORD/FROM_ADDRESS/FROM_NAME/STARTTLS_POLICY agregadas al ExecStart de /etc/systemd/system/container-grafana.service (unit original respaldada como .bak-2026-08-24)
|
|
- systemctl daemon-reload + restart de container-grafana.service; confirmado que el contenedor recreado expone las variables GF_SMTP_* nuevas
|
|
|
|
## Comandos relevantes (secretos redactados)
|
|
|
|
{% raw %}
|
|
```console
|
|
podman exec mailserver setup email list
|
|
podman exec mailserver setup email add notificaciones@mcps-epcm.org <password redactado>
|
|
swaks --to prueba@mcps-epcm.org --from notificaciones@mcps-epcm.org --server mail.mcps-epcm.org:587 --auth LOGIN --auth-user notificaciones@mcps-epcm.org --auth-password <redactado> --tls --hide-all
|
|
podman exec zammad-railsserver bash -lc "rails r 'Channel.where(area: %q(Email::Notification))...'"
|
|
podman exec zammad-railsserver bash -lc "rails r 'c = Channel.find(1); ... c.options[:outbound][:options][:password] = <redactado>; c.save!'"
|
|
podman exec zammad-railsserver bash -lc "rails r 'Mail.new(...).delivery_method(:smtp, ...).deliver'" # prueba end-to-end
|
|
systemctl cat container-grafana.service
|
|
cp /etc/systemd/system/container-grafana.service /etc/systemd/system/container-grafana.service.bak-2026-08-24
|
|
tee /etc/grafana-smtp.env # GF_SMTP_PASSWORD=<redactado>, chmod 600
|
|
systemctl daemon-reload && systemctl restart container-grafana.service
|
|
podman inspect grafana --format '{{range .Config.Env}}{{println .}}{{end}}'
|
|
```
|
|
{% endraw %}
|
|
|
|
## Validación
|
|
|
|
- swaks contra la cuenta notificaciones@ terminó con exit 0 y el log de postfix mostró sasl_username=notificaciones@mcps-epcm.org + amavis 'Passed CLEAN'
|
|
- Tras actualizar el Channel de Zammad, un envío real replicando su pipeline de entrega (Mail + delivery_method :smtp con las opciones guardadas) terminó en 'OK' y el log de postfix/amavis confirmó entrega limpia desde notificaciones@ hacia prueba@
|
|
- podman inspect grafana tras el restart mostró las 7 variables GF_SMTP_* con los valores esperados (incluida la contraseña resuelta desde el EnvironmentFile)
|
|
- systemctl is-active container-grafana.service devolvió 'active' tras el restart, sin reinicios en bucle
|
|
|
|
## Riesgo y reversión
|
|
|
|
Restaurar /etc/systemd/system/container-grafana.service.bak-2026-08-24 sobre container-grafana.service, borrar /etc/grafana-smtp.env, systemctl daemon-reload && systemctl restart container-grafana.service para volver Grafana a su estado sin SMTP. En Zammad, el Channel id=1 puede revertirse manualmente (rails runner) a host/user/password de soporte@ si se decide no usar la cuenta dedicada — no hay comando de un solo paso, hay que reconstruir el hash de options a mano. La cuenta notificaciones@mcps-epcm.org puede borrarse con 'setup email del' si se abandona este enfoque; no tiene aliases ni depende de nada más.
|