pátek 2. října 2015

ovirt-engine-extension-aaa-jdbc introduction & settings customization

oVirt 3.6 introduced new extension called  ovirt-engine-extension-aaa-jdbc. If you upgrade from older version or if you install fresh new 3.6 you will have this extension installed and configured. With this extension you can store you users/group in database. Very good for people who don't need much users and don't want to deploy LDAP. Note that your admin@internal will now be part of this extension, this migration is done transparently by engine-setup.

Auth[zn] files for internal extension can be found in etc/ovirt-engine/extensions.d/internal-authz.properties and etc/ovirt-engine/extensions.d/internal-authn.properties. Nothing interesting can be found those two files. In common configuration of auth[zn] you can then find database connection settings, which you will find in etc/ovirt-engine/aaa/internal.properties. Content of the file looks like:
config.datasource.jdbcurl=jdbc:postgresql://localhost:5432/engine?sslfactory=org.postgresql.ssl.NonValidatingFactory
config.datasource.dbuser=engine
config.datasource.dbpassword=*****
config.datasource.jdbcdriver=org.postgresql.Driver
config.datasource.schemaname=aaa_jdbc
As you can see only there are db connection details specified, so very easy configuration. Please note there is specified name of postgresql schema, which is in this case aaa_jdbc.

Exploring tables

Wanna check the data aaa-jdbc extension store? You can do as follows:
$ su postgres
bash-4.3$ psql -d engine
engine=# \dt aaa_jdbc.*;
List of relations
Schema | Name | Type | Owner
----------+-----------------------+-------+--------
aaa_jdbc | failed_logins | table | engine
aaa_jdbc | group_attributes | table | engine
aaa_jdbc | group_groups | table | engine
aaa_jdbc | groups | table | engine
aaa_jdbc | schema_version | table | engine
aaa_jdbc | settings | table | engine
aaa_jdbc | user_attributes | table | engine
aaa_jdbc | user_groups | table | engine
aaa_jdbc | user_password_history | table | engine
aaa_jdbc | users | table | engine
(10 rows)
engine=# select name, valid_from, valid_to from aaa_jdbc.users;
name | valid_from | valid_to
-------+----------------------------+----------------------------
admin | 2015-10-01 10:38:32.361+02 | 2215-10-01 10:38:32.361+02
(1 row)
As you can see your admin account is now part of this extension as said above.
Well, this is not too comfortable to work with your users. The extension provide CLI tool to manage the users more comfortable way.

CLI tool 

Cli too name is ovirt-aaa-jdbc-tool. Not much I can say about this tool, since it has good documentation in help.
So whenever you are in doubt what to use just append --help to your args. Please note that by default use the command user @internal extension. If you want to use different one just pass --db-config=/path/to/db/settings.properties of your configuration.

Adding user via CLI tool

If you explored help of this tool you can see there is user module, which you can use to manage users. So we will add  some users, which we will use later in this blog post. Please note that by default freshly added users don't have set password, so you need to set it.
$ ovirt-aaa-jdbc-tool user add user1
$ ovirt-aaa-jdbc-tool user password-reset user1 --password=pass:123456 --password-valid-to="2100-01-01 00:00:00Z"
view raw add_user.sh hosted with ❤ by GitHub

Changing settings via CLI tool

As there is user module there is also settings module to change settings of aaa-jdbc extension. To see what you can change simply run 'ovirt-aaa-jdbc-tool settings show'. There are lot of stuff you can change, the most important/interesting I will show you later.

Policies

Password history limit

You can use setting option PASSWORD_HISTORY_LIMIT  to prohibit user to set same password as he used before. Limit can be integer value, by default it's 3. That means user can't change password to last three passwords he used before.

To change it, use command below(set it to 5):
$ ovirt-aaa-jdbc-tool settings set --name PASSWORD_HISTORY_LIMIT --value 5

Password complexity 


Minimal lenght
To set minimal lenght of password you have to change MIN_LENGTH option. By default it's 6.
$ ovirt-aaa-jdbc-tool settings set --name MIN_LENGTH --value 8
Password complexity
To set complexity of password you have to change PASSWORD_COMPLEXITY option. You can create different complexity groups. By default there is no restriction.  So if you want to for example your user force to have at least one upper case letter, lower case letter and number in his password run the command below:
$ ovirt-aaa-jdbc-tool settings set --name PASSWORD_COMPLEXITY --value "UPPERCASE:chars=ABCDEFGHIJKLMNOPQRSTUVWXYZ::min=1::LOWERCASE:chars=abcdefghijklmnopqrstuvwxyz::min=1::NUMBERS:chars=0123456789::min=1::"

Account & login policy

 

Non locking policy after failed login
To prevent brute force attacks to your account and at the same time prevent denial of your account you can set non locking policy when there is too many attempts to guess password to your user account. To set it use MAX_FAILURES_PER_MINUTE option. By default it's set to 6.

Locking of account after failed login
You account can be locked after X failed logins. There are two options to configure that.
First possibility is to set  MAX_FAILURES_SINCE_SUCCESS this option means that user account is locked after X unsuccessfull login attempts to your account after last successfull login.

The second possibility is to set MAX_FAILURES_PER_INTERVAL this options means that your user account will be locked after X unsuccesfull login attempts to your account in X hours. The value of hours can be set  in option INTERVAL_HOURS.

Your accounts are locked to X minutes. The amount of minutes can be changed by value of option LOCK_MINUTES. Or you can unlock your user by running cli command:
$ ovirt-aaa-jdbc-tool user unlock user1

Removing of failed login
Failed login can be automatically removed during house keeping. All failed login which are older then X days specified in option FAILED_LOGINS_OLD_DAYS will be removed.

Other

 

Max login minutes

With MAX_LOGIN_MINUTES option you can set how long your user can be logged in. If time exceeds, he will be automatically logged out.

Many others

There are many other options. You can explore them by yourself, just run:
$ ovirt-aaa-jdbc-tool settings show

úterý 19. května 2015

SAML and oVirt 3.5

Same way as kerberos is supported for oVirt 3.5 there is also support for SAML via apache module.

There are few SAML apache modules, but I chose mod_auth_mellon, as it has very nice documentation.

First of all we need to setup some identity provider. I chose OpenAM. Please follow steps to quick install of OpenAM with embedded OpenDJ ldap.

OK I presume, that you have up and running OpenAM on tomcat with embedded OpenDJ ldap.
Next step is to setup ourt OpenAM as Identity Provider. Go to 'common-tasks' tab and hit the button 'Created Hosted Identity Provider'. Set name  of your metadata(your URL). Signing key, if you want. Then create new CoT and named it as you like, not important for us. Now very important thing. You need to add attribute mapping, so we are able to map the uid of user in ldap to REMOTE_USER env of apache. Please set 'Name in assertion' to 'common-name' and 'Local attribute name' to 'cn'. And we are done.

Apache configuration

Now we need to setup oVirt apache as service provider(I am using RHEL 6.6):
  • Create SP metadata:
    $ /usr/libexec/mod_auth_mellon/mellon_create_metadata.sh WHAT_EVER_SP_ENTITY_NAME_ID ENTITY-ID https://ovirt/mellon
  • Previous step will create for you three files:
             WHAT_EVER_SP_ENTITY_NAME_ID.xml
             WHAT_EVER_SP_ENTITY_NAME_ID.key
             WHAT_EVER_SP_ENTITY_NAME_ID.cert 
  • copy them to the /etc/httpd/mellon  and asure that all files and folder can be read by apache.
  • Create mod_auth_mellon configuration:
    $ cat /etc/httpd/conf.d/auth_mellon.conf
    LoadModule auth_mellon_module modules/mod_auth_mellon.so
    <Location />
    MellonSPCertFile /etc/httpd/mellon/WHAT_EVER_SP_ENTITY_NAME_ID.cert
    MellonSPPrivateKeyFile /etc/httpd/mellon/WHAT_EVER_SP_ENTITY_NAME_ID.key
    MellonSPMetadataFile /etc/httpd/mellon/WHAT_EVER_SP_ENTITY_NAME_ID.xml
    MellonUser "common-name"
    MellonEndpointPath /mellon
    RewriteEngine on
    RewriteCond %{LA-U:REMOTE_USER} ^(.*)$
    RewriteRule ^(.*)$ - [L,P,E=REMOTE_USER:%1]
    RequestHeader set X-Remote-User %{REMOTE_USER}s
    </Location>
    <Location /ovirt-engine/api>
    MellonEnable "auth"
    Require valid-user
    AuthType "Mellon"
    </Location>
  • In OpenAM go to 'common-tasks' , hit 'register remote service provider'. Upload your SP metadata WHAT_EVER_SP_ENTITY_NAME_ID.xml. Choose already cretead CoT. That's all, click 'configure'.

oVirt AAA configuration

We had setup both mod_auth_mellon as SP and OpenAM as IdP. Last thing is to setup oVirt to respect this setup.
  • Install oVirt AAA packages:
    $ yum install -y ovirt-engine-extension-aaa-misc ovirt-engine-extension-aaa-ldap
  • Authn configuration:
    $ cat /etc/ovirt-engine/extensions.d/http-authn.properties
    ovirt.engine.extension.name = http-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 = http
    ovirt.engine.aaa.authn.authz.plugin = saml-authz
    config.artifact.name = HEADER
    config.artifact.arg = X-Remote-User
  • Authz configuration:
    $ cat /etc/ovirt-engine/extensions.d/saml_authz.properties
    ovirt.engine.extension.name = saml-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 = /etc/ovirt-engine/aaa/opendj_saml.properties
  • Connection configuration:
    $ cat /etc/ovirt-engine/aaa/opendj_saml.properties
    include = <opendj.properties>
    pool.default.serverset.type = single
    pool.default.serverset.single.server = YOUR_OPEN_AM_URL
    pool.default.serverset.single.port = YOUR_EMBEEDED_OPENDJ_PORT # default 50389
    pool.default.auth.type = simple
    pool.default.auth.simple.bindDN = cn=Directory Manager # use user with some only read permissions
    pool.default.auth.simple.password = XXXXXXX
  • This is custom properties file of opendj, I've created it for this example saml configuration. It's not supported by oVirt:
    $ cat /usr/share/ovirt-engine-extension-aaa-ldap/profiles/opendj.properties
    include = <simple.properties>
    attrmap.map-principal-record.attr.PrincipalRecord_DN.map = _dn
    attrmap.map-principal-record.attr.PrincipalRecord_ID.map = entryUUID
    attrmap.map-principal-record.attr.PrincipalRecord_NAME.map = uid
    attrmap.map-principal-record.attr.PrincipalRecord_PRINCIPAL.map = uid
    attrmap.map-principal-record.attr.PrincipalRecord_DISPLAY_NAME.map = displayName
    attrmap.map-principal-record.attr.PrincipalRecord_DEPARTMENT.map = department
    attrmap.map-principal-record.attr.PrincipalRecord_FIRST_NAME.map = givenName
    attrmap.map-principal-record.attr.PrincipalRecord_LAST_NAME.map = sn
    attrmap.map-principal-record.attr.PrincipalRecord_TITLE.map = title
    attrmap.map-principal-record.attr.PrincipalRecord_EMAIL.map = mail
    attrmap.map-group-record.attr.GroupRecord_DN.map = _dn
    attrmap.map-group-record.attr.GroupRecord_ID.map = entryUUID
    attrmap.map-group-record.attr.GroupRecord_NAME.map = cn
    attrmap.map-group-record.attr.GroupRecord_DISPLAY_NAME.map = description
    sequence-init.init.600-opendj-init-vars = opendj-init-vars
    sequence.opendj-init-vars.010.description = set base dn
    sequence.opendj-init-vars.010.type = var-set
    sequence.opendj-init-vars.010.var-set.variable = simple_attrsBaseDN
    sequence.opendj-init-vars.010.var-set.value = namingContexts
    sequence.opendj-init-vars.020.description = set user attribute
    sequence.opendj-init-vars.020.type = var-set
    sequence.opendj-init-vars.020.var-set.variable = simple_attrsUserName
    sequence.opendj-init-vars.020.var-set.value = uid
    sequence.opendj-init-vars.030.description = set principal record attributes
    sequence.opendj-init-vars.030.type = var-set
    sequence.opendj-init-vars.030.var-set.variable = simple_attrsPrincipalRecord
    sequence.opendj-init-vars.030.var-set.value = entryUUID, uid, displayName, department, givenName, sn, title, mail
    sequence.opendj-init-vars.040.type = var-set
    sequence.opendj-init-vars.040.var-set.variable = simple_filterUserObject
    sequence.opendj-init-vars.040.var-set.value = (objectClass=person)(uid=*)
    sequence.opendj-init-vars.050.description = set group record attributes
    sequence.opendj-init-vars.050.type = var-set
    sequence.opendj-init-vars.050.var-set.variable = simple_attrsGroupRecord
    sequence.opendj-init-vars.050.var-set.value = entryUUID, cn, description
    sequence.opendj-init-vars.060.description = set group object filter
    sequence.opendj-init-vars.060.type = var-set
    sequence.opendj-init-vars.060.var-set.variable = simple_filterGroupObject
    sequence.opendj-init-vars.060.var-set.value = (objectClass=groupOfUniqueNames)
    sequence.opendj-init-vars.070.description = set group member filter
    sequence.opendj-init-vars.070.type = var-set
    sequence.opendj-init-vars.070.var-set.variable = simple_attrGroupMemberDN
    sequence.opendj-init-vars.070.var-set.value = uniqueMember
  • Check correct persmissions of all properties file, it have to be readeble by oVirt.

No we will create test user in OpenDJ. Go to OpenAM -> 'Access Control' tab -> select your realm (default /). Click 'Subjects' tab -> Add new user -> Fill appropriate values. (ie user1.)

Now go to oVirt webadmin and search within 'http' profile for user1 and assign him permissions. Now go to ovirt-engine/api URL and you will be forwarded to OpenAM login screen, fill your credentials and you are now able to access rest-api.