diff --git a/docs/proxies/nginx.md b/docs/proxies/nginx.md index 538c1bb1..f08e3ccb 100644 --- a/docs/proxies/nginx.md +++ b/docs/proxies/nginx.md @@ -21,6 +21,32 @@ Here is a commented example of configuration add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN"; + location / { + # Send a subsequent request to Authelia to verify if the user is authenticated + # and has the right permissions to access the resource. + auth_request /auth_verify; + + auth_request_set $redirect $upstream_http_redirect; + + # Set the X-Forwarded-User and X-Forwarded-Groups with the headers + # returned by Authelia for the backends which can consume them. + # This is not safe, as the backend must make sure that they come from the + # proxy. In the future, it's gonna be safe to just use OAuth. + auth_request_set $user $upstream_http_remote_user; + proxy_set_header X-Forwarded-User $user; + + auth_request_set $groups $upstream_http_remote_groups; + proxy_set_header Remote-Groups $groups; + + # If Authelia returns 401, then nginx redirects the user to the login portal. + # If it returns 200, then the request pass through to the backend. + # For other type of errors, nginx will handle them as usual. + # NOTE: do not forget to include /#/ representing the hash router of the web application. + error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; + + proxy_pass $upstream_endpoint; + } + # Virtual endpoint created by nginx to forward auth requests. location /auth_verify { internal; @@ -44,31 +70,6 @@ Here is a commented example of configuration proxy_pass $upstream_verify; } - - location / { - # Send a subsequent request to Authelia to verify if the user is authenticated - # and has the right permissions to access the resource. - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - # Set the X-Forwarded-User and X-Forwarded-Groups with the headers - # returned by Authelia for the backends which can consume them. - # This is not safe, as the backend must make sure that they come from the - # proxy. In the future, it's gonna be safe to just use OAuth. - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - # If Authelia returns 401, then nginx redirects the user to the login portal. - # If it returns 200, then the request pass through to the backend. - # For other type of errors, nginx will handle them as usual. - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } } diff --git a/example/compose/nginx/portal/nginx.conf.ejs b/example/compose/nginx/portal/nginx.conf.ejs index 2f7c14c9..43d739ac 100644 --- a/example/compose/nginx/portal/nginx.conf.ejs +++ b/example/compose/nginx/portal/nginx.conf.ejs @@ -10,16 +10,6 @@ events { } http { - server { - listen 443 ssl; - server_name _; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - return 301 https://home.example.com:8080/; - } - <% if (production) { %> server { listen 443 ssl; @@ -92,6 +82,7 @@ http { } <% } %> + # Serves the home page. server { listen 443 ssl; server_name home.example.com; @@ -111,6 +102,105 @@ http { } } + # Example configuration of domains protected by Authelia. + server { + listen 443 ssl; + server_name public.example.com + admin.example.com + secure.example.com + dev.example.com + singlefactor.example.com + mx1.mail.example.com mx2.mail.example.com; + + resolver 127.0.0.11 ipv6=off; + set $upstream_verify <%= authelia_backend %>/api/verify; + set $upstream_endpoint http://nginx-backend; + set $upstream_headers http://httpbin:8000/headers; + + ssl_certificate /etc/ssl/server.crt; + ssl_certificate_key /etc/ssl/server.key; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; + + # Reverse proxy to the backend. It is protected by Authelia by forwarding authorization checks + # to the virtual endpoint introduced by nginx and declared in the next block. + location / { + auth_request /auth_verify; + + auth_request_set $redirect $upstream_http_redirect; + + auth_request_set $user $upstream_http_remote_user; + proxy_set_header X-Forwarded-User $user; + + auth_request_set $groups $upstream_http_remote_groups; + proxy_set_header Remote-Groups $groups; + + proxy_set_header Host $http_host; + + # Authelia relies on Proxy-Authorization header to authenticate in basic auth. + # but for the sake of simplicity (because Authorization in supported in most + # clients) we take Authorization from the frontend and rewrite it to + # Proxy-Authorization before sending it to Authelia. + proxy_set_header Proxy-Authorization $http_authorization; + + error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; + + proxy_pass $upstream_endpoint; + } + + # Virtual endpoint forwarding requests to Authelia server. + location /auth_verify { + internal; + proxy_set_header Host $http_host; + + proxy_set_header X-Original-URI $request_uri; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # Authelia can receive Proxy-Authorization to authenticate however most of the clients + # support Authorization instead. Therefore we rewrite Authorization into Proxy-Authorization. + proxy_set_header Proxy-Authorization $http_authorization; + + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + + proxy_pass $upstream_verify; + } + + # Used by suites to test the forwarded users and groups headers produced by Authelia. + location /headers { + auth_request /auth_verify; + + auth_request_set $redirect $upstream_http_redirect; + + auth_request_set $user $upstream_http_remote_user; + proxy_set_header Custom-Forwarded-User $user; + + auth_request_set $groups $upstream_http_remote_groups; + proxy_set_header Custom-Forwarded-Groups $groups; + + error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; + + proxy_pass $upstream_headers; + } + } + + # Matches all domains. It redirects to the home page. + server { + listen 443 ssl; + server_name _; + + ssl_certificate /etc/ssl/server.crt; + ssl_certificate_key /etc/ssl/server.key; + + return 301 https://home.example.com:8080/; + } + + + # Fake Web Mail used to receive emails sent by Authelia. server { listen 443 ssl; server_name mail.example.com; @@ -130,308 +220,7 @@ http { } } - server { - listen 443 ssl; - server_name public.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_verify <%= authelia_backend %>/api/verify; - set $upstream_endpoint http://nginx-backend; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location /auth_verify { - internal; - proxy_set_header Host $http_host; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - - proxy_pass $upstream_verify; - } - - location / { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - proxy_set_header Host $http_host; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } - } - - server { - listen 443 ssl; - server_name admin.example.com - secure.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_verify <%= authelia_backend %>/api/verify; - set $upstream_endpoint http://nginx-backend; - set $upstream_headers http://httpbin:8000/headers; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location /auth_verify { - internal; - proxy_set_header Host $http_host; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - - proxy_pass $upstream_verify; - } - - location / { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - proxy_set_header Host $http_host; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } - - location /headers { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header Custom-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Custom-Forwarded-Groups $groups; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_headers; - } - } - - server { - listen 443 ssl; - server_name dev.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_verify <%= authelia_backend %>/api/verify; - set $upstream_endpoint http://nginx-backend; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location /auth_verify { - internal; - proxy_set_header Host $http_host; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - - proxy_pass $upstream_verify; - } - - location / { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - proxy_set_header Host $http_host; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } - } - - server { - listen 443 ssl; - server_name mx1.mail.example.com mx2.mail.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_verify <%= authelia_backend %>/api/verify; - set $upstream_endpoint http://nginx-backend; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location /auth_verify { - internal; - proxy_set_header Host $http_host; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - - proxy_pass $upstream_verify; - } - - location / { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - proxy_set_header Host $http_host; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } - } - - server { - listen 443 ssl; - server_name singlefactor.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_verify <%= authelia_backend %>/api/verify; - set $upstream_endpoint http://nginx-backend; - set $upstream_headers http://httpbin:8000/headers; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location /auth_verify { - internal; - proxy_set_header Host $http_host; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # This header is required for basic authentication. - proxy_set_header Proxy-Authorization $http_authorization; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - - proxy_pass $upstream_verify; - } - - location / { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header X-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Remote-Groups $groups; - - proxy_set_header Host $http_host; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_endpoint; - } - - location /headers { - auth_request /auth_verify; - - auth_request_set $redirect $upstream_http_redirect; - - auth_request_set $user $upstream_http_remote_user; - proxy_set_header Custom-Forwarded-User $user; - - auth_request_set $groups $upstream_http_remote_groups; - proxy_set_header Custom-Forwarded-Groups $groups; - - error_page 401 =302 https://login.example.com:8080/#/?rd=$redirect; - - proxy_pass $upstream_headers; - } - } - - server { - listen 443 ssl; - server_name authelia.example.com; - - resolver 127.0.0.11 ipv6=off; - set $upstream_endpoint <%= authelia_backend %>; - - ssl_certificate /etc/ssl/server.crt; - ssl_certificate_key /etc/ssl/server.key; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options "SAMEORIGIN"; - - location / { - proxy_set_header Host $http_host; - proxy_pass $upstream_endpoint; - } - } - + # Fake API emulating Duo behavior server { listen 443 ssl; server_name duo.example.com; diff --git a/scripts/authelia-scripts-bootstrap b/scripts/authelia-scripts-bootstrap index 2e58fb58..421f3bf6 100755 --- a/scripts/authelia-scripts-bootstrap +++ b/scripts/authelia-scripts-bootstrap @@ -48,7 +48,6 @@ async function checkHostsFile() { await checkAndFixEntry(actualEntries, 'mx2.mail.example.com', '127.0.0.1'); await checkAndFixEntry(actualEntries, 'public.example.com', '127.0.0.1'); await checkAndFixEntry(actualEntries, 'secure.example.com', '127.0.0.1'); - await checkAndFixEntry(actualEntries, 'authelia.example.com', '127.0.0.1'); await checkAndFixEntry(actualEntries, 'mail.example.com', '127.0.0.1'); await checkAndFixEntry(actualEntries, 'duo.example.com', '192.168.240.100'); diff --git a/test/suites/basic/scenarii/VerifyEndpoint.ts b/test/suites/basic/scenarii/VerifyEndpoint.ts index 1629d679..b846e505 100644 --- a/test/suites/basic/scenarii/VerifyEndpoint.ts +++ b/test/suites/basic/scenarii/VerifyEndpoint.ts @@ -2,7 +2,7 @@ import { GET_Expect401, GET_ExpectRedirect } from "../../../helpers/utils/Reques export default function() { describe('Query without authenticated cookie', function() { - it('should get a 401 on GET to https://authelia.example.com:8080/api/verify', async function() { + it('should get a 401 on GET to https://login.example.com:8080/api/verify', async function() { await GET_Expect401('https://login.example.com:8080/api/verify'); }); diff --git a/test/suites/high-availability/scenarii/BasicAuthentication.ts b/test/suites/high-availability/scenarii/BasicAuthentication.ts index b5e46a12..1a2eb43d 100644 --- a/test/suites/high-availability/scenarii/BasicAuthentication.ts +++ b/test/suites/high-availability/scenarii/BasicAuthentication.ts @@ -11,7 +11,7 @@ async function GetSecret(username: string, password: string) { } export default function() { - it("should retrieve secret when Authorization header is provided", async function() { + it("should retrieve secret when Proxy-Authorization header is provided", async function() { const res = await GetSecret('john', 'password'); if (res.indexOf('This is a very important secret!') < 0) { throw new Error('Cannot access secret.');