Summary :
This post will show about how to integrate Apache web server, openldap with keycloak.
Keycloak is an open source software product to allow single sign-on with Identity Management and Access Management aimed at modern applications and services.
OpenLDAP is a free, open-source implementation of the Lightweight Directory Access Protocol developed by the OpenLDAP Project.
Test environment :
virtual machine1:
- Installed: Centos 7 , Apache 2.4, openldap
- Host name: ldap-apache
- Internal IP: 10.152.0.31
- Temp Public IP: 35.197.180.204
virtual machine2:
- Installed: Centos 7 , keycloak
- Host name: keycloak
- Internal IP: 10.152.0.29
- Temp Public IP: 35.244.79.144
Follow below steps on virtual machine1:
Install Apache 2.4 web server
yum install httpd -y
systemctl enable httpd.service
systemctl start httpd
To set up the self-signed certificate, we have to install mod_ssl.
yum install mod_ssl -y
Create directory to keep certificate and this directory must be kept strictly private:
mkdir /etc/ssl/private
chmod 700 /etc/ssl/private
Create the SSL key and certificate files using openssl:
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key \
-out /etc/ssl/certs/apache-selfsigned.crt
Create a strong Diffie-Hellman group for to negotiate Perfect Forward Secrecy with clients:
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 cat /etc/ssl/certs/dhparam.pem | sudo tee -a /etc/ssl/certs/apache-selfsigned.crt
Install the OpenLDAP packages:
yum install openldap compat-openldap \
openldap-clients openldap-servers \
openldap-servers-sql openldap-devel -y
Enable and initialize the openLDAP service: systemctl enable slapd systemctl start slapd Allow ldap on firewall: firewall-cmd --add-service=ldap firewall-cmd --reload Configuring openLDAP server Generate the OpenLDAP root password: slappasswd -h {SSHA} –s your_password
Make entry in /etc/hosts file:
vim /etc/hosts
<ip address> ldap-apache.local
Create the openLDAP configuration file:
vim /etc/openldap/slapd.d/conf.ldif
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=ldap-apache,dc=local
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=root,dc= ldap-apache,dc=local
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}8ipIU8QRc24R18BYG2A5kpVP9yaV+EqB
Upload the configuration created to openLDAP with ldapmodify:
ldapmodify -Y EXTERNAL -H ldapi:/// -f /etc/openldap/slapd.d/conf.ldif
Configuring the openLDAP Database:
Copy the example database and grant it permissions:
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
chown ldap:ldap /var/lib/ldap/*
Add the rest of the schemas:
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
Create our file named base.ldif
vim /etc/openldap/slapd.d/base.ldif
dn: dc=ldap-apache,dc=local
dc: ldap-apache
objectClass: top
objectClass: domain
dn: cn=root ,dc=ldap-apache,dc=local
objectClass: organizationalRole
cn: root
description: LDAP Manager
dn: ou=users,dc=ldap-apache,dc=local
objectClass: organizationalUnit
ou: Users
dn: ou=Group,dc=ldap-apache,dc=local
objectClass: organizationalUnit
ou: Group
ldapadd -x -W -D "cn=root,dc=ldap-apache,dc=local" -f base.ldif
Create a user for openLDAP using newuser.ldif
vim /etc/openldap/slapd.d/newuser.ldif
dn: uid=devops,ou=users,dc=ldap-apache,dc=local
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: devops
uid: devops
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/devops
loginShell: /bin/bash
gecos: user
userPassword: {crypt}x
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
ldapadd -x -W -D "cn=root,dc=ldap-apache,dc=local" -f newuser.ldif
Give the new user a password:
ldappasswd -s ansible123 -W -D "cn=root,dc=ldap-apache,dc=local" -x "uid=devops,ou=users,dc=ldap-apache,dc=local"
Test ldap server in order:
ldapsearch -x cn=devops -b dc=ldap-apache,dc=local
Check client authentication from client machine:
Install necessary packages for client authentication:
yum install openldap openldap-clients nss-pam-ldapd
Enable the client system to authenticate using LDAP:
authconfig --enableldap --enableldapauth --ldapserver=ldap-apache.local \
--ldapbasedn="dc=ldap-apache,dc=local" --enablemkhomedir --update
Restart ldap client daemon:
systemctl restart nslcd
Check user ldap entry:
getent passwd devops
Install Keycloak
Download and unpack Keycloak 4.8.3
cd /opt
wget https://downloads.jboss.org/keycloak/4.8.3.Final/keycloak-4.8.3.Final.tar.gz
tar xzf keycloak-4.8.3.Final.tar.gz
Add keycloak user and change ownership of files
groupadd -r keycloak
useradd -m -d /var/lib/keycloak -s /sbin/nologin -r -g keycloak keycloak
chown keycloak: -R keycloak-4.8.3.Final
Restrict access to keycloak-4.8.3.Final/standalone, which will contain sensitive data for the Keycloak server
cd keycloak-4.8.3.Final
sudo -u keycloak chmod 700 standalone
Install JDK 1.8.0
yum install java-1.8.0-openjdk-devel
Added ‘admin’ to ‘/opt/keycloak-4.8.3.Final/standalone/configuration/keycloak-add-user.json’, Restart server to load user.
sudo -u keycloak ./bin/add-user-keycloak.sh --user admin --password KEYCLOAKPASS --realm master
Modify standalone/configuration/standalone.xml to enable proxying to Keycloak:
sudo -u keycloak ./bin/jboss-cli.sh \
'embed-server,/subsystem=undertow/server\
=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)'
sudo -u keycloak ./bin/jboss-cli.sh \
'embed-server,/socket-binding-group=\
standard-sockets/socket-binding=proxy-https:add(port=8443)'
sudo -u keycloak ./bin/jboss-cli.sh \
'embed-server,/subsystem=undertow/server\
=default-server/http-listener=default:write-attribute(name=redirect-socket,value=proxy-https)'
Start Keycloak Server
Create keycloak.service to start and stop the server:
sudo cat > /etc/systemd/system/keycloak.service <<EOF
[Unit]
Description=KeyCloak Jboss Application Server
After=network.target
[Service]
Type=idle
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak-4.8.3.Final/bin/standalone.sh -b 0.0.0.0
TimeoutStartSec=600
TimeoutStopSec=600
[Install]
WantedBy=multi-user.target
EOF
start keycloak:
systemctl daemon-reload
systemctl start keycloak
Install apache to use Keycloak GUI.
Open Keycloak GUI using external IP:
Integrating openLDAP with Keycloak
Console Display Name: ldap
Import Users: ON
Edit Mode: Writeable
Sync Registration: ON
Vendor: Other
Username LDAP attribute: uid
RDN LDAP attribute: uid
UUID LDAP attribute: uid
User Object Classes: inetOrgPerson, organizationalPerson
Connection URL: ldap://35.197.180.204:389 (openLDAP server IP)
Users DN: ou=users,dc=ldap-apache,dc=local
Authentication Type: Simple
Bind DN: cn=root,dc=ldap-apache,dc=local
Bind Credential: XXXXXXX (OpenLDAP admin user password)
Search Scope: one level
Use Truststore SPI : Only for ldaps
Configure clients
Client ID: apache
Client Protocol: openid-connect
Access Type: confidential
Valid Redirect URIs: https://35.197.180.204/protected/redirect_uri
Configure ssl.conf on Apache server
Listen 443 https
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout 300
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
#LoadModule auth_openidc_module modules/mod_auth_openidc.so
<VirtualHost _default_:443>
DocumentRoot "/var/www/html"
ServerName ldap-apache
ErrorLog /var/log/httpd/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
BrowserMatch "MSIE [2-5]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
#this is required by mod_auth_openidc
OIDCCryptoPassphrase a-random-secret-used-by-apache-oidc-and-balancer
OIDCProviderMetadataURL https://35.197.180.204:8443/auth/realms/master/.well-known/openid-configuration
OIDCClientID apache
OIDCClientSecret 494ae6ea-f7e3-4888-9928-03b0e3bee328
OIDCRedirectURI https://35.197.180.204/protected/redirect_uri
# maps the prefered_username claim to the REMOTE_USER environment variable
OIDCRemoteUserClaim preferred_username
OIDCSSLValidateServer Off
<Location /protected>
AuthType openid-connect
Require valid-user
</Location>
<Directory /var/www/html/protected>
Options +Includes
AddOutputFilter INCLUDES .html
</Directory>
</VirtualHost>
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
SSLCompression off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
LDAPLibraryDebug 7
Verify authentication
curl -k -d 'client_id=apache' \
-d 'username=keyuser1' \
-d 'password=test123' \
-d 'grant_type=password' \
-d 'client_secret=494ae6ea-f7e3-4888-9928-03b0e3bee328'\
'https://35.244.79.144:8443/auth/realms/master/protocol/openid-connect/token' | python -m json.tool
curl -k -u keyuser1 https://35.197.180.204 (prompt you to type the password)