blastwall is a proof of concept for using SELinux user confinement as an exploit firewall for privileged automation. The diagrams below are the argument, not decoration: they show where this model sits beside BPF LSM precision, how it moves through RHEL operations, and where AAP should decide to run, skip, or remediate.
Recent events make the argument in Privileged Automation Security feel less theoretical. Blastwall is a concrete sketch of that concern: privileged automation should arrive constrained, observable, and policy-gated before it can touch the rest of the fleet.
The Problem
The failure mode I am trying to avoid is simple: automation gets the same broad local shape as an operator, but it executes faster, across more hosts, and with less human friction. If that automation lands as an unconfined identity, every mistake and every exploit path starts from a position I do not want to defend.
Copy Fail is the concrete example here. Anthony Green's block-copyfail shows the precise BPF LSM answer: inspect the AF_ALG bind argument and deny the vulnerable authencesn shape. Blastwall asks a different operational question: if the risky path should be unavailable to privileged automation, can I make that part of the same SELinux, IdM, AAP, and content-delivery model RHEL operators already understand?
flowchart LR
COPY["Copy Fail mitigation idea"] --> BPF["block-copyfail<br/>BPF LSM precision"]
COPY --> BW["Blastwall<br/>SELinux automation boundary"]
BPF --> BPFHOOK["socket_bind hook<br/>inspect authencesn"]
BPFHOOK --> BPFDENY["Deny exact algorithm"]
BW --> IDM["IdM maps identity<br/>to blastwall_u"]
IDM --> AAP["AAP preflight<br/>chooses safe hosts"]
AAP --> SELINUX["SELinux denies<br/>alg_socket for automation"]
The Argument
I do not think FreeIPA should author SELinux policy. I want IdM to map named automation identities into SELinux users and roles that already exist on the endpoint. I also do not want AAP discovering halfway through a job that the host was never in the right confinement state.
Local Policy
Managed RHEL hosts carry a versioned policy that defines blastwall_u, blastwall_r, and the confined automation domain.
IdM Mapping
IdM maps selected automation identities into that SELinux user through HBAC-linked policy and scoped sudo.
AAP Gate
AAP reads IdM state with eigenstate.ipa before running and fails closed on unsuitable hosts.
flowchart TB
IDM["IdM / FreeIPA<br/>identity + host + policy truth"] --> EIGEN["eigenstate.ipa<br/>read policy state"]
EIGEN --> AAP["AAP preflight<br/>gate and target selection"]
AAP --> SSH["SSH to managed host"]
SSH --> PAM["SSSD + pam_selinux<br/>apply SELinux user map"]
PAM --> BW["blastwall_u confined session"]
BW --> LOCAL["Local root work<br/>inside SELinux boundary"]
BW --> BLOCK["Exploit surfaces denied<br/>by versioned policy"]
flowchart LR
AAP["AAP job<br/>automation identity"] --> INV["eigenstate.ipa.idm<br/>IdM-backed inventory"]
INV --> HBAC["HBAC-scoped hosts<br/>blastwall-automation-ssh"]
INV --> MARKERS["Host markers<br/>current or stale policy"]
HBAC --> PREFLIGHT["Preflight gate"]
MARKERS --> PREFLIGHT
PREFLIGHT --> MAP["SELinux user map<br/>blastwall-root-local-map"]
PREFLIGHT --> SUDO["Sudo policy<br/>blastwall-root-local-sudo"]
PREFLIGHT --> RUN["Run job on selected hosts"]
RUN --> LOGIN["SSH login via SSSD + pam_selinux"]
LOGIN --> DOMAIN["blastwall_u:blastwall_r:blastwall_t<br/>alias: blastwall_root_local_t"]
DOMAIN --> DENY["CIL deny<br/>no alg_socket access"]
flowchart TB
GROUP["IdM group<br/>blastwall-automation"] --> HBAC["HBAC rule<br/>blastwall-automation-ssh"]
HOSTGROUP["IdM hostgroup<br/>blastwall-managed-hosts"] --> HBAC
SERVICE["HBAC service<br/>sshd"] --> HBAC
HBAC --> MAP["SELinux user map<br/>blastwall-root-local-map"]
MAP --> SEUSER["blastwall_u:s0"]
GROUP --> SUDO["Sudo rule<br/>blastwall-root-local-sudo"]
HOSTGROUP --> SUDO
SUDO --> ROOT["RunAs root<br/>no unconfined role/type option"]
Why I Would Build This
I would build this because the logistics matter. In a RHEL automation estate, a versioned SELinux policy RPM is often easier to stage, promote, audit, and roll back than a new set of dynamically attached probes. That does not make SELinux more precise than BPF LSM. It makes the mitigation fit the machinery already wrapped around RHEL operations.
The point is not to replace kernel patches. The point is to make privileged automation start constrained while the real fix moves through the fleet. If the exploit can be mitigated by denying a broad surface for automation identities, I want that denial to have an artifact name, a rollout state, and an inventory-visible coverage claim.
-
1
Convert the exploit into managed policy
- New exploit surface
- Update Blastwall policy
-
2
Give the mitigation an artifact lifecycle
- Build/sign policy RPM
- Publish via Satellite or content pipeline
-
3
Roll out and prove host-local enforcement
- AAP rollout workflow
- Local verification: expected denial works
-
4
Feed verified state back into automation
- Update IdM host marker
- Sync
eigenstate.ipainventory - AAP preflight selects current hosts
How It Scales
That turns emergency mitigation into ordinary operational state. Hosts are not merely patched or unpatched. For a given job, they are suitable or unsuitable based on identity mapping, HBAC, sudo policy, local SELinux enforcement, and the coverage markers AAP can see before it touches the endpoint.
-
1
Scope the new surface
- New exploit surface
- Define enforceable scope: class, permission, type, or transition
-
2
Productize the policy change
- Add Blastwall policy scope
- Review impact: normal automation still works
- Bump policy version
-
3
Ship coverage through normal RHEL operations
- Build policy RPM/module
- Roll out to managed hosts
-
4
Make coverage selectable before jobs run
- Update IdM host marker
- AAP inventory sync
- Preflight selects hosts with required coverage
-
1
Host-local proof
- Policy deployment workflow
- Install/update
blastwall-selinuxRPM - Verify local policy:
alg_socketdenied
-
2
Inventory-visible claim
- Update IdM host description marker
- Sync
eigenstate.ipa.idminventory
-
3
AAP target decision
Marker matches required policy?Yes
blastwall_policy_current
preferred candidatesNo
blastwall_policy_stale
report/remediate
flowchart TD
JOB["AAP job declares required coverage"] --> REQ["Required markers<br/>policy version + scopes"]
REQ --> H1{"Host A markers<br/>0.1.0 alg_socket"}
REQ --> H2{"Host B markers<br/>0.2.0 alg_socket + userns"}
H1 -->|missing new scope| STALE["Eligible but stale<br/>skip or remediate"]
H2 -->|all required scopes| SELECT["Preferred candidate"]
STALE --> REMEDIATE["Run policy update workflow"]
REMEDIATE --> MARKER["Refresh IdM marker"]
MARKER --> SELECT
Runtime Enforcement
The final decision still happens on the host. The point of the IdM and AAP work is to make sure the session arrives in the right SELinux user and role before local root work begins.
sequenceDiagram
participant A as AAP
participant I as IdM / FreeIPA
participant S as SSSD + pam_selinux
participant H as Managed RHEL host
participant K as SELinux kernel policy
A->>I: Read inventory, HBAC, SELinux map, sudo policy
I-->>A: Eligible hosts + confinement policy state
A->>I: hbactest automation identity against host:sshd
I-->>A: access granted or denied
A->>H: SSH as automation identity
H->>S: Resolve SELinux user map at login
S-->>H: Launch session as blastwall_u:blastwall_r:blastwall_t
A->>H: Run sudo for local-root task
H->>K: Enforce blastwall_t permissions
K-->>H: Deny alg_socket create/bind/send/recv
The Tradeoff
BPF LSM is the precision tool. It can inspect kernel hook arguments and preserve unrelated AF_ALG use. Blastwall is the identity, policy, and delivery model. It blocks a broader SELinux surface for a narrower subject: privileged automation mapped into blastwall_u.
That tradeoff is often acceptable for automation. Many jobs should not need AF_ALG, raw sockets, BPF, perf, user namespace creation, or ptrace. Blocking those surfaces for automation identities is part of the point.
flowchart TD
EXPLOIT["Copy Fail path"] --> SOCK["AF_ALG socket"]
SOCK --> BIND["bind(authencesn...)"]
BIND --> VULN["vulnerable kernel path"]
BPF["block-copyfail<br/>BPF LSM approach"] --> PRECISE["Inspect sockaddr_alg<br/>deny only authencesn"]
SELINUX["Blastwall<br/>SELinux approach"] --> BROAD["Deny alg_socket class<br/>for automation domain"]
PRECISE --> SOCK
BROAD --> SOCK
Repository Layout
| Path | Purpose |
|---|---|
policy/ | SELinux reference-policy module and CIL deny rule. |
scripts/ | Local install, cleanup, and IdM command helpers. |
inventory/ | eigenstate.ipa.idm inventory source for AAP. |
playbooks/ | Preflight, deployment, and verification playbooks. |
poc-calabi/ | End-to-end lab workflow against a generic automation endpoint. |