Authenticating Reverse Proxy with KeyCloak

January 11, 2018 | 6 min Read

Authentication & user management is hard

Ok, it’s not one of the two hardest problems in Computer Science, but adding authentication to your web-based application is non-trivial. In addition to the security concerns involved, you are also required to maintain account information, registration, and identity management, which most users are tired of. Nobody wants Yet Another Password To Remember (YAPTR).

Of course, most of you will point to OAuth and OpenID. You’ll correctly point out that we should leverage the users existing identities.

This is great, but what if you have a simple static site or download server that you want to protect? Should we build a full web-application just to integrate OAuth?

The easiest answer is, of course, simple .htaccess files to protect these sites – which brings us back to the identity management problem. Can’t anything be simple?

Of course it can! Enter the Authenticating Reverse Proxy and Keycloak. An authenticating reverse proxy sits in front of your site, and only allows traffic through if it has been authenticated.

Keycloak is an Open Source Identity and Access Management solution. Combing these two technologies gives you an easy mechanism to add authentication to any web-based application.

Keycloak

Keycloak is an open source Identity and Access Management solution. It makes it easy to secure applications and services with little to no code. Keycloak handles user identities, user federation, identity brokering and social login.

Users authenticate with Keycloak, rather than with individual services. This means that each service you provide doesn’t have to manage users. Once a user signs-on with Keycloak, they don’t need to authenticate again to access other services.

In addition to providing the infrastructure required for Single Sign-On (SSO), Keycloak also provides an advanced admin UI, so you can easily manage your users without complicated CLIs or manually editing configuration files.

Through identity brokering and social login, users can login to your Keycloak service with their existing identities (such as Google, Facebook, GitHub, etc…). Through user federation, Keycloack can be integrated with existing LDAP or Active Directory servers. You can even implement your own provider if you have an existing relational database, for example.

In addition to user management, Keycloak can also act as an authentication endpoint. Keycloak implements many standard protocols such as OAuth2 and OpenID Connect. Several client adapters are also available, so integrating your existing services (such as a local Jenkins instance), or a custom service (such as a Java application) is easy.

Finally, Keycloak supports UI theming, so you can easily roll out a highly customized authentication portal as unique as you are. If you need authentication in your application or organization, take a look at Keycloak.

Authenticating Reverse Proxy

reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. The resources from these servers are returned to the client as if they originate from the Web server itself.

An authenticating reverse proxy is a reverse proxy that only retrieves the resources on behalf of a client if the client has been authenticated. If a client is not authenticated they can be redirected to a login page.

By structuring your system this way, you can put all your sensitive material on the internal web server, and protect everything through an authenticating reverse proxy. For even more security, the internal web server could be placed on a private Virtual Private Cloud, with absolutely no access from the outside, except through the proxy.

Lua-Resty-OpenIDC

To integrate Keycloak and an Authenticating Reverse Proxy, we used lua-resty-openidc.  Lua Resty OpenIDC is a library for OpenResty, a web-server based on Nginx. OpenResty describes itself as a web platform that integrates the standard Nginx core, LuaJIT and many Lua libraries and high-quality 3rd-party Nginx modules.

It is designed to help developers easily build scalable web applications, web services, and dynamic web gateways. Lua Resty OpenIDC implements the OpenID Connect Relying Party (RP) and the OAuth 2.0 Resource Server (RS) functionality.

To help you get started, I’ve created a simple Dockerfile that can be used to build a container with OpenResty, lua-resty-openidc and the required dependencies.

FROM openresty/openresty:alpine-fat

RUN mkdir /var/log/nginx

RUN apk add --no-cache openssl-dev
RUN apk add --no-cache git
RUN apk add --no-cache gcc
RUN luarocks install lua-resty-openidc

ENTRYPOINT ["/usr/local/openresty/nginx/sbin/nginx", "-g", "daemon off;"]

Build a docker container using this Dockerfile using: docker build -t authproxy . This will create a container called authproxy. You can start this proxy will an appropriate Nginx configuration. I used the following Nginx configuration file to configure lua-resty-openidc to integrate with Keycloak.

worker_processes auto; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid;

Load dynamic modules. See /usr/share/doc/nginx/README.dynamic

include /usr/share/nginx/modules/\*.conf;

events {
    worker\_connections 1024;
}

http {
   lua\_package\_path '/usr/local/openresty/lualib/?.lua;;';
   resolver 8.8.8.8;
   include /etc/nginx/conf.d/\*.conf;

## cache for discovery metadata documents

   lua\_shared\_dict discovery 1m;

## cache for JWKs

   lua\_shared\_dict jwks 1m;

   index   index.html index.htm;

   server {
        listen       80 default\_server;
        listen       \[::\]:80 default\_server;
        root         /usr/share/nginx/html;

        access\_by\_lua '
          local opts = {
            redirect\_uri\_path = "/",
            discovery = "https://keycloak\_server/auth/realms/master/.well-known/openid-configuration",
            client\_id = "clientID",
            client\_secret = "clientSecret",
            redirect\_uri\_scheme = "https",
            logout\_path = "/logout",
            redirect\_after\_logout\_uri = "https://keycloak\_server/auth/realms/master/protocol/openid-connect/logout?redirect\_uri=http%3A%2F%2Fianbull.com",
            redirect\_after\_logout\_with\_id\_token\_hint = false,
            session\_contents = {id\_token=true}
          }
          -- call introspect for OAuth 2.0 Bearer Access Token validation
          local res, err = require("resty.openidc").authenticate(opts)

          if err then
            ngx.status = 403
            ngx.say(err)
            ngx.exit(ngx.HTTP\_FORBIDDEN)
          end
       ';

       # I disbled caching so the browser won't cache the site.
       expires           0;
       add\_header        Cache-Control private;

       location / {
       }

       # redirect server error pages to the static page /40x.html
       #
       error\_page 404 /404.html;
           location = /40x.html {
       }
       # redirect server error pages to the static page /50x.html
       #
       error\_page 500 502 503 504 /50x.html;
           location = /50x.html {
       }
   }
}

You can now start your docker container, and volume mount the directory containing this configuration file. I put it in my current directory and used the following command to start the container. I also mounted the current directory under /usr/share/nginx/html so any html files in the current directory will be hosted behind the authenticating proxy. Finally, I mapped port 80 on the host to port 80 in the container.

docker run -d -it -p 80:80 -v $PWD/:/config -v /:/usr/share/nginx/html authproxy -c /config/nginx.conf

Conclusion

Protecting a site using an authenticating reverse proxy is very easy with Keycloak. Keycloak provides you with all the identity and access management tools you need, and the lua-resty-openidc library can be used to configure the proxy.

For more information about the tools and technologies we use internally at EclipseSource, follow me on twitter.

Ian Bull

Ian Bull

Ian is an Eclipse committer and EclipseSource Distinguished Engineer with a passion for developer productivity.

He leads the J2V8 project and has served on several …