Open-Sourcing OpenIDC-Proxy
Several years ago, when we started building Firecloud (“an open platform for secure and scalable analysis on the cloud”) we quickly discovered a need for a general purpose authentication and authorization proxy that we could deploy in front of each of our micro services.
Rather than having each of the engineering teams build auth and security features into their respective applications, we wanted to provide those features as a self-contained component that could be deployed along-side each micro service.
The key features we wanted to externalize included:
- Authentication of user requests
- Authorization of user requests based on groups
- Logging requests to an external service
- HTTPS encryption for all requests
Each of our services is deployed as a Docker container. So it made sense to start with Docker as the core technology for this solution. If we could provide a container that offered all of the desired features, we could deploy that in front of each service as a proxy. That way, the micro service doesn’t have to know about SSL or how to authenticate users, for example. Instead, it just receives authenticated, authorized and unencrypted requests from the proxy and processes them.
The proxy is based on the following technologies:
- Docker (containerization)
- Apache HTTPD server (web/proxy server)
- mod_auth_openidc from ZmartZone (authentication)
- mod_authnz_ldap (authorization)
How It Works
The proxy container is deployed as the front-end of the service, with the application container(s) sitting behind it on the back-end. The proxy exposes ports 80 (HTTP) and 443 (HTTPS) and automatically redirects (301 Moved Permanently) any un-encrypted requests to the SSL-encrypted port. None of the back-end application ports are exposed, so the only way to access the application is through the proxy.
Logging
By default, we set the proxy and the application containers to log all their output to syslog. That way, we just need to configure the host to send its logs to an external service (such as Loggly or Stackdriver) and we will successfully capture everything from our service as well as from the host itself. Alternatively, you could use the gcplogs driver to send the container’s output directly to Stackdriver, skipping syslog entirely (but you may want a way to capture host-level logs, depending on where your service is deployed, which is why we currently use syslog).
Authentication
We generally authenticate users via Google, which is well-supported by mod_auth_openidc, but you could also use another service such as Auth0. For endpoints that accept browser-based traffic from actual users, we support the full OpenID Connect flow for authenticating, requesting scopes, and generating access tokens with a clientid and secret. For API endpoints, we support the OAuth 2.0 protocol and accept a Authorization
header with a Bearer token.
Out of the box, a single instance proxy can support three distinct endpoints with three different auth configs, so a common setup is to have:
/
: Unauthenticated users, welcome page/login
: Browser based user logins authenticated via OpenIDC/api
: API traffic authenticated via OAuth2
With custom configs, you can support as many different endpoints with as many different auth configurations as you wish.
Authorization
For authorization, our preference would have been to use Google Groups. However, at the time that the proxy was originally developed, APIs that would have allowed us to build a “mod_auth_googlegroups” plugin were not yet available. Instead, we relied on support for mod_authnz_ldap built into mod_auth_openidc.
We deploy an instance of OpenLDAP as one of the micro services within the larger application. That way, all of the other services can use that LDAP service to do authorization. We populate LDAP groups with the correct membership for various endpoints and then we can control access at proxy based on those groups. If a user doesn’t have access to a URL based on LDAP group membership then their traffic will never reach the back-end services.
If we were building this today, we would either use Google’s new Secure LDAP service, or we would create a Google Groups auth module for Apache based on the hasMember endpoint in the G Suite Admin SDK Members API. Either approach would remove the reliance on the OpenLDAP instance.
Contributors
This project has been the result of work by several different folks in the organization, including but not limited to:
- Andrew Teixeira (@coreone1)
- David Bernick (@dbernick)
- Henry Ferrara (@habynara)
Read more about the proxy on Andrew’s Medium post announcing the public release: “Wrap HTTPS and OAuth around your container”.
Images and Source Code
Source code for the proxy is available on GitHub in two separate repos. There is a base image, that includes Apache with mod_auth_openidc:
and then the proxy image adds in all of the authentication and authorization features on top of that:
Both projects are also available as Docker images from DockerHub or Quay:
For bugs or questions, create GitHub Issues for the appropriate project. Contributions are welcome, so feel free to fork the repos and create pull requests.
Conclusion
After several years of using this technology internally and in the cloud for dozens of different applications, we’re excited to make it available to the community.
If you’re looking for something similar maintained by Google, check out the Extensible Service Proxy.