diff --git a/playbook.yml b/playbook.yml index b2079c2..b38a02c 100644 --- a/playbook.yml +++ b/playbook.yml @@ -6,6 +6,7 @@ - jellyfin - openldap - postgres + - authelia - keycloak vars_files: - vault/certs/{{ base_domain }}.yml diff --git a/provision.sh b/provision.sh new file mode 100755 index 0000000..a77faa4 --- /dev/null +++ b/provision.sh @@ -0,0 +1,2 @@ +#!/bin/env fish +ANSIBLE_VAULT_PASSWORD_FILE=(pass show ansible-homelab | psub) vagrant provision \ No newline at end of file diff --git a/roles/authelia/tasks/main.yml b/roles/authelia/tasks/main.yml new file mode 100644 index 0000000..d8e5b9e --- /dev/null +++ b/roles/authelia/tasks/main.yml @@ -0,0 +1,39 @@ +- name: ensure directories exist + file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: + - "{{ data_folder }}/authelia" +- name: copy configuration.yml + template: + src: "configuration.yml.j2" + dest: "{{ data_folder }}/authelia/configuration.yml" + mode: "755" +- name: run container + docker_container: + name: "authelia" + image: "authelia/authelia" + ports: + - "9091:9091" + networks: + - name: bridge + - name: nginx-internal + volumes: + - "{{ data_folder }}/authelia:/config" +- name: copy nginx endpoint conf + template: + src: "authelia-endpoint.conf.j2" + dest: "{{ data_folder }}/nginx/snippets/authelia-endpoint.conf" + mode: "755" +- name: copy nginx auth conf + template: + src: "authelia-auth.conf.j2" + dest: "{{ data_folder }}/nginx/snippets/authelia-auth.conf" + mode: "755" +- name: copy nginx conf + template: + src: "authelia.conf.j2" + dest: "{{ data_folder }}/nginx/conf.d/{{ role_name }}.{{ base_domain }}.conf" + mode: "755" + notify: reload nginx \ No newline at end of file diff --git a/roles/authelia/templates/authelia-auth.conf.j2 b/roles/authelia/templates/authelia-auth.conf.j2 new file mode 100644 index 0000000..8c78b57 --- /dev/null +++ b/roles/authelia/templates/authelia-auth.conf.j2 @@ -0,0 +1,11 @@ +auth_request /authelia/api/verify; +auth_request_set $target_url $scheme://$http_host$request_uri; +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-Name $name; +proxy_set_header Remote-Email $email; +error_page 401 =302 https://$http_host/authelia/?rd=$target_url; \ No newline at end of file diff --git a/roles/authelia/templates/authelia-endpoint.conf.j2 b/roles/authelia/templates/authelia-endpoint.conf.j2 new file mode 100644 index 0000000..a218595 --- /dev/null +++ b/roles/authelia/templates/authelia-endpoint.conf.j2 @@ -0,0 +1,47 @@ +location ^~ /authelia { + include /etc/nginx/snippets/proxy.conf; + set $upstream_authelia authelia; + proxy_pass http://$upstream_authelia:9091; +} + +location = /authelia/api/verify { + internal; + if ($request_uri ~ [^a-zA-Z0-9_+-=\!@$%&*?~.:#'\;\(\)\[\]]) { + return 401; + } + set $upstream_authelia authelia; + proxy_pass_request_body off; + proxy_pass http://$upstream_authelia:9091; + proxy_set_header Content-Length ""; + + # Timeout if the real server is dead + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + + # [REQUIRED] Needed by Authelia to check authorizations of the resource. + # Provide either X-Original-URL and X-Forwarded-Proto or + # X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri or both. + # Those headers will be used by Authelia to deduce the target url of the user. + # Basic Proxy Config + client_body_buffer_size 128k; + proxy_set_header Host $host; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Method $request_method; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header X-Forwarded-Ssl on; + proxy_redirect http:// $scheme://; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 4 32k; + + # Advanced Proxy Config + send_timeout 5m; + proxy_read_timeout 240; + proxy_send_timeout 240; + proxy_connect_timeout 240; +} \ No newline at end of file diff --git a/roles/authelia/templates/authelia.conf.j2 b/roles/authelia/templates/authelia.conf.j2 new file mode 100644 index 0000000..73e2ddc --- /dev/null +++ b/roles/authelia/templates/authelia.conf.j2 @@ -0,0 +1,16 @@ +server { + listen 80; + server_name auth.{{ base_domain }}; + return 301 https://$host$request_uri; +} + +server { + server_name auth.{{ base_domain }}; + listen 443 ssl http2; + + location / { + include /etc/nginx/snippets/proxy.conf; + set $upstream_authelia http://authelia:9091; # This example assumes a Docker deployment + proxy_pass $upstream_authelia; + } +} \ No newline at end of file diff --git a/roles/authelia/templates/configuration.yml.j2 b/roles/authelia/templates/configuration.yml.j2 new file mode 100644 index 0000000..f188cbe --- /dev/null +++ b/roles/authelia/templates/configuration.yml.j2 @@ -0,0 +1,58 @@ +host: 0.0.0.0 +port: 9091 +server: + read_buffer_size: 4096 + write_buffer_size: 4096 + path: "authelia" +log_level: debug +jwt_secret: somethingsomethingrandomrecret +default_redirection_url: https://{{ base_domain }} +authentication_backend: + disable_reset_password: false + ldap: + implementation: custom + url: ldap://openldap + start_tls: false + tls: + server_name: openldap + skip_verify: false + minimum_version: TLS1.2 + base_dn: dc=kucharczyk,dc=xyz + username_attribute: uid + users_filter: ({username_attribute}={input}) + groups_filter: (member={dn}) + mail_attribute: mail + user: cn=admin,dc=kucharczyk,dc=xyz + password: {{ vault_openldap_admin_password }} +access_control: + default_policy: deny + rules: + - domain: "*.{{ base_domain }}" + policy: bypass + name: authelia_session + secret: somerandomsecret + expiration: 1h + inactivity: 5m + remember_me_duration: 1M + domain: {{ base_domain }} +regulation: + max_retries: 3 + find_time: 2m + ban_time: 99y +storage: + local: + path: /config/db.sqlite3 +notifier: + disable_startup_check: false + smtp: + username: kucharczyk.lukas@gmail.com + password: {{ vault_email_gmail_password }} + host: smtp.gmail.com + port: 587 + sender: kucharczyk.lukas@gmail.com + subject: "[Authelia] {title}" + startup_check_address: test@authelia.com + disable_require_tls: false + tls: + skip_verify: false + minimum_version: TLS1.2 \ No newline at end of file diff --git a/roles/keycloak/templates/keycloak.conf.j2 b/roles/keycloak/templates/keycloak.conf.j2 index e16765c..6bb5776 100644 --- a/roles/keycloak/templates/keycloak.conf.j2 +++ b/roles/keycloak/templates/keycloak.conf.j2 @@ -13,8 +13,11 @@ server { add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; + include /etc/nginx/snippets/authelia-endpoint.conf; + location / { proxy_pass http://$keycloak:8080; + include /etc/nginx/snippets/authelia-auth.conf; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/roles/nginx/templates/snippets/proxy.conf.j2 b/roles/nginx/templates/snippets/proxy.conf.j2 new file mode 100644 index 0000000..329c492 --- /dev/null +++ b/roles/nginx/templates/snippets/proxy.conf.j2 @@ -0,0 +1,36 @@ +client_body_buffer_size 128k; + +#Timeout if the real server is dead +proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + +# Advanced Proxy Config +send_timeout 5m; +proxy_read_timeout 360; +proxy_send_timeout 360; +proxy_connect_timeout 360; + +# Basic Proxy Config +proxy_set_header Host $host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-Host $http_host; +proxy_set_header X-Forwarded-Uri $request_uri; +proxy_set_header X-Forwarded-Ssl on; +proxy_redirect http:// $scheme://; +proxy_http_version 1.1; +proxy_set_header Connection ""; +proxy_cache_bypass $cookie_session; +proxy_no_cache $cookie_session; +proxy_buffers 64 256k; + +# If behind reverse proxy, forwards the correct IP +set_real_ip_from 10.0.0.0/8; +set_real_ip_from 172.16.0.0/12; +set_real_ip_from 172.17.0.0/16; +set_real_ip_from 172.18.0.0/16; +set_real_ip_from 172.19.0.0/16; +set_real_ip_from 192.168.0.0/16; +set_real_ip_from fc00::/7; +real_ip_header X-Forwarded-For; +real_ip_recursive on; \ No newline at end of file diff --git a/show-pass.sh b/show-pass.sh new file mode 100755 index 0000000..b8a695e --- /dev/null +++ b/show-pass.sh @@ -0,0 +1,2 @@ +#!/bin/env fish +ansible-vault view --vault-password-file (pass show ansible-homelab | psub) vault/passwords.yml \ No newline at end of file diff --git a/vault/passwords.yml b/vault/passwords.yml index f31064e..cea236d 100644 --- a/vault/passwords.yml +++ b/vault/passwords.yml @@ -1,17 +1,19 @@ $ANSIBLE_VAULT;1.1;AES256 -65653231333939666430306463383836633664623438373661666234343165633864353934663563 -3335396466623862353633363264373666353036623134360a356438636230613139633264373265 -36643231356335653261616238613266306165616363643763356234363537616138353831383064 -3436353361333263330a313361306236626164343261363432343762313361636338333165376238 -38666336356361613930316536323338653338353666666162666333636261373866653934626536 -31643931343338383039616261616130613763383737313037303163366263623066633031646630 -35373436646635613665343038363931396630653264633964646434346534393531333163643836 -62323634643537363365313662363766373436633262336339643734613732663832326133363434 -38643434326266373638366262386162666661383232383965613536663239336361623861613161 -32313439653132353434316563633638353164626236633766313864343036353562303163373335 -39653437623132623635363266353636613130666363353633366134663638346263643134383762 -37316631313437646232326237313436353732333065363666316364373336396135396238363562 -39633163316532616564366632303965316362653066613536316461643237373834316136383865 -64353238643638623832656463333563633838633931636166323335336662636362643466303566 -31333962656530326664636562343738393864613561333734333134386263356533373664666666 -66373538393037373761 +35356537316639386637316365393533643061363734323630393363313237643935666639653963 +3734376266353938653631323266663139306335646635660a373233663964623335663366333434 +34386136656530386639646234316238326132616131616632346537613963636637393839613661 +6366326639643632320a386436316165343166366134633464393461653434323934326238313430 +39323439306637306134326635323138616337646336653238636539643538613664303764303661 +39636661353538393532663937396363656664613334383261336664336237356366663334633430 +36356235383930653835393439373737623036613565313131626462363034303062323662663832 +66613833613336646633383835653161386363386136663764653734313763383231626434393864 +63313061346335383933623630396336336561633938613237643238616531343766613734666132 +32306362616131396266656162653563356137383239616464306662643032623438373764306361 +32363133626662633435626232653061373831626563323861626635383039613136303632613335 +61363265316534653033393763646565393330633063323634353932353936303638356433306362 +65383938306637333765383263653939633964613230613835326630313761323561376162646439 +62323035323634323766393233326363383364653531306432663263303831623936616139306639 +64303863386265343165666435363761653464386366636366323261353731643263356635383536 +66326666616339653731633530663161363933383334376238313637356331663431336433643338 +64313861306161373538363332663363623131303561373237326436373838393965306663333835 +3764356534323963303832653964666431626538316361613137