EX362 Exam Prep
This page contains the necessary resources to help you prepare for the Red Hat Certified Specialist in Identity Management exam, EX362. This follows the youtube playlist as much as possible with various examples and ideas. Soon to come, you will also find our own example practice exam for you to try your hand at to test your knowledge.
The list of objectives can be found here. Note that the exam objectives can change at any time. It is the responsibility of the reader to always review the objectives prior to studying and taking the exam to ensure success.
Affiliation and Exam Information
Please note that we are not affiliated with Red Hat. The materials and examples used are our own and do not reflect the training programs provided by Red Hat and are educational only. We do not disclose any of the tasks, questions, or material on the exam as it would violate the NDA. Any questions sent to us about anything directly related to the exam will not be answered. We also do not provide any one-on-one tutoring or online teaching courses.
If exam objectives have changed to where the videos and this material are missing information, we can add on at any time upon request. If exam objectives have not changed but operational tasks have, we will note them as we find them. If there are things about FreeIPA that you'd like to see in the videos that may fit into objective, we can add it also upon request. However, it is likely those extra things would be better suited in the separate FreeIPA section on this site.
Overview¶
This series goes over setting up FreeIPA in a lab/VM environment by following the objectives as outlined by Red Hat. The list of objectives can be found here.
Multi-method
Throughout this material, you will see a combination of both "Script or CLI" and "Ansible" methods of working with FreeIPA (or Red Hat IdM), in selectable tabs. This is because we believe in the user understanding and knowing how to do things by hand first and foremost before ever automating it. Automation cannot be fully achieved without having an understanding of the underlying software and applications.
In conclusion, we highly recommend that any user studying for their exam reading this guide understands how to do everything by hand first before attempting to redo it via ansible.
Exam Information¶
The EX362 exam tests your knowledge in a real world format style test - Meaning just like any Red Hat exam, it is performance-based and you perform tasks as if you were on the job. You are evaluated on the tasks you perform and if they meet the objective criteria. The EX362 is related to FreeIPA or Red Hat Identity Management and counts toward the RHCA (Red Hat Certified Architect). You are expected to have familiarity with ansible for this exam. As such, ansible setup and explanation will be limited.
To take the exam, you must have at least an RHCSA. If you are attempting to become a Red Hat Certified Architect, you must have an RHCE.
Ansible Information¶
As ansible is expected for this exam, you may be required to work with ansible collections to work with FreeIPA. The community version of the collection is simply freeipa.ansible_freeipa
. This can be installed via ansible-galaxy
or via dnf install ansible-freeipa
. You will find that the Red Hat official collection name has a different name entirely.
Throughout this page, we will be using the ansible-galaxy
version of the collection, which ensure we are using a FQCN. This is because if you are using Ansible Automation Platform (or AWX), you will need to use the FQCN in just about all cases.
Note
As ansible is a fairly new addition to this exam and to this study guide, there may be inaccuracies. We highly encourage PR's or comments that address problems with the ansible data we provide here.
Resources¶
- FreeIPA
- FreeIPA Ansible Collection
- Red Hat Documentation
- Trust Anatomy/SSSD Troubleshooting
- Directory Server Tuning
- FreeIPA Workshop Curriculum
- Ansible Documentation
- Our Page
Hardware Recommendations¶
The minimum requirements for IdM are fairly low. 2GB of RAM, 1 core, and a 10GB disk. However, we believe that's too low, especially if we plan on scaling out. And during upgrades, you would need at least 4GB of RAM for the operations to be successful. Below are our minimum recommendations:
- 2 (virtual) CPU Core
- 4 GB of RAM
- 10GB+ disk or partition for /var/lib/dirsrv
Per the Red Hat documentation, consider that with at least 10k users and 100 groups, you would need at least 3GB of RAM and 1GB swap. If you end up having 100k users and 50k groups, then 16GB of RAM and 4GB of swap is recommended. In fact, in larger deployments, it's more effective to increase RAM than disk, as most data is stored in cache.
View the resources above in the previous section for directory server tuning information.
Expected lab systems¶
Below is a list of expected lab systems to perform the work on this page.
System Name | IP Address | Role |
---|---|---|
idm1.example.com | 192.168.15.2 | IdM Server |
idm2.example.com | 192.168.15.3 | IdM Server |
client.example.com | 192.168.15.10 | IdM Client |
nfs.example.com | 192.168.15.11 | NFS Server |
utility.example.com | 192.168.15.12 | Utility Server |
ansible.example.com | 192.168.15.50 | Ansible controller |
You may want to consider setting up an NTP server, if you do not wish to use the default from chrony. This can be done on the utility server. See Setup an NTP Server.
Setup Ansible Controller and Clients¶
As the exam may expect familiarity with ansible, setting up an ansible controller may be ideal.
Note
We still recommend basic familiarity with FreeIPA itself as it is ideal for understanding the entire stack. Learning by hand is important first before attempting to automate.
Controller Setup¶
# as root, install the necessary packages and create the user
% dnf install ansible -y
% useradd ansible
# ensure ansible can do root things locally.
% visudo -f /etc/sudoers.d/ansible
ansible ALL=(ALL) NOPASSWD: ALL
Become the ansible user, and finish the general configuration.
% ssh-keygen
% ansible-config init --disabled > ansible.cfg
Configure ansible.cfg
in any way you see fit. We recommend these settings at a minimum.
[defaults]
roles_path = roles:/usr/share/ansible/roles
collections_paths = collections:/usr/share/ansible/collections
remote_user = ansible
; id_rsa is the default generated key. you can use any format.
private_key_file = /home/ansible/.ssh/id_rsa
ansible_managed = EX362 Study
[inventory]
enable_plugins = host_list, virtualbox, yaml, constructed, script, ini, auto
Configure the base inventory. For the inventory, you should ensure all lab systems are listed.
[ipa:children]
ipaserver
ipareplicas
ipaclients
[ipa:vars]
[ipaserver:vars]
[ipareplica:vars]
[ipaclients:vars]
[ipaserver]
idm1.example.com ansible_host=192.168.15.2
[ipareplica]
idm2.example.com ansible_host=192.168.15.2
[ipaclients]
ansible.example.com ansible_connection=local
client.example.com ansible_host=192.168.15.10
nfs.example.com ansible_host=192.168.15.11
utility.example.com ansible_host=192.168.15.12
Install the required collections.
% ansible-galaxy collection install freeipa.ansible_freeipa
# if you plan on managing network manager using ansible, use this collection.
% ansible-galaxy collection install community.general
# if you plan on managing firewalld and other features, use this collection.
% ansible-galaxy collection install ansible.posix
At this point, you will need to configure all the clients with an ansible user and the public key. See the ansible documentation for more details.
Install and configure Red Hat Identity Management (IdM)¶
Install IdM using either scripts or using Ansible Automation Platform¶
System Name | IP Address |
---|---|
idm1.example.com | 192.168.15.2 |
idm2.example.com | 192.168.15.3 |
ansible.example.com | 192.168.15.50 |
Domain/Realm Information
The domain/realm for this will be example.com
Static Addresses
IPA Servers should either have a DHCP reservation or a static address. In the event that you have either, DNS should always be pointing at 127.0.0.1, especially if your replica serves DNS. Both of our replicas serve DNS, so loopback is sufficient and recommended for our name server.
In later versions of FreeIPA, there is support to force network manager to ensure resolv.conf is loopback without the need to set it by hand with nmcli.
% hostnamectl set-hostname idm1.example.com
# Set a static address - It's important for your IdM servers
# to have static addresses or a DHCP reservation.
% nmcli con mod eth0 ipv4.address 192.168.15.2/24
% nmcli con mod eth0 ipv4.gateway 192.168.15.1
% nmcli con mod eth0 ipv4.method manual
% nmcli con mod eth0 ipv4.dns-search example.com
# You should set this if your replica serves DNS! If not, set it to
# one or more of your IdM replicas that do.
% nmcli con mod eth0 ipv4.dns 127.0.0.1
% nmcli con up eth0
# Examples of using ipa-server-install
# RHEL 9
% dnf install ipa-server ipa-server-dns ipa-client sssd sssd-ipa
# Installation, interactive, does not setup specific components
% ipa-server-install
# Installation, mostly automatic (recommended)
# This will setup DNS and the necessary pieces for an AD trust
# Optionally, you can set --setup-adtrust use the --netbios-name switch
# to set your forest netbios name
% ipa-server-install --domain example.com --realm EXAMPLE.COM \
--reverse-zone=15.168.192.in-addr.arpa. \
--no-forwarders \
--no-ntp \
--setup-dns \
-p Passw0rd! \
-a Passw0rd!
# Same as the above, but sets NTP server to sync to before starting
# the installation.
% ipa-server-install --domain example.com --realm EXAMPLE.COM \
--reverse-zone=15.168.192.in-addr.arpa. \
--no-forwarders \
--ntp-server=192.168.15.12 \
--setup-dns \
-p Passw0rd! \
-a Passw0rd!
% firewall-cmd --permanent --add-service={freeipa-4,dns}
% kinit admin
# We need to make sure that any A records get a corresponding PTR record, otherwise you're making them manually.
% ipa dnsconfig-mod --allow-sync-ptr=True
Ensure that your ansible controller is setup and install the collections as needed.
Ensure ansible is operable on all machines
It is recommended that on all machines in this lab, you are configuring ansible as a user with full sudo rights.
Static Addressing, command vs collection
Earlier, it was suggested to install community.general as it provides an nmcli module. We will be using this. It should be noted that you may not have access to that collection on the exam.
We also suggested ansible.posix. You may not also have access to this on the exam.
Modify the inventory with the necessary variables and domain information.
[ipa:children]
ipaserver
ipareplicas
ipaclients
; Based on exam requirements, these vars might have to be set differently
[ipa:vars]
; if you are using an ntp server, set to false and set ipaclient_ntp_servers
; ipaclient_no_ntp=false
; ipaclient_ntp_servers='["192.168.15.12"]'
ipaclient_no_ntp=true
; we plan on setting up roaming home directories. setting this
; to true shouldn't hurt.
ipaclient_mkhomedir=true
ipaclient_ssh_trust_dns=true
[ipaserver:vars]
ipaadmin_principal=admin
ipaadmin_password='Passw0rd!'
ipadm_password='Passw0rd!'
ipaserver_domain=example.com
ipaserver_realm=EXAMPLE.COM
ipaserver_setup_dns=true
ipaserver_setup_kra=true
ipaserver_setup_firewalld=true
ipaserver_no_forwarders=true
ipaserver_auto_forwarders=false
ipaserver_no_host_dns=true
ipaserver_reverse_zones='["15.168.192.in-addr.arpa."]'
ipaserver_external_ca=false
; ipaserver_setup_adtrust=true
; ipaserver_netbios_name=EXAMPLEAD
[ipareplica:vars]
ipaadmin_principal=admin
ipaadmin_password='Passw0rd!'
ipadm_password='Passw0rd!'
ipaserver_realm=EXAMPLE.COM
ipareplica_domain=example.com
ipareplica_setup_ca=true
ipareplica_setup_dns=true
ipareplica_setup_kra=true
ipareplica_setup_firewalld=true
ipareplica_no_forwarders=true
ipareplica_auto_forwarders=false
; ipareplica_setup_adtrust=true
; ipareplica_netbios_name=EXAMPLEAD
[ipaclients:vars]
ipaclient_domain=example.com
ipaclient_realm=EXAMPLE.COM
; the reason why we have a separate principal and password
; is because we may have a service account that enrolls instead
ipaadmin_principal=admin
ipaadmin_password='Passw0rd!'
[ipaserver]
idm1.example.com ansible_host=192.168.15.2
[ipareplica]
idm2.example.com ansible_host=192.168.15.2
[ipaclients]
ansible.example.com ansible_connection=local
client.example.com ansible_host=192.168.15.10
nfs.example.com ansible_host=192.168.15.11
utility.example.com ansible_host=192.168.15.12
Create the role.
% vi role_ipa_server.yml
---
- name: "Standup IPA Server"
hosts: ipaserver
become: true
pre_tasks:
# ensure hostname is what is expected
- name: "Set hostname"
ansible.builtin.hostname:
name: idm1.example.com
use: systemd
# This sets up network manager using community.general.
- name: "Set static address"
community.general.nmcli:
ifname: enp1s0
conn_name: enp1s0
type: ethernet
method4: manual
ip4:
- 192.168.15.2/24
gw4: 192.168.15.1
dns4_search: example.com
dns4: 127.0.0.1
autoconnect: true
state: present
roles:
- role: freeipa.ansible_freeipa.ipaserver
state: present
post_tasks:
# We need to ensure firewalld was setup the way we wanted it to
- name: "Ensure firewalld rules are accurate"
ansible.posix.firewalld:
service: "{{ item }}"
permanent: true
immediate: true
state: enabled
with_items:
- "freeipa-4"
- "dns"
# We need to make sure that any A records get a PTR record.
- name: "Ensure PTR is in sync"
freeipa.ansible_freeipa.ipadnsconfig:
ipaadmin_principal: "{{ ipaadmin_principal }}"
ipaadmin_password: "{{ ipaadmin_password }}"
allow_sync_ptr: true
Run the role to setup the server.
% ansible-playbook role_ipa_server.yml
Install and configure a replica IdM Server¶
% hostnamectl set-hostname idm2.example.com
% nmcli con mod eth0 ipv4.address 192.168.15.3/24
% nmcli con mod eth0 ipv4.gateway 192.168.15.1
% nmcli con mod eth0 ipv4.method manual
% nmcli con mod eth0 ipv4.dns-search example.com
% nmcli con mod eth0 ipv4.dns 192.168.15.2
% nmcli con up eth0
# Adding a replica, optionally change --no-ntp to --ntp-server
% ipa-replica-install --setup-dns \
--setup-ca \
--no-forwarders \
--no-ntp
# Adding a replica unattended without forwarders.
# Optionally set --ntp-server.
% ipa-client-install --realm EXAMPLE.COM --no-ntp
% kinit admin
% ipa hostgroup-add-member --hosts=ipa02.example.com ipaservers
% ipa-replica-install --setup-dns \
--setup-ca \
--no-forwarders \
--no-ntp \
--unattended
% vi role_ipa_replica.yml
---
- name: "Standup IPA Replica"
hosts: ipareplicas
become: true
pre_tasks:
# ensure hostname is what is expected
- name: "Set hostname"
ansible.builtin.hostname:
name: idm2.example.com
use: systemd
# This sets up network manager using community.general.
- name: "Set static address"
community.general.nmcli:
ifname: enp1s0
conn_name: enp1s0
type: ethernet
method4: manual
ip4:
- 192.168.15.3/24
gw4: 192.168.15.1
dns4_search: example.com
dns4: 192.168.15.2
autoconnect: true
state: present
- name: "Ensure firewalld rules are accurate"
ansible.posix.firewalld:
service: "{{ item }}"
permanent: true
immediate: true
state: enabled
with_items:
- "freeipa-4"
- "dns"
roles:
- role: freeipa.ansible_freeipa.ipareplica
state: present
Run the role to setup the replica.
% ansible-playbook role_ipa_replica.yml
Create Users, Groups, and Policies¶
Users | Login Name | Type | Group | Role | UID/GID |
---|---|---|---|---|---|
John Smith | jsmith | Normal | admins | Auto | |
Bob Rufus | brufus | Normal | corp | Auto | |
Larry Dufus | ldufus | Normal | helpdesk | Auto | |
Robert Cole | rcole | Staged | Auto | ||
Thomas Snyder | tsnyder | Preserved | Auto | ||
SysHost Management | syshostmgt | Normal | Host Manager | 10000 |
Groups | Policy |
---|---|
HelpDesk | helpdesk |
corp | |
enrollers | Enrollment Administrator |
Roles | Privilege |
---|---|
Host Manager | Host administrators |
Host group administrators | |
Netgroups administrators | |
Host enrollment |
Custom UID/GID
It is possible to create the users with a custom uid/gid with the switches --uid and --gidnumber which you will see below. It is also possible to set random passwords with --random.
See ipa user-add --help for more switches.
Password Expiration
When you make a user with the --password switch or use ipa passwd to set a password, it is automatically expired and must be changed on next login. If you want to avoid this from happening, you will need to set a random password via --password or --random, and then use kpasswd username to change it to the desired password. This does not make the account non-expiring.
# Creating users with a password, create all the accounts from the table (except from syshost)
% ipa user-add --first="John" --last="Smith" --password jsmith
# Create the system account with a password of Sup3R$ecre7! and a UID of 10000
% ipa user-add --first="SysHost" --last="Management" --uid=10000 --gidnumber=10000 --password syshostmgt
# Stage a user
% ipa stageuser-add --first="Robert" --last="Cole" rcole
# Preserve a user
% ipa user-del tsynder --preserve
# Create a regular (POSIX) group
% ipa group-add corp
# Create a member only group
% ipa group-add --nonposix HelpDesk
% ipa group-add --nonposix enrollers
# Add the HelpDesk group to the helpdesk policy
# Add the enrollers group to the Enrollment Administrator role
% ipa role-add-member "helpdesk" --groups=HelpDesk
% ipa role-add-member "Enrollment Administrator" --groups=enrollers
# Create a role with privileges
% ipa role-add "Host Manager"
% ipa role-add-privilege "Host Manager" \
--privileges="Host administrators" \
--privileges="Host group administrators" \
--privileges="Netgroups administrators" \
--privileges="Host enrollment"
# Add the syshostmgt user as a member of the role
% ipa role-add-member "Host Manager" --users="syshostmgt"
# Set our user passwords to CentOS123!$ so that way we don't have to change them later
% kpasswd jsmith
# If we already set the password we want but we don't want it to expire without making a policy or prompt for a password change (NOT RECOMMENDED)
% ldapmodify -x -w 'Passw0rd!' -D 'cn=Directory Manager'
dn: uid=syshostmgt,cn=users,cn=accounts,dc=example,dc=com
changetype: modify
delete: krbLastPwdChange
(Press CTRL+D)
% vi create_ipa_users.yml
---
- name: "Create users"
hosts: ipaserver
become: false
vars:
# All users are setup as a dictionary
users:
- name: jsmith
first: John
last: Smith
password: "CentOS123!$"
- name: brufus
first: Bob
last: Rufus
password: "CentOS123!$"
- name: ldufus
first: Larry
last: Dufus
password: "CentOS123!$"
- name: syshostmgt
first: SysHost
last: Management
uid: 10000
gid: 10000
password: "CentOS123!$"
- name: tsnyder
first: Thomas
last: Snyder
password: "CentOS123!$"
staged_users:
- name: rcole
first: Robert
last: Cole
preserved_users:
- tsnyder
tasks:
- name: Create all users
freeipa.ansible_freeipa.ipauser:
ipaadmin_password: "{{ ipaadmin_password }}"
users: "{{ users }}"
- name: Preserve users
freeipa.ansible_freeipa.ipauser:
ipaadmin_password: "{{ ipaadmin_password }}"
name: "{{ item }}"
state: absent
preserve: true
# The current freeipa collection doesn't support staged users
- name: kinit as admin
ansible.builtin.shell: "set -o pipefail && echo \"{{ ipaadmin_password }}\" | kinit {{ ipa_admin }}"
- name: Stage users
ansible.builtin.shell: 'ipa stageuser-add --first="{{ item.first }}" --last="{{ item.last }}" {{ item.name }}'
loop: "{{ staged_users }}"
% vi create_ipa_groups.yml
---
- name: "Create groups and add users to them"
hosts: ipaserver
become: false
vars:
groups:
- name: admins
user:
- jsmith
- name: HelpDesk
nonposix: true
user:
- ldufus
- name: enrollers
nonposix: true
- name: corp
posix: true
user:
- brufus
tasks:
- name: Create all groups
freeipa.ansible_freeipa.ipagroup:
ipaadmin_password: "{{ ipaadmin_password }}"
groups: "{{ groups }}"
% vi create_ipa_policy.yml
---
- name: "Create policies"
hosts: ipaserver
become: false
vars:
roles:
- name: "Host Manager"
privilege:
- Host administrators
- Host group administrators
- Netgroups administrators
- Host enrollment
user:
- syshostmgt
- name: "helpdesk"
privilege:
- Modify Group membership
- Modify Users and Reset passwords
group:
- HelpDesk
- name: "Enrollment Administrator"
privilege:
- Host Enrollment
group:
- enrollers
tasks:
- name: "Ensure all roles exist"
freeipa.ansible_freeipa.iparole:
ipaadmin_password: "{{ ipaadmin_principal }}"
name: "{{ item.name }}"
privilege: "{{ item.privilege|default(omit) }}"
group: "{{ item.group|default(omit) }}"
user: "{{ item.user|default(omit) }}"
loop: "{{ roles }}"
New Passwords Expired¶
The common question we receive (and even the #freeipa IRC receive) is "Why can't we just set the password to not be expired right away?" See this page for information on why this is. You may also look at the pagure page and the Red Hat bugzilla related bug.
Implement Single Sign On (SSO)¶
Create an SSO client¶
To setup a very, very simple SSO, you can setup a simple location that requires a login.
% ipa-getkeytab -s idm1.example.com -p http/http.example.com -k /etc/httpd/conf/http.keytab
% vi /etc/httpd/conf.d/location.conf
<Location "/">
AuthType Kerberos
AuthName "IPA Kerberos Auth"
# Keytab
Krb5Keytab /etc/httpd/conf/http.keytab
# Kerb settings
KrbMethodNegotiate on
KrbMethodK5Passwd on
KrbServiceName HTTP
KrbAuthRealms EXAMPLE.COM
KrbSaveCredentials off
Require valid-user
</Location>
Verify SSO client operation¶
...
Install and configure an IdM Client¶
Install and configure IdM Clients¶
Client Name | IP Address |
---|---|
client.example.com | 192.168.15.10 |
nfs.example.com | 192.168.15.11 |
utility.example.com | 192.168.15.12 |
Note
Depending on your architecture and setup, IdM clients should either be pointing directly at the IdM servers for DNS (at least two of them) or pointing at the DNS server in the environment that is delegating that domain to the IdM domain controllers.
In our lab, our IdM servers are our only DNS servers, thus it makes sense that our clients should point to them. In that scenario, you would configure your DHCP server to use the IdM servers as the name servers and/or configure them in a static manner depending on your environment.
# If your client is not pointing at the IdM DNS and you
# don't have another DNS server that's performing delegation,
# change your name servers.
% nmcli con mod eth0 ipv4.dns 192.168.15.2
% nmcli con mod eth0 +ipv4.dns 192.168.15.3
% nmcli con mod eth0 ipv4.dns-search example.com
# Optionally, if your clients don't have DHCP
# reservations, set a static address.
% nmcli con mod eth0 ipv4.address 192.168.15.10/24
% nmcli con mod eth0 ipv4.gateway 192.168.15.1
% nmcli con mod eth0 ipv4.method manual
# It might be a good idea to set your hostname if you haven't already
% hostnamectl set-hostname client.example.com
% hostname client.example.com
# Install the ipa-client packages
% dnf install ipa-client -y
# Optionally set --no-ntp to --ntp-server
% ipa-client-install --realm EXAMPLE.COM --domain example.com --no-ntp
. . .
% id admin
uid=686600000(admin) gid=686600000(admins) groups=686600000(admins)
Create the role for the client.
% vi role_ipa_client.yml
---
- name: "Enroll client system"
hosts: ipaclients
become: true
roles:
- role: freeipa.ansible_freeipa.ipaclient
state: present
Now run the role to setup the client.
% ansible-playbook role_ipa_client.yml
Configure Kerberized services¶
One of the things that you may end up doing, whether by hand or in an automated fashion, is creating kerberized services. In a later section, we address creating an NFS service for both a server and a client for the purpose of automating home directory mounts on a client when a user logs in. Before we dive into that, this just goes over simple kerberized service creation.
# Create kerberos service
% ipa service-add HTTP/http.example.com
Not only that, it's probably a good idea to actually get the keytab.
% kinit admin
% ipa-getkeytab -s idm1.example.com -p HTTP/http.example.com -k /etc/krb5.keytab
For an example of automating keytab creation and retrieval, see the CentOS/FreeIPA page on this site.
Manage the IdM integrated certificate authority¶
Configure and manage a certificate authority¶
By default FreeIPA stands up its own CA. And because of this, this allows you or your workplace to be able to issue certificates, that can be used in a wide variety of services, the most common or obvious one would be for Apache httpd.
There's a couple of ways you can get a certificate signed by FreeIPA. One method is to generate your own CSR and request it to be signed by FreeIPA. Another way is you can do it all from one command, ipa-getcert
, and optionally, either have the certificate in PEM format or an NSS database. We'll address these examples.
# Creating an SSL certificate in the PEM format
% ipa service-add HTTP/http.example.com
% ipa-getcert request -f /etc/pki/tls/certs/http.pem -k /etc/pki/tls/private/http.key -K HTTP/http.example.com -D http.example.com
New signing request "20190902000318" added.
# Verify
% ipa-getcert list
Number of certificates and requests being tracked: 1.
Request ID '20190902000318':
status: MONITORING
stuck: no
key pair storage: type=FILE,location='/etc/pki/tls/private/http.key'
certificate: type=FILE,location='/etc/pki/tls/certs/http.pem'
CA: IPA
issuer: CN=Certificate Authority,O=EXAMPLE.COM
subject: CN=http.example.com,O=EXAMPLE.COM
expires: 2021-09-02 00:03:19 UTC
dns: http.example.com
principal name: HTTP/http.example.com@EXAMPLE.COM
key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
eku: id-kp-serverAuth,id-kp-clientAuth
pre-save command:
post-save command:
track: yes
auto-renew: yes
# Create an SSL certificate in the NSS format
% ipa-getcert request -d /etc/pki/tls/certs/nss -n 'Test' -K HTTP/http.example.com -D http.example.com
New signing request "20190902000756" added.
# Verify
% ipa-getcert list
. . .
Request ID '20190902000756':
status: MONITORING
stuck: no
key pair storage: type=NSSDB,location='/etc/pki/tls/certs/nss',nickname='Test',token='NSS Certificate DB'
certificate: type=NSSDB,location='/etc/pki/tls/certs/nss',nickname='Test',token='NSS Certificate DB'
CA: IPA
issuer: CN=Certificate Authority,O=EXAMPLE.COM
subject: CN=http.example.com,O=EXAMPLE.COM
expires: 2021-09-02 00:07:57 UTC
dns: http.example.com
principal name: HTTP/http.example.com@EXAMPLE.COM
key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
eku: id-kp-serverAuth,id-kp-clientAuth
pre-save command:
post-save command:
track: yes
auto-renew: yes
By default, when a certificate request is performed (and succeeds to be signed by the IPA CA), it is typically tracked and auto-renewed by default. This is done by the certmonger service, which eliminates the need to have to renew anything by hand.
Create Secret Vaults¶
When a domain supports the KRA role, it can hold password vaults or anything that's considered "secret". You can add the KRA role by installing the relevant package and installing the role.
On each IdM server, you will need to enable the role.
% dnf install ipa-server-kra
% ipa-kra-install
Create a private vault (as a user)
% kinit admin
% ipa vault-add admin_private --desc "Admin Private Vault"
(more to come)
If you are following the ansible method, you already have this role installed based on the inventory configuration. Now it's a matter of creating a simple secret.
---
- name: "Create Simple Vault"
hosts: ipaserver
become: true
tasks:
- name: "Create vault with simple data"
freeipa.ansible_freeipa.ipavault:
ipaadmin_password: "{{ ipaadmin_password }}"
name: simplevault
description: "A simple vault"
username: admin
password: "VaultPassword21!"
data: "Simple data"
action: member
Create and configure IdM users and user policies¶
In FreeIPA, there are two sets of policies:
- Role Based Access Control (RBAC) which are the permissions, delegated or otherwise, that allow (or deny) access to various pieces of FreeIPA. This can be users that have the ability to reset passwords, modify groups, or perhaps they can issue keytabs. This was partially covered in a previous section.
- Host Based Access Control (HBAC) which are the permissions granted to a user or users to access systems on various (PAM) services, such as ssh or logging into a desktop system (eg, GDM).
Configure Policies and User Access¶
HBAC, or Host Based Access Controls, are permissions that grant user or users access to systems via any number of services. The services are PAM services. No doubt you have looked in /etc/pam.d
before and have seen quite a few files or even modified them by hand at some point.
% ls -l /etc/pam.d/
total 80
-rw-r--r--. 1 root root 272 May 11 2019 atd
-rw-r--r--. 1 root root 232 Apr 15 15:28 config-util
-rw-r--r--. 1 root root 328 Nov 8 2019 crond
lrwxrwxrwx. 1 root root 32 Jan 14 2020 fingerprint-auth -> /etc/authselect/fingerprint-auth
-rw-r--r--. 1 root root 70 Apr 24 06:35 ksu
-rw-r--r--. 1 root root 715 Apr 24 05:38 login
-rw-r--r--. 1 root root 154 Apr 15 15:28 other
-rw-r--r--. 1 root root 168 Apr 6 20:08 passwd
lrwxrwxrwx. 1 root root 29 Jan 14 2020 password-auth -> /etc/authselect/password-auth
-rw-r--r--. 1 root root 155 Apr 8 22:00 polkit-1
lrwxrwxrwx. 1 root root 25 Jan 14 2020 postlogin -> /etc/authselect/postlogin
-rw-r--r--. 1 root root 640 Apr 24 05:38 remote
-rw-r--r--. 1 root root 143 Apr 24 05:38 runuser
-rw-r--r--. 1 root root 138 Apr 24 05:38 runuser-l
lrwxrwxrwx. 1 root root 30 Jan 14 2020 smartcard-auth -> /etc/authselect/smartcard-auth
lrwxrwxrwx. 1 root root 25 Jun 15 10:18 smtp -> /etc/alternatives/mta-pam
-rw-r--r--. 1 root root 76 Apr 6 20:11 smtp.postfix
-rw-r--r--. 1 root root 727 Feb 4 2020 sshd
-rw-r--r--. 1 root root 214 Apr 23 20:48 sssd-shadowutils
-rw-r--r--. 1 root root 566 Apr 24 05:38 su
-rw-r--r--. 1 root root 154 Apr 23 19:40 sudo
-rw-r--r--. 1 root root 178 Apr 23 19:40 sudo-i
-rw-r--r--. 1 root root 137 Apr 24 05:38 su-l
lrwxrwxrwx. 1 root root 27 Jan 14 2020 system-auth -> /etc/authselect/system-auth
-rw-r--r--. 1 root root 248 Jul 21 07:57 systemd-user
-rw-r--r--. 1 root root 84 May 11 2019 vlock
On a typical Red Hat system, the most common ones (such as su
, sshd
, sudo
) imports the system-auth
file, so the login request is processed through those means. When defining HBAC rules, you either must allow "all" services or be selective. For example, if an HBAC rule allows "sshd", a user is allowed to ssh into a system, but wouldn't allow them to login locally on the console, as that goes through login
. If you want the user to be able to run the su
and sudo
commands, you would also need to allow those services. Otherwise, the user is denied, even if sudo policies are available.
[label@mgt ~]$ sudo -i
[sudo] password for label:
sudo: PAM account management error: Permission denied
In FreeIPA, there is typically a rule already predefined that allows everyone to access all systems and all services. This can be removed or disabled and this removes host access to everything immediately. This is typically recommended in most environments where there are security standards and procedures in place.
# To disable
% ipa hbacrule-disable allow_all
# To delete instead
% ipa hbacrule-del allow_all
When performing a FreeIPA installation, it is possible to add --no-hbac-allow
that will disable the allow_all rule.
Below are some examples of adding access.
# Allow all admins to access all systems
% ipa hbacrule-add --hostcat=all --servicecat=all --desc='Allow all admins to access all systems' All_Admins
% ipa hbacrule-add-user --groups=admins All_Admins
# And then test...
% ipa hbactest --rules=All_Admins --user=jsmith --host=client.example.com --service=login
# Allow the corp users to access the client system only using the sshd pam services
% ipa hbacrule-add --desc='Allow corp users to access client on ssh' corp_access
% ipa hbacrule-add-user --groups=corp corp_access
% ipa hbacrule-add-host --hosts=client.example.com corp_access
% ipa hbacrule-add-service --hbacsvcs=sshd corp_access
# And then test...
% ipa hbactest --rules=corp_access --user=brufus --host=client.example.com --service=sshd
To do this the ansible way, you can make a playbook like this.
---
Configure roaming or automounted home directories¶
You will need to configure your NFS server to serve up roaming home directories for users and then your client should have automouting enabled.
Client Kerberos Service
It may not be required to create an nfs kerberos service for the client. The ipa-client-automount command may already handle this but it does not hurt to create one. In fact, the host keytab is used on the client side anyway. Creating an NFS client keytab may have been required in the past.
# IDM Steps
% kinit admin
% ipa service-add nfs/nfs.example.com
% ipa service-add nfs/client.example.com
# Setup the automounting locations
% ipa automountmap-add default auto.home
% ipa automountkey-add default --key "/home" --info auto.home auto.master
% ipa automountkey-add default --key "*" --info "-fstype=nfs4,rw,sec=krb5,soft nfs.example.com:/exports/home/&" auto.home
# NFS Server Steps
% dnf install nfs-utils -y
% mkdir /exports/home
% vi /etc/exports
/exports/home *(rw,sec=sys:krb5:krb5i:krb5p)
# Make the home directories for all users and move them to /export/home
% mkhomedir_helper jsmith
% mv /home/jsmith /export/home/
# Create the necessary keytabs
% kinit admin
% ipa-getkeytab -s idm1.example.com -p nfs/nfs.example.com -k /etc/krb5.keytab
# Verify keytab
% klist -ket /etc/krb5.keytab
# Enable and start nfs
% systemctl enable nfs-server --now
# Open the necessary firewall ports
% firewall-cmd --add-service=nfs --permanent
% firewall-cmd --complete-reload
# Client steps
% kinit admin
% ipa-getkeytab -s idm1.example.com -p nfs/client.example.com -k /etc/krb5.keytab
% ipa-client-automount --location=default
# Verify keytab
% klist -ket /etc/krb5.keytab
To test, login to the system via ssh or console and verify the home directory has mounted. /var/log/messages and secure will display errors in case of failure.
Use Ansible Tower to configure and manage IdM Users¶
Several sections ago, we setup users either manually or via ansible playbooks. This would be generally the same, but may entail further configuration.
With that said, Ansible Tower (AWX or AAP) is out of scope for this guide, as there is no straight forward way to set it up in a lab. AWX for example has a kubernetes operator and they encourage the use of docker for testing purposes. You can do this, but this is not formally tested.
AAP on the other hand has installation steps for non-kubernetes environments. However, it is a Red Hat product and requires a subscription to use.
Configure IdM as an LDAP backend for external services¶
Most services and applications that authenticate users do typically have LDAP support. IdM can be used as an LDAP backend. You typically need only a few things to authenticate users from IdM to an application.
- Base DN, this always ends up being the top level of your domain: dc=example,dc=com - All accounts share this common base.
- Bind DN, this is a system account that binds to the directory to assist with searches and authentication
- Attribute mappings
- Groups, depending on the application
Below is a table of common DN's you may specify in an application:
DN's | Path | Filter (if applicable) |
---|---|---|
Base DN | dc=example,dc=com | |
User DN | cn=users,cn=accounts,dc=example,dc=com | uid=... |
Group DN | cn=groups,cn=accounts,dc=example,dc=com | (objectClass=groupOfNames) |
Bind DN | uid=account,cn=sysaccounts,cn=etc,dc=example,dc=com |
% ipa user-show admin --all | grep '^dn'
dn: uid=admin,cn=users,cn=accounts,dc=example,dc=com
Below is a table of common attributes that may be used to map user information in the application.
Type | Attribute |
---|---|
Login Name | uid |
First Name | givenName |
Surname | sn |
Groups | memberOf |
Full Name | cn |
Below are two ways to create a bind account (bind DN). The first way is the LDAP way. The second way is the ipa-ldap-updater.
% kinit admin
% ldapadd -Y GSSAPI
. . .
dn: uid=binder,cn=sysaccounts,cn=etc,dc=example,dc=com
objectclass: account
objectclass: simplesecurityobject
uid: binder
userPassword: password123
passwordExpirationTime: 20380119031407Z
nsIdleTimeout: 0
# Press CTRL+d
adding new entry "uid=binder,cn=sysaccounts,cn=etc,dc=example,dc=com"
% kinit admin
% cat << EOF > binder.update
dn: uid=binder,cn=sysaccounts,cn=etc,dc=example,dc=com
add:objectclass:account
add:objectclass:simplesecurityobject
add:uid:binder
add:userPassword:password123
add:passwordExpirationTime:20380119031407Z
add:nsIdleTimeout:0
EOF
% ipa-ldap-updater binder.update
When this account is created, you can then specify the full DN for that object into a bind DN field, along with it's password into an accompanying bind password field.
If you'd like an example of setting up Ansible Tower (or AWX, the open source version of tower) against IdM, you can click here.
Kerberos
On some applications, it is possible to use kerberos authentication rather than a straight bind account. The general idea is the same when picking out the base dn, attributes, and the like. However, instead you would create an account with an accompanying LDAP/... service principal to do the authentication.
Maintain IdM services¶
Configure NTP on all IdM components¶
NTP Server Setup
The utility server that is part of this lab can be used to run an NTP server. See Setup an NTP Server.
When the domain was initially setup, we may have used --no-ntp
, including for the clients. This means there's no attempt to configure nor sync chrony. This automatically assumes chrony is working as intended with the default pool configured from the chrony package (or by IT policy via automation). However, for this lab, if you have an NTP server you want to use, you can set it up in the /etc/chrony.conf
file.
% vi /etc/chrony.conf
. . .
# pool 2.centos.pool.ntp.org iburst
server 192.168.15.12
. . .
% systemctl restart chronyd.service
% chronyc tracking
Configure firewall on all IdM components¶
If the domain is working, then you setup firewalld correctly.
Back up an IdM infrastructure¶
There are multiple ways you can backup IPA.
- Full backup: Default, shuts down IPA before performing a backup. This backs up with raw files. As such, it must be done offline.
- Data backup: Backs up a copy of the ldap data and the changelog (the IPA-REALM instance, DogTag, IPA backend). This can be done online.
# Turns off IPA completely and perform a backup
% ipa-backup
# Backs up and gpg encrypts
% ipa-backup --gpg --gpg-keyring=/root/keys
To restore a backup, the ipa-restore command is available.
% ipa-restore /var/lib/ipa/backup/
. . .
Perform a backup without interruption of services¶
It is possible to perform a backup without taking down services. However, not everything will get backed up as a result.
The backup command allows you to pass an online flag to ensure a backup taken doesn't down the IPA services. Note that not everything can be backed up online.
# Backs up data only and doesn't take down IPA
% ipa-backup --data --online
# Backs up data only and gpg encrypts
% ipa-backup --gpg --gpg-keyring=/root/keys --data --online
. . .
Value Add¶
Use the REST api to query IdM¶
When you invoke the ipa
command, you are actually communicating with the API that runs on the IdM replicas. Operations done are sent via a POST with JSON data. The return data is also in JSON and translated to be readable in the terminal. Because it's JSON, custom scripts can be made with say perl or python that communicates with the API to send the calls, perhaps for specific tasks, jobs, or other operations that could be automated. You can also use curl
to do this also if you so choose.
The question becomes, "well, how do I know the right data to send?" You can issue the -vv switch to see the request being sent.
% ipa -vv ping
ipa: INFO: trying https://idm1.example.com/ipa/json
ipa: INFO: [try 1]: Forwarding 'schema' to json server 'https://idm1.example.com/ipa/json'
ipa: INFO: trying https://idm1.example.com/ipa/session/json
ipa: INFO: [try 1]: Forwarding 'ping/1' to json server 'https://idm1.example.com/ipa/session/json'
ipa: INFO: Request: {
"id": 0,
"method": "ping/1",
"params": [
[],
{
"version": "2.251"
}
]
}
ipa: INFO: Response: {
"error": null,
"id": 0,
"principal": "admin@EXAMPLE.COM",
"result": {
"summary": "IPA server version 4.10.2. API version 2.251"
},
"version": "4.10.2"
}
--------------------------------------------
IPA server version 4.10.2. API version 2.251
--------------------------------------------
If you look at the 'request' section, you can see the data that is sent. Each request has a method
and params
, where method is a command to be excuted and params is simply an array that contains positional arguments and a dictionary of options. If you take a look at say, group-show, you would see a different request.
% ipa -vv group-show admins
ipa: INFO: trying https://idm1.example.com/ipa/session/json
ipa: INFO: [try 1]: Forwarding 'group_show/1' to json server 'https://idm1.example.com/ipa/session/json'
ipa: INFO: Request: {
"id": 0,
"method": "group_show/1",
"params": [
[
"admins"
],
{
"version": "2.230"
}
]
}
### Lots of output ###
Let's say I wanted to perform that in a simple bash script that uses curl. I would perform a kinit
and then run the script below to have it login for me via kerberos and do the work.
#!/bin/bash
ipaReplica=idm1.example.com
cookieJar=my.cookie.jar
# Login with Kerberos
curl -v \
-H referer:https://$ipaReplica/ipa \
-c $cookieJar -b $cookieJar \
--cacert /etc/ipa/ca.crt \
--negotiate -u : \
-X POST \
https://$ipaReplica/ipa/session/login_kerberos
# Send user_find method request
curl -v \
-H referer:https://$ipaReplica/ipa \
-H "Content-Type:application/json" \
-H "Accept:applicaton/json"\
-c $cookieJar -b $cookieJar \
--cacert /etc/ipa/ca.crt \
-d '{"method":"group_show/1","params":[["admins"],{}],"id":0}' \
-X POST \
https://$ipaReplica/ipa/session/json
Any of the commands ran via ipa
can be reviewed with the -vv switch so you can see what kind of call it's making and how it's making it. Thus, making it easier to tie into your own scripts. On the Web UI, you can go to IPA Server -> API Browser to find more information on the specific API calls.
Implement an IdP¶
While not strictly a certification objective at this present time, there may be a chance it could be. FreeIPA 4.10+ have the ability to implement authentication to external identity providers. FreeIPA allows you to use RADIUS proxy authentication for example, but using this same method, an OAuth 2.0 authorization server could be used as well. When it comes to an IdP, you can instead configure IdP clients using ipa idp-add
and use software like Keycloak or otherwise that supports OAuth 2.0 workflows. We recommend checking out the FreeIPA Workshop Unit 12 for more details.
Setup an NTP Server¶
It is unlikely you'll need to setup an NTP server on an exam. However, rather than relying on the built-in pool servers provided by the chrony package, you may ask IdM to use another NTP server or pool for itself and the clients that enroll. Using the utility server, we can setup a quick NTP server.
% vi /etc/chrony.conf
. . .
allow 192.168.15.0/24
% systemctl restart chronyd.service
% firewall-cmd --add-service=ntp --permanent
% firewall-cmd --reload
For your IdM domain, you can then add a SRV record. This is supposed to allow the client installation to automatically set the NTP server.
% ipa dnsrecord-add example.com _ntp \
--srv-port=123 \
--srv-target=utility.example.com. \
--srv-weight=100 \
--srv-priority=0
Active Directory Trust¶
Active Directory trusts are no longer part of the main objectives for the exam. However, that does not mean it will not be part of it. It is important to still know how to set it up manually. In the installation section of this guide, there are commented variables for a trust configuration.
Create trust relationships with Active Directory¶
AD Setup
We do not cover setting up an AD forest here. This is out of scope for this series. If you are using Server 2016 or higher and you are using "core", look up the commands:
Install-WindowsFeature AD-domain-services Import-Module ADDSDeployment Install-ADDSForest
Server Name | IP Address |
---|---|
ad.example.net | 192.168.15.15 |
For our trust, the AD server will need to be configured to be the example.net domain with the hostname of ad.example.net. This way, we are not colliding in DNS and both AD and IdM should be able to communicate with each other as two separate forests. It is recommended to use Windows Server 2016 (with the same domain functional level) for this setup, as experience with that product is a recommended prerequisite for the exam.
% dnf install ipa-server-trust-ad -y
% firewall-cmd --add-service=freeipa-trust --permanent
success
% firewall-cmd --reload
success
% ipa-adtrust-install
. . .
# This is the admin@REALM IPA account
admin password:
WARNING: The smb.conf already exists. Running ipa-adtrust-install will break your existing samba configuration.
# Type 'yes' here
Do you wish to continue? [no]: yes
Do you want to enable support for trusted domains in Schema Compatibility plugin?
This will allow clients older than SSSD 1.9 and non-Linux clients to work with trusted users.
# You can press enter here to accept the default. If you have BSD, Solaris, Omnios, HP-UX, AIX, or RHEL 5 and older clients
# you may want to enable this. Some apps may benefit from this also.
Enable trusted domains support in slapi-nis? [no]:
Enter the NetBIOS name for the IPA domain.
Only up to 15 uppercase ASCII letters, digits and dashes are allowed.
Example: EXAMPLE.
# You can accept the default or put your own.
NetBIOS domain name [IPA]: IPA0
WARNING: 4 existing users or groups do not have a SID identifier assigned.
Installer can run a task to have ipa-sidgen Directory Server plugin generate
the SID identifier for all these users. Please note, in case of a high
number of users and groups, the operation might lead to high replication
traffic and performance degradation. Refer to ipa-adtrust-install(1) man page
for details.
# You should always say yes.
Do you want to run the ipa-sidgen task? [no]: yes
. . .
# This will complete and list ports to open and such. We did this earlier.
Now that the AD trust components are prepped, depending on the setup, we'll need to do some DNS zone forwards. It is likely you have IPA and AD running their own DNS. Note: This may not be the case in a real world scenario.
# We need to create a forward zone here for the example.net zone
% ipa dnsforwardzone-add example.net --forwarder=192.168.15.15 --forward-policy=only
Server will check DNS forwarder(s).
This may take some time, please wait ...
Zone name: example.net.
Active zone: TRUE
Zone forwarders: 192.168.15.15
Forward policy: only
# We should probably create a few dns records...
# Assuming the AD netbios name is EXAMPLEAD, use the syntax hostname.NETBIOS here
% ipa dnsrecord-add example.com ad.EXAMPLEAD --a-ip-address=192.168.15.15
# Same idea here, but we're only doing the netbios name and saying the name server record is the AD server
% ipa dnsrecord-add example.com EXAMPLEAD --ns-hostname=ad.EXAMPLEAD
# We need to allow the zones to be transferable to the AD domain
% ipa dnszone-mod example.com --allow-transfer=192.168.15.15
On the AD side, we need to create the IPA zone. It's absolutely required.
C:\Windows\System32>dnscmd 127.0.0.1 /ZoneAdd example.com /Secondary 192.168.15.2
% dig _ldap._tcp.example.com SRV
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> SRV _ldap._tcp.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14793
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_ldap._tcp.example.com. IN SRV
;; ANSWER SECTION:
_ldap._tcp.example.com. 86400 IN SRV 0 100 389 idm1.example.com.
_ldap._tcp.example.com. 86400 IN SRV 0 100 389 idm2.example.com.
;; AUTHORITY SECTION:
example.com. 86400 IN NS idm1.example.com.
example.com. 86400 IN NS idm2.example.com.
;; ADDITIONAL SECTION:
idm1.example.com. 1200 IN A 192.168.15.2
idm2.example.com. 1200 IN A 192.168.15.3
# Same with the AD records
% dig _ldap._tcp.example.net SRV
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> SRV _ldap._tcp.example.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12195
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 9
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_ldap._tcp.example.net. IN SRV
;; ANSWER SECTION:
_ldap._tcp.example.net. 600 IN SRV 0 100 389 ad.example.net.
. . .
Now that they are returning, intiate the trust.
% ipa trust-add --type=ad example.net --admin Administrator --password
Active Directiron domain administrator's password: (type password here)
-----------------------------------------------------
Added Active Directory trust for realm "example.net"
-----------------------------------------------------
Realm name: example.net
Domain NetBIOS name: EXAMPLEAD
Domain Security Identifier: S-1-5-21-XXXXXXXXXX-YYYYYYYYY-ZZZZZZZZZZ
Trust direction: Trusting forest
Trust type: Active Directory domain
Trust status: Established and verified
# Check that an AD user is resolvable. You can do this with DOMAIN\name or name@DOMAIN
% id EXAMPLEAD\\administrator
% id administrator@example.net
Authenticate users with an Active Directory domain¶
As we disabled the allow_all rule, let's create a set of groups first and then the HBAC rule.
# Create the starting AD group
% ipa group-add adusers
# Create an external group. This is required for AD users.
% ipa group-add --external adgroup_external
# Add an AD user into the external group
% ipa group-add-member --users=administrator@example.net adgroup_external
# Make the external group a member of ad users
% ipa group-add-member --groups=adgroup_external adusers
As we've made an HBAC rule before, this should be simple.
% ipa hbacrule-add --hostcat=all --servicecat=all --desc='ad users all access' adusers_access
% ipa hbacrule-add-user --groups=adusers adusers_access
% ipa hbactest --rules=adusers_access --user=administrator@example.net --host=client.example.com --service=sshd
The test should pass without any issues.
Group Types
While this may not be required information while working on the exam, it's important to understand that there are different group types in AD and the behavior changes based on the group type.
Groups in Active Directory have three types. These three types can actually change the behavior of how SSSD on the IPA domain controllers resolve them or if they'll even be resolvable at all. The three types are 'Domain Local', 'Global', and 'Universal'. If at all possible, avoid groups being 'Global'. Domain Local or Universal is recommended.