Step-by-Step Guide to Setting Up 2FA with FreeIPA and LDAP for SSH and LDAP Enabled Applications
Tags: freeipa, 2fa, ldap, ssh
Published: 2023-11-24 22:01:31

## Introduction

In this tutorial, we'll setup FreeIPA server on Oracle Linux 9. FreeIPA is an open-source identity and authentication management system for Linux networked environments. Then we will install FreeIPA client on Ubuntu 22.04 and set up 2FA for SSH. We also create a bind user to be able to integrate LDAP enabled applications with the LDAP server.

## Installing FreeIPA server
### Preparing the Server

Set the hostname (FQDN):

```shell
sudo hostnamectl set-hostname ipa.example.com
```

Get the IP address the server:

```shell
ip -br a
```
> Example output:
> ```
> lo               UNKNOWN        127.0.0.1/8
> ens160           UP             192.168.136.134/24
> ```

Edit the hosts file:

```shell
sudo vim /etc/hosts
```
> Example:
> ```
> 192.168.136.134 ipa.example.com
> ```

Open the required ports:

```shell
sudo firewall-cmd --permanent --add-service=freeipa-4
```
```shell
sudo firewall-cmd --reload
```
### Install and Configure the FreeIPA Server
Install the required packages:
```shell
sudo dnf install -y ipa-server
```
Start the installation and configuration by running the following command:
```shell
sudo ipa-server-install
```
> Example output:
> ```
> This program will set up the IPA Server.
> Version 4.10.2
> This includes:
>   * Configure a stand-alone CA (dogtag) for certificate management
>   * Configure the NTP client (chronyd)
>   * Create and configure an instance of Directory Server
>   * Create and configure a Kerberos Key Distribution Center (KDC)
>   * Configure Apache (httpd)
>   * Configure SID generation
>   * Configure the KDC to enable PKINIT
> To accept the default shown in brackets, press the Enter key.
> ...
> ```

Select the default response of `no` when asked to configure the integrated DNS.

```
Do you want to configure integrated DNS (BIND)? [no]:
```
Accept the default FQDN.

```
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 [ipa.example.com]:
```

Accept the default domain name.

```
The domain name has been determined based on the host name.

Please confirm the domain name [example.com]:
```

Accept the default realm name.

```
The kerberos protocol requires a Realm name to be defined.
This is typically the domain name converted to uppercase.

Please provide a realm name [EXAMPLE.COM]:
```

Choose a secure password for the `Directory Manager` user and confirm it.

```
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):
```

Choose a secure password for the `admin` user and confirm it.

```
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):
```

Accept the default NETBIOS domain name.

```
Trust is configured but no NetBIOS domain name found, setting it now.
Enter the NetBIOS name for the IPA domain.
Only up to 15 uppercase ASCII letters, digits and dashes are allowed.
Example: EXAMPLE.


NetBIOS domain name [EXAMPLE]:
```

Accept the default response of `no` for configuring chrony.

```
Do you want to configure chrony with NTP server or pool address? [no]:
```
Finally the script displays a summary of the configuration. To proceed with the installation enter `yes`. 

```
The IPA Master Server will be configured with:
Hostname:       ipa.example.com
IP address(es): 192.168.136.134
Domain name:    example.com
Realm name:     EXAMPLE.COM

The CA will be configured with:
Subject DN:   CN=Certificate Authority,O=EXAMPLE.COM
Subject base: O=EXAMPLE.COM
Chaining:     self-signed

Continue to configure the system with these values? [no]:
```

The script needs several minutes to configure the server. Upon completion, it displays some information including a file containing a list of records to add to the DNS system.

```
Please add records in this file to your DNS system: /tmp/ipa.system.records.7hnslqjy.db
==============================================================================
Setup complete

Next steps:
        1. You must make sure these network ports are open:
                TCP Ports:
                  * 80, 443: HTTP/HTTPS
                  * 389, 636: LDAP/LDAPS
                  * 88, 464: kerberos
                UDP Ports:
                  * 88, 464: kerberos
                  * 123: ntp

        2. You can now obtain a kerberos ticket using the command: 'kinit admin'
           This ticket will allow you to use the IPA tools (e.g., ipa user-add)
           and the web user interface.

Be sure to back up the CA certificates stored in /root/cacert.p12
These files are required to create replicas. The password for these
files is the Directory Manager password
The ipa-server-install command was successful
```
Here are the contents of the `/tmp/ipa.system.records.7hnslqjy.db` file generated at the end of this installation:

```
_kerberos-master._tcp.example.com. 3600 IN SRV 0 100 88 ipa.example.com.
_kerberos-master._udp.example.com. 3600 IN SRV 0 100 88 ipa.example.com.
_kerberos._tcp.example.com. 3600 IN SRV 0 100 88 ipa.example.com.
_kerberos._udp.example.com. 3600 IN SRV 0 100 88 ipa.example.com.
_kerberos.example.com. 3600 IN TXT "EXAMPLE.COM"
_kerberos.example.com. 3600 IN URI 0 100 "krb5srv:m:tcp:ipa.example.com."
_kerberos.example.com. 3600 IN URI 0 100 "krb5srv:m:udp:ipa.example.com."
_kpasswd._tcp.example.com. 3600 IN SRV 0 100 464 ipa.example.com.
_kpasswd._udp.example.com. 3600 IN SRV 0 100 464 ipa.example.com.
_kpasswd.example.com. 3600 IN URI 0 100 "krb5srv:m:tcp:ipa.example.com."
_kpasswd.example.com. 3600 IN URI 0 100 "krb5srv:m:udp:ipa.example.com."
_ldap._tcp.example.com. 3600 IN SRV 0 100 389 ipa.example.com.
ipa-ca.example.com. 3600 IN A 192.168.136.134
```

### Test the Server

Authenticate as the `admin` user. The `kinit` command obtains and caches a Kerberos ticket-granting ticket.

```shell
kinit admin
```

You can list the ticket's information with:

```shell
klist
```

> Example output:
> ```
> Ticket cache: KCM:1000
> Default principal: admin@EXAMPLE.COM
> Valid starting       Expires              Service principal
> 11/17/2023 13:37:44  11/18/2023 12:41:14  krbtgt/EXAMPLE.COM@EXAMPLE.COM
> ```

Get a list of the users with:

```shell
ipa user-find
```

> Example output:
>
> ```
> --------------
> 1 user matched
> --------------
>   User login: admin
>   Last name: Administrator
>   Home directory: /home/admin
>   Login shell: /bin/bash
>   Principal alias: admin@EXAMPLE.COM, root@EXAMPLE.COM
>   UID: 487800000
>   GID: 487800000
>   Account disabled: False
> ----------------------------
> Number of entries returned 1
> ```

### Disable anonymous binds

Create a file containing the required configuration:

```shell
cat > ~/disable.ldif <<EOF
dn: cn=config
changetype: modify
replace: nsslapd-allow-anonymous-access
nsslapd-allow-anonymous-access: rootdse
EOF
```
Apply the changes.

```shell
ldapmodify -x -D "cn=Directory Manager" -W -h ipa.example.com -p 389 -f ~/disable.ldif
```

Restart the 389 Directory Server instance.

```shell
sudo systemctl restart dirsrv.target
```

Verify the modification.

```
ldapsearch -x -D "cn=Directory Manager" -b cn=config -W -h ipa.example.com  -p 389 nsslapd-allow-anonymous-access | grep nsslapd-allow-anonymous-access
```

> Expected output:
>
> ```shell
> Enter LDAP Password:
> # requesting: nsslapd-allow-anonymous-access
> nsslapd-allow-anonymous-access: rootdse
> ```

### Creating a Bind User

We need to create a read-only on our LDAP server. Other applications use this user to query the LDAP server. We can use Apache Directory Studio to create the user. First we need to connect to the server using the `admin` account.

![LDAP connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9omxrng77xkzs5037hgw.png)

Now we need to create a new entry:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ij3yd1kq43iwfuv8i30b.png)

Configure a `uid`:

![Configuring uid](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwsr4qx29yypstoo3nrb.png)

Add a `userPassword` attribute.

![userPassword](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bgd02jhspl93rvjbk2gw.png)

And set a plain text password (pre-hashed passwords are not valid).

![Plain text password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y85366vmop5km05y0rb1.png)

Click finish. You can use the `readonly_user` to integrate LDAP enabled application with the LDAP server.

## Installing FreeIPA client

Set the hostname (FQDN):

```shell
sudo hostnamectl set-hostname client.example.com
```
Modify the `hosts` file.

```shell
sudo vim /etc/hosts
```

> Example:
>
> ```
> 192.168.136.134 ipa.example.com ipa
> 192.168.136.135 client.example.com client
> ```

Install the required packages.

```shell
sudo apt install freeipa-client
```
During installation you'll be prompted with several times. When asked to enter default Kerberos realm, accept the default `EXAMPLE.COM`.

![Kerberos realm prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v831t8duw9solh8u9xb0.png)

When asked to enter Kerberos servers for your realm, hit `Ok` to skip.

![Kerberos servers prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/22dp2v9p3ix7jrz5fkni.png)

When asked to enter administrative server for your Kerberos realm, hit `Ok` to skip.

![Kerberos administrative server prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elc64mfyucie7elbg6hg.png)

Hit `Ok` again to finish the installation.

![Service restart prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbiimlbchc94tgvzv1l2.png)

Configure the IPA client.

```shell
sudo ipa-client-install --hostname=$(hostname -f) --mkhomedir --server=ipa.example.com --domain example.com --realm EXAMPLE.COM
```

The script is interactive and uses several prompts. When asked about no DNS discovery, choose `yes`.

```
Autodiscovery of servers for failover cannot work with this configuration.
If you proceed with the installation, services will be configured to always access the discovered server for all operations and will not fail over to other servers in case of failure.
Proceed with fixed values and no DNS discovery? [no]: yes
```
Enter `yes` if you want to configure chrony with NTP server.

```
Do you want to configure chrony with NTP server or pool address? [no]: yes
```

Enter a NTP server address, if you have entered `yes` in the previous step.

```
Enter NTP source server addresses separated by comma, or press Enter to skip: time.cloudflare.com
```

Press enter whenever you have provided all the servers you want to proceed to the next step.

```
Enter a NTP source pool address, or press Enter to skip:
```
At this point the script displays a summary of the configuration. Enter `yes` if you want to continue with the displayed configuration.

```
Client hostname: client.example.com
Realm: EXAMPLE.COM
DNS Domain: example.com
IPA Server: ipa.example.com
BaseDN: dc=example,dc=com
NTP server: time.cloudflare.com

Continue to configure the system with these values? [no]: yes
```
The script continues to configure the client.

```
Synchronizing time
Configuration of chrony was changed by installer.
Attempting to sync time with chronyc.
Time synchronization was successful.
User authorized to enroll computers: admin
Password for admin@EXAMPLE.COM:
Successfully retrieved CA cert
    Subject:     CN=Certificate Authority,O=EXAMPLE.COM
    Issuer:      CN=Certificate Authority,O=EXAMPLE.COM
    Valid From:  2023-11-17 13:23:41
    Valid Until: 2043-11-17 13:23:41

Enrolled in IPA realm EXAMPLE.COM
Created /etc/ipa/default.conf
Configured /etc/sssd/sssd.conf
Configured /etc/krb5.conf for IPA realm EXAMPLE.COM
Systemwide CA database updated.
Adding SSH public key from /etc/ssh/ssh_host_rsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ed25519_key.pub
Adding SSH public key from /etc/ssh/ssh_host_dsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ecdsa_key.pub
Could not update DNS SSHFP records.
SSSD enabled
Configured /etc/openldap/ldap.conf
Configured /etc/ssh/ssh_config
Configured /etc/ssh/sshd_config.d/04-ipa.conf
Configuring example.com as NIS domain.
Client configuration complete.
The ipa-client-install command was successful
```

On Ubuntu user's home directory won't be created automatically. To fix that, open `/usr/share/pam-configs/mkhomedir` file for editing.

```shell
sudo vim /usr/share/pam-configs/mkhomedir

```
And replace its contents by the following:

```
Name: Create home directory on login - FreeIPA
Default: yes
Priority: 900
Session-Type: Additional
Session:
	required pam_mkhomedir.so umask=0027 skel=/etc/skel
```
Now run the following command.

```shell
sudo pam-auth-update
```

When prompted to select PAM profiles, make sure `Create home directory on login - FreeIPA` is selected and then hit `Ok`.

![Pam profiles to be enabled prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1cvsavxapseab62ehhm9.png)

Now on the FreeIPA server, add the client to the `hosts` file.

```shell
sudo bash -c 'echo 192.168.136.135 client.example.com client >> /etc/hosts'
```

## Adding a User

We will use the web UI to add a new user. The UI is accessible through `https://ipa.example.com/ipa/ui/` address. Log in as `admin` user.

![Administration web UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/exu8dn98dzc1m5ia69b1.png)

Click on `Add` button.

![List of users](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fzur9pecbchwrmx6svxa.png)

Fill in the required fields and press `Add` button.

![User attributes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pluoj4xrbj710oj0efbc.png)

After adding the user, you'll see a list of active users. Click on the new user's login name.

![List of users](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98zomhxxghusbuhey08h.png)

To enable 2FA, select `Two factor authentication (password + OTP)` and then click the `Save` button.

![Enabling 2FA](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg6andcb9jzds5cpy5w2.png)

## Setting up 2FA

Now the newly added user is able to use the web UI and create a TOTP token for herself. 

![Web UI login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3b46u1mz4c5d0f73fv8.png)

At first login the user must change the password provided by the administrator.

![First login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acsr9qh4ichrckqf1lfs.png)

To generate the OTP token, the user must navigate to `OTP Tokens` tab. 

![User's info](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x479037povzugn3h5dmd.png)

Here the user needs to click on the `Add` button.

![Add OTP token](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pmoldqph9avlu5qp3a6.png)

The user must select the type of the token.

![Add OTP Token](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1dhm51anzi7ayur44b5.png)

A QR code will be displayed. The user should scan the code using an application like Google Authenticator.

![QR code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4uxvkyghew4flob0axq.png)

At the end the list of all the tokens will be displyed.

![Token list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z46c6x0dj7rfi8ffoam1.png)

Now, `Jane Doe` can log in to `client.example.com` via SSH. When prompted to enter the password, she should enter the password she selected earlier, followed by the one-time password displayed by the authenticator app.

![SSH login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uoo7526e8gd2xp65ku2c.png)

## References and Further Reading

- https://docs.oracle.com/en/learn/ol-freeipa/index.html
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/installing_identity_management/index
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/managing_idm_users_groups_hosts_and_access_control_rules/index
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/accessing_identity_management_services/index
- https://luna.oracle.com/lab/a03cfc90-4c3c-488d-9e66-ba514e00b619/steps
- https://www.linuxtechi.com/configure-freeipa-client-on-ubuntu/
- https://computingforgeeks.com/how-to-configure-freeipa-client-on-ubuntu-centos/
- https://www.howtoforge.com/how-to-install-freeipa-client-on-ubuntu-server-1804/
- https://www.tenable.com/audits/items/CIS_Debian_Linux_8_Server_v2.0.2_L1.audit:632ea5de5002b78e71581003f107448a