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.
This commit is contained in:
parent
434121be99
commit
4d9e77c968
29 changed files with 793 additions and 99 deletions
59
ansible/roles/goss/files/goss-baseline-check.sh
Executable file
59
ansible/roles/goss/files/goss-baseline-check.sh
Executable file
|
|
@ -0,0 +1,59 @@
|
|||
#!/bin/bash
|
||||
# Recurring declared-vs-live check. Installed by the goss role.
|
||||
# Writes TAP + a one-line status; notifies only on pass/fail transitions.
|
||||
set -euo pipefail
|
||||
|
||||
GOSS_BIN="${GOSS_BIN:-/usr/local/bin/goss}"
|
||||
GOSS_FILE="${GOSS_FILE:-/etc/goss/baseline.yaml}"
|
||||
STATE_DIR="${STATE_DIR:-/var/lib/railiance/goss}"
|
||||
NOTIFY_URL="${RAILIANCE_GOSS_NOTIFY_URL:-}"
|
||||
HOST="$(hostname -s)"
|
||||
|
||||
mkdir -p "${STATE_DIR}"
|
||||
chmod 0755 "${STATE_DIR}"
|
||||
|
||||
if [[ ! -x "${GOSS_BIN}" || ! -f "${GOSS_FILE}" ]]; then
|
||||
echo "skip: goss binary or baseline missing" | tee "${STATE_DIR}/last.status"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set +e
|
||||
"${GOSS_BIN}" -g "${GOSS_FILE}" validate --format tap > "${STATE_DIR}/last.tap"
|
||||
rc=$?
|
||||
set -e
|
||||
|
||||
if [[ "${rc}" -eq 0 ]]; then
|
||||
result=pass
|
||||
else
|
||||
result=fail
|
||||
fi
|
||||
|
||||
printf 'result=%s host=%s ts=%s rc=%s\n' \
|
||||
"${result}" "${HOST}" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${rc}" \
|
||||
> "${STATE_DIR}/last.status"
|
||||
|
||||
prev=""
|
||||
if [[ -f "${STATE_DIR}/last.result" ]]; then
|
||||
prev="$(cat "${STATE_DIR}/last.result")"
|
||||
fi
|
||||
echo "${result}" > "${STATE_DIR}/last.result"
|
||||
|
||||
logger -t railiance-goss "baseline ${result} on ${HOST} (rc=${rc})"
|
||||
|
||||
if [[ "${result}" == "fail" ]]; then
|
||||
touch "${STATE_DIR}/FAILED"
|
||||
else
|
||||
rm -f "${STATE_DIR}/FAILED"
|
||||
fi
|
||||
|
||||
if [[ -n "${NOTIFY_URL}" && "${result}" != "${prev}" ]]; then
|
||||
payload=$(printf \
|
||||
'{"summary":"Goss baseline %s on %s","event_type":"note","author":"railiance-goss-timer"}' \
|
||||
"${result}" "${HOST}")
|
||||
curl -sS -m 10 -X POST "${NOTIFY_URL}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "${payload}" >/dev/null || \
|
||||
logger -t railiance-goss "notify failed for ${HOST} ${result}"
|
||||
fi
|
||||
|
||||
exit "${rc}"
|
||||
4
ansible/roles/goss/handlers/main.yml
Normal file
4
ansible/roles/goss/handlers/main.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: Reload systemd daemon
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
|
@ -32,6 +32,39 @@
|
|||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Install recurring Goss check wrapper
|
||||
ansible.builtin.copy:
|
||||
src: goss-baseline-check.sh
|
||||
dest: /usr/local/sbin/goss-baseline-check
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Install Goss baseline systemd service
|
||||
ansible.builtin.template:
|
||||
src: railiance-goss-baseline.service.j2
|
||||
dest: /etc/systemd/system/railiance-goss-baseline.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Reload systemd daemon
|
||||
|
||||
- name: Install Goss baseline systemd timer
|
||||
ansible.builtin.template:
|
||||
src: railiance-goss-baseline.timer.j2
|
||||
dest: /etc/systemd/system/railiance-goss-baseline.timer
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Reload systemd daemon
|
||||
|
||||
- name: Enable hourly Goss baseline timer
|
||||
ansible.builtin.systemd:
|
||||
name: railiance-goss-baseline.timer
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
|
||||
- name: Run Goss assertions (TAP output)
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ goss_bin }} -g {{ goss_dir }}/baseline.yaml validate --format tap"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Railiance declared-vs-live Goss baseline
|
||||
Documentation=file:///etc/goss/baseline.yaml
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/goss-baseline-check
|
||||
Nice=10
|
||||
# The wrapper records TAP even when assertions fail.
|
||||
SuccessExitStatus=0 1
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Hourly Railiance Goss baseline (RAIL-HO-WP-0009-T05)
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=1h
|
||||
RandomizedDelaySec=5min
|
||||
Persistent=true
|
||||
Unit=railiance-goss-baseline.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue