I will be configuring AWX to integrate with the Keycloak Single Sign-On previously installed. Previously, I set up oauth2 integration with Nextcloud, but this time I’m going to set up authentication using SAML. Fortunately, the RHSSO solution uses Keycloak and I found this nifty hands-on guide for configuring Tower with RHSSO.

SAML Certificate

I’ve not previously generated an SSL certificate to be used with SAML.

$ openssl req -new -x509 -days 365 -nodes -out saml.crt -keyout saml.key
Generating a RSA private key
...................+++++
...................................+++++
writing new private key to 'saml.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:State
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Domain.tld
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:sso.domain.tld
Email Address []:sso@domain.tld

Using the realm I created previously, I went to the keys tab and created a new keystore of type RSA.

  • Console display name - domain
  • Priority - 100
  • Enabled - On
  • Active - On
  • Algorithm - RSA
  • Private key - select saml.key created above
  • X509 Certificate - select saml.crt created above

Then Save. I also lowered the priority of the default generated keys so they wouldn’t be used, but I think I could have removed them as well.

Configure AWX

First, a few I need update some settings in the AWX Settings panel. Specifically, I need to define the base URL of the AWX system in the System section of settings. I will update it to https://awx.domain.tld.

Next, go Settings > Authentication > SAML and complete the required fields:

  • EntityID for SAML Service Provider: awx.domain.tld (must match Keyguard client_id name)
  • Pub Cert: copy/paste saml.crt
  • Private Key: copy/paste saml.key

For the SAML Service Provider Organization Info:

{
  "en-US": {
    "url": "https://sso.domain.tld",
    "displayname": "Domain",
    "name": "Domain"
  }
}

For the SAML Service Provider Technical and Support Contact fields:

{
  "givenName": "Your Name",
  "emailAddress": "you@domain.tld"
}

For the SAML Enabled Identity Providers:

{
   "realm": {
      "attr_last_name": "last_name",
      "attr_username": "username",
      "entity_id": "https://sso.domain.tld/auth/realms/domain",
      "attr_user_permanent_id": "name_id",
      "url": "https://sso.domain.tld/auth/realms/domain/protocol/saml",
      "attr_email": "email",
      "x509cert": "",
      "attr_first_name": "first_name",
      "attr_groups": "groups"
   }
}

To get the value for x509cert, execute this command to format the SAML certficate from above and copy/paste in.

sed ':a;N;$!ba;s/\n//g' saml.crt

For the SAML Organization Map:

{
   "Default": {
      "users": true
   },
   "Systems Engineering": {
      "admins": [
         "you@domain.tld"
      ],
      "remove_admins": false,
      "remove_users": false,
      "users": true
   }
}

### Configure Keyguard Client

I will grab the configuration from AWX and use it to import it into the Keyguard client configuration:

curl -L -k https://awx.domain.tld/sso/metadata/saml/ > client-info.xml


Next, I will create a new client in the Keyguard administration panel and import client-info.xml with a few modifications:

* Client ID - awx.domain.tld
* Client Protocol - saml

Then complete the additional configuration details for the new client from defaults:

* Client ID - awx.domain.tld
* Name - AWX
* Description - AWX automation and management platform
* Enabled - On
* Consent Required - Off
* Client Protocol - saml
* Include AuthnStatement - On
* Include OneTimeUse Condition - Off
* Sign Documents - On
* Optimize REDIRECT signing key lookup - Off
* Sign Assertions - On
* Signature Algorithm - RSA_SHA256
* SAMLSignature key name - KEY_ID
* Canonicalization Method - EXCLUSIVE
* Encrypt Assertions - Off
* Client Signature Required - Off
* Force POST Binding - On
* Name ID Format - username
* Root URL - https://awx.domain.tld
* Valid Redirect URIs - https://awx.domain.tld/sso/complete/saml/
* IDP Initiated  SSO URL Name - awx.domain.tld (matches client_id)
* Fine Grain SAML Endpoint Configuration > Assertion Consumer Service POST Binding URL - https://awx.domain.tld/sso/complete/saml/

### Configure Mappers

The purpose of mappers are to  define the information that comes from Keycloak, which will be mapped against Ansible Tower users. In the client Mappers tab, create new mappers for user_name, last_name, email, user_permanent_id, first_name.

### User Name

* Name - user_name
* Type - user_property
* Property - username
* Friendly Name - User Name
* SAML Attribute name - username
* SAMLAttribute name format - basic

### First Name

* Name - first_name
* Type - user_property
* Property - firstName (case-sensitive)
* Friendly Name - First Name
* SAML Attribute name - first_name
* SAMLAttribute name format - basic

### Last Name

* Name - last_name
* Type - user_property
* Property - lastName (case-sensitive)
* Friendly Name - Last Name
* SAML Attribute name - last_name
* SAMLAttribute name format - basic

### Email

* Name - email
* Type - user_property
* Property - email
* Friendly Name - Email
* SAML Attribute name - email
* SAMLAttribute name format - basic

### Permanent ID

* Name - user_permanent_id
* Type - user_attribute
* User Attribute - uid
* Friendly Name - name_id
* SAML Attribute name - name_id
* SAMLAttribute name format - basic

After attempting to login, I was getting an error stating there was a duplicated name attribute. After a bit of searching, the solution is hiden in the settings:

Client Scopes -> role_list -> Mappers -> role list -> Single Role Attribute to On

In the next post, I will create an organization and start importing my inventory, roles, and playbooks to create jobs.