Client Certificate Authentication with LDAP Authorization for Rundeck

The community version doesn’t provide SingleSignOn, or SSO like enterprise features out-of-the-box. This is usually not an issue. But once I got used to not putting my credentials in the login screen I didn’t want to go back.

I didn’t find a straight forward how-to-guide so I compiled this from multiple sources. Having a certificate authority (CA), server and client certificates are a prerequisit for this set up to work but creating them is out of scope of this article. This is still not complete but it should be a good starting point.

Configure Rundeck

In the Rundeck documentation are several approaches to authentication listed. I chose the approach that I am most familiar. Turning the Rundeck authentication off and run it through Apache HTTP means I have to ensure that no one can access the default port of Rundeck other than HTTP. A simple firewall rule blocking external traffic will suffice.

rundeck-config.properties

grails.serverURL=https://example.com:4443

framework.properties

framework.server.port = 4443
framework.server.url = https://example.com:4443

profile

RDECK_HTTPS_PORT="${RDECK_HTTPS_PORT:-4443}" 

firewall-rules

Providing that external interface is eth0.

iptables -A INPUT -m state --state NEW -p tcp --dport 4443 -i eth0 -j DROP

rundeck-config.properties

rundeck.security.authorization.preauthenticated.enabled=true
rundeck.security.authorization.preauthenticated.attributeName=REMOTE_USER_GROUPS
rundeck.security.authorization.preauthenticated.delimiter=,
rundeck.security.authorization.preauthenticated.userNameHeader=X-Forwarded-Uuid
rundeck.security.authorization.preauthenticated.userRolesHeader=X-Forwarded-Roles

Configure Apache

The following modules mod_ssl, mod_ldap and mod_proxy are used. The Apache Documentation is a good starting point but what goes exactly where is not necessarly straigh forward. I hope this helps.

ssl.conf

Listen 443 https
 
ServerName example.com:443
SSLProtocol -all +TLSv1.2
SSLCipherSuite HIGH:!aNULL:!eNULL:!EDH:!DHE:!ADH:!DH:!MD5:!LOW:!EXP:!DES:!RC4:+HIGH
SSLHonorCipherOrder on
 
SSLCertificateFile /opt/certificates/example.com.pem
SSLCertificateKeyFile /opt/certificates/example.com.pvk
SSLCACertificateFile /opt/certificates/ca.pem

SSLVerifyClient require
SSLVerifyDepth 2
SSLUserName SSL_CLIENT_S_DN_CN
RequestHeader set SSL_CLIENT_S_DN ""
RequestHeader set SSL_CLIENT_I_DN ""
RequestHeader set SSL_SERVER_S_DN_OU ""
RequestHeader set SSL_CLIENT_VERIFY ""
RequestHeader set X-Forwarded-Uuid ""
RequestHeader set X-Forwarded-Groups ""
RequestHeader set X-Forwarded-Roles ""

AuthType basic
AuthName "Client Cert Authentication with LDAP Authorization"
AuthBasicProvider ldap
AuthLDAPURL "ldaps://example-ldap1.com example-ldap2.com/OU=group,DC=example,DC=com?sAMAccountName?sub?"
AuthLDAPBindDN "CN=ldapbinduser,OU=group,DC=example,DC=com"
AuthLDAPBindPassword "secure-password"
AuthLDAPRemoteUserAttribute sAMAccountName
AuthLDAPGroupAttribute member
AuthLDAPGroupAttributeIsDN off
Require valid-user
Require ldap-attribute memberOf="CN=group-name,OU=group,DC=example,DC=com"
RequestHeader set SSL_CLIENT_S_DN "%{SSL_CLIENT_S_DN}s"
RequestHeader set SSL_CLIENT_I_DN "%{SSL_CLIENT_I_DN}s"
RequestHeader set SSL_SERVER_S_DN_OU "%{SSL_SERVER_S_DN_OU}s"
RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
RequestHeader set X-Forwarded-Uuid "%{SSL_CLIENT_S_DN_CN}s"
RequestHeader set X-Forwarded-Groups "group-name"
RequestHeader set X-Forwarded-Roles "admin"
 
CustomLog /var/log/httpd/tls-clientcert-ldap_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b \"%{SSL_CLIENT_S_DN_CN}x\" \"%{REMOTE_USER}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_SERVER_S_DN_OU}x\" \"%{SSL_CLIENT_VERIFY}x\""
SSLProxyEngine On
ProxyPass / https://example.com:4443/
ProxyPassReverse / https://example.com:4443/