diff --git a/roles/authelia/tasks/main.yml b/roles/authelia/tasks/main.yml index 73775e8..9a6747a 100644 --- a/roles/authelia/tasks/main.yml +++ b/roles/authelia/tasks/main.yml @@ -59,6 +59,64 @@ msg: "AUTHELIA_OIDC_PRIVATE_KEY_PEM is required" when: authelia_oidc_private_key_pem | length == 0 +- name: Read Authelia notifier disable startup check + set_fact: + authelia_notifier_disable_startup_check: "{{ (AUTHELIA_NOTIFIER_DISABLE_STARTUP_CHECK | default(lookup('env', 'AUTHELIA_NOTIFIER_DISABLE_STARTUP_CHECK') | default('false', true), true)) | bool }}" + no_log: true + +- name: Read Authelia SMTP address (raw) + set_fact: + authelia_smtp_address_raw: "{{ AUTHELIA_SMTP_ADDRESS | default(lookup('env', 'AUTHELIA_SMTP_ADDRESS') | default('', true), true) }}" + no_log: true + +- name: Read Authelia notifier type + set_fact: + authelia_notifier_type: >- + {{ + (AUTHELIA_NOTIFIER_TYPE | default(lookup('env', 'AUTHELIA_NOTIFIER_TYPE') | default('', true), true)) + | default(('smtp' if (authelia_smtp_address_raw | length > 0) else 'filesystem'), true) + }} + no_log: true + +- name: Fail if Authelia notifier type is invalid + assert: + that: + - authelia_notifier_type in ['smtp', 'filesystem'] + fail_msg: "AUTHELIA_NOTIFIER_TYPE must be 'smtp' or 'filesystem'" + +- name: Configure Authelia SMTP notifier + block: + - name: Read Authelia SMTP settings + set_fact: + authelia_smtp_address: "{{ authelia_smtp_address_raw }}" + authelia_smtp_username: "{{ AUTHELIA_SMTP_USERNAME | default(lookup('env', 'AUTHELIA_SMTP_USERNAME') | default('', true), true) }}" + authelia_smtp_password: "{{ AUTHELIA_SMTP_PASSWORD | default(lookup('env', 'AUTHELIA_SMTP_PASSWORD') | default('', true), true) }}" + authelia_smtp_sender: "{{ AUTHELIA_SMTP_SENDER | default(lookup('env', 'AUTHELIA_SMTP_SENDER') | default('', true), true) }}" + authelia_smtp_identifier: "{{ AUTHELIA_SMTP_IDENTIFIER | default(lookup('env', 'AUTHELIA_SMTP_IDENTIFIER') | default('localhost', true), true) }}" + authelia_smtp_startup_check_address: "{{ AUTHELIA_SMTP_STARTUP_CHECK_ADDRESS | default(lookup('env', 'AUTHELIA_SMTP_STARTUP_CHECK_ADDRESS') | default('', true), true) }}" + no_log: true + + - name: Fail if Authelia SMTP address is missing + fail: + msg: "AUTHELIA_SMTP_ADDRESS is required" + when: authelia_smtp_address | length == 0 + + - name: Fail if Authelia SMTP username/password pairing is invalid + fail: + msg: "AUTHELIA_SMTP_USERNAME and AUTHELIA_SMTP_PASSWORD must both be set, or both be empty" + when: (authelia_smtp_username | length == 0) != (authelia_smtp_password | length == 0) + + - name: Fail if Authelia SMTP sender is missing + fail: + msg: "AUTHELIA_SMTP_SENDER is required" + when: authelia_smtp_sender | length == 0 + + - name: Fail if Authelia SMTP startup check address is missing + fail: + msg: "AUTHELIA_SMTP_STARTUP_CHECK_ADDRESS is required" + when: authelia_smtp_startup_check_address | length == 0 + when: authelia_notifier_type == 'smtp' + - name: Read OIDC client secret for Grafana set_fact: authelia_oidc_grafana_client_secret_plain: "{{ AUTHELIA_OIDC_GRAFANA_CLIENT_SECRET | default(lookup('env', 'AUTHELIA_OIDC_GRAFANA_CLIENT_SECRET')) }}" @@ -104,6 +162,16 @@ path: /opt/authelia state: directory +- name: Ensure proxy network exists + command: docker network inspect proxy + register: authelia_proxy_network + changed_when: false + failed_when: false + +- name: Create proxy network if missing + command: docker network create proxy + when: authelia_proxy_network.rc != 0 + - name: Copy Authelia configuration template: src: configuration.yml.j2 @@ -115,6 +183,6 @@ dest: /opt/authelia/docker-compose.yml - name: Deploy Authelia - command: docker compose up -d --force-recreate + command: docker compose up -d args: chdir: /opt/authelia diff --git a/roles/authelia/templates/configuration.yml.j2 b/roles/authelia/templates/configuration.yml.j2 index 2f2be86..8c367ca 100644 --- a/roles/authelia/templates/configuration.yml.j2 +++ b/roles/authelia/templates/configuration.yml.j2 @@ -1,9 +1,42 @@ server: address: 'tcp://:9091/' + endpoints: + rate_limits: + session_elevation_start: + enable: true + buckets: + - period: '1 minute' + requests: 20 + - period: '10 minutes' + requests: 60 + + session_elevation_finish: + enable: true + buckets: + - period: '1 minute' + requests: 20 + - period: '10 minutes' + requests: 60 + + second_factor_totp: + enable: true + buckets: + - period: '1 minute' + requests: 30 + - period: '10 minutes' + requests: 100 log: level: 'info' +totp: + disable: true + issuer: '{{ auth_hostname }}' + +webauthn: + disable: true + display_name: 'Authelia' + identity_validation: reset_password: jwt_secret: "{{ authelia_reset_password_jwt_secret }}" @@ -20,15 +53,28 @@ storage: path: '/config/db.sqlite3' notifier: + disable_startup_check: {{ authelia_notifier_disable_startup_check | ternary('true', 'false') }} +{% if authelia_notifier_type == 'filesystem' %} filesystem: filename: '/config/notification.txt' +{% else %} + smtp: + address: "{{ authelia_smtp_address }}" + timeout: '5s' + username: "{{ authelia_smtp_username }}" + password: "{{ authelia_smtp_password }}" + sender: "{{ authelia_smtp_sender }}" + identifier: "{{ authelia_smtp_identifier }}" + subject: "[Authelia] {title}" + startup_check_address: "{{ authelia_smtp_startup_check_address }}" +{% endif %} authentication_backend: ldap: implementation: 'lldap' address: 'ldap://lldap:3890' base_dn: '{{ lldap_base_dn }}' - user: 'cn=admin,ou=people,{{ lldap_base_dn }}' + user: 'uid=admin,ou=people,{{ lldap_base_dn }}' password: "{{ lldap_admin_password }}" access_control: @@ -41,9 +87,18 @@ identity_providers: - algorithm: 'RS256' use: 'sig' key: | -{% for line in authelia_oidc_private_key_pem.splitlines() %} - {{ line }} -{% endfor %} +{% set jwks_key_pem = authelia_oidc_private_key_pem | regex_replace('\r\n', '\n') | regex_replace('\\\\n', '\n') | trim %} +{% if '\n' not in jwks_key_pem %} +{% set jwks_key_pem = jwks_key_pem | regex_replace('-----BEGIN ([^-]+)-----\\s*', '-----BEGIN \\1-----\n') | regex_replace('\\s*-----END ([^-]+)-----', '\n-----END \\1-----') %} +{% endif %} +{% set jwks_lines = jwks_key_pem.splitlines() | map('trim') | list %} +{% if jwks_lines | length >= 3 %} +{% set jwks_header = jwks_lines[0] %} +{% set jwks_footer = jwks_lines[-1] %} +{% set jwks_body = (jwks_lines[1:-1] | join('')) | regex_replace('\\s+', '') %} +{% set jwks_key_pem = jwks_header ~ '\n' ~ jwks_body ~ '\n' ~ jwks_footer %} +{% endif %} +{{ jwks_key_pem.splitlines() | map('trim') | join('\n') | indent(10, true) }} clients: - client_id: 'grafana' client_name: 'Grafana' @@ -69,4 +124,4 @@ identity_providers: - 'profile' - 'groups' authorization_policy: 'one_factor' - require_pkce: true + require_pkce: false diff --git a/roles/lldap/tasks/main.yml b/roles/lldap/tasks/main.yml index dce8550..a756fe6 100644 --- a/roles/lldap/tasks/main.yml +++ b/roles/lldap/tasks/main.yml @@ -34,12 +34,22 @@ path: /opt/lldap state: directory +- name: Ensure proxy network exists + command: docker network inspect proxy + register: lldap_proxy_network + changed_when: false + failed_when: false + +- name: Create proxy network if missing + command: docker network create proxy + when: lldap_proxy_network.rc != 0 + - name: Copy Docker Compose file for LLDAP template: src: docker-compose.yml.j2 dest: /opt/lldap/docker-compose.yml - name: Deploy LLDAP - command: docker compose up -d --force-recreate + command: docker compose up -d args: chdir: /opt/lldap