diff --git a/roles/authentik/defaults/main.yml b/roles/authentik/defaults/main.yml index 460ba2d..9b2ca9a 100644 --- a/roles/authentik/defaults/main.yml +++ b/roles/authentik/defaults/main.yml @@ -13,7 +13,7 @@ authentik_docker_volume_dir: "{{ docker_volume_base_dir }}/{{ authentik_service_ # Authentik service configuration authentik_domain: "authentik.local.test" -authentik_image: "ghcr.io/goauthentik/server:2025.12.0" +authentik_image: "ghcr.io/goauthentik/server:2026.2.2" authentik_port: 9000 authentik_secret_key: "changeme-generate-a-random-string" @@ -57,11 +57,29 @@ authentik_proxy_outposts: [] # authentik_host_browser: "https://authentik.local.test/" # log_level: "info" +authentik_ldap_apps: [] +# - slug: ldap +# name: LDAP +# base_dn: "dc=local,dc=test" +# search_mode: cached # cached | direct +# bind_mode: cached # cached | direct +# search_group: null # optional: group name whose members can search +# certificate: null # optional: certificate name for LDAPS +# uid_start_number: 2000 +# gid_start_number: 4000 + +authentik_ldap_outpost: {} +# name: "ldap-outpost" +# token: "changeme" # known token for outpost authentication +# config: +# authentik_host: "https://authentik.local.test/" +# log_level: "info" + authentik_oidc_apps: [] # - slug: grafana # name: Grafana -# client_id_env: GRAFANA_OIDC_CLIENT_ID -# client_secret_env: GRAFANA_OIDC_CLIENT_SECRET +# client_id: "grafana" +# client_secret: "changeme" # redirect_uris: # - url: "https://grafana.example.com/login/generic_oauth" # matching_mode: strict @@ -71,21 +89,14 @@ authentik_oidc_apps: [] # invalidation_slug: default-provider-invalidation-flow # scopes: [openid, email, profile, offline_access] -authentik_blueprint_env: [] -# GRAFANA_OIDC_CLIENT_ID: "grafana" -# GRAFANA_OIDC_CLIENT_SECRET: "{{ vault_grafana_oidc_secret }}" -# ENTRA_TENANT_ID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -# ENTRA_CLIENT_ID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -# ENTRA_CLIENT_SECRET: "{{ vault_entra_client_secret }}" - # Oauth sources authentik_entra_sources: [] # - slug: entra-id # name: "Login with Entra" # tenant_mode: single # single | common -# tenant_id_env: ENTRA_TENANT_ID -# client_id_env: ENTRA_CLIENT_ID -# client_secret_env: ENTRA_CLIENT_SECRET +# tenant_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +# client_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +# client_secret: "changeme" # scopes: # - openid # - profile @@ -105,12 +116,19 @@ authentik_login_user_fields: - username - email +# Groups to provision +authentik_groups: [] +# - name: admins +# - name: editors +# is_superuser: false +# parent: null + # Local users to provision authentik_local_users: [] # - username: admin # name: "Admin User" # email: "admin@example.com" -# password_env: AUTHENTIK_ADMIN_PASSWORD # reference env var in authentik_blueprint_env +# password: "changeme" # is_active: true # groups: # - authentik Admins diff --git a/roles/authentik/tasks/blueprints.yml b/roles/authentik/tasks/blueprints.yml index e40b774..18ef7f5 100644 --- a/roles/authentik/tasks/blueprints.yml +++ b/roles/authentik/tasks/blueprints.yml @@ -9,17 +9,17 @@ register: existing_blueprints - name: Build list of expected blueprint files + vars: + _oidc: "{{ authentik_oidc_apps | map(attribute='slug') | map('regex_replace', '^', '50-oidc-') | map('regex_replace', '$', '.yaml') | list }}" + _ldap: "{{ authentik_ldap_apps | map(attribute='slug') | map('regex_replace', '^', '55-ldap-') | map('regex_replace', '$', '.yaml') | list }}" + _proxy: "{{ authentik_proxy_apps | map(attribute='slug') | map('regex_replace', '^', '60-proxy-') | map('regex_replace', '$', '.yaml') | list }}" + _outpost: "{{ authentik_proxy_outposts | map(attribute='name') | map('regex_replace', '^', '70-outpost-') | map('regex_replace', '$', '.yaml') | list }}" + _entra: "{{ authentik_entra_sources | map(attribute='slug') | map('regex_replace', '^', '40-source-entra-') | map('regex_replace', '$', '.yaml') | list }}" + _ldap_out: "{{ ['75-outpost-ldap.yaml'] if authentik_ldap_outpost.name is defined else [] }}" + _users: "{{ ['10-local-users.yaml'] if (authentik_local_users | length > 0 or authentik_groups | length > 0) else [] }}" + _cleanup: "{{ ['00-cleanup.yaml'] if (authentik_removed_oidc_apps + authentik_removed_proxy_apps + authentik_removed_local_users) | length > 0 else [] }}" set_fact: - expected_blueprints: >- - {{ - (authentik_oidc_apps | map(attribute='slug') | map('regex_replace', '^(.*)$', '50-oidc-\1.yaml') | list) + - (authentik_proxy_apps | map(attribute='slug') | map('regex_replace', '^(.*)$', '60-proxy-\1.yaml') | list) + - (authentik_proxy_outposts | map(attribute='name') | map('regex_replace', '^(.*)$', '70-outpost-\1.yaml') | list) + - (authentik_entra_sources | map(attribute='slug') | map('regex_replace', '^(.*)$', '40-source-entra-\1.yaml') | list) + - ['45-login-sources.yaml'] + - ((authentik_local_users | length > 0) | ternary(['10-local-users.yaml'], [])) + - (((authentik_removed_oidc_apps | length > 0) or (authentik_removed_proxy_apps | length > 0) or (authentik_removed_local_users | length > 0)) | ternary(['00-cleanup.yaml'], [])) - }} + expected_blueprints: "{{ _oidc + _ldap + _proxy + _outpost + _entra + ['45-login-sources.yaml'] + _ldap_out + _users + _cleanup }}" - name: Remove stale blueprint files file: @@ -36,6 +36,14 @@ loop: "{{ authentik_oidc_apps }}" register: oidc_templates +- name: Render LDAP blueprints + ansible.builtin.template: + src: blueprints/blueprint-ldap-app.yaml.j2 + dest: "{{ authentik_docker_volume_dir }}/blueprints/55-ldap-{{ item.slug }}.yaml" + mode: "0644" + loop: "{{ authentik_ldap_apps }}" + register: ldap_templates + - name: Render Proxy blueprints ansible.builtin.template: src: blueprints/blueprint-proxy-app.yaml.j2 @@ -52,6 +60,14 @@ loop: "{{ authentik_proxy_outposts }}" register: outpost_bp +- name: Render LDAP outpost blueprint + ansible.builtin.template: + src: blueprints/outpost-ldap.yaml.j2 + dest: "{{ authentik_docker_volume_dir }}/blueprints/75-outpost-ldap.yaml" + mode: "0644" + when: authentik_ldap_outpost.name is defined + register: ldap_outpost_bp + - name: Render Entra source blueprints ansible.builtin.template: src: blueprints/blueprint-source-entra.yaml.j2 @@ -72,7 +88,7 @@ src: blueprints/blueprint-local-users.yaml.j2 dest: "{{ authentik_docker_volume_dir }}/blueprints/10-local-users.yaml" mode: "0644" - when: authentik_local_users | length > 0 + when: authentik_local_users | length > 0 or authentik_groups | length > 0 register: local_users_bp - name: Render cleanup blueprint @@ -88,8 +104,10 @@ blueprints_changed: >- {{ (oidc_templates is defined and (oidc_templates.results | selectattr('changed') | list | length > 0)) + or (ldap_templates is defined and (ldap_templates.results | selectattr('changed') | list | length > 0)) or (proxy_templates is defined and (proxy_templates.results | selectattr('changed') | list | length > 0)) or (outpost_bp is defined and (outpost_bp.results | selectattr('changed') | list | length > 0)) + or (ldap_outpost_bp.changed | default(false)) or (entra_bp is defined and (entra_bp.results | selectattr('changed') | list | length > 0)) or (login_bp is defined and login_bp.changed) or (local_users_bp.changed | default(false)) diff --git a/roles/authentik/tasks/main.yml b/roles/authentik/tasks/main.yml index aa14bd3..1471836 100644 --- a/roles/authentik/tasks/main.yml +++ b/roles/authentik/tasks/main.yml @@ -2,44 +2,18 @@ --- # tasks file for authentik -- name: Create docker compose directory +- name: Create authentik directories file: - path: "{{ authentik_docker_compose_dir }}" + path: "{{ item }}" state: directory mode: '0755' - -- name: Create authentik data directory - file: - path: "{{ authentik_docker_volume_dir }}/data" - state: directory - mode: '0755' - -- name: Create authentik certs directory - file: - path: "{{ authentik_docker_volume_dir }}/certs" - state: directory - mode: '0755' - -- name: Create authentik templates directory - file: - path: "{{ authentik_docker_volume_dir }}/templates" - state: directory - mode: '0755' - -- name: Create postgres data directory - file: - path: "{{ authentik_docker_volume_dir }}/postgresql" - state: directory - mode: '0755' - -- name: Create blueprints directory - file: - path: "{{ authentik_docker_volume_dir }}/blueprints" - state: directory - mode: '0755' - -- name: Render blueprints - import_tasks: blueprints.yml + loop: + - "{{ authentik_docker_compose_dir }}" + - "{{ authentik_docker_volume_dir }}/data" + - "{{ authentik_docker_volume_dir }}/certs" + - "{{ authentik_docker_volume_dir }}/templates" + - "{{ authentik_docker_volume_dir }}/postgresql" + - "{{ authentik_docker_volume_dir }}/blueprints" - name: Create docker-compose file for authentik template: @@ -51,6 +25,46 @@ community.docker.docker_compose_v2: project_src: "{{ authentik_docker_compose_dir }}" state: present - recreate: "{{ blueprints_changed | ternary('always', 'auto') }}" wait: true - wait_timeout: 300 \ No newline at end of file + wait_timeout: 300 + +- name: Render blueprints + import_tasks: blueprints.yml + +- name: Render blueprint wait script + template: + src: wait-for-blueprints.py.j2 + dest: "{{ authentik_docker_volume_dir }}/data/wait-for-blueprints.py" + mode: '0644' + +- name: Wait for custom blueprints to be applied + community.docker.docker_compose_v2_exec: + project_src: "{{ authentik_docker_compose_dir }}" + service: server + command: ak shell -c "exec(open('/data/wait-for-blueprints.py').read())" + register: blueprint_wait_result + changed_when: "'changed' in blueprint_wait_result.stdout" + retries: 30 + delay: 10 + until: blueprint_wait_result.rc == 0 + when: blueprints_changed + +- name: Render LDAP outpost token script + template: + src: set-outpost-token.py.j2 + dest: "{{ authentik_docker_volume_dir }}/data/set-outpost-token.py" + mode: '0644' + when: authentik_ldap_outpost.name is defined + register: ldap_token_script + +- name: Set known token for LDAP outpost + community.docker.docker_compose_v2_exec: + project_src: "{{ authentik_docker_compose_dir }}" + service: server + command: ak shell -c "exec(open('/data/set-outpost-token.py').read())" + register: ldap_token_result + changed_when: "'changed' in ldap_token_result.stdout" + retries: 30 + delay: 10 + until: ldap_token_result.rc == 0 + when: authentik_ldap_outpost.name is defined and (blueprints_changed or ldap_token_script.changed) \ No newline at end of file diff --git a/roles/authentik/templates/blueprints/blueprint-ldap-app.yaml.j2 b/roles/authentik/templates/blueprints/blueprint-ldap-app.yaml.j2 new file mode 100644 index 0000000..6747d95 --- /dev/null +++ b/roles/authentik/templates/blueprints/blueprint-ldap-app.yaml.j2 @@ -0,0 +1,124 @@ +# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json +version: 1 +metadata: + name: "ldap-{{ item.slug }}" + labels: + blueprints.goauthentik.io/instantiate: "true" + blueprints.goauthentik.io/description: "LDAP provider + application for {{ item.slug }}" + +entries: + # Simple password-only flow for LDAP bind (no browser policies) + - model: authentik_stages_password.passwordstage + id: ldap-password-stage + identifiers: + name: ldap-bind-password + attrs: + name: ldap-bind-password + backends: + - authentik.core.auth.InbuiltBackend + - authentik.core.auth.TokenBackend + - authentik.sources.ldap.auth.LDAPBackend + + - model: authentik_stages_identification.identificationstage + id: ldap-identification-stage + identifiers: + name: ldap-bind-identification + attrs: + name: ldap-bind-identification + user_fields: + - username + - email + password_stage: !KeyOf ldap-password-stage + + - model: authentik_stages_user_login.userloginstage + id: ldap-login-stage + identifiers: + name: ldap-bind-login + attrs: + name: ldap-bind-login + + - model: authentik_flows.flow + id: ldap-bind-flow + identifiers: + slug: ldap-bind + attrs: + name: LDAP Bind + slug: ldap-bind + title: LDAP Bind + designation: authentication + authentication: none + + - model: authentik_flows.flowstagebinding + identifiers: + target: !KeyOf ldap-bind-flow + stage: !KeyOf ldap-identification-stage + order: 0 + attrs: + target: !KeyOf ldap-bind-flow + stage: !KeyOf ldap-identification-stage + order: 0 + + - model: authentik_flows.flowstagebinding + identifiers: + target: !KeyOf ldap-bind-flow + stage: !KeyOf ldap-login-stage + order: 10 + attrs: + target: !KeyOf ldap-bind-flow + stage: !KeyOf ldap-login-stage + order: 10 + +{% if item.search_group is defined and item.search_group %} + - model: authentik_rbac.role + id: ldap-search-role-{{ item.slug }} + identifiers: + name: ldap-search-{{ item.slug }} + attrs: + name: ldap-search-{{ item.slug }} +{% endif %} + + - model: authentik_providers_ldap.ldapprovider + id: ldap-provider-{{ item.slug }} + identifiers: + name: {{ item.name }} + attrs: + name: {{ item.name }} + base_dn: "{{ item.base_dn }}" + authorization_flow: !KeyOf ldap-bind-flow + invalidation_flow: !Find [authentik_flows.flow, [slug, {{ item.invalidation_flow_slug | default('default-provider-invalidation-flow') }}]] + authentication_flow: !KeyOf ldap-bind-flow + search_mode: {{ item.search_mode | default('cached') }} + bind_mode: {{ item.bind_mode | default('direct') }} +{% if item.certificate is defined and item.certificate %} + certificate: !Find [authentik_crypto.certificatekeypair, [name, {{ item.certificate }}]] +{% endif %} +{% if item.uid_start_number is defined %} + uid_start_number: {{ item.uid_start_number }} +{% endif %} +{% if item.gid_start_number is defined %} + gid_start_number: {{ item.gid_start_number }} +{% endif %} +{% if item.search_group is defined and item.search_group %} + permissions: + - permission: authentik_providers_ldap.search_full_directory + role: !KeyOf ldap-search-role-{{ item.slug }} +{% endif %} + +{% if item.search_group is defined and item.search_group %} + # Assign the LDAP search role to the search group + - model: authentik_core.group + identifiers: + name: {{ item.search_group }} + attrs: + roles: + - !KeyOf ldap-search-role-{{ item.slug }} +{% endif %} + + - model: authentik_core.application + id: app-{{ item.slug }} + identifiers: + slug: {{ item.slug }} + attrs: + name: "{{ item.name | default(item.slug) }}" + slug: {{ item.slug }} + provider: !KeyOf ldap-provider-{{ item.slug }} diff --git a/roles/authentik/templates/blueprints/blueprint-local-users.yaml.j2 b/roles/authentik/templates/blueprints/blueprint-local-users.yaml.j2 index d40454b..8a158b0 100644 --- a/roles/authentik/templates/blueprints/blueprint-local-users.yaml.j2 +++ b/roles/authentik/templates/blueprints/blueprint-local-users.yaml.j2 @@ -4,9 +4,24 @@ metadata: name: "local-users" labels: blueprints.goauthentik.io/instantiate: "true" - blueprints.goauthentik.io/description: "Local user accounts" + blueprints.goauthentik.io/description: "Local groups and user accounts" entries: +{% for group in authentik_groups %} + - model: authentik_core.group + id: group-{{ group.name | regex_replace('[^a-zA-Z0-9]', '-') }} + identifiers: + name: {{ group.name }} + attrs: + name: {{ group.name }} +{% if group.is_superuser is defined %} + is_superuser: {{ group.is_superuser | lower }} +{% endif %} +{% if group.parent is defined and group.parent %} + parent: !Find [authentik_core.group, [name, {{ group.parent }}]] +{% endif %} + +{% endfor %} {% for user in authentik_local_users %} - model: authentik_core.user id: user-{{ user.username }} @@ -17,8 +32,8 @@ entries: name: "{{ user.name | default(user.username) }}" email: "{{ user.email | default('') }}" is_active: {{ user.is_active | default(true) | lower }} -{% if user.password_env is defined %} - password: !Env {{ user.password_env }} +{% if user.password is defined %} + password: "{{ user.password }}" {% endif %} {% if user.groups is defined and user.groups | length > 0 %} groups: diff --git a/roles/authentik/templates/blueprints/blueprint-oidc-app.yaml.j2 b/roles/authentik/templates/blueprints/blueprint-oidc-app.yaml.j2 index 7270de8..b5813a8 100644 --- a/roles/authentik/templates/blueprints/blueprint-oidc-app.yaml.j2 +++ b/roles/authentik/templates/blueprints/blueprint-oidc-app.yaml.j2 @@ -13,9 +13,11 @@ entries: name: {{ item.slug }} attrs: name: {{ item.slug }} - client_type: confidential - client_id: !Env {{ item.client_id_env }} - client_secret: !Env {{ item.client_secret_env }} + client_type: {{ item.client_type | default('confidential') }} + client_id: "{{ item.client_id }}" +{% if item.client_type | default('confidential') == 'confidential' %} + client_secret: "{{ item.client_secret }}" +{% endif %} redirect_uris: {% for ru in item.redirect_uris %} diff --git a/roles/authentik/templates/blueprints/blueprint-source-entra.yaml.j2 b/roles/authentik/templates/blueprints/blueprint-source-entra.yaml.j2 index acab07b..00bf902 100644 --- a/roles/authentik/templates/blueprints/blueprint-source-entra.yaml.j2 +++ b/roles/authentik/templates/blueprints/blueprint-source-entra.yaml.j2 @@ -15,12 +15,12 @@ entries: name: "{{ item.name | default('Microsoft Entra ID') }}" slug: {{ item.slug }} - # Authentik’s OAuth sources support vendor-specific types. - # Entra guide calls it “Entra ID OAuth Source”. + # Authentik's OAuth sources support vendor-specific types. + # Entra guide calls it "Entra ID OAuth Source". provider_type: entraid - consumer_key: !Env {{ item.client_id_env }} - consumer_secret: !Env {{ item.client_secret_env }} + consumer_key: "{{ item.client_id }}" + consumer_secret: "{{ item.client_secret }}" scopes: {% for s in (item.scopes | default(['openid','profile','email'])) %} @@ -28,10 +28,10 @@ entries: {% endfor %} {% if (item.tenant_mode | default('single')) == 'single' %} - authorization_url: !Format ["https://login.microsoftonline.com/%s/oauth2/v2.0/authorize", !Env {{ item.tenant_id_env }}] - access_token_url: !Format ["https://login.microsoftonline.com/%s/oauth2/v2.0/token", !Env {{ item.tenant_id_env }}] + authorization_url: "https://login.microsoftonline.com/{{ item.tenant_id }}/oauth2/v2.0/authorize" + access_token_url: "https://login.microsoftonline.com/{{ item.tenant_id }}/oauth2/v2.0/token" profile_url: "https://graph.microsoft.com/v1.0/me" - oidc_jwks_url: !Format ["https://login.microsoftonline.com/%s/discovery/v2.0/keys", !Env {{ item.tenant_id_env }}] + oidc_jwks_url: "https://login.microsoftonline.com/{{ item.tenant_id }}/discovery/v2.0/keys" {% else %} authorization_url: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" access_token_url: "https://login.microsoftonline.com/common/oauth2/v2.0/token" diff --git a/roles/authentik/templates/blueprints/outpost-ldap.yaml.j2 b/roles/authentik/templates/blueprints/outpost-ldap.yaml.j2 new file mode 100644 index 0000000..e1d5fbf --- /dev/null +++ b/roles/authentik/templates/blueprints/outpost-ldap.yaml.j2 @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json +version: 1 +metadata: + name: "outpost-{{ authentik_ldap_outpost.name }}" + labels: + blueprints.goauthentik.io/instantiate: "true" + +entries: + - model: authentik_outposts.outpost + identifiers: + name: "{{ authentik_ldap_outpost.name }}" + attrs: + name: "{{ authentik_ldap_outpost.name }}" + type: ldap + service_connection: null + + providers: +{% for app in authentik_ldap_apps %} + - !Find [authentik_providers_ldap.ldapprovider, [name, {{ app.name }}]] +{% endfor %} + +{% if authentik_ldap_outpost.config is defined %} + config: +{% for k, v in authentik_ldap_outpost.config.items() %} + {{ k }}: {{ v | tojson }} +{% endfor %} +{% endif %} diff --git a/roles/authentik/templates/docker-compose.yml.j2 b/roles/authentik/templates/docker-compose.yml.j2 index 6daa2a1..c9796a2 100644 --- a/roles/authentik/templates/docker-compose.yml.j2 +++ b/roles/authentik/templates/docker-compose.yml.j2 @@ -35,11 +35,6 @@ services: AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_postgres_password }} AUTHENTIK_LOG_LEVEL: {{ authentik_log_level }} AUTHENTIK_ERROR_REPORTING__ENABLED: "{{ authentik_error_reporting_enabled | lower }}" -{% if authentik_blueprint_env|length > 0 %} -{% for k, v in authentik_blueprint_env.items() %} - {{ k }}: "{{ v }}" -{% endfor %} -{% endif %} volumes: - {{ authentik_docker_volume_dir }}/blueprints:/blueprints/custom - {{ authentik_docker_volume_dir }}/data:/data @@ -75,11 +70,6 @@ services: AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_postgres_password }} AUTHENTIK_LOG_LEVEL: {{ authentik_log_level }} AUTHENTIK_ERROR_REPORTING__ENABLED: "{{ authentik_error_reporting_enabled | lower }}" -{% if authentik_blueprint_env|length > 0 %} -{% for k, v in authentik_blueprint_env.items() %} - {{ k }}: "{{ v }}" -{% endfor %} -{% endif %} volumes: - {{ authentik_docker_volume_dir }}/data:/data - {{ authentik_docker_volume_dir }}/certs:/certs diff --git a/roles/authentik/templates/set-outpost-token.py.j2 b/roles/authentik/templates/set-outpost-token.py.j2 new file mode 100644 index 0000000..0b61705 --- /dev/null +++ b/roles/authentik/templates/set-outpost-token.py.j2 @@ -0,0 +1,10 @@ +from authentik.outposts.models import Outpost +from authentik.core.models import Token +o = Outpost.objects.get(name='{{ authentik_ldap_outpost.name }}') +t = Token.objects.get(identifier=o.token_identifier) +if t.key != '{{ authentik_ldap_outpost.token }}': + t.key = '{{ authentik_ldap_outpost.token }}' + t.save(update_fields=['key']) + print('changed') +else: + print('ok') diff --git a/roles/authentik/templates/wait-for-blueprints.py.j2 b/roles/authentik/templates/wait-for-blueprints.py.j2 new file mode 100644 index 0000000..ff78f24 --- /dev/null +++ b/roles/authentik/templates/wait-for-blueprints.py.j2 @@ -0,0 +1,20 @@ +from authentik.blueprints.models import BlueprintInstance +from authentik.blueprints.v1.importer import Importer + +failed = list(BlueprintInstance.objects.filter(enabled=True, path__startswith="custom/").exclude(status="successful").order_by("path")) +if not failed: + print("ok") +else: + for bp in failed: + content = bp.retrieve() + importer = Importer.from_string(content) + valid, _ = importer.validate() + if valid: + importer.apply() + bp.status = "successful" + bp.save() + still_failed = BlueprintInstance.objects.filter(enabled=True, path__startswith="custom/").exclude(status="successful") + if still_failed.exists(): + names = ", ".join(bp.name for bp in still_failed) + raise Exception(f"Blueprints still failing: {names}") + print("changed") diff --git a/roles/authentik_outpost_ldap/tasks/main.yml b/roles/authentik_outpost_ldap/tasks/main.yml index 7d58beb..79a350a 100644 --- a/roles/authentik_outpost_ldap/tasks/main.yml +++ b/roles/authentik_outpost_ldap/tasks/main.yml @@ -23,7 +23,6 @@ community.docker.docker_compose_v2: project_src: "{{ authentik_outpost_ldap_docker_compose_dir }}" state: present - recreate: always wait: true wait_timeout: 120 retries: 3