FreeIPA HBAC and Sudo Rules

Host-based access control — who can log in to what, and centrally managed 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 allow_all in production. Leave it enabled only in development/testing environments. In production, disable it and create specific rules for each user group and host group.
# 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:

Creating an HBAC rule

Via web UI

  1. IPA web UI → Policy → Host-Based Access Control → HBAC Rules
  2. Click + Add
  3. Name the rule (e.g. allow-webteam-webservers)
  4. Add users/groups, hosts/hostgroups, and services
  5. 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
Always use hbactest before asking a user to try logging in. It tells you exactly which rules matched (or did not match) without requiring a live login attempt. Also useful for diagnosing "why can't alice log in?" calls.
# 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:

# 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"
Incident workflow: During a security incident, 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