Files
computer-playbook/docs/requirements/029-web-app-checkmk.md
kevinveenbirkenbachandClaude Opus 4.8 4039313266 refactor(tasks): enforce and apply a single task-file numbering scheme
Add tests/lint/repository/test_task_file_numbering.py: numbered task
files use exactly two leading digits, a numbered *_core.yml must be
00_core.yml, per directory the numbers are unique/consecutive and start
at 01 (00 with a core file), numbered includes appear in ascending
order, and shared helpers live in tasks/utils/ instead of the numbered
chain.

Apply it across every role: rename NN_core.yml to 00_core.yml with a
consecutive down-shift of the siblings, move letter-suffix children into
a subdirectory named after their parent task, relocate helpers included
from more than one place into tasks/utils/, and update every reference
(include_tasks, path_absolute, .ansible-lint-ignore, requirement docs).
Legacy narration comments in the touched files are deleted; the upstream
xwiki.properties reference block opts out via nocheck. The unused
MAILU_IP6_PUBLIC var (only ever named in now-removed comments) is dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 20:01:31 +02:00

9.9 KiB

029 - Checkmk Role with oauth2-proxy SSO + LDAP

User Story

As a platform administrator of Infinito.Nexus, I want Checkmk integrated as a web-app-checkmk role with Keycloak SSO (via the oauth2-proxy gate) and native LDAP user management so that operators can run the open-source Checkmk monitoring server behind the platform's central Single Sign-On, validated end-to-end with Playwright personas.

Background

Checkmk is an open-source IT/infrastructure & application monitoring system. The Raw / Community edition (100% open source) ships an official all-in-one container that bundles the monitoring core, RRD storage, and the Apache-served web GUI — it needs no external database.

Upstream facts established by research

Topic Finding Source
Image checkmk/check-mk-raw (Raw/Community, free); renamed checkmk/check-mk-community from 2.5. Pin a concrete patch tag (no :latest). Docker Hub, Docker docs
Bootstrap env CMK_SITE_ID (OMD site, default cmk), CMK_PASSWORD (initial cmkadmin password, first run only), TZ, MAIL_* for outbound mail. managing_docker
Ports 5000 = site Apache (GUI at /<site>/check_mk/), 8000 = agent receiver (TLS agent registration). introduction_docker
Database None external — Checkmk Raw bundles Nagios core + RRDtool; all state on one persistent volume (/omd/sites). managing_docker
LDAP Native in all editions (incl. Raw): LDAP "connections" sync users, contact groups, roles. ldap.html
SAML Commercial editions only; Raw needs mod_auth_mellon (manual, unsupported). saml.html
OIDC Not native in any edition; Raw only via Apache mod_auth_openidc (manual PoC). → use the platform oauth2-proxy gate instead. Forum HOWTO
Header SSO Global setting "Authenticate users by incoming HTTP requests" / auth_by_http_header = "X-Remote-User" — reads the username from a trusted reverse-proxy header. Werk #7819, omd_https

In-repo analogues

  • SSO flavor is oauth2 (oauth2-proxy sidecar → Keycloak), NOT native OIDC — because Checkmk Raw has no OIDC. The oauth2-proxy authenticates against Keycloak and passes X-Remote-User; Checkmk's site Apache trusts it via auth_by_http_header. This mirrors web-app-openproject's header-SSO bridge (OPENPROJECT_AUTH__SOURCE__SSO_HEADER + LDAP-gated header trust).
  • LDAP native (the user record + roles/contact groups), gated on svc-db-openldap, so the X-Remote-User (Keycloak preferred_username) resolves to a real Checkmk user.
  • No external DB consumer (unlike the Semaphore role, which is tracked on a separate branch/PR).

Confirmed Decisions

These decisions were confirmed by the operator before implementation starts and are NOT subject to re-litigation during implementation.

# Decision Rationale
1 Canonical hostname monitoring.{{ DOMAIN_PRIMARY }}; GUI served under the site path /<site>/check_mk/. Standard single-host convention; Checkmk serves its GUI under the OMD site path.
2 Edition is Raw / Community (checkmk/check-mk-raw). Operator decision: 100% open source, matches the platform; OIDC handled via the oauth2-proxy gate.
3 SSO is the oauth2-proxy gate + Checkmk header-auth (auth_by_http_header = "X-Remote-User") + native LDAP. Operator decision: Keycloak SSO at the proxy, Checkmk trusts the proxy-supplied user, LDAP supplies the user record/roles/contact groups.
4 The agent receiver (port 8000) IS exposed (mapped + proxied) for TLS agent registration. Operator decision: enable remote-host agent registration in v1.
5 Image pinned to a concrete stable Checkmk 2.x patch tag (no :latest). Standard upstream-pin policy.
6 OMD site id cmk; single site; no external DB; one persistent volume for /omd/sites. Checkmk Raw bundles its own core/RRD; nothing external needed.

Target Schema

Role layout

roles/web-app-checkmk/
├── README.md
├── files/playwright/{_shared,playwright.spec,test-guest,test-login-oidc-biber,test-login-oidc-administrator,test-login-ldap-biber}.js
├── meta/{main,info,server,services,schema,users,rbac,variants,volumes}.yml
├── tasks/{main,00_core}.yml
├── templates/{compose.yml.j2,env.j2,playwright.env.j2}
└── vars/main.yml

meta/services.yml excerpt (oauth2-proxy flavor, no external DB)

sso:
  enabled: "{{ 'web-app-keycloak' in group_names }}"
  shared:  "{{ 'web-app-keycloak' in group_names }}"
  flavor:  oauth2
  oauth2:
    origin: { host: application, port: "5000" }
ldap:
  enabled: "{{ 'svc-db-openldap' in group_names }}"
  shared:  "{{ 'svc-db-openldap' in group_names }}"
checkmk:
  image:   checkmk/check-mk-raw
  version: "X.Y.Zp?"
  name:    checkmk
  ports:
    internal: { http: 5000 }
    local:    { http: <free port> }
  run_after: [web-app-keycloak]
  lifecycle: alpha

Acceptance Criteria

Routing & TLS

  • monitoring.{{ DOMAIN_PRIMARY }} resolves through sys-svc-proxy (and, when SSO is on, the oauth2-proxy gate) to the Checkmk site Apache; GET /<site>/check_mk/ returns the Checkmk login/GUI.
  • The site-path redirect (/ → /<site>/check_mk/) works behind the proxy.
  • The role emits a Content-Security-Policy header on the canonical surface.
  • The agent receiver (container port 8000) is mapped to a host port (Decision #4) and reachable for TLS agent registration.

Role layout & image

  • roles/web-app-checkmk/ exists per the Target Schema; image pinned to a concrete Checkmk 2.x patch (no :latest).
  • All meta/*.yml exist and pass the role-meta lint.

Bootstrap

  • CMK_SITE_ID, CMK_PASSWORD (from a rendered credential), TZ seed the site + cmkadmin on first run; the stack reaches a steady running state on one persistent volume.

SSO / oauth2 + header auth (Decision #3)

  • When SSO is enabled, the oauth2-proxy gate fronts Checkmk and authenticates against Keycloak (client auto-provisioned via the redirect_uris filter).
  • Checkmk's auth_by_http_header = "X-Remote-User" is configured so the proxy-supplied user is logged in without a second login.
  • A Playwright OIDC flow (biber + administrator) passes the oauth2-proxy → Keycloak chain and lands authenticated in the Checkmk GUI (administrator additionally reaches a Setup/admin-only surface).

LDAP (Decision #3)

  • When svc-db-openldap is in group_names, an LDAP connection is provisioned (files/configure-sso.sh) so LDAP users (matching the X-Remote-User) exist with roles/contact groups. LDAP is a backend identity source behind the oauth2 gate — there is no separate LDAP login surface, so it is exempted from a Playwright gate (# nocheck: playwright-service-flag), mirroring web-app-openproject.

Variants

  • meta/variants.yml defines three variants (V1 sso+ldap, V2 all-false, V3 ldap-only); all deploy cleanly on a fresh box.

Playwright

  • Persona coverage via the shared oauth2-gate helpers (mirroring web-app-openproject): test-baseline.js (reachability + guest/biber/administrator personas), test-oidc-login.js (oauth2 gate + X-Remote-User session, gated on sso), test-oidc-security.js (forged-header bypass guard). biber/administrator are gated to SSO via PERSONA_*_BLOCKED. templates/playwright.env.j2 exposes every read env var; make compose-playwright role=web-app-checkmk exits 0 with no stub tests and a clean logged-out final state.

Health & quality

  • Stack steady across all three variants; make test green tree-wide.

Documentation

  • README.md documents edition + bump policy, the oauth2-proxy+header-auth+LDAP model, the site-path routing, the agent-receiver decision, and the no-external-DB design.
  • This requirement is cross-linked from the implementing PR.

Validation Apps

INFINITO_APPS="web-app-checkmk" make deploy-fresh-purged-apps INFINITO_FULL_CYCLE=true

Smoke: visit https://monitoring.{{ DOMAIN_PRIMARY }}/ → (SSO) Keycloak chain → Checkmk GUI; open Setup (admin); confirm an LDAP user resolves.

Prerequisites

Before implementation, the agent MUST read AGENTS.md, then Role Loop and the Playwright contract.

Implementation Strategy

Execute autonomously after the Open Questions are resolved. Scaffold using roles/web-app-openproject/ as the structural template (oauth2 flavor + header SSO + LDAP). Verify all Checkmk env names, the auth_by_http_header config mechanism, site-path routing, and the GUI selectors against the pinned upstream version before claiming done.

Commit Policy

  • No git commit until every Acceptance Criterion is checked off.
  • When met and make test is green, instruct the operator to run git-sign-push outside the sandbox. The agent MUST NOT push.

Context