-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathplaybook-keycloak-servers.yaml
More file actions
136 lines (127 loc) · 6.12 KB
/
Copy pathplaybook-keycloak-servers.yaml
File metadata and controls
136 lines (127 loc) · 6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
---
- name: Keycloak Servers
hosts: keycloak_servers
roles:
- galaxyproject.general.services
post_tasks:
- name: Create Keycloak directory
ansible.builtin.file:
path: /srv/keycloak/context
state: directory
mode: "0755"
owner: root
group: root
- name: Copy context files
ansible.builtin.template:
src: "templates/keycloak/{{ item.name }}.j2"
dest: /srv/keycloak/context/{{ item.name }}
mode: "{{ item.mode | default('0644') }}"
owner: root
group: root
loop:
- name: Dockerfile
- name: init-galaxy-scope.sh
mode: "0755"
register: __keycloak_context
- name: Create Keycloak Docker image
community.docker.docker_image_build:
name: galaxy-keycloak:latest
path: /srv/keycloak/context
# rebuild=never (the default) skips the build when the tag already
# exists, so Dockerfile/script edits are never picked up; rebuild=always
# makes this an always-changed task. Instead rebuild only when the build
# context actually changed (a keycloak_image_version bump or init-script
# edit flips the template task to changed). If the image is ever deleted
# by hand while the context is unchanged, the build is skipped and the
# Run task fails loudly - re-touch a template or bump the tag to rebuild.
rebuild: "{{ __keycloak_context is changed | ternary('always', 'never') }}"
- name: Run Keycloak
community.docker.docker_container:
name: galaxy-keycloak
image: galaxy-keycloak:latest
command:
- start
- --hostname={{ keycloak_hostname }}
- --http-enabled=true
- --proxy-headers=xforwarded
- --proxy-trusted-addresses={{ lookup('dig', groups.galaxy_main_load_balancers[0]) }}
ports:
- "8180:8180"
restart_policy: unless-stopped
# Container hardening: drop all Linux capabilities (a JVM on :8180 needs
# none) and block privilege escalation; bound memory/CPU/PIDs so a
# runaway can't starve the Galaxy worker sharing this host; and cap the
# otherwise-unbounded json-file logs with rotation. (Image runs non-root.)
cap_drop:
- all
security_opts:
- "no-new-privileges:true"
memory: "{{ keycloak_container_memory }}"
cpus: "{{ keycloak_container_cpus }}"
pids_limit: "{{ keycloak_container_pids_limit }}"
log_driver: json-file
log_options:
max-size: "{{ keycloak_log_max_size }}"
max-file: "{{ keycloak_log_max_file }}"
env:
# KC_BOOTSTRAP_ADMIN_* are intentionally NOT set here: while present,
# Keycloak re-establishes (re-enables) the bootstrap admin on every
# container start, undoing the script's disable. Admin accounts already
# exist in the DB, so no bootstrap is needed. (For a fresh/empty DB,
# temporarily re-add them for the first run only.)
KC_HTTP_PORT: "8180"
KC_DB: postgres
KC_DB_URL: "{{ keycloak_database_url }}"
KC_DB_USERNAME: "{{ keycloak_database_username }}"
KC_DB_PASSWORD: "{{ keycloak_database_password }}"
- name: Configure Galaxy API scopes and user federation
community.docker.docker_container_exec:
container: galaxy-keycloak
command: /opt/keycloak/init-galaxy-scope.sh
env:
KC_ADMIN_USERNAME: "{{ keycloak_admin_username }}"
KC_ADMIN_PASSWORD: "{{ keycloak_admin_password }}"
KC_DISABLE_BOOTSTRAP_ADMIN: "{{ keycloak_disable_bootstrap_admin | default(false) | string | lower }}"
# Username only (no password): lets the disable step identify the
# bootstrap account. It is no longer used to authenticate, and is no
# longer in the container env, so Keycloak won't re-create it.
KC_BOOTSTRAP_ADMIN_USERNAME: "{{ keycloak_bootstrap_admin_username }}"
# Per-realm federation DB credentials and per-(realm,client) confidential
# client secrets, injected here so they are never rendered into the
# baked image. Names match the derivation in init-galaxy-scope.sh.j2:
# KC_FED_{USER,PASS}_<REALM> and KC_SECRET_<REALM>_<CLIENTID>
# (uppercased, hyphens -> underscores).
KC_FED_USER_GALAXY: "{{ keycloak_galaxy_db_username }}"
KC_FED_PASS_GALAXY: "{{ keycloak_galaxy_db_password }}"
KC_FED_USER_GALAXY_TEST: "{{ vault_keycloak_test_database_username }}"
KC_FED_PASS_GALAXY_TEST: "{{ vault_keycloak_test_database_password }}"
KC_SECRET_GALAXY_BRC_ANALYTICS: "{{ vault_keycloak_brc_analytics_client_secret }}"
KC_SECRET_GALAXY_GALAXY_API: "{{ vault_keycloak_galaxy_api_client_secret }}"
KC_SECRET_GALAXY_TEST_DEV_BRC_ANALYTICS: "{{ vault_keycloak_dev_brc_analytics_client_secret }}"
KC_SECRET_GALAXY_TEST_GALAXY_API: "{{ vault_keycloak_galaxy_api_test_client_secret }}"
register: keycloak_init_galaxy_scope
# The script waits internally for Keycloak to accept admin logins.
changed_when: "'Created' in keycloak_init_galaxy_scope.stdout"
# Docker publishes 8180 via NAT, filtered in the DOCKER-USER chain rather
# than INPUT. Restrict it to the load balancer(s) so the plaintext port
# cannot be reached directly, bypassing the nginx allowlist/TLS/admin ACL.
- name: Install Keycloak port-restriction script
ansible.builtin.template:
src: templates/keycloak/keycloak-restrict-port.sh.j2
dest: /usr/local/sbin/keycloak-restrict-port.sh
mode: "0755"
owner: root
group: root
- name: Install Keycloak port-restriction service
ansible.builtin.template:
src: templates/keycloak/keycloak-restrict-port.service.j2
dest: /etc/systemd/system/keycloak-restrict-port.service
mode: "0644"
owner: root
group: root
- name: Enable and apply Keycloak port restriction
ansible.builtin.systemd:
name: keycloak-restrict-port.service
enabled: true
state: restarted
daemon_reload: true