19.1 Configure Firewall Settings with firewall-cmd and firewalld
Key Takeaways
- firewalld is the RHEL host firewall; keep the service enabled and use firewall-cmd for runtime and permanent policy.
- Zones define trust (public, trusted, drop, internal, …); bind interfaces or sources, then open services/ports in the correct zone.
- Always pair --permanent changes with firewall-cmd --reload so runtime matches saved policy after reboot.
- Prefer predefined services (--add-service=http) when available; use --add-port=PORT/PROTO for custom listeners; rich rules cover source-limited allows.
- Verify with --get-active-zones, --list-all, --list-services, and --list-ports; prove persistence by checking permanent config, not only live state.
19.1 Configure Firewall Settings with firewall-cmd and firewalld
Quick Answer: Keep
firewalldrunning and enabled. Open what the task requires withfirewall-cmd --permanent --add-service=…or--add-port=…/tcp(in the right zone), thenfirewall-cmd --reload. Inspect with--get-active-zonesand--list-all. For tighter policy, assign interfaces/sources to zones and use rich rules when you must allow only specific sources.
Why this is a security objective (not only networking)
Chapter 17.4 introduced firewalld as the way to restrict network access under Manage basic networking. Under Manage security, EX200 still expects competent firewall settings: correct zone, permanent rules, reload, and verification that the host only exposes intended services. Lab language looks like:
- “Configure the firewall so HTTP and HTTPS are permanently allowed.”
- “Open TCP port 8443 in the default zone.”
- “Assign the interface to the
internalzone and allow onlysshandcockpit.” - “Allow NFS-related services from subnet
192.168.10.0/24only.”
You are graded on end state after reboot: firewalld active, permanent configuration contains the required allows, and runtime matches after reload.
firewalld service baseline
systemctl status firewalld
systemctl is-enabled firewalld
systemctl is-active firewalld
sudo systemctl enable --now firewalld
If firewalld is stopped or masked, permanent XML never becomes live policy. Prefer firewalld on RHEL 10 training systems; do not replace the exam path with hand-built raw iptables/nft rule sets unless a task forces it (unlikely for standard EX200 wording).
firewall-cmd --state
# running
Runtime vs permanent vs reload
| Mode | What it changes | Survives reload/reboot? |
|---|---|---|
Runtime (default firewall-cmd without --permanent) | Live policy now | Until reload/restart/reboot (not saved) |
Permanent (--permanent) | On-disk zone/service config | After reload or service restart |
firewall-cmd --reload | Loads permanent → runtime | Makes permanent rules active without full reboot |
Exam habit: for lasting change, always:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
firewall-cmd --list-services
Optional dual-write (runtime now and permanent) without waiting for reload of only permanent:
sudo firewall-cmd --add-service=http
sudo firewall-cmd --permanent --add-service=http
# or after a series of runtime tweaks:
sudo firewall-cmd --runtime-to-permanent
--runtime-to-permanent snapshots current runtime into permanent files—useful after experimental runtime testing, dangerous if runtime is messy. Prefer explicit --permanent + --reload for clean exam steps.
sudo firewall-cmd --complete-reload # harder reset; can drop connections
Prefer ordinary --reload on the exam unless something is stuck.
Zones: trust model
Zones are named policy buckets. Each zone has a default target (accept/reject/drop behavior for unmatched traffic) and a set of allowed services/ports/rich rules. Interfaces and source addresses are assigned to zones.
firewall-cmd --get-zones
firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
firewall-cmd --list-all-zones | less
Common zones you will meet:
| Zone | Typical use |
|---|---|
public | Default-ish external: limited services (often ssh, dhcpv6-client) |
trusted | Accept almost everything (very open) |
drop | Drop incoming (stealthy deny) |
block | Reject incoming with ICMP/TCP reset |
internal / work / home | More services allowed for trusted networks |
dmz / external | Edge/gateway-style policies |
Default zone vs active zone
- Default zone: used for interfaces not explicitly assigned elsewhere.
- Active zones: zones currently binding interfaces and/or sources that have traffic context.
firewall-cmd --get-default-zone
sudo firewall-cmd --set-default-zone=public
firewall-cmd --get-active-zones
Changing default zone is permanent when done with firewall-cmd --set-default-zone (it writes configuration). Still verify which zone your NIC actually sits in.
Assign interface or source to a zone
# Interface permanently in internal zone
sudo firewall-cmd --permanent --zone=internal --change-interface=ens192
sudo firewall-cmd --reload
firewall-cmd --get-active-zones
# Source network treated as trusted (example)
sudo firewall-cmd --permanent --zone=trusted --add-source=192.168.50.0/24
sudo firewall-cmd --reload
Tip: Opening http in public does nothing useful if the interface is active only in internal without that service. Always --list-all for the zone that owns the NIC.
firewall-cmd --zone=public --list-all
firewall-cmd --zone=internal --list-all
# default zone list-all:
firewall-cmd --list-all
Services vs ports
Predefined services
firewalld ships XML service definitions (ports + protocols + helpers) under /usr/lib/firewalld/services/ (and overrides under /etc/firewalld/services/).
firewall-cmd --get-services
firewall-cmd --info-service=http
firewall-cmd --info-service=https
firewall-cmd --info-service=ssh
Allow a service in a zone:
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
firewall-cmd --zone=public --list-services
Remove when a task requires closing:
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload
Prefer services when Red Hat/firewalld already defines the app (http, https, ssh, samba, nfs, cockpit, postgresql, …). Graders and docs often phrase “allow the http service.”
Ports (custom listeners)
When the task names a bare port (for example TCP 8080 or 8443):
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --reload
firewall-cmd --list-ports
UDP example:
sudo firewall-cmd --permanent --add-port=53/udp
sudo firewall-cmd --reload
Port ranges:
sudo firewall-cmd --permanent --add-port=3000-3010/tcp
sudo firewall-cmd --reload
Remove:
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload
| Approach | When |
|---|---|
--add-service=NAME | Named application service exists |
--add-port=N/tcp or /udp | Custom or explicitly numeric port |
Do not assume “HTTP is always 80 only via port add”—using --add-service=http is cleaner when the service is standard.
Query and audit commands (memorize)
firewall-cmd --state
firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
firewall-cmd --list-all
firewall-cmd --list-all-zones
firewall-cmd --list-services
firewall-cmd --list-ports
firewall-cmd --list-rich-rules
firewall-cmd --permanent --list-all
firewall-cmd --permanent --zone=public --list-all
--permanent --list-all shows what will load after reload/reboot. --list-all (no permanent) shows runtime. Both should match after a successful permanent change + reload.
Rich rules (introduction for security tasks)
Rich rules express finer policy: allow a service or port only from a source, log, or limit. Syntax is picky—use patterns you can type under pressure.
# Allow SSH only from a management subnet (example)
sudo firewall-cmd --permanent --zone=public \
--add-rich-rule='rule family="ipv4" source address="192.168.100.0/24" service name="ssh" accept'
sudo firewall-cmd --reload
firewall-cmd --list-rich-rules
Port from one host:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.25" port port="8443" protocol="tcp" accept'
sudo firewall-cmd --reload
Reject everything from a bad host (illustrative):
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.50" reject'
sudo firewall-cmd --reload
Remove a rich rule by repeating the same rule string with --remove-rich-rule.
Exam note: Many EX200 tasks stop at service/port + zone. Use rich rules when the task requires source restriction. If you only need “open HTTP globally in the zone,” do not invent rich rules.
Interfaces, NetworkManager, and zones
NetworkManager can store a connection’s firewall zone:
nmcli -f connection.zone connection show ens192
sudo nmcli connection modify ens192 connection.zone internal
sudo nmcli connection up ens192
firewall-cmd --get-active-zones
Alternatively, use firewall-cmd --change-interface as shown earlier. After interface moves, re-check which zone has your services.
SELinux is separate
Opening a port in firewalld does not relabel SELinux port types. If a daemon binds a non-default port, you may also need SELinux port labeling (later security chapters). Conversely, correct SELinux does not open firewalld. On multi-part tasks, fix both when symptoms match each layer.
Panic recovery without locking yourself out
When working over SSH, never permanently remove ssh from the only zone that holds your interface without another access path. Sequence for risky changes:
- Add new allows first.
- Test.
- Remove old rules only after verification.
- Prefer temporary runtime test, then permanent.
# Temporary test (gone after reload if not permanent)
sudo firewall-cmd --add-port=8080/tcp
# verify connectivity, then permanent + reload
Exam workflows
Workflow A — Permanent HTTP/HTTPS in default zone
sudo systemctl enable --now firewalld
firewall-cmd --get-default-zone
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
firewall-cmd --list-services
firewall-cmd --permanent --list-services
Workflow B — Custom TCP port
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
firewall-cmd --list-ports
Workflow C — Zone + services for an interface
sudo firewall-cmd --permanent --zone=internal --change-interface=ens192
sudo firewall-cmd --permanent --zone=internal --add-service=ssh
sudo firewall-cmd --permanent --zone=internal --add-service=cockpit
sudo firewall-cmd --reload
firewall-cmd --get-active-zones
firewall-cmd --zone=internal --list-all
Workflow D — Source-limited allow (rich rule)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="172.25.250.0/24" port port="9090" protocol="tcp" accept'
sudo firewall-cmd --reload
firewall-cmd --list-rich-rules
Workflow E — Verify permanence mindset
firewall-cmd --state
firewall-cmd --list-all
firewall-cmd --permanent --list-all
systemctl is-enabled firewalld
Common traps
- Runtime-only
--add-servicewithout--permanent—works now, gone after reboot/reload of permanent-only disk state. --permanentwithout--reload—disk updated, runtime still old.- Adding rules to the wrong zone while the NIC is active in another zone.
- Using
--add-port=80/tcpwhen the task said allowhttpservice (often both work for port 80, but service name is what docs expect). - Removing ssh permanently over a remote session and locking yourself out.
- Assuming firewalld is running—always check after minimal installs or hard problems.
- Confusing default zone with active zones.
- Opening the firewall but forgetting the daemon/service itself is not installed or not listening.
- Expecting rich-rule typos to work—quote carefully; verify with
--list-rich-rules. - Treating
iptables -Fas a firewalld configuration method on modern RHEL exams.
Relationship to other sections
| Topic | Where |
|---|---|
| Restrict network access (intro) | 17.4 |
| Deep firewall settings (this) | 19.1 |
| Services listening / systemd | Operate / deploy chapters |
| SELinux ports/booleans | Security SELinux chapters |
| SSH access path | 19.3 and essential SSH |
Section checkpoint
You should enable firewalld, choose the correct zone, open services and ports permanently, reload, optionally use interface/source assignment and simple rich rules, and prove runtime and permanent lists match the task. That is the EX200 security bar for firewall settings with firewall-cmd on RHEL 10.
Which sequence permanently allows the http service and makes it active in the running firewalld policy?
You added a port with firewall-cmd --permanent --add-port=8080/tcp but clients still time out, and firewall-cmd --list-ports does not show 8080/tcp. What is the most likely missing step?
firewall-cmd --list-all shows services in zone public, but your NIC is listed under zone internal in --get-active-zones. You added http only to public. What is wrong?
A task requires allowing TCP 9090 only from 172.25.250.0/24. Which tool feature best matches that requirement?