[ovirt-users] advanced users authentication, using kerberos, CAS SSO and Active Directory
Fabrice Bacchella
fabrice.bacchella at orange.fr
Mon Apr 25 10:58:14 UTC 2016
I have a production were hard coded password are avoided. We prefer to use kerberos. We also provided a SSO for Web UI using CAS <http://jasig.github.io/cas/4.2.x/index.html>. We use ActiveDirectory for user backend.
So I wanted a oVirt installation that will use kerberos for API authentication. For the web ui, kerberos is not always the best solution, so I wanted to integrated it in our CAS.
The Apache part was easy to setup.
I will show only subpart of the whole Apache setup and only authentication related part
# The CAS modules
LoadModule authz_user_module /usr/lib64/httpd/modules/mod_authz_user.so
# Needed because auth_cas_module forget to link openssl
LoadModule ssl_module /usr/lib64/httpd/modules/mod_ssl.so
LoadModule auth_cas_module /usr/lib64/httpd/modules/mod_auth_cas.so
# For the kerberos authentication on the API
LoadModule auth_gssapi_module /usr/lib64/httpd/modules/mod_auth_gssapi.so
LoadModule session_module /usr/lib64/httpd/modules/mod_session.so
LoadModule session_cookie_module /usr/lib64/httpd/modules/mod_session_cookie.so
CASLoginURL https://sso/cas/login
CASValidateSAML On
CASValidateURL https://sso/cas/samlValidate
<VirtualHost *:443>
RequestHeader unset X-Remote-User early
<LocationMatch ^/api($|/)>
RewriteEngine on
RewriteCond %{LA-U:REMOTE_USER} ^(.*@DOMAIN)$
RewriteRule ^(.*)$ - [L,P,E=REMOTE_USER:%1]
RequestHeader set X-Remote-User %{REMOTE_USER}s
AuthType GSSAPI
AuthName "GSSAPI Single Sign On Login"
GssapiCredStore keytab:.../httpd.keytab
Require valid-user
GssapiUseSessions On
Session On
SessionCookieName ovirt_gssapi_session path=/private;httponly;secure;
</LocationMatch>
<LocationMatch ^/(ovirt-engine($|/)|RHEVManagerWeb/|OvirtEngineWeb/|ca.crt$|engine.ssh.key.txt$|rhevm.ssh.key.txt$)>
AuthType CAS
Require valid-user
CASAuthNHeader X-Remote-User
</LocationMatch>
</VirtualHost>
The authn file /etc/ovirt-engine/extensions.d/apachesso-authn.properties is :
ovirt.engine.extension.name = apachesso-authn
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine-extensions.aaa.misc
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engineextensions.aaa.misc.http.AuthnExtension
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authn
ovirt.engine.aaa.authn.profile.name = apachesso
ovirt.engine.aaa.authn.authz.plugin = DOMAIN-authz
config.artifact.name = HEADER
config.artifact.arg = X-Remote-User
And the authz file /etc/ovirt-engine/extensions.d/DOMAIN-authz.properties is:
ovirt.engine.extension.name = DOMAIN-authz
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine-extensions.aaa.ldap
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engineextensions.aaa.ldap.AuthzExtension
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authz
config.profile.file.1 = ../aaa/DOMAIN.properties
I had some difficulties with AD backend. A straightforward solution would have been :
include = <ad.properties>
vars.domain = DOMAIN
vars.user = BINDDN
vars.password = BINDPWD
vars.forest = domain.com
pool.default.auth.simple.bindDN = ${global:vars.user}
pool.default.auth.simple.password = ${global:vars.password}
pool.default.serverset.type = srvrecord
pool.default.serverset.srvrecord.domain = ${global:vars.domain}
pool.default.ssl.startTLS = true
pool.default.ssl.truststore.file = .../domain.jks
pool.default.ssl.truststore.password =
# Only TLSv1.2 is secure nowadays
pool.default.ssl.startTLSProtocol = TLSv1.2
# long time out should be avoided
pool.default.connection-options.connectTimeoutMillis = 500
But if fails. We have a special setup with about 100 domain controlers and only two of them can be reached from the ovirt engine. So my first try was so defined them directly in the configuration file:
pool.default.serverset.type = failover
pool.default.serverset.failover.1.server = dcX.domain.com
pool.default.serverset.failover.2.server = dcY.domain.com
But that fails. Server-engine was still using a lot of unreachable domain controler. After some digging I found that other part of the ldap extension use a different serverset, I don’t know why it don’t reuse the default pool. It’s called pool.default.dc-resolve (it should be called pool.dc-resolve, as it’s not the default but a custom one), so I added in my configuration:
pool.default.dc-resolve.default.serverset.type = failover
pool.default.dc-resolve.serverset.failover.1.server = dcX.domain.com
pool.default.dc-resolve.serverset.failover.2.server = dcY.domain.com
But there is a better solution. Ondra Machacek point it to me. In Active Directory, there is something called a “site”, with a subset of all the domain controler in it. It can be found under CN=Sites,CN=Configuration,DC=DOMAIN,...
To list them:
ldapsearch -H ldap://somedc -b CN=Sites,CN=Configuration,DC=DOMAIN -s one -o ldif-wrap=no cn
The information to write down is the cn returned
You get a list of all domain, just pick the right one, remove all the serverset configuration and add :
pool.default.serverset.srvrecord.domain-conversion.type = regex
pool.default.serverset.srvrecord.domain-conversion.regex.pattern = ^(?<domain>.*)$
pool.default.serverset.srvrecord.domain-conversion.regex.replacement = GOOD_SITE._sites.${domain}
The entry _sites.${domain} don’t exist in the DNS, so to check that your regex is good, try instead:
dig +short _ldap._tcp.GOOD_SITE._sites.${domain} srv
It should return only reachable domain controlers.
So the final /etc/ovirt-engine/aaa/DOMAIN.properties was :
include = <ad.properties>
vars.domain = DOMAIN
vars.user = BINDDN
vars.password = BINDPWD
vars.forest = domain.com
pool.default.auth.simple.bindDN = ${global:vars.user}
pool.default.auth.simple.password = ${global:vars.password}
pool.default.serverset.type = srvrecord
pool.default.serverset.srvrecord.domain = ${global:vars.domain}
pool.default.ssl.startTLS = true
pool.default.ssl.truststore.file = .../domain.jks
pool.default.ssl.truststore.password =
pool.default.ssl.startTLSProtocol = TLSv1.2
pool.default.connection-options.connectTimeoutMillis = 500
pool.default.serverset.srvrecord.domain-conversion.type = regex
pool.default.serverset.srvrecord.domain-conversion.regex.pattern = ^(?<domain>.*)$
pool.default.serverset.srvrecord.domain-conversion.regex.replacement = GOOD_SITE._sites.${domain}
With this setup, my python client <https://github.com/fbacchella/ovirtcmd> can connect to ovirt-engine using kerberos ticket, web users are authenticated using CAS. And there is no need to duplicate user base.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ovirt.org/pipermail/users/attachments/20160425/4590efa9/attachment-0001.html>
More information about the Users
mailing list