FreeIPA is a centralised identity management system. In this workshop you will learn how to deploy FreeIPA servers and enrol client machines, define and manage user and service identities, set up access policies, configure network services to take advantage of FreeIPA's authentication and authorisation facilities and issue X.509 certificates for services.
- Unit 1: Installing the FreeIPA server
- Unit 2: Enrolling client machines
- Unit 3: User management and Kerberos authentication
- Unit 4: Host-based access control (HBAC)
- Unit 5: Web application authentication and authorisation
- Unit 6: Certificate management
- Unit 7: Replica installation
- Unit 8: Sudo rule management
- Unit 9: SELinux User Maps
- Unit 10: SSH user and host key management
Parts of the workshop involve editing files on virtual
machines. The vi
and GNU nano
editors are available on the
VMs. If you are not familiar with vi
or you are unsure of what to use, you
should choose nano
.
This guide contains many examples of commands. Some of the commands should be executed on your host, others on a particular guest VM. For clarity, commands are annotated with the host on which they are meant to be executed, as in these examples:
$ echo "Run it on virtualisation host (no annotation)" [server]$ echo "Run it on FreeIPA server" [client]$ echo "Run it on IPA-enrolled client" ...
Some preparation is needed prior to the workshop. The workshop is designed to be carried out in a Vagrant environment that configures three virtual machines with all software network configuration ready for the workshop.
several VMs. The goal of the preparation is to be able to
successfully vagrant up
the VMs as the first step of the
workshop.
For the FreeIPA workshop you will need to:
- Install Vagrant and VirtualBox 4.3 (VirtualBox 5 is not supported by Vagrant). (On Fedora, you can use libvirt instead of VirtualBox).
- Use Git to clone the repository containing the
Vagrantfile
- Fetch the Vagrant box for the workshop
- Add entries for the guest VMs to your hosts file (so you can access them by their hostname)
Please set up these items prior to the workshop. More detailed instructions follow.
If you intend to use the libvirt
provider (recommended), install
vagrant-libvirt
and vagrant-libvirt-doc
:
$ sudo dnf install -y vagrant-libvirt vagrant-libvirt-doc
Also ensure you have the latest versions of selinux-policy
and
selinux-policy-targeted
.
Allow your regular user ID to start and stop Vagrant boxes. A PolicyKit rule
will be added that allows users in the vagrant
group to control VMs through
libvirt. The necessary rule is included in the vagrant-libvirt-doc
package. Run the following commands to add your local user to the vagrant
group and to copy the necessary rule to the right place:
$ usermod -a -G vagrant $USER $ cp /usr/share/vagrant/gems/doc/vagrant-libvirt-*/polkit/10-vagrant-libvirt.rules \ /etc/polkit-1/rules.d
On Fedoda 24 you need to enable virtlogd
:
$ systemctl enable virtlogd.socket $ systemctl start virtlogd.socket
Finally restart the services:
$ systemctl restart libvirtd $ systemctl restart polkit
Otherwise, you will use VirtualBox and the virtualbox
provider.
VirtualBox needs to build kernel modules, and that means that you must
first install kernel headers and Dynamic Kernel Module Support:
$ sudo dnf install -y vagrant kernel-devel dkms
Next, install VirtualBox from the official VirtualBox package repository. Before using the repo, check that its contents match what appears in the transcript below (to make sure it wasn't tampered with):
$ sudo curl -o /etc/yum.repos.d/virtualbox.repo \ http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo $ cat /etc/yum.repos.d/virtualbox.repo [virtualbox] name=Fedora $releasever - $basearch - VirtualBox baseurl=http://download.virtualbox.org/virtualbox/rpm/fedora/$releasever/$basearch enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://www.virtualbox.org/download/oracle_vbox.asc $ sudo dnf install -y VirtualBox-4.3
Finally, load the kernel modules:
$ sudo modprobe vboxdrv vboxnetadp
Install Vagrant for Mac OS X from https://www.vagrantup.com/downloads.html.
Install VirtualBox 4.3 for OS X hosts from https://www.virtualbox.org/wiki/Download_Old_Builds_4_3.
Install Git from https://git-scm.com/download/mac or via your preferred package manager.
Install Vagrant and Git:
$ sudo apt-get install -y vagrant git
Virtualbox 4.3 may be available from the system package manager, depending your your release. Find out which version of VirtualBox is available:
$ apt list virtualbox Listing... done virtualbox/trusty-updates,trusty-security 4.3.10-dfsg-1ubuntu5 amd64
If version 4.3 is available, install it via apt-get
:
$ sudo apt-get install -y virtualbox
If VirtualBox 4.3 was not available in the official packages for your release, follow the instructions at https://www.virtualbox.org/wiki/Linux_Downloads to install it.
Install Vagrant via the .msi
available from
https://www.vagrantup.com/downloads.html.
Install VirtualBox 4.3 for Windows hosts from https://www.virtualbox.org/wiki/Download_Old_Builds_4_3.
You will also need to install an SSH client, and Git. Git for Windows also comes with an SSH client so just install Git from https://git-scm.com/download/win.
This repository contains the Vagrantfile
that is used for the
workshop, which you will need locally.
$ git clone https://github.com/freeipa/freeipa-workshop.git
Please fetch the Vagrant box prior to the workshop. It is > 500MB so it may not be feasible to download it during the workshop.
$ vagrant box add ftweedal/freeipa-workshop
If you are running an older version of Vagrant that does not know about the Atlas service where the box is hosted, you can add it by URL instead:
$ vagrant box add ftweedal/freeipa-workshop \ https://atlas.hashicorp.com/ftweedal/boxes/freeipa-workshop/versions/0.0.7/providers/virtualbox.box
This step is necessary if you want to access the FreeIPA Web UI in the VM from a browser on your host, but otherwise this step is optional. All workshop units can be completed using the CLI.
Add the following entries to your hosts file:
192.168.33.10 server.ipademo.local 192.168.33.11 replica.ipademo.local 192.168.33.20 client.ipademo.local
On Unix systems (including Mac OS X), the hosts file is /etc/hosts
(you need elevated permissions to edit it.)
On Windows, edit C:\Windows\System32\system\drivers\etc\hosts
as
Administrator.
In this unit you will install a FreeIPA server. All tasks in subsequent units require the services and data provided by the server.
First, in the directory containing the Vagrantfile
(the clone of
this repository), execute vagrant up
to bring up the Vagrant
environment. (If you are using the VirtualBox provider on a platform
where that is not the default, e.g. Fedora, you will also need the
--provider virtualbox
option).
$ vagrant up --provider virtualbox
The Vagrant environment contains three hosts:
server.ipademo.local
replica.ipademo.local
client.ipademo.local
From the directory containing the Vagrantfile
, SSH into the
server
machine:
$ vagrant ssh server
On server
, start the FreeIPA server installation program:
[server]$ sudo ipa-server-install --no-host-dns --mkhomedir
The --no-host-dns
argument is needed because there are no reverse
DNS records for the Vagrant environment. For production deployment,
this important sanity check should not be skipped. The --mkhomedir
flag configure PAM to create missing home directories when users log
into the host for the first time. FreeIPA supports automount so
consider using that for production deployments.
You will be asked a series of questions. Accept the defaults for most of the questions, except as outlined below.
Configure FreeIPA's DNS server:
Do you want to configure integrated DNS (BIND)? [no]: yes
Accept default values for the server hostname, domain name and realm:
Enter the fully qualified domain name of the computer on which you're setting up server software. Using the form <hostname>.<domainname> Example: master.example.com. Server host name [server.ipademo.local]: Warning: skipping DNS resolution of host server.ipademo.local The domain name has been determined based on the host name. Please confirm the domain name [ipademo.local]: The kerberos protocol requires a Realm name to be defined. This is typically the domain name converted to uppercase. Please provide a realm name [IPADEMO.LOCAL]:
Enter passwords for Directory Manager (used to manage the directory server) and admin (the main account used for FreeIPA administration). Use something simple that you're not going to forget during the workshop!
Certain directory server operations require an administrative user. This user is referred to as the Directory Manager and has full access to the Directory for system management tasks and will be added to the instance of directory server created for IPA. The password must be at least 8 characters long. Directory Manager password: Password (confirm): The IPA server requires an administrative user, named 'admin'. This user is a regular system account used for IPA server administration. IPA admin password: Password (confirm):
Do not configure a DNS forwarder (you will want to configure a DNS forwarder for a real-world deployment but it is not needed for this workshop) and accept the defaults for configuring the reverse zone:
Checking DNS domain ipademo.local., please wait ... Do you want to configure DNS forwarders? [yes]: no No DNS forwarders configured Do you want to search for missing reverse zones? [yes]:
Next, you will be presented with a summary of the server configuration and asked for final confirmation. Give confirmation to begin the server installation:
The IPA Master Server will be configured with: Hostname: server.ipademo.local IP address(es): 192.168.33.10 Domain name: ipademo.local Realm name: IPADEMO.LOCAL BIND DNS server will be configured to serve IPA domain with: Forwarders: No forwarders Forward policy: only Reverse zone(s): No reverse zone Continue to configure the system with these values? [no]: yes
The installation takes a few minutes; you will see output indicating the progress.
When it completes, run kinit admin
and enter your admin
password to obtain a Kerberos ticket granting ticket (TGT) for the
admin
user:
[server]$ kinit admin Password for [email protected]: <enter password>
Run klist
to view your current Kerberos tickets:
[server]$ klist Ticket cache: KEYRING:persistent:1000:1000 Default principal: [email protected] Valid starting Expires Service principal 10/15/15 01:48:59 10/16/15 01:48:57 krbtgt/[email protected]
The FreeIPA server is now set up and you are ready to begin enrolling client machines, creating users, managing services, and more!
To prepare for the next unit, exit the server
SSH session (but
do not shut the VM down).
In this unit, you will enrol a host as a client of your FreeIPA domain. This means that users in your FreeIPA realm (or Active Directory realms for which there is a trust with FreeIPA) can log into the client machine (subject to access policies) and that services on the client can leverage FreeIPA's authentication and authorisation services.
From the directory that contains the Vagrantfile
, SSH into the
client
machine:
$ vagrant ssh client
On client
, start the FreeIPA client enrolment program:
[client]$ sudo ipa-client-install --mkhomedir
The FreeIPA server should be detected through DNS autodiscovery.
(If DNS discovery fails, e.g. due to client machine having incorrect
/etc/resolv.conf
configuration, you would be prompted to
manually enter the domain and server hostname instead).
The autodetected server settings will be displayed; confirm to proceed:
[client]$ sudo ipa-client-install Discovery was successful! Client hostname: client.ipademo.local Realm: IPADEMO.LOCAL DNS Domain: ipademo.local IPA Server: server.ipademo.local BaseDN: dc=ipademo,dc=local Continue to configure the system with these values? [no]: yes
You might see a warning about time synchronisation, which for this
workshop can be ignored. Next you will be be prompted to enter
credentials of a user authorised to enrol hosts (admin
):
User authorized to enroll computers: admin Password for [email protected]:
The enrolment now proceeds; no further input is required. You will
see output detailing the operations being completed. Unlike
ipa-server-install
, client enrolment only takes a few seconds.
Users in your FreeIPA domain can now log into FreeIPA-enrolled hosts, subject to Host-based access control (HBAC) rules. Users logged onto the host can also acquire Kerberos tickets for accessing services in your domain.
This unit introduces the ipa
CLI program and the web
interface. We will perform some simple administrative tasks: adding
groups and users and managing group membership.
Visit https://server.ipademo.local/
. You'll get a TLS
untrusted issuer warning which you can dismiss (by adding a temporary
exception). Log in as admin
.
Welcome to the FreeIPA Web UI. Most management activities can be
performed here, or via the ipa
CLI program. Use the Web UI to
perform the following actions:
- Add a User with the username
alice
. - Add a User Group for system administrators named
sysadmin
. - Add
alice
to thesysadmin
group.
Make sure you have a Kerberos ticket for admin
(reminder:
kinit admin
).
Most FreeIPA adminstrative actions can be carried out using the
ipa
CLI program. Let's see what commands are available:
[server]% ipa help commands automember-add Add an automember rule. automember-add-condition Add conditions to an automember rule. automember-default-group-remove Remove default (fallback) group for all unmatched entries. automember-default-group-set Set default (fallback) group for all unmatched entries. automember-default-group-show Display information about the default (fallback) automember groups. ...
Whoa! There are nearly 400 commands! We'll be using only a handful
of these today. Note that command completion is enabled in the
shell, so you can type a partial command and press <TAB>
a
couple of times to see what commands are available, e.g. all the
commands starting with cert-
:
[server]$ ipa cert-<TAB> cert-find cert-request cert-show cert-remove-hold cert-revoke cert-status
You'll notice that commands are grouped by plugin. You can read a
general overview of a plugin by running ipa help <plugin>
, and
specific information on a particular command by running ipa help
<command>
.
Add a user named bob
from the CLI. See if you can work out how
to do this using the CLI help commands. (hint: the user
plugin provides the command).
We have seen how to authenticate as admin
. The process is the
same for regular users - just kinit <username>
!
Try to authenticate as bob
:
[server]$ kinit bob kinit: Generic preauthentication failure while getting initial credentials
If you did not encounter this error, congratulations - you must be
a disciplined reader of documentation! To set an initial password
when creating a user via the ipa user-add
command you must
supply the --password
flag (the command will prompt for the
password).
Use the ipa passwd
command to (re)set a user's password:
[server]$ ipa passwd bob New Password: Enter New Password again to verify: ---------------------------------------- Changed password for "[email protected]" ----------------------------------------
Whenever a user has their password reset (including the first time
it is set), the next kinit
will prompt them to enter a new
password:
[server]$ kinit bob Password for [email protected]: Password expired. You must change it now. Enter new password: Enter it again:
Now bob
has a TGT (run klist
to confirm) which he can use to
authenticate himself to other hosts and services. Try logging into
client.ipademo.local
:
[server]$ ssh [email protected] Creating home directory for bob. [bob@client]$
You are now logged into the client as bob
. Type ^D
or
exit
to log out and return to the server
shell. If you run
klist
again, you will see not only the TGT but a service ticket
that was automatically acquired to log in to
client.ipademo.local
without prompting for a password. Kerberos
is a true single sign-on protocol!
[server]$ klist Ticket cache: KEYRING:persistent:1000:krb_ccache_dYtyLyU Default principal: [email protected] Valid starting Expires Service principal 15/10/15 07:15:11 16/10/15 07:15:02 host/[email protected] 15/10/15 07:15:03 16/10/15 07:15:02 krbtgt/[email protected]
FreeIPA's host-based access control (HBAC) feature allows you to define policies that restrict access to hosts or services based on the user attempting to log in and that user's groups, the host that they are trying to access (or its Host Groups), and (optionally) the service being accessed.
In this unit, we will define an HBAC policy that restricts
access to client.ipademo.local
to members of the
sysadmin
user group.
Instead of defining the HBAC rule to directly talk about
client.ipademo.local
, create a Host Group named webservers
and add client.ipademo.local
to it. You can do this via the Web
UI or the ipa
CLI program (don't forget to kinit admin
; see
if you can work out what plugin provides the host group
functionality).
Hint: if you use the CLI will need to run two commands - one to
create the host group, and one to add client.ipademo.local
as a
member of the host group.
HBAC rules are managed via the hbacrule
plugin. You can
complete the following actions via the Web UI as well, but we will
cover the CLI commands.
List the existing HBAC rules:
[server]$ ipa hbacrule-find ------------------- 1 HBAC rule matched ------------------- Rule name: allow_all User category: all Host category: all Service category: all Description: Allow all users to access any host from any host Enabled: TRUE ---------------------------- Number of entries returned 1 ----------------------------
The FreeIPA server is installed with a single default allow_all
rule. This rule must be disabled for other HBAC rules to take
effect. Look for a command that can do this, and run it.
HBAC rules are built up incrementally. The rule is created, then users or groups, hosts or hostsgroups and HBAC services are added to the rule. The following transcript details the process:
[server]$ ipa hbacrule-add sysadmin_webservers ------------------------------------- Added HBAC rule "sysadmin_webservers" ------------------------------------- Rule name: sysadmin_webservers Enabled: TRUE [server]$ ipa hbacrule-add-host sysadmin_webservers --hostgroup webservers Rule name: sysadmin_webservers Enabled: TRUE Host Groups: webservers ------------------------- Number of members added 1 ------------------------- [server]$ ipa hbacrule-add-user sysadmin_webservers --group sysadmin Rule name: sysadmin_webservers Enabled: TRUE User Groups: sysadmin Host Groups: webservers ------------------------- Number of members added 1 ------------------------- [server]$ ipa hbacrule-mod sysadmin_webservers --servicecat=all ---------------------------------------- Modified HBAC rule "sysadmin_webservers" ---------------------------------------- Rule name: sysadmin_webservers Service category: all Enabled: TRUE User Groups: sysadmin Host Groups: webservers
The --servicecat=all
option applies this rule for all services on
matching hosts. It could have been set during the hbacrule-add
command instead.
You can test HBAC rule evaluation using the ipa hbactest
command:
[server]$ ipa hbactest --host client.ipademo.local --service sshd --user bob --------------------- Access granted: False --------------------- Not matched rules: sysadmin_webservers
Poor bob
. He won't be allowed in because he is not a member of
the sysadmin
group. What about alice
?
kinit
as bob
and try to log in to the client:
[server]$ kinit bob Password for [email protected]: [server]$ ssh [email protected] packet_write_wait: Connection to UNKNOWN port 0: Broken pipe
Then try alice
:
[server]$ kinit alice Password for [email protected]: [server]$ ssh [email protected] Creating home directory for alice. [alice@client]$
You can configure many kinds of applications to rely on FreeIPA's
centralised authentication, including web applications. In this
unit you will configure the Apache web server to use Kerberos
authentication to authenticate users, PAM to enforce HBAC rules, and
mod_lookup_identity
to populate the request environment with
user attributes.
All activities in this unit take place on client
unless
otherwise specified.
The demo web application is trivial. It just reads its request
environment and responds in plain text with a list of variables
starting with the string "REMOTE_"
. It should be up and running
already:
[client]$ curl http://client.ipademo.local NOT LOGGED IN REMOTE_* REQUEST VARIABLES: REMOTE_ADDR: 192.168.33.20 REMOTE_PORT: 34356
Create a service representing the web application on
client.ipademo.local
. A service principal name has the service
type as its first part, separated from the host name by a slash,
e.g. HTTP/www.example.com
. The host part must correspond to an
existing host in the directory.
You must be getting the hang of FreeIPA by now, so I'll leave the rest of this step up to you. (It's OK to ask for help!)
The service needs access to its Kerberos key in order to
authenticate users. Retrieve the key from the FreeIPA server and
store it in a keytab file (you will need a TGT for admin
):
[client]$ ipa-getkeytab -s server.ipademo.local \ -p HTTP/client.ipademo.local -k app.keytab Keytab successfully retrieved and stored in: app.keytab
We also have to move the file, change its ownership and apply the
proper SELinux labels to the keytab file so that the Apache process
which runs under the confined apache
user may read it:
[client]$ sudo mv app.keytab /etc/httpd [client]$ sudo chown apache:apache /etc/httpd/app.keytab [client]$ sudo restorecon /etc/httpd/app.keytab
In this section we will use mod_auth_gssapi to enable Kerberos Negotiate / SPNEGO authentication for a web application.
The Apache configuration for the demo application lives in the file
/etc/httpd/conf.d/app.conf
. Update the configuration (use
sudo vi
or sudo nano
) to enable Kerberos authentication:
<VirtualHost *:80> ServerName client.ipademo.local WSGIScriptAlias / /usr/share/httpd/app.py <Location /> AuthType GSSAPI AuthName "Kerberos Login" GssapiCredStore keytab:/etc/httpd/app.keytab Require valid-user </Location> <Directory /usr/share/httpd> <Files "app.py"> Require all granted </Files> </Directory> </VirtualHost>
When the configuration is in place, restart Apache:
[client]$ sudo systemctl restart httpd
To test that Kerberos Negotiate authentication is working, kinit
and make a request using curl
:
[client]$ kinit bob Password for [email protected]: [client]$ curl -u : --negotiate http://client.ipademo.local/ LOGGED IN AS: [email protected] REMOTE_* REQUEST VARIABLES: REMOTE_ADDR: 192.168.33.20 REMOTE_USER: [email protected] REMOTE_PORT: 42499
The REMOTE_USER
variable in the request environment indicates
that there is a logged-in user and identifies that user.
Applications need to know more than just the username of a logged-in user. They want to know the user's name, to send mail to their email address and perhaps to know their group memberships or other attributes. In this section, we will use mod_lookup_identity to populate the HTTP request environment with variables providing information about the authenticated user.
mod_lookup_identity
retrieves user attributes from SSSD (via D-Bus).
Edit /etc/sssd/sssd.conf
; enable the SSSD ifp
InfoPipe
responder, permit the apache
user to query it, and configure the
attributes that you want to expose. Add the following configuration to
sssd.conf
:
[domain/ipademo.local] ... ldap_user_extra_attrs = mail, givenname, sn [sssd] services = nss, sudo, pam, ssh, ifp ... [ifp] allowed_uids = apache, root user_attributes = +mail, +givenname, +sn
Restart SSSD:
[client]$ sudo systemctl restart sssd
If you had not added an email address to your users when you created them, you will need to empty the SSSD cache:
[client]$ sudo sss_cache -E
You can test the SSSD InfoPipe directly via the dbus-send
utility:
[client]$ sudo dbus-send --print-reply --system \ --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe \ org.freedesktop.sssd.infopipe.GetUserAttr string:alice array:string:mail method return sender=:1.117 -> dest=:1.119 reply_serial=2 array [ dict entry( string "mail" variant array [ string "[email protected]" ] ) ]
Now update the Apache configuration to populate the request
environment. The LookupUserXXX
directives define the mapping of
user attributes to request environment variables. Multi-valued
attributes can be expanded into multiple variables, as in the
LookupUserGroupsIter
directive. Do not forget the
LoadModule
directive!
LoadModule lookup_identity_module modules/mod_lookup_identity.so <VirtualHost *:80> ServerName client.ipademo.local WSGIScriptAlias / /usr/share/httpd/app.py <Location /> AuthType GSSAPI AuthName "Kerberos Login" GssapiCredStore keytab:/etc/httpd/app.keytab Require valid-user LookupUserAttr mail REMOTE_USER_MAIL LookupUserAttr givenname REMOTE_USER_FIRSTNAME LookupUserAttr sn REMOTE_USER_LASTNAME LookupUserGroupsIter REMOTE_USER_GROUP </Location> ... </VirtualHost>
Default SELinux policy prevents Apache from communicating with SSSD
over D-Bus. Flip httpd_dbus_sssd
to 1
:
[client]$ sudo setsebool -P httpd_dbus_sssd 1
Restart Apache:
[client]$ sudo systemctl restart httpd
Now make another request to the application and observe that user
information that was injected into the request environment by
mod_lookup_identity
is reflected in the response:
[client]$ curl -u : --negotiate http://client.ipademo.local/ LOGGED IN AS: [email protected] REMOTE_* REQUEST VARIABLES: REMOTE_USER_GECOS: Alice Able REMOTE_USER_GROUP_N: 2 REMOTE_ADDR: 192.168.33.20 REMOTE_USER_FIRSTNAME: Alice REMOTE_USER_LASTNAME: Able REMOTE_USER: [email protected] REMOTE_USER_GROUP_2: ipausers REMOTE_USER_GROUP_1: sysadmin REMOTE_PORT: 42586 REMOTE_USER_EMAIL: [email protected]
The final task for this unit is to configure Apache to use FreeIPA's HBAC rules for access control. We will use mod_authnz_pam in conjunction with SSSD's PAM responder to achieve this.
First add an HBAC service named app
for the web application.
You can do this as admin
via the Web UI or CLI. Hint: the
hbacsvc
plugin provides this functionality.
Next, add an HBAC rule allowing members of the sysadmin
user
group access to app
(on any host):
[client]$ ipa hbacrule-add --hostcat=all sysadmin_app ------------------------------ Added HBAC rule "sysadmin_app" ------------------------------ Rule name: sysadmin_app Host category: all Enabled: TRUE [client]$ ipa hbacrule-add-user sysadmin_app --group sysadmin Rule name: sysadmin_app Host category: all Enabled: TRUE User Groups: sysadmin ------------------------- Number of members added 1 ------------------------- [client]$ ipa hbacrule-add-service sysadmin_app --hbacsvcs app Rule name: sysadmin_app Host category: all Enabled: TRUE User Groups: sysadmin Services: app ------------------------- Number of members added 1 -------------------------
Next, define the PAM service on client
. The name must match the
hbacsvc
name (in our case: app
), and the name is indicated
by the name of the file that configures the PAM stack. Create
/etc/pam.d/app
with the following contents:
account required pam_sss.so
Finally, update the Apache configuration. Find the line:
Require valid-user
Replace with:
Require pam-account app
Also add the LoadModule
directive to the top of the file:
LoadModule authnz_pam_module modules/mod_authnz_pam.so
Once again, we must set a special SELinux boolean to allow
mod_authnz_pam
to work:
[client]$ sudo setsebool -P allow_httpd_mod_auth_pam 1
Restart Apache and try and perform the same curl
request again
as alice
. Everything should work as before because alice
is
a member of the sysadmin
group. What happens when you are
authenticated as bob
instead?
You probably noticed that the web service was not hosted over HTTPS, so there is no TLS-based authentication or confidentiality. In this unit, we will issue an X.509 certificate for the web service via the certmonger program.
Certmonger supports multiple CAs including FreeIPA's CA, and can
generate keys, issue certifiate requests, track certificates, and
renew tracked certificates when the expiration time approaches.
Certmonger works with NSS, so we will also use mod_nss
with
Apache, rather than mod_ssl
.
Let's start by confirming that the HTTP service does not yet have a certificate:
[client]$ ipa service-show HTTP/client.ipademo.local Principal: HTTP/[email protected] Keytab: True Managed by: client.ipademo.local
Enable and start certmonger:
[client]$ sudo systemctl enable certmonger Created symlink from /etc/systemd/system/multi-user.target.wants/certmonger.service to /usr/lib/systemd/system/certmonger.service. [client]$ sudo systemctl start certmonger
Now let's request a certificate. We will generate keys and store
certificates in the NSS database at /etc/httpd/alias
:
[client]$ sudo ipa-getcert request -d /etc/httpd/alias -n app \ -K HTTP/client.ipademo.local \ -D client.ipademo.local New signing request "20151026222558" added.
Let's break down some of those command arguments.
-d <path>
- Path to NSS database
-n <nickname>
- Nickname to use for storing the key and certificate
-K <principal>
- Kerberos service principal; because different kinds of services may be accessed at one hostname, this argument is needed to tell certmonger which service principal is the subject
-D <dnsname>
- Requests the given domain name to appear in the Subject Alternative Name (SAN) extension. The hostname will appear in the Common Name (CN) field but this practice is deprecated, so it is important to also include it in the SAN extension.
Another important argument is -N <subject-name>
but this
defaults to the system hostname, which in our case
(client.ipademo.local
) is appropriate.
Let's check the status of our certificate request using the tracking
identifier given in the ipa-getcert request
output:
[client]$ sudo getcert list -i 20151026222558 Number of certificates and requests being tracked: 1. Request ID '20151026222558': status: MONITORING stuck: no key pair storage: type=NSSDB,location='/etc/httpd/alias',nickname='app',token='NSS Certificate DB' certificate: type=NSSDB,location='/etc/httpd/alias',nickname='app',token='NSS Certificate DB' CA: IPA issuer: CN=Certificate Authority,O=IPADEMO.LOCAL subject: CN=client.ipademo.local,O=IPADEMO.LOCAL expires: 2017-10-26 22:26:00 UTC dns: client.ipademo.local principal name: HTTP/[email protected] key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment eku: id-kp-serverAuth,id-kp-clientAuth pre-save command: post-save command: track: yes auto-renew: yes
Confirm that the certificate was issued and that certmonger is now
MONITORING
the certificate and will auto-renew
it when it is
close to expiration. Now if you run ipa service-show
, you will
see a number of attributes related to the certificate, including the
certificate itself. Can you work out how to save the PEM-encoded
certificate to a file?
You can also see that the certificate is present in the NSS database, identified by the specified nickname:
[client]# sudo certutil -d /etc/httpd/alias -L -n app Certificate: Data: Version: 3 (0x2) Serial Number: 11 (0xb) Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption Issuer: "CN=Certificate Authority,O=IPADEMO.LOCAL" Validity: Not Before: Mon Oct 26 22:26:00 2015 Not After : Thu Oct 26 22:26:00 2017 Subject: "CN=client.ipademo.local,O=IPADEMO.LOCAL" ... Signed Extensions: ... Name: Certificate Subject Alt Name DNS name: "client.ipademo.local" ...
Now we can reconfigure Apache to serve our app over TLS. Update
app.conf
to listen on port 443 and add the NSS directives:
... Listen 443 <VirtualHost *:443> NSSEngine on NSSCertificateDatabase /etc/httpd/alias NSSNickname app NSSCipherSuite +aes_128_sha_256,+aes_256_sha_256,+ecdhe_ecdsa_aes_128_gcm_sha_256,+ecdhe_ecdsa_aes_128_sha,+ecdhe_ecdsa_aes_256_gcm_sha_384,+ecdhe_ecdsa_aes_256_sha,+ecdhe_rsa_aes_128_gcm_sha_256,+ecdhe_rsa_aes_128_sha,+ecdhe_rsa_aes_256_gcm_sha_384,+ecdhe_rsa_aes_256_sha,+rsa_aes_128_gcm_sha_256,+rsa_aes_128_sha,+rsa_aes_256_gcm_sha_384,+rsa_aes_256_sha ServerName client.ipademo.local ...
Restart Apache and make a request to the app over HTTPS:
[client]$ sudo systemctl restart httpd [client]$ curl -u : --negotiate https://client.ipademo.local LOGGED IN AS: [email protected] REMOTE_* REQUEST VARIABLES: REMOTE_USER_MAIL: [email protected] REMOTE_USER_GECOS: Alice Able REMOTE_USER: [email protected] REMOTE_USER_GROUP_N: 1 REMOTE_ADDR: 192.168.33.20 REMOTE_USER_FIRSTNAME: Alice REMOTE_USER_LASTNAME: Able REMOTE_USER_GROUP_1: ipausers REMOTE_PORT: 47894
FreeIPA is designed to be run in a replicated multi-master environment. In this unit, we will deploy a single FreeIPA replica. For recommended production topologies, see http://www.freeipa.org/page/Deployment_Recommendations#Replicas.
If you have disabled the allow_all
HBAC rule, add a new rule
that will allow ``admin`` to access the ``sshd`` service on any
host.
As of FreeIPA 4.3, replica installation is accomplished by promoting an enrolled client machine to a server.
SSH to the replica
VM and enrol it per Unit 2: Enrolling
client machines.
Now promote the client to server. We will set up the replica
without CA or DNS, but in a production deployment there should be
at least one instance of these services in each datacentre. These
components can be added later via ipa-ca-install(1)
and
ipa-dns-install(1)
.
[replica]$ sudo ipa-replica-install Password for [email protected]: Run connection check to master Connection check OK Configuring NTP daemon (ntpd) [1/4]: stopping ntpd [2/4]: writing configuration ...
The rest of the replica installation process is almost identical to server installation. One important difference is the initial replication of data to the new Directory Server instance:
[28/43]: setting up initial replication Starting replication, please wait until this has completed. Update in progress, 7 seconds elapsed Update succeeded
After ipa-replica-install
finishes, the replica is operational.
Sudo is a program that allows users to run programs as another user
with different privileges (possibly root
). Sudo rules provide
fine-grained control over who can execute which processes, as which
users. FreeIPA allows centralised management of Sudo rules. To
simplify management, Sudo rules can refer to User Groups, Host
Groups and Command Groups as well as individual users, hosts and
commands.
The goal of this unit is to allow alice
(being a sysadmin
)
to run any command on any FreeIPA-enrolled machine, and to allow
bob
(who is merely a web server administrator) to control
httpd
on hosts that are webservers
.
Let's deal with alice
first. Before we do anything else, log in
as alice
and attempt to run the id
command as root
.
Observe that the action is denied:
[client]$ su -l alice Password: [alice@client]$ sudo id [sudo] password for alice: alice is not allowed to run sudo on client. This incident will be reported. [alice@client]$ exit logout
Now define the sysadmin_sudo
rule, which allows members of the
sysadmin
User Group to to run any command on any host:
[client]$ ipa sudorule-add sysadmin_sudo \ --hostcat=all --runasusercat=all --runasgroupcat=all --cmdcat=all ------------------------------- Added Sudo Rule "sysadmin_sudo" ------------------------------- Rule name: sysadmin_sudo Enabled: TRUE Host category: all Command category: all RunAs User category: all RunAs Group category: all
Next add the sysadmin
User Group to the Sudo rule:
[client]$ ipa sudorule-add-user sysadmin_sudo --group sysadmin Rule name: sysadmin_sudo Enabled: TRUE Host category: all Command category: all RunAs User category: all RunAs Group category: all User Groups: sysadmin ------------------------- Number of members added 1 -------------------------
Now attempt to sudo id
as alice
again:
[client]$ su -l alice Password: [alice@client]$ sudo id [sudo] password for alice: uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
This time the action was allowed, and we can see from the output
that alice
indeed executed the id
command as root
.
Now let us turn our attention to bob
. The goal is to allow
bob
and other web servers administrators to run commands related
to web server administration (and only such commands). First, let's
observe that bob
currently cannot restart Apache:
[client]$ su -l bob Password: [bob@client]$ sudo systemctl restart httpd [sudo] password for bob: Sorry, user bob is not allowed to execute '/bin/systemctl restart httpd' as root on client.ipademo.local.
Make a new User Group named webadmin
and add bob
as a
member. Add an hbacrule
that allows bob
to log into hosts
that are members of the webservers
Host Group.
Now define the webadmin_sudo
rule. Note that we do not use
--hostcat=all
or cmdcat=all
this time.
[client]$ ipa sudorule-add webadmin_sudo \ --runasusercat=all --runasgroupcat=all ------------------------------- Added Sudo Rule "webadmin_sudo" ------------------------------- Rule name: webadmin_sudo Enabled: TRUE RunAs User category: all RunAs Group category: all [client]$
Add the webadmin
User Group and webservers
Host Group to the rule:
[client]$ ipa sudorule-add-user webadmin_sudo --group webadmin Rule name: webadmin_sudo Enabled: TRUE RunAs User category: all RunAs Group category: all User Groups: webadmin ------------------------- Number of members added 1 ------------------------- [client]$ ipa sudorule-add-host webadmin_sudo --hostgroup webservers Rule name: webadmin_sudo Enabled: TRUE RunAs User category: all RunAs Group category: all User Groups: webadmin Host Groups: webservers ------------------------- Number of members added 1 -------------------------
Next, define Sudo Commands and a Sudo Command Group for web server administration:
[client]$ ipa sudocmd-add "/usr/bin/systemctl start httpd" --------------------------------------------------- Added Sudo Command "/usr/bin/systemctl start httpd" --------------------------------------------------- Sudo Command: /usr/bin/systemctl start httpd [client]$ ipa sudocmd-add "/usr/bin/systemctl restart httpd" ----------------------------------------------------- Added Sudo Command "/usr/bin/systemctl restart httpd" ----------------------------------------------------- Sudo Command: /usr/bin/systemctl restart httpd [client]$ ipa sudocmdgroup-add webadmin_cmds ---------------------------------------- Added Sudo Command Group "webadmin_cmds" ---------------------------------------- Sudo Command Group: webadmin_cmds [client]$ ipa sudocmdgroup-add-member webadmin_cmds \ --sudocmds "/usr/bin/systemctl start httpd" \ --sudocmds "/usr/bin/systemctl restart httpd" Sudo Command Group: webadmin_cmds Member Sudo commands: /usr/bin/systemctl start httpd, /usr/bin/systemctl restart httpd ------------------------- Number of members added 2 -------------------------
Finally, add this new command group to the Sudo rule:
[client]$ ipa sudorule-add-allow-command webadmin_sudo \ --sudocmdgroups webadmin_cmds Rule name: webadmin_sudo Enabled: TRUE RunAs User category: all RunAs Group category: all User Groups: webadmin Host Groups: webservers Sudo Allow Command Groups: webadmin_cmds ------------------------- Number of members added 1 -------------------------
Now log in again as bob
and observe that we have reached our goal: he can
restart (or start) Apache, but not run other commands via sudo
:
[client]$ su -l bob Password: [bob@client]$ sudo systemctl restart httpd [sudo] password for bob: [bob@client]$ sudo id Sorry, user bob is not allowed to execute '/bin/id' as root on client.ipademo.local.
SELinux is a mandatory access controls mechanism for Linux,
providing more powerful and flexible access control than traditional
Unix permissions. Users have an SELinux context consisting of a
user, role and type. The goal of this unit is to cause users
to be confined by an SELinux role-based access control (RBAC)
policy when the log into hosts that are members of the
webservers
Host Group.
Note: SELinux contexts are applied during PAM-based login, so
when testing our changes in this unit su -l <user>
will not
suffice: it is necessary to log in via SSH. You can do this from
any of the VMs (even client
itself).
Log in as alice
and run id -Z
to see her current SELinux
context:
[alice@client]$ id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
alice
is currently unconfined. We want her to be confined to
the staff_u
context when she logs in, to limit the impact of an
account compromise.
SELinux User Maps can refer to users and hosts directly, or they can inherit the users and hosts of an existing HBAC rule. Because access control is defined by HBAC, it is a good administration practice to link SELinux User Maps to HBAC rules, so that when users or hosts are added to the HBAC rule, the correct SELinux context will automatically be used.
Recall that members of the sysadmin
User Group already have
access to webservers
via the sysadmin_webservers
rule that
was created in Unit 4: Host-based access control (HBAC). Create
the SELinux User Map:
[client]$ ipa selinuxusermap-add sysadmin_staff_t \ --hbacrule sysadmin_webservers --selinuxuser staff_u:s0-s0:c0.c1023 ----------------------------------------- Added SELinux User Map "sysadmin_staff_t" ----------------------------------------- Rule name: sysadmin_staff_t SELinux User: staff_u:s0-s0:c0.c1023 HBAC Rule: sysadmin_webservers Enabled: TRUE
Now login in as alice
over SSH and observe that she is confined
by the staff_u
policy:
[server]$ ssh [email protected] [email protected]'s password: Last login: Fri Sep 2 05:47:03 2016 [alice@client]$ id -Z staff_u:staff_r:staff_t:s0-s0:c0.c1023
Note: in production use you should ensure that only one HBAC rule allows access for a given user/host/SELinux User Map combination. Only one SELinux policy will be applied, and if multiple policies match, the winning policy may be chosen inconsistently.
alice
is now confined by the staff_u
policy, but being a
sysadmin
she needs to be unconfined when running commands via
sudo
. With the current configuration, commands run via sudo
inherit a user's context, as the following commands demonstrate:
[alice@client]$ sudo -s [sudo] password for alice: sh-4.3# id -Z staff_u:staff_r:staff_t:s0-s0:c0.c1023 sh-4.3# systemctl restart httpd Failed to restart httpd.service: Access denied See system logs and 'systemctl status httpd.service' for details. sh-4.3#
Now let's make it so that alice
can do her job. We need to
update the Sudo rule to change the SELinux context:
[alice@client]$ ipa sudorule-add-option sysadmin_sudo --sudooption type=unconfined_t ------------------------------------------------------------- Added option "type=unconfined_t" to Sudo Rule "sysadmin_sudo" ------------------------------------------------------------- Rule name: sysadmin_sudo Enabled: TRUE Host category: all Command category: all RunAs User category: all RunAs Group category: all Sudo Option: type=unconfined_t [alice@client]$ ipa sudorule-add-option sysadmin_sudo --sudooption role=unconfined_r ------------------------------------------------------------- Added option "role=unconfined_r" to Sudo Rule "sysadmin_sudo" ------------------------------------------------------------- Rule name: sysadmin_sudo Enabled: TRUE Host category: all Command category: all RunAs User category: all RunAs Group category: all Sudo Option: type=unconfined_t, role=unconfined_r
Now when alice
runs sudo
it changes the SELinux context of
the program being run:
[alice@client]$ sudo -s sh-4.3# id -Z staff_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 sh-4.3# systemctl restart httpd sh-4.3#
In this module you will explore how to use FreeIPA as a backend
provider for SSH keys. Instead of distributing authorized_keys
and known_hosts
files, SSH keys are uploaded to their
corresponding user and host entries in FreeIPA.
OpenSSH can use public-private key pairs to authenticate users. A
user wanting to access a host can get her public key added to an
authorized_keys
file on the target host. When the user attempts
to log in, she presents her public key and the host grants access if
her key is in an authorized_keys
file. There are system-wide
and per-user authorized_keys
files, but if the target systems do
not mount a network-backed home directory (e.g. NFS), then the user
must copy her public key to every system she intends to log in to.
On FreeIPA-enrolled systems, SSSD can be configured to cache and retrieve user SSH keys so that applications and services only have to look in one location for user public keys. FreeIPA provides the centralized repository of keys, which users can manage themselves. Administrators do not need to worry about distributing, updating or verifying user SSH keys.
Generate a user keypair on the client system:
[client]$ sudo -i -u alice [alice@client]$ [alice@client]$ ssh-keygen -C [email protected] Generating public/private rsa key pair. Enter file in which to save the key (/home/alice/.ssh/id_rsa): Created directory '/home/alice/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/alice/.ssh/id_rsa. Your public key has been saved in /home/alice/.ssh/id_rsa.pub. The key fingerprint is: SHA256:TbuWICAdqkdXwG3uQoXxh03DuJdRC6Vh3ntOcacdfHM [email protected] The key's randomart image is: +---[RSA 2048]----+ | .+=.o*oo | | oo+=*o* . . | | + ++o.=o+ . .+E| | o o..o.oo o o +=| |. .. ...S + o . .| | . . .. . * | | . + . | | . | | | +----[SHA256]-----+
The public key is stored in /home/alice/.ssh/id_rsa.pub
in an
OpenSSH-specific format. alice
can now upload it to her user
entry in FreeIPA:
[alice@client]$ kinit alice Password for [email protected]: [alice@client]$ ipa user-mod alice \ --sshpubkey="$(cat /home/alice/.ssh/id_rsa.pub)" --------------------- Modified user "alice" --------------------- User login: alice First name: Alice Last name: Able Home directory: /home/alice Login shell: /bin/sh Email address: [email protected] UID: 1278000001 GID: 1278000001 SSH public key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDH8pLi61DjkEPqNZnfOgGLLZfLdu9EqVL9UrZeXD3M/j3ig+xeDCCO80YjzuND0UZE4CHgA+uGrtoinQMYkt/FRkm/ie8wcinP/8BxSoOeYSHDNG+cG3iSNJrDiHoqPeQ/+nzBS5n6HWy18N5IMNoqC+f9f2VDuHWZCKqPHMLD29MAX6vOgawdHWFcAk416O+EgS43w3ub89+VPz3Egz4z9K+gjpoboFHk94n7n09B+qyzzImVMsz9vMFSr0rcaVRd9Tb0Q6HlUXkU7aH1Vjkl/DJdQalCpPYJXujkRYAZIs1ouU5IBuuq6k54fk1vBmwjv2tK2NkpvfWfhaxQVwdn [email protected] Account disabled: False Password: True Member of groups: ipausers, sysadmin Indirect Member of Sudo rule: sysadmin_sudo Indirect Member of HBAC rule: sysadmin_all Kerberos keys available: True SSH public key fingerprint: C4:62:89:7A:65:F9:82:12:EF:08:96:D1:C9:7D:51:A5 [email protected] (ssh-rsa)
During enrolment of the systems, SSSD has been configured to use FreeIPA as one of its identity domains and OpenSSH has been configured to use SSSD for managing user keys.
If you have disabled the allow_all
HBAC rule, add a new rule
that will allow ``alice`` to access the ``sshd`` service on any
host.
Logging in to the server using SSH public key authentication should now work:
[alice@client]$ ssh -o GSSAPIAuthentication=no server.ipademo.local Last login: Tue Feb 2 15:10:13 2016 [alice@server]$
To verify the SSH public key was used for authentication, you can
check the sshd
service journal on the server, which should have
an entry like:
server.ipademo.local sshd[19729]: \ Accepted publickey for alice from 192.168.33.20 port 37244 \ ssh2: RSA SHA256:rgVSyPM/yn/b5bsZQIsAXWF+16zkP59VS9GS+k+bbOg
OpenSSH uses public keys to authenticate hosts. When a client
attempts to log in over SSH, the target host presents its public
key. The first time the host authenticates, the user may have to
examine the target host's public key and manually authenticate it.
The client then stores the host's public key in a known_hosts
file. On subsequent attempts to log in, the client checks its
known_hosts
files and automatically grants access to recognised
hosts.
Based on the last exercise, try to figure out how to upload SSH host keys to the FreeIPA server.
Note: OpenSSH has already been configured to look up known hosts on the FreeIPA server, so no manual configuration is required for this section.