railiance-infra/goss/baseline.yaml.j2
codex 4d9e77c968
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Close RAIL-HO-WP-0009 declared-state gaps; leave live 6443 prune gated
Make the k3s API tunnel-only (ADR-005), stop declaring Flannel VXLAN
open to Anywhere, tag the base role so firewall can be scoped, and
schedule the Goss declared-vs-live check. CoulombCore sets ufw_manage
false so a converge cannot enable UFW there. T02 still needs operator
approval for make converge-firewall HOST=Railiance01.
2026-08-15 15:41:59 +02:00

114 lines
3.5 KiB
Django/Jinja

# Goss baseline assertions for railiance managed nodes.
# Derived from spec/server-baseline.yaml — keep in sync.
# Run: goss -g /etc/goss/baseline.yaml validate
#
# THIS IS A TEMPLATE. It is rendered per host from inventory variables, so the
# firewall assertions below are generated from the SAME declaration that
# converges the host (k3s_api_allowed_sources, flannel_vxlan_allowed_sources,
# ufw_extra_allowed in group_vars). That is deliberate: a hand-written
# assertion drifts from the declaration it is meant to check, which is exactly
# how RAIL-HO-WP-0009 happened.
package:
ufw:
installed: true
fail2ban:
installed: true
git:
installed: true
curl:
installed: true
vim:
installed: true
htop:
installed: true
# age and sops are binary installs, not apt packages — checked via command below
service:
ufw:
enabled: true
running: true
fail2ban:
enabled: true
running: true
# Ubuntu 24.04 uses socket activation: ssh.service is disabled by design,
# ssh.socket keeps it running. Assert the socket is enabled.
ssh.socket:
enabled: true
running: true
file:
/etc/ssh/sshd_config.d/10-hardening.conf:
exists: true
contents:
- "PermitRootLogin no"
- "PasswordAuthentication no"
- "PubkeyAuthentication yes"
user:
tegwick:
exists: true
# sudo access is via /etc/sudoers.d/tegwick (NOPASSWD), not group membership
shell: /bin/bash
command:
"ufw status":
exit-status: 0
stdout:
- "Status: active"
- /OpenSSH.*ALLOW/
{% for src in k3s_api_allowed_sources | default([]) %}
- '/6443\/tcp\s+ALLOW\s+{{ src.address | regex_escape }}/'
{% endfor %}
{% for src in flannel_vxlan_allowed_sources | default([]) %}
- '/8472\/udp\s+ALLOW\s+{{ src.address | regex_escape }}/'
{% endfor %}
{% for rule in ufw_extra_allowed | default([]) %}
- '/{{ rule.port }}\/{{ rule.proto | default("tcp") }}\s+ALLOW/'
{% endfor %}
# Exact allowlist size: extra hand grants must fail, not only missing ones.
# The previous assertion matched /6443\/tcp.*ALLOW/, which passes identically
# whether the API is restricted to one operator address or open to the entire
# internet — it asserted that the port was allowed, not from whom.
"ufw status | grep -Ec '6443/tcp[[:space:]]+ALLOW[[:space:]]+Anywhere' || true":
exit-status: 0
stdout:
- "0"
"ufw status | grep -E '6443/tcp[[:space:]]+ALLOW' | grep -vc 'Anywhere' || true":
exit-status: 0
stdout:
- "{{ k3s_api_allowed_sources | default([]) | length }}"
"ufw status | grep -Ec '8472/udp[[:space:]]+ALLOW[[:space:]]+Anywhere' || true":
exit-status: 0
stdout:
- "0"
"ufw status | grep -E '8472/udp[[:space:]]+ALLOW' | grep -vc 'Anywhere' || true":
exit-status: 0
stdout:
- "{{ flannel_vxlan_allowed_sources | default([]) | length }}"
{% for src in k3s_api_revoked_sources | default([]) %}
# Revoked operator source must not retain access: {{ src.comment | default('') }}
"ufw status | grep -Ec '6443/tcp[[:space:]]+ALLOW[[:space:]]+{{ src.address }}' || true":
exit-status: 0
stdout:
- "0"
{% endfor %}
"grep NOPASSWD /etc/sudoers.d/tegwick":
exit-status: 0
stdout:
- "NOPASSWD"
"grep -r HISTCONTROL /etc/profile.d/":
exit-status: 0
stdout:
- "ignorespace"
"fail2ban-client status sshd":
exit-status: 0
stdout:
- "Status for the jail: sshd"
"test -x /usr/local/bin/age":
exit-status: 0
"test -x /usr/local/bin/sops":
exit-status: 0