FreeIPA HBAC and Sudo Rules
What HBAC is
HBAC (Host-Based Access Control) is FreeIPA's mechanism for controlling which users (and groups) can log in to which hosts (and host groups). Instead of managing sudoers files on every server, you define rules centrally in FreeIPA and SSSD enforces them on each enrolled host.
Without HBAC rules granting access, a valid FreeIPA user cannot log in to an enrolled host — even if their credentials are correct.
The default allow_all rule
New FreeIPA installations have a rule called allow_all that permits any FreeIPA user to log in to any enrolled host. This is convenient but insecure for production.
# Disable the default allow_all rule
ipa hbacrule-disable allow_all
# Verify it is disabled
ipa hbacrule-show allow_all
HBAC rule components
Each HBAC rule has four components:
- Who — users or user groups allowed
- Where — hosts or host groups they can access
- What service — PAM services (sshd, sudo, login, etc.)
- Enabled/Disabled — rules can be toggled without deletion
Creating an HBAC rule
Via web UI
- IPA web UI → Policy → Host-Based Access Control → HBAC Rules
- Click + Add
- Name the rule (e.g.
allow-webteam-webservers) - Add users/groups, hosts/hostgroups, and services
- Click Add and Edit to configure details, then save
Via CLI
# Create the rule
ipa hbacrule-add allow-webteam-webservers \
--desc "Web team access to web servers"
# Add who (user group)
ipa hbacrule-add-user allow-webteam-webservers \
--groups=webteam
# Add where (host group)
ipa hbacrule-add-host allow-webteam-webservers \
--hostgroups=webservers
# Add which service (sshd = SSH login)
ipa hbacrule-add-service allow-webteam-webservers \
--hbacsvcs=sshd
# Verify the rule
ipa hbacrule-show allow-webteam-webservers
Testing HBAC rules
Before relying on a rule to work, test it. The test simulates an access check without actually logging in.
# Test if user alice can SSH to web01.example.com
ipa hbactest \
--user=alice \
--host=web01.example.com \
--service=sshd
# Expected output if allowed:
# Access granted
# Matched rules: allow-webteam-webservers
# If denied:
# Access denied
# Test all rules for a user across all hosts
ipa hbactest --user=alice --host=web01.example.com --service=sshd --enabled
# Show which rules were evaluated
ipa hbactest --user=alice --host=web01.example.com --service=sshd --detail
HBAC services
Common PAM service names to use in HBAC rules:
sshd— SSH loginslogin— console/terminal loginssudo— sudo usage (also controlled via IPA sudo rules)su— switching users with su
# List available HBAC services
ipa hbacsvc-find
# Allow SSH and sudo in one rule
ipa hbacrule-add-service allow-webteam-webservers \
--hbacsvcs=sshd,sudo
FreeIPA sudo rules
FreeIPA can manage sudo rules centrally. Instead of editing /etc/sudoers on every host, you define rules in FreeIPA and SSSD distributes them to enrolled hosts.
For this to work, the host must have sudoers: sss in /etc/nsswitch.conf (set by ipa-client-install).
# Check nsswitch.conf includes sss for sudo
grep sudoers /etc/nsswitch.conf
# sudoers: files sss
Creating a sudo rule
# Create a sudo rule for the webteam
ipa sudorule-add allow-webteam-restart-nginx \
--desc "Allow webteam to restart nginx"
# Apply to a user group
ipa sudorule-add-user allow-webteam-restart-nginx \
--groups=webteam
# Apply to host group
ipa sudorule-add-host allow-webteam-restart-nginx \
--hostgroups=webservers
# Allow specific commands
ipa sudorule-add-allow-command allow-webteam-restart-nginx \
--sudocmds="/usr/bin/systemctl restart nginx,/usr/bin/systemctl reload nginx"
# Allow running as specific user
ipa sudorule-mod allow-webteam-restart-nginx \
--runasusercat=all
Sudo command groups
Group related commands together for easier management:
# Create a command group for web service management
ipa sudocmdgroup-add web-service-commands \
--desc "Commands for managing web services"
# Add commands to the group
ipa sudocmdgroup-add-member web-service-commands \
--sudocmds="/usr/bin/systemctl restart nginx" \
--sudocmds="/usr/bin/systemctl reload nginx" \
--sudocmds="/usr/bin/systemctl status nginx"
# Use the group in a sudo rule
ipa sudorule-add-allow-command allow-webteam-restart-nginx \
--sudocmdgroups=web-service-commands
Troubleshooting access denied
User has correct password but cannot log in
# Test HBAC rules
ipa hbactest --user=alice --host=web01.example.com --service=sshd --detail
# If denied, check which groups alice is in
ipa user-show alice
# Check which HBAC rules apply to the host
ipa hbacrule-find --host=web01.example.com
sudo commands denied even with a rule
# On the client host, invalidate the sudo rule cache
sss_cache -R # invalidate all cached sudo rules (--sudo-rules)
sudo -l -U alice # list what alice can sudo (if run by root)
# Check nsswitch.conf lists sss for sudoers
grep sudoers /etc/nsswitch.conf
# Check SSSD cache and domain status
sssctl user-show alice
sssctl domain-status example.com
HBAC rule exists but access denied after adding user to group
SSSD caches group membership. Force a cache refresh:
sss_cache -u alice
systemctl restart sssd # nuclear option — forces full cache refresh
sudo command objects
Instead of specifying raw command strings inline, the proper long-term pattern is to create reusable sudo command objects in FreeIPA and group them. This makes it easier to audit what commands are allowed and update them in one place.
Create individual sudo command objects
# Create a sudo command object for each allowed command
ipa sudocmd-add /usr/bin/systemctl
ipa sudocmd-add /usr/sbin/ss
ipa sudocmd-add /usr/bin/journalctl
# List all defined sudo commands
ipa sudocmd-find
# Show details for a specific command
ipa sudocmd-show /usr/bin/systemctl
Create a sudo command group
# Create a group to hold related commands
ipa sudocmdgroup-add ops-cmds --desc "Common ops commands"
# Add command objects to the group
ipa sudocmdgroup-add-member ops-cmds \
--sudocmds=/usr/bin/systemctl \
--sudocmds=/usr/sbin/ss \
--sudocmds=/usr/bin/journalctl
# Verify the group
ipa sudocmdgroup-show ops-cmds
Assign the command group to a sudo rule
# Create the sudo rule
ipa sudorule-add allow-ops-team
# Assign users/groups
ipa sudorule-add-user allow-ops-team --groups=ops-team
# Assign hosts
ipa sudorule-add-host allow-ops-team --hostgroups=production-servers
# Assign the command group
ipa sudorule-add-allow-command allow-ops-team --sudocmdgroups=ops-cmds
The advantage over inline strings: if a command path changes (e.g. /sbin/ss → /usr/sbin/ss), you update the command object once and all rules using it update automatically.
HBAC rule lifecycle
HBAC rules can be enabled or disabled without deleting them. This is useful for temporarily blocking access during incidents or maintenance.
# Disable a rule (users affected immediately after SSSD cache clears)
ipa hbacrule-disable allow-ops-ssh-production
# Re-enable the rule
ipa hbacrule-enable allow-ops-ssh-production
# Check rule status
ipa hbacrule-show allow-ops-ssh-production | grep ipaenabledflag
# List all rules and their enabled status
ipa hbacrule-find --all | grep -E "Rule name|Enabled"
ipa hbacrule-disable is faster and safer than deleting the rule. You can re-enable it once the incident is resolved, with full history preserved.
runasuser / runasgroup
Sudo rules can restrict which user or group a command may be run as — the "run as" part of sudo. For example, allowing someone to run a command as postgres but not as root.
# Allow ops-team to run backup as the postgres user only
ipa sudorule-add allow-ops-pg-backup
ipa sudorule-add-user allow-ops-pg-backup --groups=ops-team
ipa sudorule-add-host allow-ops-pg-backup --hostgroups=db-servers
# Restrict the "run as" user to postgres
ipa sudorule-add-runasuser allow-ops-pg-backup --users=postgres
# Restrict the "run as" group
ipa sudorule-add-runasgroup allow-ops-pg-backup --groups=dba
# Add the allowed command
ipa sudorule-add-allow-command allow-ops-pg-backup \
--sudocmds="/usr/bin/pg_dump"
Result in /etc/sudoers terms, this is equivalent to:
# %ops-team ALL=(postgres:dba) /usr/bin/pg_dump
Usage on the host:
# Run pg_dump as the postgres user
sudo -u postgres /usr/bin/pg_dump mydb > /tmp/mydb.sql
# Run as postgres in the dba group
sudo -u postgres -g dba /usr/bin/pg_dump mydb