Skip to content

fix(nginx): DRY security headers via nginx snippets (#6842) - #7736

Merged
mrveiss merged 1 commit into
Dev_new_guifrom
issue-6842
May 16, 2026
Merged

mrveiss merged 1 commit into
Dev_new_guifrom
issue-6842

Conversation

@mrveiss

@mrveiss mrveiss commented May 16, 2026

Copy link
Copy Markdown
Owner

Thinking Path

autobot-slm.conf.j2 had 5 add_header lines copy-pasted verbatim at the server level, /grafana/api/live/, and /grafana/ location blocks. Because nginx add_header in a child location block replaces all parent-level add_header directives, each block had to re-declare the full header set — causing PR #6751 to update CSP at three independent sites.

Fix: two nginx snippet files, one strict (server default) and one permissive (iframe-host for Grafana/Prometheus), deployed via Ansible before the main nginx site config.

What Changed

  • templates/autobot-security-headers-strict.conf.j2: new — X-Frame-Options SAMEORIGIN, CSP with frame-ancestors 'none'
  • templates/autobot-security-headers-iframe-host.conf.j2: new — CSP with frame-ancestors 'self', unsafe-eval/blob: for Grafana
  • tasks/main.yml: 3 new tasks — ensure snippets dir exists, deploy strict snippet, deploy iframe-host snippet (all tagged slm,nginx, all notify test+reload)
  • templates/autobot-slm.conf.j2: replace duplicate add_header blocks at server level, /grafana/api/live/, and /grafana/ with include directives; add strict include to colocated / location (which previously dropped server-level security headers via its own add_header)

Verification

After Ansible playbook run:

# Strict headers observable at default locations
curl -sI https://<slm-host>/ | grep -E "X-Frame|Content-Security|X-Content"
# iframe-host headers observable at Grafana
curl -sI https://<slm-host>/grafana/ | grep -E "Content-Security|frame-ancestors"
# frame-ancestors 'self' (not 'none') for Grafana
curl -sI https://<slm-host>/grafana/ | grep "frame-ancestors"

Risks

  • /slm/index.html sub-location still has only Cache-Control + Pragma headers — security headers are dropped at that specific path. Pre-existing gap, filed as discovery below.
  • CORS headers on /grafana/ remain as-is (optional, CORS_ENABLED guard).

Model Used

Claude Sonnet 4.6 (claude-sonnet-4-6)

Issue Link

Closes #6842

Checklist

  • Code follows AutoBot patterns from CLAUDE.md
  • Tests added or updated (nginx config — verified via nginx -t on deploy; no unit tests for Jinja2 templates)
  • Documentation updated if behavior changed
  • Pre-commit hooks pass (git commit runs them automatically)
  • PR targets Dev_new_gui (not main)
  • No secrets or credentials in the diff

Before: 5 add_header lines duplicated verbatim at 3+ locations in
autobot-slm.conf.j2 (server level, /grafana/api/live/, /grafana/).
Any CSP change required editing all sites.

After: Two snippet files deployed by Ansible to /etc/nginx/snippets/:
- autobot-security-headers-strict.conf: server default (frame-ancestors 'none')
- autobot-security-headers-iframe-host.conf: Grafana/dashboard embedding
  (frame-ancestors 'self', unsafe-eval/blob: for chart rendering)

Each location now uses `include` instead of inline add_header blocks.
Also wires strict snippet into the colocated `/` location which previously
dropped server-level security headers via its own add_header directives.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@mrveiss
mrveiss merged commit f853a15 into Dev_new_gui May 16, 2026
4 of 5 checks passed
@mrveiss
mrveiss deleted the issue-6842 branch May 16, 2026 07:45
@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

@mrveiss
mrveiss restored the issue-6842 branch May 17, 2026 08:38
@mrveiss
mrveiss deleted the issue-6842 branch May 17, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant