OpenShift 4 with FreeIPA container as an Identity Provider

About this tutorial

more then once I came across a document or two (2) which either provides a very goo explanation about OpenShift 4 and how to connect it to an LDAP as an Identity provider or either a very good document about how to setup Red Hat but very few of then also focus on security in that matter and to make sure your environment is actually secure.

Prerequisites

this tutorial already assume that you have OpenShift 4 cluster running and that you already have a RHEL machine already installed

  1. OpenShift 4 Cluster
  2. RHEL 7/8 —

In this tutorial I will use RHEL7 but very small changes need to made when you are working on RHEL8 which this document will NOT go into.

FreeIPA Container

in today’s world we can run almost anything in a container. For our use case we will use a very good tutorial from FreeIPA GIT Repository which explain how to build a FreeIPA container and run it.

We will use it to run the FreeIPA on our Bastion server and connect our OpenShift 4 Cluster to work with the FreeIPA server.

First we will make sure we have all of our tools set (podman , buikdah)

# yum install -y buildah podman git openldap-clients

Next we will clone the repository from github:

# git clone https://github.com/freeipa/freeipa-container.git

Change our current working directory to our new directory:

#cd freeipa-container/

And now all we need to do is to start our Build Process :

# buildah bud -f Dockerfile.rhel-7 -t freeipa-server .

Once the command is completed we can build our data directory and setup the server

Next if we have SElinux enabled we will need to add the following module in order for the build to work :

# setsebool -P container_manage_cgroup 1

Now let’s create a directory on our bastion server to save all the data for the FreeIPA container :

# mkdir /var/lib/ipa-dataenable

In order to expose our IPA container to our LAN IP range we need to edit the server /etc/hosts file and add the name of our IPA container to the first line of the file.

# vi /etc/hosts
192.168.1.1 ipa.example.test

Make sure to use the IP address for the public network.

For the FreeIPA installation we need to use podman to run the container for the first time which then will invoke the “ipa-server-configure-first” command :

podman run  --name freeipa-server-container -ti -e IPA_SERVER_IP=192.168.1.1 -p 53:53/udp -p 53:53 -p  88:88/udp -p  389:389/tcp -p  123:123/udp -p 464:464/udp -p 636:636/tcp -p 88:88/tcp -p 464:464/tcp -h ipa.example.test -v /sys/fs/cgroup:/sys/fs/cgroup:ro --tmpfs /run --tmpfs /tmp -v /var/lib/ipa-data:/data:Z freeipa-server --realm=EXAMPLE.TEST --admin-password=password --no-ntp --setup-dns --forwarder 8.8.8.8 --forwarder 8.8.4.4 -p password --ip-address=192.168.1.1

Let’s go over the arguments real quickly :

  • realm — the realm for the Kerberos domain to be used , in our example we are using EXAMPLE.TEST as our domian
  • admin-password — the password we want to give to the admin user
  • no-ntp — this option is very simple to understand , this means that the IPA server will not be the NTP Server
  • setup-dns — when we want the installation process to setup our DNS servers
  • forwarder — the DNS servers to forward the request to when the domain is not EXAMPLE.TEST

At the end of the Installation you will see something like :

==============================================================================
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
* 53: bind
UDP Ports:
* 88, 464: kerberos
* 53: bind
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.
3. Kerberos requires time synchronization between clients
and servers for correct operation. You should consider enabling ntpd.
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

Once the installation process is completed the podman process will not kill itself so we need to start a new session (SSH again to the server from a nother terminal and use podman to stop is :

# podman stop freeipa-server-container# podman rm freeipa-server-container

for running the FreeIPA server we need first to open the firewall with the ports we need but we also want our local LAN to be the only one that has access to those servers. For that porpoise we will set our work zone as our active zone and add the services to it.

First we will setup our active zone :

#firewall-cmd --zone=work --change-interface=eth0

Now let’s add our source IP address to the work zone (this example is using 192.168.1.0/24 as the network /subnet configuration :

#firewall-cmd --zone=work --add-source=192.168.1.0/24 

In my case I had also added the

Now we will add the services of the firewall rules :

#firewall-cmd --zone=work --permanent --add-service=https#firewall-cmd --zone=work --permanent --add-service=http#firewall-cmd --zone=work --permanent --add-service=ldap#firewall-cmd --zone=work --permanent --add-service=ldaps

The rest of the ports:

#firewall-cmd --zone=work --permanent --add-port=53/udp#firewall-cmd --zone=work --permanent --add-port=53/tcp#firewall-cmd --zone=work --permanent --add-port=88#firewall-cmd --zone=work --permanent --add-port=88/udp#firewall-cmd --zone=work --permanent --add-port=464/udp#firewall-cmd --zone=work --permanent --add-port=464#firewall-cmd --zone=work --permanent --add-port=123/udp

Reload the firewall service so the rules will take into effect :

#firewall-cmd --reload

And now to start the pod:

podman run  --name freeipa-server-container -ti -e IPA_SERVER_IP=192.168.1.1 -p 53:53/udp -p 53:53 -p  88:88/udp -p  389:389 -p  123:123/udp -p 464:464/udp -p 636:636 -p 88:88 -p 464:464 -h ipa.example.test -v /sys/fs/cgroup:/sys/fs/cgroup:ro --tmpfs /run --tmpfs /tmp -v /var/lib/ipa-data:/data:Z freeipa-server

for testing we are going to use the ldapsearch command to see that we are getting all the IPA tree:

# ldapsearch -x -h 192.168.1.2 -b "dc=example,dc=test" -D "cn=Directory Manager" -w password '(objectClass=*)'

if your are getting all your directory structure then you are good to go.

In most cases we would like the service to start at boot time , for that we will create a file with bash interpeter as it’s runner and copy/paste our “podman run …” command into it. Next we will generate a systemd file and make sure it runs on boot.

For creating the file all we need to do is add it to our /user/sbin/ directory and make sure it executable :

#touch /usr/sbin/start_freeipa.sh#chmod a+x /usr/sbin/start_freeipa.sh

Next we will add the content of our command to the file with the interpreter :

# echo '#!/bin/bash' > /usr/sbin/start_freeipa.sh

And the command :

# cat >> /usr/sbin/start_freeipa.sh << EOF
podman run --name freeipa-server-container -d --rm -e IPA_SERVER_IP=192.168.1.2 -p 53:53/udp -p53:53 -p 88:88/udp -p 389:389 -p 123:123/udp -p 464:464/udp -p 636:636 -p 88:88 -p 464:464 -h bastion-1.example.test -v /sys/fs/cgroup:/sys/fs/cgroup:ro --tmpfs /run --tmpfs /tmp -v /var/lib/ipa-data:/data:Z freeipa-server
EOF

Rap it up in a systemd template :

# cat > /etc/systemd/system/freeipa-container.service << EOF
[Unit]
Description=Starting the IPA server Container
After=network.target,firewalld.target

[Service]
Type=forking
ExecStart=/usr/sbin/start_freeipa.sh

[Install]
WantedBy=multi-user.target
EOF

Restart start the systemd daemon and make sure it is running on boot time

#systemctl daemon-reload#systemctl enable freeipa-container.service

For testing just reboot the service (or kill the container and start it again using systemctl )

#podman stop freeipa-server-container#podman rm freeipa-server-container#systemctl start freeipa-container.service

OpenShift IDP

By default, only a kubeadmin user exists on your cluster. To specify an identity provider, you must create a Custom Resource (CR) that describes that identity provider and add it to the cluster.
OpenShift 4 comes with it’s own Identity Provider connector to LDAP , all we need to do is tell it to use it. With a few simple steps we will be able to have up and running :

  1. Copying the IPA ca certificate
  2. Creating a CA configmap
  3. Creating a password secret for the LDAP bind user
  4. Configuring the Oauth to work with out LDAP connection

Every IPA installation generates a CA file which is our main CA file we would use to work with our FreeIPA deployment.

to obtain the CA file all we need to to is to access the container with podman and cat the ca.crt file by running :

#CONTAINER_ID=`podman ps | grep freeipa-server | awk '{print $1}'`#podman exec -it ${CONTAINER_ID} /bin/cat /etc/ipa/ca.crt

the output should look like our public CA file :

-----BEGIN CERTIFICATE-----
cascassc...
-----END CERTIFICATE-----

We will create a new directory and save the file in it as ca.crt :

#mkdir ~/Ldap ; cd Ldap#podman exec -it ${CONTAINER_ID} /bin/cat /etc/ipa/ca.crt > ca.crt

Now that we have our ca.crt in place let’s generate a ConfigMap from it :

#oc create configmap ca-config-map --from-file=ca.crt=$HOME/Ldap/ca.crt -n openshift-config

Identity providers use OpenShift Container Platform ConfigMaps in the openshift-config namespace to contain the certificate authority bundle. These are primarily used to contain certificate bundles needed by the identity provider.

To use the identity provider, you must define an OpenShift Container Platform Secret that contains the bindPassword.
For this command we will use the admin-password value we impletmented in our ipa-server-install command when we ran the container for the first time :

#oc create secret generic ldap-secret --from-literal=bindPassword=password -n openshift-config

for our last step we will create a auth-ldap.yaml file which contain the all the LDAP values we need with the ConfigMap and the secret we just created.

#cat > oauth-ldap.yaml << EOF
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
name: cluster
spec:
identityProviders:
- name: ldapidp
mappingMethod: claim
type: LDAP
ldap:
attributes:
id:
- dn
email:
- mail
name:
- cn
preferredUsername:
- uid
bindDN: "uid=admin,cn=users,cn=accounts,dc=example,dc=test"
bindPassword:
name: ldap-secret
ca:
name: ca-config-map
insecure: false
url: "ldap://bastion.example.test/cn=users,cn=accounts,dc=example,dc=test?uid?sub?(uid=*)"
EOF

Now we will apply the configuration and reset the pod for the authentication :

#oc create -f oauth-ldap.yaml

Kill all the pods in openshift-authentication

#oc delete pod --all -n openshift-authentication

Try to login with one of the users you created
(In case our user is user01 with the “password” for password)

#oc login --username user01 --password password api.cluster.exmaple.test:6443

If the login was unsuccessful then you can check the log for the authentication pods and look for errors :

oc get pods -n openshift-authentication -o name | xargs oc logs -n openshift-authentication

That is it

Have fun !!!

Open Source contributer for the past 15 years