Keycloak works, add example yml

This commit is contained in:
Albert Stefanov 2024-02-17 11:00:06 +02:00
parent 2523515243
commit a29efe00e0
15 changed files with 207 additions and 49 deletions

1
ansible/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.secret.yml

View File

@ -0,0 +1,6 @@
global_ssh_keys:
- albert_rsa
- ignisf
- zeridon
- shteryana
- dexxter00

View File

@ -0,0 +1,23 @@
keycloak_config:
hostname: auth.openfest.org
db:
host: host.containers.internal
user: keycloak
database: keycloak
password: slojnaparola
access_host: all
ansible_host: infrahost
podman:
user: auth
home: /home/auth
datadir: /home/auth/keycloak
listen_address: 127.0.0.1:9091
reverse_proxy:
external_url: auth.openfest.org
proxy_url: 127.0.0.1:9091
ansible_host: infrahost
tls:
type: internal
admin:
user: admin
password: slojnaparola

View File

@ -0,0 +1,2 @@
postgresql:
listen_addresses: "*"

View File

@ -3,46 +3,62 @@
- name: Check parameters - name: Check parameters
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- keycloak_podman_user_name is defined - keycloak.podman.user is defined
- keycloak_db_password is defined - keycloak.db.password is defined
- name: Create PostgreSQL database - name: Create PostgreSQL database
include_tasks: create_postgres_db.yml ansible.builtin.include_tasks: create_postgres_db.yml
vars: vars:
postgres_username: keycloak user: "{{ keycloak.db.user }}"
postgres_database: keycloak database: "{{ keycloak.db.database }}"
postgres_password: "{{ keycloak_db_password }}" #TODO: change for a password manager password: "{{ keycloak.db.password }}"
access_host: "{{ keycloak.db.access_host | default(omit) }}"
args: args:
apply: apply:
delegate_to: "{{ keycloak_db_ansible_host | default(omit) }}" delegate_to: "{{ keycloak.db.ansible_host | default(omit) }}"
- name: Set up container user - name: Set up container user
include_role: ansible.builtin.include_role:
name: container-user name: container-user
vars: vars:
podman_user: "{{ keycloak_podman_user_name }}" user: "{{ keycloak.podman.user }}"
podman_home: "{{ keycloak_podman_user_home | default(omit) }}" home: "{{ keycloak.podman.home | default(omit) }}"
podman_uid: "{{ keycloak_podman_user_uid | default(omit) }}" uid: "{{ keycloak.podman.uid | default(omit) }}"
#- name: Create secrets
# containers.podman.podman_secret:
# become: true
# become_user: "{{ keycloak_podman_user_name }}"
- name: Create data directories - name: Create data directories
ansible.builtin.file: ansible.builtin.file:
state: directory state: directory
path: "{{ item }}" path: "{{ item }}"
with_items: with_items:
- "{{ keycloak_data_dir }}/keystore/" - "{{ keycloak.datadir }}/keystore/"
- name: Upload unit files - name: Upload unit files
ansible.builtin.template: ansible.builtin.template:
src: units/sso-keycloak.container.j2 src: units/sso-keycloak.container.j2
dest: ~/.config/containers/systemd/sso-keycloak.container dest: ~/.config/containers/systemd/sso-keycloak.container
become: true become: true
become_user: "{{ keycloak_podman_user_name }}" become_user: "{{ keycloak.podman.user }}"
- name: Set up podman secrets
containers.podman.podman_secret:
name: "{{ item.key }}"
data: "{{ item.value }}"
state: present
skip_existing: false
force: true
vars:
secrets:
keycloak-admin-user: "{{ keycloak.admin.user }}"
keycloak-admin-password: "{{ keycloak.admin.password }}"
keycloak-db-host: "{{ keycloak.db.host }}"
keycloak-db-name: "{{ keycloak.db.database }}"
keycloak-db-user: "{{ keycloak.db.user }}"
keycloak-db-password: "{{ keycloak.db.password }}"
with_dict: "{{ secrets }}"
no_log: true # Secret values
become: true
become_user: "{{ keycloak.podman.user }}"
# Note: enabled in the unit file # Note: enabled in the unit file
- name: Start Keycloak - name: Start Keycloak
@ -52,4 +68,15 @@
daemon_reload: true daemon_reload: true
state: started state: started
become: true become: true
become_user: "{{ keycloak_podman_user_name }}" become_user: "{{ keycloak.podman.user }}"
- name: Set up reverse proxy
ansible.builtin.include_tasks: create_vhost.yml
vars:
external_url: "{{ keycloak.reverse_proxy.external_url }}"
proxy_url: "{{ keycloak.reverse_proxy.proxy_url }}"
app_name: "{{ keycloak.reverse_proxy.app_name | default('keycloak') }}"
tls: "{{ keycloak.reverse_proxy.tls | default(omit) }}"
args:
apply:
delegate_to: "{{ keycloak.reverse_proxy.ansible_host | default(omit) }}"

View File

@ -6,6 +6,4 @@
- name: Set up Keycloak - name: Set up Keycloak
include_tasks: keycloak.yml include_tasks: keycloak.yml
vars: vars:
podman_user_name: "{{ keycloak_podman_user_name }}" keycloak: "{{ keycloak_config }}"
podman_user_home: "{{ keycloak_podman_user_home | default(omit) }}"
podman_user_uid: "{{ keycloak_podman_user_uid | default(omit) }}"

View File

@ -6,7 +6,7 @@ ContainerName=sso-keycloak
Image=quay.io/keycloak/keycloak:latest Image=quay.io/keycloak/keycloak:latest
Environment=JAVA_OPTS="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseG1GC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=80 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512" Environment=JAVA_OPTS="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseG1GC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=80 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512"
Volume={{ keycloak_data_dir }}/keystore/:/keystore/ Volume={{ keycloak.datadir }}/keystore/:/keystore/
Secret=keycloak-admin-user,type=env,target=KEYCLOAK_ADMIN Secret=keycloak-admin-user,type=env,target=KEYCLOAK_ADMIN
Secret=keycloak-admin-password,type=env,target=KEYCLOAK_ADMIN_PASSWORD Secret=keycloak-admin-password,type=env,target=KEYCLOAK_ADMIN_PASSWORD
@ -18,9 +18,9 @@ Secret=keycloak-db-password,type=env,target=KC_DB_PASSWORD
Environment=KC_DB=postgres Environment=KC_DB=postgres
Environment=KC_HEALTH_ENABLED=true Environment=KC_HEALTH_ENABLED=true
Exec=start --features=preview --hostname {{ keycloak_hostname }} --proxy edge Exec=start --features=preview --hostname {{ keycloak.hostname }} --proxy edge
PublishPort={{ keycloak_listen_address }}:8080 PublishPort={{ keycloak.listen_address }}:8080
AutoUpdate=registry AutoUpdate=registry
[Install] [Install]
WantedBy=default.target WantedBy=default.target

View File

@ -3,7 +3,7 @@
- name: Check if required parameters are set - name: Check if required parameters are set
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- podman_user_name is defined - user is defined
- name: Set up as container host - name: Set up as container host
ansible.builtin.include_role: ansible.builtin.include_role:
@ -11,17 +11,17 @@
- name: Create user - name: Create user
ansible.builtin.user: ansible.builtin.user:
name: "{{ podman_user_name }}" name: "{{ user }}"
home: "{{ podman_user_home | default(omit) }}" home: "{{ home | default(omit) }}"
uid: "{{ podman_user_uid | default(omit) }}" uid: "{{ uid | default(omit) }}"
state: present state: present
- name: Add public keys for user '{{ podman_user_name }}' - name: Add public keys for user '{{ podman_user_name }}'
ansible.posix.authorized_key: ansible.posix.authorized_key:
user: "{{ podman_user_name }}" user: "{{ user }}"
key: "{{ lookup('file', '../../access/keys/' + item + '.pub') }}" key: "{{ lookup('file', '../../access/keys/' + item + '.pub') }}"
state: present # Note: we don't remove other/existing keys state: present # Note: we don't remove other/existing keys
with_items: "{{ global_ssh_keys + (ssh_keys[podman_user_name] | default([])) + (ssh_keys['*'] | default([])) }}" with_items: "{{ global_ssh_keys + (ssh_keys[user] | default([])) + (ssh_keys['*'] | default([])) }}"
- name: Create unit files dir - name: Create unit files dir
@ -29,15 +29,15 @@
path: ~/.config/containers/systemd path: ~/.config/containers/systemd
state: directory state: directory
become: true become: true
become_user: "{{ podman_user_name }}" become_user: "{{ user }}"
# Note: We check whether lingering is already enabled so we show as OK/skipped instead of changed # Note: We check whether lingering is already enabled so we show as OK/skipped instead of changed
- name: Check if user is lingering - name: Check if user is lingering
ansible.builtin.stat: ansible.builtin.stat:
path: "/var/lib/systemd/linger/{{ podman_user_name }}" path: "/var/lib/systemd/linger/{{ user }}"
register: user_lingering register: user_lingering
- name: Enable session lingering - name: Enable session lingering
ansible.builtin.command: "loginctl enable-linger {{ podman_user_name }}" ansible.builtin.command: "loginctl enable-linger {{ user }}"
when: when:
- not user_lingering.stat.exists - not user_lingering.stat.exists

View File

@ -28,3 +28,12 @@
community.postgresql.postgresql_user: community.postgresql.postgresql_user:
name: root name: root
role_attr_flags: SUPERUSER role_attr_flags: SUPERUSER
- name: Change listen addresses
community.postgresql.postgresql_set:
name: listen_addresses
value: "{{ postgresql.listen_addresses }}"
become: true
become_user: postgres
when: postgresql.listen_addresses is defined
notify: Restart PostgreSQL

View File

@ -0,0 +1,12 @@
(vhost-access-log) {
log {
output file /var/log/caddy/{args[0]}-access.log
}
}
# Note: Requires a new caddy version
#{
# persist_config off
#}
import /etc/caddy/sites-enabled/*.caddy

View File

@ -0,0 +1,4 @@
- name: Reload Caddy
ansible.builtin.service:
name: caddy
state: reloaded

View File

@ -0,0 +1,25 @@
---
- name: Install Caddy
ansible.builtin.package:
name: caddy
state: present
- name: Update Caddyfile
ansible.builtin.copy:
src: Caddyfile
dest: /etc/caddy/Caddyfile
- name: Create site config directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
with_items:
- /etc/caddy/sites-available
- /etc/caddy/sites-enabled
- name: Enable and start the Caddy server
ansible.builtin.service:
name: caddy.service
enabled: true
state: started

View File

@ -3,9 +3,9 @@
- name: Check params - name: Check params
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- postgres_username is defined - user is defined
- postgres_database is defined - database is defined
- not(postgres_access_host is defined and postgres_password is defined) - not(access_host is defined and password is not defined)
- name: Set up PostgreSQL - name: Set up PostgreSQL
ansible.builtin.include_role: ansible.builtin.include_role:
@ -13,25 +13,32 @@
- name: Create user - name: Create user
community.postgresql.postgresql_user: community.postgresql.postgresql_user:
name: "{{ postgres_username }}" name: "{{ user }}"
password: "{{ postgres_password | default(omit) }}" password: "{{ password | default(omit) }}"
become: true become: true
become_user: postgres become_user: postgres
- name: Create postgres_database - name: Create database
community.postgresql.postgresql_db: community.postgresql.postgresql_db:
name: "{{ postgres_database }}" name: "{{ database }}"
owner: "{{ postgres_username }}" owner: "{{ user }}"
become: true become: true
become_user: postgres become_user: postgres
- name: Get pg_hba.conf location
community.postgresql.postgresql_query:
query: SHOW hba_file
become: true
become_user: postgres
register: postgres_hba_file_query
- name: Update pg_hba scram - name: Update pg_hba scram authentication
community.postgresql.postgresql_pg_hba: community.postgresql.postgresql_pg_hba:
contype: host contype: host
users: "{{ postgres_username }}" users: "{{ user }}"
source: "{{ postgres_access_host }}" source: "{{ access_host }}"
databases: "{{ postgres_database }}" databases: "{{ database }}"
method: "scram-sha-256" method: "scram-sha-256"
when: postgres_access_host is defined dest: "{{ postgres_hba_file_query.query_result[0].hba_file }}"
when: access_host is defined
notify: Restart PostgreSQL notify: Restart PostgreSQL

View File

@ -0,0 +1,27 @@
---
- name: Check params
ansible.builtin.assert:
that:
- app_name is defined
- external_url is defined
- proxy_url is defined
- not(tls.type == "cloudflare" and tls.cloudflare_token is undefined)
- not(tls.type == "file" and (tls.cert is undefined or tls.key is undefined))
- tls.type is not defined or (tls.type in ['auto', 'internal', 'cloudflare', 'file'] )
- name: Set up Caddy
ansible.builtin.include_role:
name: reverse-proxy
- name: Template vhost file
ansible.builtin.template:
src: vhost.caddy.j2
dest: "/etc/caddy/sites-available/{{ app_name }}.caddy"
- name: Symlink vhost
ansible.builtin.file:
src: "/etc/caddy/sites-available/{{ app_name }}.caddy"
dest: "/etc/caddy/sites-enabled/{{ app_name }}.caddy"
state: link
notify: Reload Caddy

View File

@ -0,0 +1,17 @@
{{ external_url }} {
{% if tls is defined and tls.type != 'auto' %}
{% if tls.type == 'internal' %}
tls internal
{% elif tls.type == 'cloudflare' %}
tls {
dns cloudflare {{ tls.cloudflare_token }}
}
{% elif tls.type == 'file' %}
tls {{ tls.cert }} {{ tls.key }}
{% endif %}
{% endif %}
reverse_proxy {{ proxy_url }}
import vhost-access-log {{ app_name }}
}