Giter VIP home page Giter VIP logo

ansible-keycloak's Introduction

Ansible Keycloak Role

This role is designed to deploy Keycloak on a systemd managed system for testing and development purposes. The role will install Keycloak from an official downloaded Keycloak zip archive on the target system.

The Keycloak server will be configured as a systemd service named keycloak, running as a keycloak system user. The role will handle the creation of the system user and the service.

This role also handles some of the initial Keycloak server configuration. This includes configuring what ports to listen on, creating an initial admin user, and configuring TLS via self-signed or provided certificates. Firewall configuration is also handled.

Usage

Choose a playbook for whichever TLS scenario you are interested in. The following example playbooks are included in this repo:

  • tls-self-signed.yml - TLS via auto-generated self-signed certificate
  • tls-cert-key.yml - TLS via provided cert/key files
  • tls-pkcs12.yml - TLS via provided PKCS12 bundle

All of the example playbooks use ansible-vault for security sensitive variables. The examples use password for all secrets, including the vault password itself. New secrets should be generated and updated in the playbooks to avoid using the hard-coded example. Instructions for doing this are in comments in the example playbooks.

To execute your chosen playbook, be sure to add the --ask-vault-pass option as in this example:

ansible-playbook --ask-vault-pass -i <inventory/host list> <playbook>

If a deployment of the same version of Keycloak exists on the target system, the playbook will fail to prevent losing data within Keycloak's database. A force variable can be set to overwrite the existing deployment. This can be either be set as a variable in the playbook, or added on the command line as an extra-var:

ansible-playbook ... --extra-vars "keycloak_force_install=yes"

Controlling the location of the Keycloak archive

By default the Keycloak archive will be downloaded to the local system where the playbook is being run from. It will reside in the directory specified by the variable keycloak_local_download_dest. When the archive is extracted on the target system the archive will be read on the local system and the files created on the destination target. This behavior has the advantage of downloading the archive only once and not storing the archive on the target but it incurs a network penalty of transferring the archive contents again for every target during the extraction process. If you have a slow upload network link on the host running the playbook the non-local extraction may be untenable.

Alternately you have the option to download the archive directly to the target and extract the archive on the target, this is controlled by the keycloak_archive_on_target variable. This has the advantage of transferring the archive data only once. The archive extraction will be fast because there is no network traffic during the extraction because all data is local to the target. However it will leave the archive on the target after extraction.

To change the location of the archive on the command line add this argument to your playbook command line:

-e "{keycloak_archive_on_target: True}"

Variables

You can choose what version of Keycloak to install by setting the following variable. This will be used to determine the download URL to use from https://www.keycloak.org/downloads.html:

  • keycloak_version (default: 4.8.2.Final)

The following variable always needs to be provided, as the role does not hardcode a default:

  • keycloak_admin_password (use ansible-vault to protect)

You can choose a non-default admin account name by setting the following variable:

  • keycloak_admin_user (default: admin)

To configure the interface and ports that the Keycloak server listens on, the following variables can be set:

  • keycloak_bind_address (default: 0.0.0.0)
  • keycloak_http_port (default: 8080)
  • keycloak_https_port (default: 8443)

For TLS via PKCS12 bundle, the following additional variables must be provided:

  • keycloak_tls_pkcs12 (path to PKCS12 bundle)
  • keycloak_tls_pkcs12_passphrase (use ansible-vault to protect)
  • keycloak_tls_pkcs12_alias (name of key/cert in keycloak_tls_pkcs12)

For TLS via key/cert files, the following additional variables must be provided:

  • keycloak_tls_cert (path to TLS server cert file)
  • keycloak_tls_key (path to TLS server key file)

NOTE: the source TLS files (keycloak_tls_pkcs12, keycloak_tls_cert, keycloak_tls_key) used to create the Keycloak keystore may reside either on the Ansible controller (i.e. local) or on the remote target host. By default the role assumes the source TLS files are local. If however the source TLS files are located on the remote target set the variable keycloak_tls_files_on_target to True.

You can control timeout values with the following variables:

keycloak_startup_timeout: Number of seconds to wait for Keycloak to start.

keycloak_jboss_config_connect_timeout: Number of milliseconds to wait for jboss configuration utilityto connect to wildfly server.

keycloak_jboss_config_command_timeout: Number of seconds to wait for jboss configuration utility to complete each command executed in configuration file

See roles/keycloak/defaults/main.yml for a list of other variable defaults that one may want to override.

Testing

In-tree tests are provided that use molecule to test the role against docker containers. These tests are designed to be used by CI, but they can also be run locally to test it out while developing.

Role name issue

WARNING: For in-tree testing the directory name must match the Ansible Galaxy role name

NOTE: In these examples it is assumed the repo has been cloned into ~/src/

Ansible expects a role to have a prescribed directory structure. For example if the role is named my_role Ansible will expect to find a directory named my_role in the ANSIBLE_ROLES_PATH with sub-directories similar to this:

my_role/
├── defaults
├── files
├── handlers
├── meta
├── tasks
├── templates
├── tests
└── vars

By convention most Galaxy roles are created in a git repo whose top level directory contains the above role sub-directories thus the directory created when cloning the git repo becomes the role name. Using the above example the git repo would be named my_role. However, most git repositories are not named identically as their Galaxy role name. If you try to run molecule test at top level of a git tree cloned with the default repo name you will get a role not found error like this:

ERROR! the role 'nkinder.keycloak' was not found in /home/$USER/src/ansible-keycloak/molecule/default/roles:/tmp/molecule/ansible-keycloak/default/roles:/home/$USER/src:/home/$USER/src/ansible-keycloak/molecule/default

The error appears to have been in '/home/$USER/src/ansible-keycloak/molecule/default/playbook.yml': line 6, column 7, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

  roles:
    - role: nkinder.keycloak
      ^ here

The solution to this is simple, when cloning the git repo provide a directory name that matches the role name in the molecule/default/playbook.yml file.

To determine the role name molecule will use find it's definition in molecule/default/playbook.yml:

  roles:
    - role: nkinder.keycloak

Hence the role name molecule will use is nkinder.keycloak.

Thus to clone this repo do this:

$ cd ~/src
$ git clone [email protected]:nkinder/ansible-keycloak.git nkinder.keycloak

Of course if you're cloning from a github fork you'll need to adjust the repo URL accordingly.

You'll need to cd into the cloned git repo:

$ cd nkinder.keycloak

When you run molecule test from the top level directory of the git repo molecule will get the current working directory path and from that find the parent directory path, it will then set the ANSIBLE_ROLES_PATH to include the parent directory of the role repo. Thus when ansible runs it will find your role via the directory name of your git repo. For example:

ANSIBLE_ROLES_PATH: /tmp/molecule/ansible-keycloak/default/roles:/home/$USER/src

Because ansible is looking for a role named nkinder.keycloak it will search the directories listed in ANSIBLE_ROLES_PATH and utilize the files in finds in /home/$USER/src/nkinder.keycloak.

NOTE: molecule will stage some files in a temporary directory for the duration of a test run, this is the MOLECULE_EPHEMERAL_DIRECTORY and in our examples it is /tmp/molecule/ansible-keycloak/default, hence the first path in the above ANSIBLE_ROLES_PATH.

NOTE: git does not require the directory name of the top level directory in the repo match the name of the git repo. Even though the directory name of the cloned repo will be different than the repo name all git operations will work as expected because the repo URL is specified as a remote in .git/config.

Testing is best done by installing molecule in a virtualenv:

  $ virtualenv .venv
  $ source .venv/bin/activate
  $ pip install molecule docker

NOTE: You must name the virtualenv directory .venv because molecule expects this.

WARNING: If you had already cloned the repo under as the repo name instead of the role name you can rename the repo directory however if you had created .venv before the rename you must remove .venv and recreate it because the virtualenv will have embedded the old pathnames.

By default molecule uses docker to build and run test images. You will need docker installed and have the docker daemon running:

# To install the docker package
$ sudo dnf install docker

#To start the Docker service use:
$ sudo systemctl start docker

# Verify that Docker was correctly installed and is running by running
# the Docker hello-world image.

$ sudo docker run hello-world

# To optionally start the Docker daemon at boot
$ sudo systemctl enable docker

It is required to run the tests as a user who is authorized to run the docker command without using sudo. This is typically accomplished by adding your user to the 'docker' group on your system.

$ sudo groupadd docker
$ sudo gpasswd -a $USER docker
$ sudo systemctl restart docker

# Group membership is evaluated when you create a new login session.
# Unless you log out and back in again you'll need to use `newgrp`
# to add your `docker` group membership in the current login session.
$ newgrp docker

Additionally, there is a challenge around python-libselinux on platforms that use SELinux. If you are using a virtualenv, you need to make sure that the selinux python module is available in the virtualenv. Even if it is installed on your ansible controller host and the target host, some of the tasks that are delegated to the locahost will use the virtualenv. The selinux module can't be installed via pip. A workaround for this is to copy the entire selinux directory from your system site-packages location (/usr/lib64/$PY_VERSION/site-packages/selinux on x86_64) into the virtualenv site-packages directory. You will also need to copy the selinux.so binary from file from site-packages directory (it is not located inside the selinux directory). The name of the selunux.so varies between Python2 and Python3.

In Python2 the basename of the .so is _selinux.so, for Python 2.7 on x86_64 this would be this .so:

/usr/lib64/python2.7/site-packages/_selinux.so

In Python3 the basename of the .so appends cpython, the python version, the arch and the OS, for Python 3.7 on x86_64 it would look like this:

/usr/lib64/python3.7/site-packages/_selinux.cpython-37m-x86_64-linux-gnu.so

Once your virtualenv is properly set up, the tests can be run with these commands:

$ cd nkinder.keycloak # Your repo whose directory matches the Galaxy role name
$ molecule test

HINT: Adding --debug to the molecule command can aid in diagnosing problems as well as capturing the output in a log file, you might want to do this:

$ molecule --debug test 2>&1 | tee molecule.log

By default, the test target will be the latest centos image from Docker Hub. You can test against a different image/tag like so:

$ MOLECULE_DISTRO="fedora:28" molecule test`

TODO

  • Add example playbook that uses ansible-freeipa to create keycloak service and get cert
  • Add example playbook that creates realm/client using keycloak_client module
  • Add ability to configure IdM as an identity backend for keycloak via SSSD provider

ansible-keycloak's People

Contributors

evgeniy-pupkov avatar jhrozek avatar moisesguimaraes avatar nkinder avatar spoore1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ansible-keycloak's Issues

ansible-role-keycloak : create admin user is failing

TASK [ansible-role-keycloak : create admin user] *******************************************************************************************************************
fatal: [keycloak-server]: FAILED! => {"changed": true, "cmd": "/var/lib/keycloak/keycloak-7.0.0/bin/add-user-keycloak.sh -u admin -p admin", "delta": "0:00:00.018981", "end": "2020-09-22 15:23:21.687752", "msg": "non-zero return code", "rc": 127, "start": "2020-09-22 15:23:21.668771", "stderr": "/var/lib/keycloak/keycloak-7.0.0/bin/add-user-keycloak.sh: line 75: java: command not found", "stderr_lines": ["/var/lib/keycloak/keycloak-7.0.0/bin/add-user-keycloak.sh: line 75: java: command not found"], "stdout": "", "stdout_lines": []}

i had to manually install java in the vm

Keycloak not started during force reinstallation

Hello!
When trying to re-install keycloak using keycloak_force_install=true variable, playbook gets stuck on "wait for Keycloak management interface to be available" step. The reason is that restart handlers are not triggered, as systemd keyclaok service file left unchanged.
I've achieved it working by adding

  notify:
      - restart keycloak

into " extract Keycloak archive on target" and " extract Keycloak archive on local" steps.

add-user-keycloak.sh fails with newer version of RH-SSO

Testing with RH-SSO (instead of upstream keycloak), I see the following error:

TASK [keycloak : create Keycloak admin user] **********************************************************
fatal: [keycloak.kite.test]: FAILED! => changed=true
cmd:

  • /opt/rh-sso/rh-sso-7.3/bin/add-user-keycloak.sh
  • -rmaster
  • -uadmin
  • -pSecret123
    delta: '0:00:01.001522'
    end: '2020-01-21 13:55:06.160746'
    msg: non-zero return code
    rc: 1
    start: '2020-01-21 13:55:05.159224'
    stderr: 'Option: -m was not found.'
    stderr_lines:
  • 'Option: -m was not found.'
    stdout: ''
    stdout_lines:

Python 3 bindings missing for yum / controlling ansible_python_interpreter

Hi!

I'm getting errors on CentOS 7 when using Python 3 and yum (dnf is not installed):

PLAY [INSTALL - tasks for keycloak] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [keycloak1]

TASK [nkinder.keycloak : check if all required variables are set] **************
skipping: [keycloak1]

TASK [nkinder.keycloak : Verify Python3 import] ********************************
ok: [keycloak1]

TASK [nkinder.keycloak : Set python interpreter to 3] **************************
ok: [keycloak1]

TASK [nkinder.keycloak : Set python interpreter to 2] **************************
skipping: [keycloak1]

TASK [nkinder.keycloak : create local download location] ***********************
ok: [keycloak1]

TASK [nkinder.keycloak : install dependencies] *********************************
failed: [keycloak1] (item=firewalld) => {"ansible_loop_var": "item", "changed": false, "item": "firewalld", "msg": "The Python 2 bindings for rpm are needed for this module. If you require Python 3 support use the `dnf` Ansible module instead.. The Python 2 yum module is needed for this module. If you require Python 3 support use the `dnf` Ansible module instead."}
failed: [keycloak1] (item=java-1.8.0-openjdk-headless) => {"ansible_loop_var": "item", "changed": false, "item": "java-1.8.0-openjdk-headless", "msg": "The Python 2 bindings for rpm are needed for this module. If you require Python 3 support use the `dnf` Ansible module instead.. The Python 2 yum module is needed for this module. If you require Python 3 support use the `dnf` Ansible module instead."}
failed: [keycloak1] (item=unzip) => {"ansible_loop_var": "item", "changed": false, "item": "unzip", "msg": "The Python 2 bindings for rpm are needed for this module. If you require Python 3 support use the `dnf` Ansible module instead.. The Python 2 yum module is needed for this module. If you require Python 3 support use the `dnf` Ansible module instead."}
failed: [keycloak1] (item=pyOpenSSL) => {"ansible_loop_var": "item", "changed": false, "item": "pyOpenSSL", "msg": "The Python 2 bindings for rpm are needed for this module. If you require Python 3 support use the `dnf` Ansible module instead.. The Python 2 yum module is needed for this module. If you require Python 3 support use the `dnf` Ansible module instead."}

The package module detects that yum is installed and tries to use it, but Python 3 lacks support for it. The common solution for this is to set ansible_python_interpreter as needed, but that's not possible as the variable is managed internally by tasks/python_2_3_test.yml, which will also default to Python 3 when both versions are installed (so having Python 2 becomes irrelevant to solve the problem).

This affects all CentOS with Python 3 and yum. Yum is still the default package manager, and Python 3 is needed in most scenarios now, including those that also have Python 2. This happens frequently with Ansible where there's a need to apply multiple roles, each with multiple, arbitrarily large dependency trees.

Would it be possible to have python_2_3_test.yml to run the autodetection only when ansible_python_interpreter isn't already set? I can test and send a patch for that. Note that it would be compatible with both the current version and the changes in #25 (and any other solution in that line) with a trivial modification. But it would preserve the ability to control this important variable from outside the role when it is needed.

Note: removing Python 3, or installing dnf, or removing the lines in main.yml that call python_2_3_test.yml are solutions that I tested and can confirm they work. But I think they carry a bigger toll on interop/usefulness when compared to the above.

pyOpenSSL fails to install on RHEL8

I see the following error when trying to install on RHEL8:

patch to follow

TASK [keycloak : install dependencies] ****************************************************************
changed: [keycloak.kite.test] => (item=java-1.8.0-openjdk-headless)
changed: [keycloak.kite.test] => (item=unzip)
failed: [keycloak.kite.test] (item=pyOpenSSL) => changed=false
failures:

  • 'pyOpenSSL No match for argument: pyOpenSSL'
    item: pyOpenSSL
    msg: Failed to install some of the specified packages
    rc: 1
    results: []
    to retry, use: --limit @/tmp/tmppeph7sjx.retry

Travis CI failing

Hello!
I can see that Travis CI builds necessary for Ansible Galaxy fails on 'configure firewall for Keycloak ports' task. It seems that this task tries to open ports before firewalld service completes startup. I propose to add a looped check task before it. Something like this should work:

- name: check if firewalld started
  shell:
    cmd: firewall-cmd --state 
  register: firewalld_state
  until: >
    'running' in firewalld_state.stdout
  retries: 60
  delay: 5

I'm going to create a PR, and if it fails on Travis CI, I'll try to fix it

Keycloak role not idempotent

I was trying this role and during the first run it works quite fine. Ansible roles should be idempotent, that means when running the playbook again with the same parameters, nothing should change.

This module fails with the following error:

fatal: [idp.mydomain.com]: FAILED! => {"changed": false, "msg": "Keycloak deployment already exists at /opt/keycloak/keycloak-8.0.1 (force=yes to overwrite)"}

Yes it does not change anything, but it also does not allow me to run the playbook for this host anymore. Instead of failing, it should just skip if everything is at its place and nothing is to do.

Admin user not created during installation

Hello!

Keycloak version: 7.0.0

After deployment using this role, all steps marked as successful. But welcome screen of Keycloak shows that no admin user created and I have to connect from cli to create one. Also, logs contain these lines:

2019-09-19 13:22:54,196 INFO  [org.keycloak.services] (ServerService Thread Pool -- 61) KC-SERVICES0050: Initializing master realm
2019-09-19 13:22:56,403 INFO  [org.keycloak.services] (ServerService Thread Pool -- 61) KC-SERVICES0006: Importing users from '/opt/keycloak/keycloak-7.0.0/standalone/configuration/keycloak-add-user.json'
2019-09-19 13:22:56,603 ERROR [org.keycloak.services] (ServerService Thread Pool -- 61) KC-SERVICES0008: Failed to add user  keyadmin to realm  master: realm not found
2019-09-19 13:22:56,611 ERROR [org.keycloak.services] (ServerService Thread Pool -- 61) KC-SERVICES0011: Failed to add user ' keyadmin' to realm ' master': java.lang.NullPointerException

As you can see, user name and realm name contain spaces.
I've overcome it changing

  - -r master
  - -u {{ keycloak_admin_user }}
  - -p {{ keycloak_admin_password }}

to

- -rmaster
- -u{{ keycloak_admin_user }}
- -p{{ keycloak_admin_password }}

in "create Keycloak admin user" step

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.