test(integration): askari_inputonly — INPUT-only default-deny reboot gate
Adds the ADR-025 integration-test profile that proves the askari mesh-hardening REDESIGN (INPUT-only default-deny, forward ACCEPT for Docker) is reboot-safe on a throwaway KVM VM before the live cut-over. Profile applies base (firewall + sshd) and offsite (docker_host + reverse_proxy). Post-reboot verify checks: input policy drop, forward policy accept, admin-addr break-glass SSH (192.168.150.1), Docker up, and a published port answered from the controller. GREEN on 2026-06-19. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d9b8676fce
commit
1042f161b6
3 changed files with 73 additions and 2 deletions
17
tests/integration/overrides/askari_inputonly.yml
Normal file
17
tests/integration/overrides/askari_inputonly.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
# Integration overlay (ADR-025) — the askari mesh-hardening REDESIGN (2026-06-19).
|
||||
# Validates INPUT-only default-deny on a Docker host: input policy drop, forward policy
|
||||
# accept (Docker-safe), SSH via the admin-addr break-glass, reboot-survivable.
|
||||
integration_profile: askari_inputonly
|
||||
base__firewall_apply: true
|
||||
base__firewall_input_only: true
|
||||
# No sshd ListenAddress change — never wt0-only in a throwaway VM.
|
||||
base__ssh_listen_mesh_only: false
|
||||
# Isolated VM: never touch the real mesh.
|
||||
base__mesh_enabled: false
|
||||
# The non-mesh SSH break-glass = the admin-addr path the real design uses. Point it at the
|
||||
# VM's libvirt-NAT gateway (where the harness connects from), by source IP so it is
|
||||
# interface-independent and the default-deny + reboot don't lock out the driver. This
|
||||
# mirrors askari's real base__firewall_admin_addrs (ubongo's WAN) in the test topology.
|
||||
base__firewall_admin_addrs:
|
||||
- 192.168.150.1
|
||||
10
tests/integration/profiles/askari_inputonly.json
Normal file
10
tests/integration/profiles/askari_inputonly.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"groups": ["offsite_hosts"],
|
||||
"applies": [
|
||||
{"playbook": "site.yml", "tags": ["base"]},
|
||||
{"playbook": "offsite.yml", "tags": ["docker_host", "reverse_proxy"]}
|
||||
],
|
||||
"extra_vars_files": ["overrides/askari_inputonly.yml"],
|
||||
"mem_mib": 3072,
|
||||
"vcpus": 2
|
||||
}
|
||||
|
|
@ -11,8 +11,8 @@
|
|||
ansible.builtin.assert:
|
||||
that:
|
||||
- integration_profile is defined
|
||||
- integration_profile in ['askari', 'ubongo']
|
||||
fail_msg: "integration_profile must be set in the profile overlay (askari|ubongo)"
|
||||
- integration_profile in ['askari', 'askari_inputonly', 'ubongo']
|
||||
fail_msg: "integration_profile must be set in the profile overlay (askari|askari_inputonly|ubongo)"
|
||||
|
||||
# ── askari profile — Docker host: published-port forwarding survives the reboot ──
|
||||
# The load-bearing check probes the VM's published :80 FROM the controller (ubongo) — if
|
||||
|
|
@ -83,3 +83,47 @@
|
|||
ubongo profile: expected input policy drop, forward policy accept (input-only),
|
||||
the ssh-from-control lifeline (192.168.150.1), and both admin-addr
|
||||
(192.168.150.98/99) SSH allows in the live ruleset.
|
||||
|
||||
# ── askari_inputonly profile — the mesh-hardening REDESIGN (2026-06-19) ──
|
||||
# INPUT-only default-deny on a Docker host: input policy drop, forward policy ACCEPT
|
||||
# (Docker-safe), SSH via the admin-addr break-glass, published-port DNAT survives reboot.
|
||||
- name: (askari_inputonly) Read the live nftables ruleset
|
||||
when: integration_profile == 'askari_inputonly'
|
||||
ansible.builtin.command: nft list ruleset
|
||||
register: _nft_io
|
||||
changed_when: false
|
||||
|
||||
- name: (askari_inputonly) INPUT default-deny, forward permissive, admin-addr break-glass
|
||||
when: integration_profile == 'askari_inputonly'
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'hook input priority filter; policy drop;' in _nft_io.stdout"
|
||||
- "'hook forward priority filter; policy accept;' in _nft_io.stdout"
|
||||
- "'ip saddr 192.168.150.1 tcp dport 22 accept' in _nft_io.stdout"
|
||||
fail_msg: >-
|
||||
askari_inputonly: expected input policy drop, forward policy accept (input-only),
|
||||
and the admin-addr break-glass (192.168.150.1) SSH allow in the live ruleset.
|
||||
|
||||
- name: (askari_inputonly) Gather service facts
|
||||
when: integration_profile == 'askari_inputonly'
|
||||
ansible.builtin.service_facts:
|
||||
|
||||
- name: (askari_inputonly) Docker daemon is active
|
||||
when: integration_profile == 'askari_inputonly'
|
||||
ansible.builtin.assert:
|
||||
that: "ansible_facts.services['docker.service'].state == 'running'"
|
||||
fail_msg: "docker.service is not running"
|
||||
|
||||
- name: (askari_inputonly) Published port answers from the controller (DNAT + forward alive)
|
||||
when: integration_profile == 'askari_inputonly'
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
ansible.builtin.uri:
|
||||
url: "http://{{ ansible_host }}/"
|
||||
follow_redirects: none
|
||||
status_code: [200, 301, 308, 404, 502, 503]
|
||||
timeout: 10
|
||||
register: _probe_io
|
||||
retries: 5
|
||||
delay: 6
|
||||
until: _probe_io is succeeded
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue