This Blastwall proof was recorded in Calabi, my nested-KVM lab for modeling disconnected OpenShift and support-service boundaries in a controlled environment. Calabi gives this run a real IdM server, bastion host, mirror registry, Kerberos flow, and managed endpoint; Blastwall itself does not require Calabi.

What This Proves

This demo shows the whole control path without requiring AAP. AAP is not needed to prove the local behavior: the same IdM state AAP would consume is visible before the mutation step, and the final denial is enforced by the target host SELinux policy.

The run starts from bastion-01, uses eigenstate.ipa to read IdM state before enforcement, deploys policy to mirror-registry, runs AF_ALG, BPF, packet_socket, userns, and io_uring probes as the mapped automation identity, then proves self-protection by blocking sudo-expanded policy manipulation.

The observable flow is:

  • bastion-01 runs the Calabi PoC playbooks locally.
  • eigenstate.ipa validates the IdM SELinux user map, HBAC rule, sudo rule, and candidate host view.
  • mirror-registry receives the Blastwall policy RPM.
  • The automation identity logs in with the expected SELinux context.
  • The AF_ALG/authencesn, BPF, packet_socket, userns, io_uring, xfrm, and RxRPC probes are blocked for that mapped automation session.
  • The target audit log shows denied socket, bpf, and namespace syscall evidence for blastwall_t; the io_uring denial is visible in the probe output.
  • A temporary sudo expansion exposes /usr/sbin/semodule, and SELinux still prevents the automation identity from removing a deny module.
Ansible Demo Flow The non-AAP proof starts on the bastion, reads IdM state before mutation, deploys policy, runs probes, and finishes with audit and self-protection evidence.
Ansible demo flow from bastion PoC tree through IdM read-side proof, policy deployment, denied probes, and audit self-protection evidence

What This Does Not Prove

  • It does not compete with the AAP demo as the main operator-facing proof. This is the bootstrap and host-local proof.
  • It does not require AAP to prove the local behavior. AAP later consumes and records the state shown here.
  • It does not run live exploit payloads. The probes exercise safe entry points that should be denied before useful exploit behavior.

Ansible Demo

Evidence Map

  1. The IdM side is not assumed. It is queried before the endpoint enforcement play runs.
  2. The inventory candidate view includes mirror-registry.workshop.lan through the Blastwall policy objects.
  3. The target host can install or refresh the Blastwall SELinux policy RPM through an ordinary Ansible workflow.
  4. The mapped automation session reports blastwall_u:blastwall_r:blastwall_t:s0.
  5. The AF_ALG/authencesn probe reports BLOCKED.
  6. The BPF probe reports BLOCKED for both BPF_MAP_CREATE and BPF_PROG_LOAD.
  7. The packet_socket probe reports BLOCKED for AF_PACKET socket creation.
  8. The userns probe reports BLOCKED for unshare(CLONE_NEWUSER).
  9. The io_uring probe reports BLOCKED for io_uring_setup, or SKIP on kernels without that object class.
  10. The Dirty Frag probe reports BLOCKED for NETLINK_XFRM and AF_RXRPC socket creation.
  11. The self-protection play shows sudo can be expanded while SELinux still denies semodule execution from blastwall_t.
  12. A conventional audit-log check shows the SELinux denial evidence from the target host.

Recording Guide

1. Start from the bastion-local PoC tree

pwd
cd ~/blastwall/poc-calabi

Execution starts from the staged repository on bastion-01. That keeps the boundary honest: the workstation is not directly driving guest configuration.

2. Create and prove the IdM identity boundary

ansible-playbook 10-configure-idm.yml
kinit admin
ipa user-show svc-ansible-runner --all --raw | grep -E 'uid:|memberof_group:|memberOf:'
ipa group-show blastwall --all --raw | grep -E 'cn:|member_user:|member:'

The service identity, the blastwall group, and membership are visible before the enforcement play touches mirror-registry.

3. Run the read-side IdM gate

ansible-playbook 15-validate-idm-with-eigenstate.yml | tee /tmp/blastwall-eigenstate.log

eigenstate.ipa reads the SELinux map, HBAC rule, sudo rule, and inventory candidate view before the enforcement play touches mirror-registry.

hbac_rule: blastwall-ssh
selinux_map: blastwall-root-local-map
sudo_rule: blastwall-root-local-sudo
target: mirror-registry.workshop.lan

4. Deploy policy and run the playbook proof

ansible-playbook 30-deploy-and-test.yml | tee /tmp/blastwall-proof.log

The target host installs the Blastwall RPM, refreshes local policy state, and runs the automated validation for AF_ALG, BPF, packet_socket, userns, io_uring, xfrm, and RxRPC.

5. Mark the Dirty Frag response date

date -u '+Dirty Frag response marker: %Y-%m-%d %H:%M:%S UTC'
echo 'Blastwall 0.5.2: verify xfrm and RxRPC are denied for confined automation'

This callout keeps the timing visible in the non-AAP proof: Dirty Frag was publicly documented on May 7, 2026, and this run verifies the xfrm and RxRPC deny scopes on May 8, 2026.

6. Inspect and run the probes directly

kinit svc-ansible-runner
ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-copyfail-afalg.py

ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-bpf-deny.py

ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-packet-socket-deny.py

ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-userns-deny.py

ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-io-uring-deny.py

ssh -o GSSAPIAuthentication=yes \
  svc-ansible-runner@mirror-registry.workshop.lan \
  /usr/local/libexec/blastwall-poc/trigger-dirtyfrag-deny.py

The operator inspects the probe source, gets a Kerberos ticket for svc-ansible-runner, and runs the probes over GSSAPI SSH so the denial is visible as normal command output.

blastwall_u:blastwall_r:blastwall_t:s0
BLOCKED: AF_ALG socket creation denied with errno 13
BLOCKED: bpf(BPF_MAP_CREATE) denied with errno 13
BLOCKED: bpf(BPF_PROG_LOAD) denied with errno 13
BLOCKED: AF_PACKET socket creation denied with errno 13
BLOCKED: unshare(CLONE_NEWUSER) denied with EACCES errno 13
BLOCKED: io_uring_setup denied with EPERM  [CVE-2026-43006]
BLOCKED: Dirty Frag NETLINK_XFRM socket creation denied with errno 13
BLOCKED: Dirty Frag AF_RXRPC socket creation denied with errno 13

7. Read the target audit log

ansible automation_endpoints -i inventory.yml -b -m shell -a '
  grep -a '\''subj=blastwall'\'' /var/log/audit/audit.log |
  tr '\''\035'\'' '\''\n'\'' |
  grep -E '\''type=SYSCALL.*(syscall=41|syscall=321|syscall=272).*exit=-13|SYSCALL=(socket|bpf|unshare).*AUID="svc-ansible-runner"'\'' |
  sed -E '\''s/.*audit\(([^)]*)\).*syscall=([0-9]+).*exit=(-?[0-9]+).*comm="([^"]+)".*subj=([^ ]+).*/type=SYSCALL audit(\1) syscall=\2 exit=\3 comm="\4" subj=\5/; s/.*SYSCALL=([^ ]+).*AUID="([^"]+)".*/ARCH SYSCALL=\1 AUID="\2"/'\'' |
  tail -n 16'

The audit check is intentionally conventional, but it is executed through Ansible against the target endpoint. It is there to show SELinux enforcement from the target host, not just stored Ansible variables.

8. Prove the policy protects itself

ansible-playbook 35-test-self-protection.yml | tee /tmp/blastwall-selfprotect.log
grep -E \
  'sudo_expansion_seen|semodule_attempt_rc|semodule_attempt_stderr|Permission denied|blastwall-(alg|bpf|packet|userns|io-uring|xfrm|rxrpc|policy)' \
  /tmp/blastwall-selfprotect.log

The self-protection play temporarily adds /usr/sbin/semodule to the Blastwall sudo command group, verifies the automation identity can see that sudo expansion, then attempts to remove a deny module. Sudo is not the final boundary: SELinux denies semodule from blastwall_t, and the deny modules remain installed.

Expected Result

A successful bootstrap proof shows the mapped context blastwall_u:blastwall_r:blastwall_t:s0, sudo UID 0 without leaving that context, blocked AF_ALG, BPF, packet_socket, userns, io_uring, xfrm, and RxRPC probes, audit evidence on the target host, and a self-protection denial when the confined automation identity attempts policy manipulation.

Scope Notes

  • It does not replace a kernel fix.
  • SELinux does not inspect the same kernel hook arguments as BPF LSM.
  • It does not require AAP to prove the local behavior.
  • It does not run live exploit payloads. The probes exercise safe entry points that should be denied before reaching the dangerous path.
  • It does not say host markers are proof by themselves. They are useful only after a local verification workflow writes them.