zmartzone / lua-resty-openidc

OpenID Connect Relying Party and OAuth 2.0 Resource Server implementation in Lua for NGINX / OpenResty
Apache License 2.0
976 stars 249 forks source link

TLS termination use case #509

Open ArcFreez opened 9 months ago

ArcFreez commented 9 months ago

Hello everyone,

I'm trying to setup a TLS terminating nginx configuration where the TLS terminated nginx server listening on port 80 will do the openidc authentication, and redirect them to the secured static content. Any help is appreciated.

Thank you.

Environment
Expected behavior

This setup is basically a login/logout cycle on an nginx server serving static content.

  1. The user will login via clicking a login link in the home page that will take them to the keycloak login page (username, password etc.)
  2. User authenticates, and lua-resty-openidc will handle redirecting them to a protected app page (static content on the nginx server).
  3. When the user logs out via the logout button on the home page, the user will be redirected to the home page.
Actual behavior
  1. The user is sent to keycloak login screen after pressing the login link on the main page.
  2. After the authentication, I am redirected to openresty 404 page with the uri: https://${HOME_DOMAIN}/auth?state=b6b178fc48d14abdcb65f92e62adb25a&session_state=75cc0f5f-a2bd-405b-9bc3-67c634028c4e&iss=https%3A%2F%2F${KEYCLOAK_INTERNAL_URL}%2Frealms%2F${KEYCLOAK_REALM}&code=4959cd9c-e162-46d2-ad25-3268966efcbc.75cc0f5f-a2bd-405b-9bc3-67c634028c4e.b2a4ca15-b77f-4a3f-ae99-bdddcfd8f332

Based off of what I read from 240, I think this is a right use case of redirect uri. I suspect there might be something going on with the redirect_uri (I don't have a redirect_uri for this basic configuration, and I've just left it as a uri that keycloak validates against to make sure it gets redirected to the right uri).

Minimized example

Minimal, complete configuration that reproduces the behavior. Here is my nginx configuration and Dockerfile.dev

FROM openresty/openresty:alpine-fat

RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-http\
    && /usr/local/openresty/luajit/bin/luarocks install lua-resty-session\
    && /usr/local/openresty/luajit/bin/luarocks install lua-resty-jwt\
    && /usr/local/openresty/luajit/bin/luarocks install lua-resty-openidc
# the configuration lives under /usr/local/openresty/nginx/conf/nginx.conf in the container
worker_processes auto;

events {
    worker_connections 128;
}

http {
    include mime.types;
    default_type  application/octet-stream;

    # lua-resty-openidc required http context config
    lua_package_path '~/lua/?.lua;;';

    resolver ${LUA_RESTY_NGINX_RESOLVER};

    # cache for discovery metadata documents
    lua_shared_dict discovery 1m;
    # cache for JWKs
    lua_shared_dict jwks 1m;

    # tls server settings
    keepalive_timeout 70;

    error_log stderr debug;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    # reduce processor load when using tls
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # global proxy settings
    proxy_buffering on;
    proxy_buffer_size   256k;
    proxy_buffers   4 512k;
    proxy_http_version 1.1;

    # Pretend to be a reverse proxy in front of our oidc auth and application
    server {
        listen ${PROXY_PORT} ssl;
        server_name ${HOME_DOMAIN};

        ssl_certificate /etc/nginx/ssl/server.crt;
        ssl_certificate_key /etc/nginx/ssl/server.key;

        # Redirect from http to https.
        error_page 497 301 =307 https://$host:$server_port$request_uri;

        add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';

        root /var/www/html/home;

        location / {
        }

        location /app {
            return 302 /app/;
        }

        location /app/ {
            proxy_set_header Host $host;
            proxy_pass http://localhost:80/;
        }
    }

    # Do OIDC auth when our endpoint is hit
    server {
        listen 80;
        server_name ${HOME_DOMAIN};

        allow 127.0.0.1;
        deny all;

        location / {
            proxy_set_header Host ${HOME_DOMAIN}.internal;
            proxy_pass http://localhost:80/;

            access_by_lua_block {
                local opts = {
                    client_id="${CLIENT_ID}",
                    client_secret="${CLIENT_SECRET}",
                    ssl_verify="${OPENIDC_SERVER_VERIFY}",
                    redirect_uri = "https://${HOME_DOMAIN}/auth",
                    logout_path = "/logout",
                    post_logout_redirect_uri = "https://${HOME_DOMAIN}/",
                    use_pkce = true,
                    discovery = "${KEYCLOAK_INTERNAL_URL}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration"
                }
                local openidc = require("resty.openidc")
                openidc.set_logging(ngx.log, { DEBUG = ngx.INFO })
                local res, err = openidc.authenticate(opts)

                if err then
                    ngx.status = 500
                    ngx.say(err)
                    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
                end

                ngx.req.set_header("X-USER", res.id_token.sub)
            }
        }
    }

    # Serve the application
    server {
        listen 80;
        server_name ${HOME_DOMAIN}.internal;

        allow 127.0.0.1;
        deny all;

        root /var/www/html/app;

        location / {
        }
    }
}
Configuration and NGINX server log files

Config and logs for the minimized example, possibly provided as attachments.

2024-02-05 11:07:29 172.28.0.4 - - [05/Feb/2024:18:07:29 +0000] "GET /app HTTP/1.1" 302 151 "https://${HOME_DOMAIN}/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:1520: authenticate(): session.present=nil, session.data.id_token=false, session.data.authenticated=nil, opts.force_reauthorize=nil, opts.renew_access_token_on_expiry=nil, try_to_renew=true, token_expired=false, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:556: openidc_discover(): openidc_discover: URL is: https://${KEYCLOAK_INTERNAL_URL}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:107: openidc_cache_get(): cache hit: type=discovery key=https://${KEYCLOAK_INTERNAL_URL}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:674: openidc_get_token_auth_method(): 1 => private_key_jwt, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:64: supported(): Can't use private_key_jwt without opts.client_rsa_private_key, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:674: openidc_get_token_auth_method(): 2 => client_secret_basic, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:677: openidc_get_token_auth_method(): no configuration setting for option so select the first supported method specified by the OP: client_secret_basic, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:691: openidc_get_token_auth_method(): token_endpoint_auth_method result set to client_secret_basic, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}l/"
2024-02-05 11:07:29 2024/02/05 18:07:29 [info] 10#10: *17 [lua] openidc.lua:1551: authenticate(): Authentication is required - Redirecting to OP Authorization endpoint, client: 127.0.0.1, server: ${HOME_DOMAIN}, request: "GET / HTTP/1.1", host: "${HOME_DOMAIN}", referrer: "https://${HOME_DOMAIN}/"
2024-02-05 11:07:29 127.0.0.1 - - [05/Feb/2024:18:07:29 +0000] "GET / HTTP/1.1" 302 151 "https://${HOME_DOMAIN}/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
2024-02-05 11:07:29 172.28.0.4 - - [05/Feb/2024:18:07:29 +0000] "GET /app/ HTTP/1.1" 302 151 "https://${HOME_DOMAIN}/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
2024-02-05 11:07:33 2024/02/05 18:07:33 [error] 14#14: *13 open() "/var/www/html/home/auth" failed (2: No such file or directory), client: 172.28.0.4, server: ${HOME_DOMAIN}, request: "GET /auth?state=73290099b5e81f7cb4c40a8086c1dcd9&session_state=75cc0f5f-a2bd-405b-9bc3-67c634028c4e&iss=https%3A%2F%2F${KEYCLOAK_INTERNAL_URL}%2Frealms%2F${KEYCLOAK_REALM}&code=c7750501-6fe2-4a72-9956-e9d02672dff3.75cc0f5f-a2bd-405b-9bc3-67c634028c4e.b2a4ca15-b77f-4a3f-ae99-bdddcfd8f332 HTTP/1.1", host: "${HOME_DOMAIN}"
2024-02-05 11:07:33 172.28.0.4 - - [05/Feb/2024:18:07:33 +0000] "GET /auth?state=73290099b5e81f7cb4c40a8086c1dcd9&session_state=75cc0f5f-a2bd-405b-9bc3-67c634028c4e&iss=https%3A%2F%2F${KEYCLOAK_INTERNAL_URL}%2Frealms%2F${KEYCLOAK_REALM}&code=c7750501-6fe2-4a72-9956-e9d02672dff3.75cc0f5f-a2bd-405b-9bc3-67c634028c4e.b2a4ca15-b77f-4a3f-ae99-bdddcfd8f332 HTTP/1.1" 404 561 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"