Linux Firewall Hardening
/install linux-firewall-hardening
Linux Firewall Hardening
When to Use
- Check if a Linux server has active firewall protection.
- Enable and configure a firewall without locking yourself out of SSH.
- Audit existing rules, troubleshoot connectivity, or apply a security profile.
- Automate firewall hardening via an AI agent or CI/CD pipeline.
When NOT to Use
| Condition | Alternative |
|---|---|
| Kubernetes worker node | Use NetworkPolicies / CiliumNetworkPolicy |
| Firewall managed by Terraform/Ansible/Puppet/Chef | Update IaC source of truth |
| Cloud workload with Security Group / NSG only | Use cloud provider's firewall API |
| Inside a container | Escalate to host operator |
| WSL2, macOS, or shared/managed hosting | See references/special-environments.md |
Support files:
scripts/audit-firewall.sh(run first),scripts/firewall-plan.sh(dry-run),scripts/firewall-verify.sh(post-apply). Detailed backend guides, Docker/K8s policies, observability, compliance, and recovery are inreferences/.
Prerequisites
- Root or sudo access.
- An active SSH session (risk of lockout).
- Know which ports your services use.
NEVER DO (14 Rules)
- Never flush iptables/nftables on Kubernetes nodes. CNI plugins manage netfilter.
- Never run
iptables -Fornft flush rulesetwithout a verified backup. Docker/K8s networking will break. - Never disable firewalld and use raw iptables simultaneously. Undefined behavior.
- Never set
DROPpolicy on INPUT before allowing your current SSH port. Immediate lockout. - Never disable Docker's
iptablesmanagement without replacement NAT/routing rules. - Never restart
networking.serviceorNetworkManagerremotely without console access. - Never apply cloud SG and host firewall changes simultaneously without testing.
- Never enable logging on high-traffic DROP rules without
limit rate. Disk flood. - Never manage nftables/iptables directly when ufw or firewalld owns the policy. Split-brain state.
- Never apply outbound default-deny without explicitly allowing DNS, NTP, package mirrors.
- Never restore firewall backups from a different host, kernel version, or backend mode.
- Never assume IPv4 rules protect IPv6. Verify both stacks separately.
- Never change sysctl hardening values on K8s/CNI hosts without explicit CNI profile support.
- Never enable verbose packet logging without rate limits and log rotation.
State Machine
Follow states in order. Do not skip.
DETECT → SELECT → PLAN → VALIDATE → APPLY → VERIFY
State: DETECT
Run the audit script:
bash scripts/audit-firewall.sh # Human-readable
bash scripts/audit-firewall.sh --json # Machine-readable
Key outputs: confidence, risk_tier, recommended_backend, halt_reasons, k8s_node, iac_owner.
Risk Tiers & Confidence Gating
| Tier | Confidence | Agent Behavior |
|---|---|---|
auto |
≥ 90% | Proceed automatically to PLAN |
confirmed |
70–89% | Proceed but require human confirmation before APPLY |
manual |
50–69% | Audit-only mode. Generate recommendations, do not apply. |
halt |
\x3C 50% | Stop immediately. Escalate findings to operator. |
Additional halt triggers (regardless of confidence): containerized, K8s node, IaC managed, no rollback mechanism available.
Decision Tree
| Condition | Path | Detail |
|---|---|---|
Risk tier = halt |
STOP | Resolve blockers first |
| Inside container | STOP | Escalate to host operator |
| K8s node detected | STOP | references/k8s-policy.md |
| Ubuntu/Debian + ufw active | Phase: UFW | references/backend-ufw.md |
| ufw + firewalld both active | STOP | Resolve conflict |
| RHEL/Rocky/Alma + firewalld active | Phase: firewalld | references/backend-firewalld.md |
| nftables active, no frontend | Phase: nftables | references/backend-nftables.md |
| iptables only | Phase: iptables | references/backend-iptables.md |
| Docker host | Apply Docker Hardening after phase above | references/docker-hardening.md |
Ownership Boundary
Before modifying rules, verify no IaC tool manages the firewall. If Terraform/Ansible/Puppet/Chef/cloud-init is detected → do not mutate. Update the source of truth instead. Full detection logic is in scripts/audit-firewall.sh.
State: SELECT
Optionally load a pre-built security profile (references/security-profiles.md):
| Profile | Use Case |
|---|---|
public-web-server |
Open 22, 80, 443. Rate-limit SSH. |
internal-database |
SSH from mgmt subnet only. DB port from app subnet only. |
bastion-host |
SSH only. Aggressive rate limiting. |
zero-trust-node |
Default deny all inbound and outbound. |
Or use declarative YAML (references/declarative-policy.md):
Imperative (state machine) → Ad-hoc hardening, incident response
Declarative (YAML) → GitOps, multi-host, reproducible
Mixed → YAML as source-of-truth, state machine for verification
State: PLAN (NEW)
Generate a dry-run diff before applying:
bash scripts/firewall-plan.sh --profile public-web-server
bash scripts/firewall-plan.sh --ports 22,80,443
bash scripts/firewall-plan.sh --json # Machine-readable diff
Review the output. If risk_tier is confirmed, present the plan and wait for human confirmation before APPLY.
State: VALIDATE
1. Create Backup (Mandatory)
BACKUP_DIR="$HOME/firewall-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
sudo iptables-save > "$BACKUP_DIR/iptables-v4.rules" 2>/dev/null || true
sudo ip6tables-save > "$BACKUP_DIR/iptables-v6.rules" 2>/dev/null || true
sudo nft list ruleset > "$BACKUP_DIR/nftables.rules" 2>/dev/null || true
sudo ufw status verbose > "$BACKUP_DIR/ufw-status.txt" 2>/dev/null || true
sudo firewall-cmd --list-all --zone=$(sudo firewall-cmd --get-default-zone) > "$BACKUP_DIR/firewalld-default.txt" 2>/dev/null || true
echo "Backup saved to $BACKUP_DIR"
2. Schedule Rollback (Mandatory for Remote)
The rollback restores from backup — not just disables the firewall — so Docker NAT and pre-existing rules are preserved. Dual-backend: at preferred, systemd-run fallback. Full script in SKILL.md under Validate state (see previous version), also summarized in references/recovery.md.
3. Pre-Flight Checklist
- Backup created successfully
- Rollback scheduled (verify with
atqorsystemctl --user list-units) - Second SSH session open and idle
- Real SSH port identified
- Confidence ≥ 70% and risk_tier is
autoorconfirmed - Ownership verified — no IaC managing firewall
- Change window appropriate (maintenance window or low traffic)
- PLAN output reviewed and approved
State: APPLY
All commands use idempotent patterns: check-before-set. Safe to run repeatedly.
| Backend | Pattern |
|---|---|
| ufw | sudo ufw status | awk '{print $1}' | grep -qx "22/tcp" || sudo ufw allow 22/tcp |
| firewalld | sudo firewall-cmd --query-service=ssh || sudo firewall-cmd --permanent --add-service=ssh |
| iptables | sudo iptables -C INPUT -p tcp --dport 22 -j ACCEPT 2>/dev/null || sudo iptables -A ... |
| nftables | Atomic ruleset: nft -c -f /etc/nftables.conf.new && nft -f /etc/nftables.conf.new |
Full step-by-step commands per backend: references/backend-ufw.md, references/backend-firewalld.md, references/backend-nftables.md, references/backend-iptables.md.
Docker Hosts
Docker bypasses ufw by default. Use DOCKER-USER chain. Full guide: references/docker-hardening.md.
Kubernetes Nodes
Default: AUDIT-ONLY. Never modify host firewall. Full policy: references/k8s-policy.md.
State: VERIFY
Run post-hardening checks:
bash scripts/firewall-verify.sh
Success criteria (all must pass):
- SSH remains reachable from current and second session
- Only intended ports are externally reachable
- Rules survive reboot (verified via service persistence)
- IPv6 exposure matches IPv4 policy
- Docker-published ports are intentional (no accidental
0.0.0.0) - fail2ban jails active (if installed) with correct backend
- Rollback timer cancelled after successful verification
fail2ban Integration
If fail2ban is installed:
| Host Firewall | Recommended backend |
|---|---|
| ufw | ufw or systemd |
| firewalld | firewalld |
| nftables | nftables |
| iptables | auto (default) |
After changing backend: sudo fail2ban-client restart && sudo fail2ban-client status sshd.
Recovery
If you lose connectivity, priority order:
- Wait for auto-rollback (scheduled during VALIDATE)
- Use second SSH session
- Cloud serial console / hypervisor console
- Restore from backup
- Emergency ACCEPT (last resort — exposes host completely)
Full procedures: references/recovery.md.
Cloud Security Group Reminder
The host firewall is your second layer. Verify cloud SGs are aligned:
| Cloud | Outer Firewall |
|---|---|
| AWS | Security Groups |
| GCP | VPC Firewall Rules |
| Azure | Network Security Groups |
| DigitalOcean/Linode/Vultr | Cloud Firewall |
Observability
Establish baselines after hardening: conntrack usage, dropped packet rates, fail2ban ban rate. Monitor for anomalies. Full guide: references/observability.md.
Compliance
Practices map to CIS, PCI-DSS, and SOC2 controls. Full mapping: references/compliance.md.
Quick Reference
| Task | Command |
|---|---|
| Audit environment | bash scripts/audit-firewall.sh --json |
| Plan changes | bash scripts/firewall-plan.sh --profile web |
| Verify after apply | bash scripts/firewall-verify.sh |
| Allow port (ufw, idempotent) | sudo ufw status | awk '{print $1}' | grep -qx "80/tcp" || sudo ufw allow 80/tcp |
| View ufw rules | sudo ufw status numbered |
| View nft rules | sudo nft list ruleset |
| View iptables rules | sudo iptables -L -n -v |
| View ip6tables rules | sudo ip6tables -L -n -v |
| Atomic iptables replace | sudo iptables-restore \x3C /tmp/rules.v4 |
| Dry-run nftables | sudo nft -c -f /etc/nftables.conf |
| Backup rules | sudo iptables-save > ~/iptables.backup |
| fail2ban status | sudo fail2ban-client status sshd |
| Cancel rollback (at) | atrm \x3Cjobid> |
| Cancel rollback (systemd-run) | systemctl --user stop firewall-rollback-\x3Cpid> |
See Also
references/backend-ufw.md— Full UFW phasereferences/backend-firewalld.md— Full firewalld phasereferences/backend-nftables.md— Full nftables phasereferences/backend-iptables.md— Full iptables phasereferences/docker-hardening.md— Docker firewall hardeningreferences/k8s-policy.md— Kubernetes node policyreferences/security-profiles.md— Pre-built configurationsreferences/declarative-policy.md— YAML policy schemareferences/observability.md— Monitoring and baselinesreferences/compliance.md— CIS/PCI-DSS/SOC2 mappingreferences/recovery.md— Recovery proceduresreferences/special-environments.md— WSL2, containers, exit codesscripts/audit-firewall.sh— Environment detectionscripts/firewall-plan.sh— Dry-run diffscripts/firewall-verify.sh— Post-apply verification
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install linux-firewall-hardening - After installation, invoke the skill by name or use
/linux-firewall-hardening - Provide required inputs per the skill's parameter spec and get structured output
What is Linux Firewall Hardening?
Safe Linux firewall hardening with backend detection, idempotent atomic rules, rollback protection, and AI-executable state-machine workflows. Covers ufw, fi... It is an AI Agent Skill for Claude Code / OpenClaw, with 55 downloads so far.
How do I install Linux Firewall Hardening?
Run "/install linux-firewall-hardening" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is Linux Firewall Hardening free?
Yes, Linux Firewall Hardening is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does Linux Firewall Hardening support?
Linux Firewall Hardening is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created Linux Firewall Hardening?
It is built and maintained by discovery219 (@discovery219); the current version is v1.0.0.