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.


_______________________________________________
Users mailing list
Users@ovirt.org
http://lists.ovirt.org/mailman/listinfo/users

Reply via email to