Archive for May 5, 2016

Efficient Authentication: Configure Oauth2_proxy for Multiple Upstreams

What is Oauth2_proxy?

Authentication is necessary for security. There are some places where you need a username and password to reach. A common solution to this is BasicAuth, which gets the job done, but it is not the most elegant solution. Basicauth is not difficult to implement, but it must be repeated across multiple applications, whereas oauth2_proxy can be set in one place and applied to many applications(upstreams). An upstream is the url a user attempts to reach before getting prompted for authentication with a third party.
Oauth-2 proxy, an open-source reverse proxy by bitly, provides authentication by email, domain or group with a third-party authentication provider, such as Github or Google. It has been programmed with Go. This proxy is a great solution for my company because it helps us to securely manage the authentication of multiple users across multiple applications (upstreams) with a single application. I have recently created a prototype with a Google API, Oauth2_proxy, and Nginx for internal applications used by the product team. It will most likely be scaled up in the future as a Kubernetes cluster.

Assumptions to Get Started

I made all external web traffic come through port 8080 and created an elastic load balancer in Amazon Web Services for HTTPS with a TCP passthrough of 443. Below is an example configuration for your reference:

1. Oauth2_proxy Configuration

Here are the configuration settings for the Oauth_2 proxy, which can be set via the command line.

./oauth2_proxy
--cookie-domain=".internal.example.com" \ 
--upstream="http://localhost:8081"\
--cookie-name="oauth2_proxy" \  
--cookie-secret="<cookie-secret>" \
--client-id="<client-id>.apps.googleusercontent.com" \
--client-secret="<client-secret>" \
--redirect-url="https://auth.internal.example.com/oauth2/callback" \
--email-domain="example.com" \ 
--request-logging=true \ --pass-host-header=true \
--tls-cert="/path/to/my.crt" \
--tls-key="/path/to/my.key" \

2. Nginx Configurations

You need to create serveral files in Nginx to set this up.

Sites-enabled Folder: google-auth

 upstream google-auth {
    least_conn;
    server 127.0.0.1:443;
 }

server {
    rewrite_log on;
    listen *:8080;
    server_name ~^auth.(?<domain>internal.*)$;
    location = /oauth2/callback {
    proxy_pass https://google-auth;
 }
    location ~/(?<sub>[^/]+)(?<remaining_uri>.*)$ {
       rewrite ^ https://$sub.$domain$remaining_uri;
    }
 }

server {
    listen *:8080;
    server_name ~^(.+).internal.*;
    location = /oauth2/start {
    proxy_pass https://google-auth/oauth2/start?rd=%2F$1;
 }
    location / {
       proxy_pass https://google-auth;
       proxy_set_header Host $host;
    }
 }

 Sites-enabled Folder: upstreams

upstream app2 {
    least_conn;
    server <app2 private IP>;
 }

upstream app1 {
    least_conn;
    server <app1 private IP>;
 }

server {
    access_log /var/log/nginx/default.log oauth;
    listen 8081;
    server_name "";
   add_header Content-Type text/plain;
 }
 # app1
 server {
    access_log /var/log/nginx/app1.log oauth;
    listen 8081;
    server_name ftp.internal.*;
    location / {
      proxy_pass http://ftp;
      proxy_redirect off;
    }
 }
 # app2
 server {
    access_log /var/log/nginx/app2.log oauth;
    listen 8081;
    server_name app2.internal.*;
    location / {
       proxy_pass http://app2;
       proxy_redirect off;
    }
 }

Nginx.conf: add this for logging

Because logs make life better 🙂

 rewrite_log on;
 log_format oauth '"[$time_local]" host: "$host" host_header:
   "$http_HOST" server_name: "$server_name" "$request"
   remote address: "$remote_addr" to upstream: "$upstream_addr:"';

Resources:

  • https://github.com/bitly/oauth2_proxy
  • https://golang.org
  • https://nginx.org
  • https://console.developers.google.com