From aca23d6af64b8b1f6984c75cacd81e8ac45159b1 Mon Sep 17 00:00:00 2001 From: Viyurz Date: Sun, 31 Mar 2024 18:26:05 +0200 Subject: [PATCH] Add Authelia. --- env.yml | 4 ++ roles/authelia/tasks/backup.yml | 24 +++++++ roles/authelia/tasks/main.yml | 14 ++++ roles/authelia/tasks/setup.yml | 23 ++++++ roles/authelia/tasks/update.yml | 24 +++++++ roles/authelia/templates/configuration.yml | 72 +++++++++++++++++++ roles/authelia/templates/docker-compose.yaml | 16 +++++ roles/reverse-proxy/tasks/main.yml | 18 ++--- .../templates/authelia-authrequest.conf | 15 ++++ .../templates/authelia-location.conf | 18 +++++ .../templates/reverse-proxy.conf | 32 +++++++++ secrets.yml.example | 16 ++++- 12 files changed, 266 insertions(+), 10 deletions(-) create mode 100644 roles/authelia/tasks/backup.yml create mode 100644 roles/authelia/tasks/main.yml create mode 100644 roles/authelia/tasks/setup.yml create mode 100644 roles/authelia/tasks/update.yml create mode 100644 roles/authelia/templates/configuration.yml create mode 100644 roles/authelia/templates/docker-compose.yaml create mode 100644 roles/reverse-proxy/templates/authelia-authrequest.conf create mode 100644 roles/reverse-proxy/templates/authelia-location.conf diff --git a/env.yml b/env.yml index f9921db..485a409 100644 --- a/env.yml +++ b/env.yml @@ -39,6 +39,7 @@ cifs_mounts: projects: + - authelia - coturn - element - etebase @@ -56,6 +57,7 @@ projects: projects_to_backup: + - authelia - etebase - hedgedoc - lldap @@ -79,6 +81,7 @@ borg_prune_options: | # Ports exposed to host ports: + authelia: 9091 coturn_listening: 3478 coturn_tls_listening: 5349 coturn_relay_min: 49152 @@ -107,6 +110,7 @@ ports: # UID in containers users: + authelia: 1008 coturn: 666 etebase: 373 hedgedoc: 1004 diff --git a/roles/authelia/tasks/backup.yml b/roles/authelia/tasks/backup.yml new file mode 100644 index 0000000..69f1c50 --- /dev/null +++ b/roles/authelia/tasks/backup.yml @@ -0,0 +1,24 @@ +- name: "Backup PostgreSQL authelia database" + shell: > + docker exec postgres + pg_dump -c {{ role_name }} | + borg create + --compression lzma + "{{ borg_repodir }}::{{ role_name }}-{now:%Y-%m-%d_%H-%M-%S}" + - + --stdin-name dump_{{ role_name }}.sql + environment: + DOCKER_HOST: "{{ docker_host }}" + BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" + become: true + +- name: Prune borg repository + command: + cmd: | + borg prune + --glob-archives='{{ role_name }}-*' + {{ borg_prune_options }} + {{ borg_repodir }} + environment: + BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" + become: true diff --git a/roles/authelia/tasks/main.yml b/roles/authelia/tasks/main.yml new file mode 100644 index 0000000..89bf793 --- /dev/null +++ b/roles/authelia/tasks/main.yml @@ -0,0 +1,14 @@ +- name: Include backup tasks + include_tasks: + file: backup.yml + when: run_backup | default(false) | bool + +- name: Include setup tasks + include_tasks: + file: setup.yml + when: run_setup | default(false) | bool + +- name: Include update tasks + include_tasks: + file: update.yml + when: run_update | default(false) | bool diff --git a/roles/authelia/tasks/setup.yml b/roles/authelia/tasks/setup.yml new file mode 100644 index 0000000..06a31af --- /dev/null +++ b/roles/authelia/tasks/setup.yml @@ -0,0 +1,23 @@ +- name: "Create {{ project_dir }} project directory" + file: + path: "{{ project_dir }}" + state: directory + +- name: Template docker-compose.yaml & configuration.yml to project directory + template: + src: "{{ item }}" + dest: "{{ project_dir }}/{{ item }}" + owner: "{{ host_uid }}" + group: "{{ host_uid }}" + mode: '640' + loop: + - docker-compose.yaml + - configuration.yml + register: authelia_template_configuration_result + +# Separate task because template module cannot chown/chgrp to a non-existing user/group +- name: "Change group of homeserver.yaml to Authelia GID ({{ users['authelia'] + uid_shift }})" + file: + path: "{{ project_dir }}/configuration.yml" + group: "{{ users['authelia'] + uid_shift }}" + become: true diff --git a/roles/authelia/tasks/update.yml b/roles/authelia/tasks/update.yml new file mode 100644 index 0000000..4edca50 --- /dev/null +++ b/roles/authelia/tasks/update.yml @@ -0,0 +1,24 @@ +- name: Pull project services + community.docker.docker_compose: + project_src: "{{ project_dir }}" + recreate: never + pull: true + debug: true + when: docker_pull_images | bool + register: authelia_docker_compose_pull_result + +- name: Display pulled image(s) name + set_fact: + authelia_pulled_images: "{{ authelia_pulled_images | default([]) + [item.pulled_image.name] }}" + loop: "{{ authelia_docker_compose_pull_result['actions'] | default([]) | selectattr('pulled_image', 'defined') }}" + +- name: Include backup tasks + include_tasks: + file: backup.yml + # Make a backup if we didn't already make one and we pulled a new image + when: not run_backup and authelia_pulled_images is defined + +- name: Create/Restart project services + community.docker.docker_compose: + project_src: "{{ project_dir }}" + restarted: "{{ authelia_template_configuration_result['changed'] | default(false) | bool }}" diff --git a/roles/authelia/templates/configuration.yml b/roles/authelia/templates/configuration.yml new file mode 100644 index 0000000..b117c32 --- /dev/null +++ b/roles/authelia/templates/configuration.yml @@ -0,0 +1,72 @@ +theme: 'auto' + +totp: + issuer: '{{ domain }}' + +identity_validation: + reset_password: + jwt_secret: '{{ authelia_secrets["jwt_secret"] }}' + +authentication_backend: + refresh_interval: '1m' + ldap: + implementation: 'custom' + address: 'ldap://lldap:3890' + base_dn: '{{ ldap_base_dn }}' + users_filter: '(&({username_attribute}={input})(objectClass=person))' + groups_filter: '(member={dn})' + user: '{{ authelia_secrets["ldap_user"] }}' + password: '{{ authelia_secrets["ldap_password"] }}' + attributes: + distinguished_name: 'distinguishedName' + username: 'uid' + mail: 'mail' + member_of: 'memberOf' + group_name: 'cn' + +password_policy: + standard: + enabled: true + min_length: 12 + max_length: 128 + require_uppercase: true + require_lowercase: true + require_number: true + require_special: true + +access_control: + default_policy: 'deny' + rules: + - domain: 'auth.{{ domain }}' + policy: 'bypass' + + - domain: 'ldap.{{ domain }}' + policy: 'two_factor' + subject: 'group:lldap_admin' + + - domain: 'syncthing.{{ domain }}' + policy: 'two_factor' + subject: 'user:viyurz' + +session: + cookies: + - name: 'authelia_session' + domain: '{{ domain }}' + authelia_url: 'https://auth.{{ domain }}' + +storage: + encryption_key: '{{ authelia_secrets["encryption_key"] }}' + postgres: + address: postgres.{{ domain }} + database: authelia + username: '{{ authelia_secrets["postgres_user"] }}' + password: '{{ authelia_secrets["postgres_password"] }}' + +notifier: + smtp: + address: 'submissions://mail.{{ domain }}:{{ ports["mailserver_smtps"] }}' + username: '{{ authelia_secrets["smtp_user"] }}' + password: '{{ authelia_secrets["smtp_password"] }}' + sender: 'Authelia ' + +# identity_providers: diff --git a/roles/authelia/templates/docker-compose.yaml b/roles/authelia/templates/docker-compose.yaml new file mode 100644 index 0000000..7c969d3 --- /dev/null +++ b/roles/authelia/templates/docker-compose.yaml @@ -0,0 +1,16 @@ +services: + authelia: + container_name: authelia + image: docker.io/authelia/authelia:4.38 + restart: always + user: {{ users['authelia'] }}:{{ users['authelia'] }} + networks: + - authelia + ports: + - 127.0.0.1:{{ ports['authelia'] }}:9091 + volumes: + - ./configuration.yml:/config/configuration.yml + +networks: + authelia: + name: authelia diff --git a/roles/reverse-proxy/tasks/main.yml b/roles/reverse-proxy/tasks/main.yml index c901201..ea8a31a 100644 --- a/roles/reverse-proxy/tasks/main.yml +++ b/roles/reverse-proxy/tasks/main.yml @@ -5,14 +5,17 @@ apt: name: nginx - - name: Template nginx.conf to /etc/nginx/nginx.conf + - name: Template configuration files to /etc/nginx/ template: - src: nginx.conf - dest: /etc/nginx/nginx.conf + src: "{{ item }}" + dest: "/etc/nginx/{{ item }}" owner: root group: root mode: '644' - register: nginx_template_nginx_conf_result + loop: + - nginx.conf + - authelia-location.conf + - authelia-authrequest.conf - name: Template reverse-proxy.conf to /etc/nginx/sites-available/reverse-proxy.conf template: @@ -21,8 +24,7 @@ owner: root group: root mode: '644' - register: nginx_template_reverse_proxy_conf_result - + - name: Copy ssl-headers.conf to /etc/nginx/conf.d/ssl-headers.conf copy: src: files/ssl-headers.conf @@ -30,7 +32,6 @@ owner: root group: root mode: '644' - register: nginx_copy_ssl_headers_conf_result - name: Remove all enabled NGINX sites file: @@ -74,6 +75,5 @@ - name: Start/Reload NGINX service service: name: nginx - # Reload if conf changed, if not make sure it is started - state: "{{ (nginx_template_nginx_conf_result['changed'] or nginx_template_reverse_proxy_conf_result['changed'] or nginx_copy_ssl_headers_conf_result['changed']) | ternary('reloaded', 'started') }}" + state: reloaded enabled: yes diff --git a/roles/reverse-proxy/templates/authelia-authrequest.conf b/roles/reverse-proxy/templates/authelia-authrequest.conf new file mode 100644 index 0000000..7d2f293 --- /dev/null +++ b/roles/reverse-proxy/templates/authelia-authrequest.conf @@ -0,0 +1,15 @@ +auth_request /internal/authelia/authz; + +auth_request_set $user $upstream_http_remote_user; +auth_request_set $groups $upstream_http_remote_groups; +auth_request_set $name $upstream_http_remote_name; +auth_request_set $email $upstream_http_remote_email; + +proxy_set_header Remote-User $user; +proxy_set_header Remote-Groups $groups; +proxy_set_header Remote-Email $email; +proxy_set_header Remote-Name $name; + +auth_request_set $redirection_url $upstream_http_location; + +error_page 401 =302 $redirection_url; diff --git a/roles/reverse-proxy/templates/authelia-location.conf b/roles/reverse-proxy/templates/authelia-location.conf new file mode 100644 index 0000000..fe728f9 --- /dev/null +++ b/roles/reverse-proxy/templates/authelia-location.conf @@ -0,0 +1,18 @@ +location /internal/authelia/authz { + internal; + + proxy_pass http://127.0.0.1:{{ ports['authelia'] }}/api/authz/auth-request; + + proxy_set_header X-Original-Method $request_method; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Content-Length ""; + proxy_set_header Connection ""; + + proxy_pass_request_body off; + proxy_http_version 1.1; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 4 32k; + client_body_buffer_size 128k; +} diff --git a/roles/reverse-proxy/templates/reverse-proxy.conf b/roles/reverse-proxy/templates/reverse-proxy.conf index eca19ec..87a57bd 100644 --- a/roles/reverse-proxy/templates/reverse-proxy.conf +++ b/roles/reverse-proxy/templates/reverse-proxy.conf @@ -61,6 +61,19 @@ server { } +# Authelia +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name auth.{{ domain }}; + + location / { + proxy_pass http://127.0.0.1:{{ ports['authelia'] }}; + } +} + + # Element server { listen 443 ssl http2; @@ -138,8 +151,11 @@ server { server_name ldap.{{ domain }}; + include /etc/nginx/authelia-location.conf; + location / { proxy_pass http://127.0.0.1:{{ ports['lldap'] }}; + include /etc/nginx/authelia-authrequest.conf; } } @@ -177,6 +193,22 @@ server { } +# Syncthihng +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name syncthing.{{ domain }}; + + include /etc/nginx/authelia-location.conf; + + location / { + proxy_pass http://127.0.0.1:{{ ports['syncthing_webui'] }}; + include /etc/nginx/authelia-authrequest.conf; + } +} + + # Syncthing Discovery upstream stdisco.{{ domain }} { # Local IP address:port for discovery server diff --git a/secrets.yml.example b/secrets.yml.example index 9b9e41b..c98f7c7 100644 --- a/secrets.yml.example +++ b/secrets.yml.example @@ -1,3 +1,5 @@ +# To generate random secret: openssl rand -base64 + ansible_become_password: borg_passphrase: @@ -6,7 +8,19 @@ cifs_credentials: username: password: -# To generate random secret: openssl rand -base64 50 + +authelia_secrets: + # Encryption key for the database, must be saved + encryption_key: + jwt_secret: + # LDAP bind dn + ldap_user: + ldap_password: + postgres_user: + postgres_password: + smtp_user: + smtp_password: + coturn_secrets: static_auth_secret: