Securing APIs using sidecar pattern

Bibin Sebastian
4 min readJul 1, 2019

We have an application exposing set of API and we want to make them secure. How do we approach this problem?

Solution

We essentially need to build an auth module to secure the APIs. Straight forward solution to this problem is to build an auth module with in the API app for access control.

But think about it again. Is there a better approach out there?

Going by true “single responsibility principle”, we probably don’t want to keep our auth logic with in the API app as authentication and authorisation are not the core functionality of the API application. We want to clearly separate out the auth logic from API logic.

In the micro-services world, a new approach is to use sidecar pattern. Idea here is to run your auth module in a sidecar container and let your application just focus on the API logic. All the API requests are routed through a sidecar proxy, which uses the auth module to do the access control and then route the requests to the API application only after successful authorisation.

For this example, we will use netflix-zuul as the reverse proxy. Spring cloud makes it easy to embed zuul proxy in your spring boot app. We have coded the auth module with in proxy itself for simplicity (but you have the choice to separate auth module in to a separate app of its own if you want). Auth module here does two things - it generates the access token for the clients and also does the token verification (access control) for the APIs (You can definitely move these into separate apps).

API application runs in a container and our reverse proxy runs as a sidecar in another container. API application ports are not exposed outside, so no one can directly access the APIs from outside. Request to the APIs are routed via the reverse proxy and it does the authorisation check. We use spring-security OAuth 2.0 based authorisation check in the proxy.

Here is the zuul configuration to route the api requests to API app. API app is running on port 8080 on the same machine (localhost/127.0.0.1).

zuul:
sensitiveHeaders: Cookie,Set-Cookie
routes:
api:
path: /api/**
url: http://127.0.0.1:8080/

Both API app and the proxy side car containers are deployed in a Kubernetes pod.

Here is the kubernetes deployment file

apiVersion: v1
kind: Namespace
metadata:
name: my-apps

---
apiVersion: v1
kind: Pod
metadata:
name: api
labels:
app: api
namespace: my-apps
spec:
containers:
- name: api
image: springio/api-app:latest
imagePullPolicy: Never
- name: proxy
image: springio/proxy:latest
imagePullPolicy: Never
ports:
- containerPort: 8081

If you want to see this in action on your local machine, do the below

Install minikube

Refer to https://kubernetes.io/docs/setup/learning-environment/minikube/#installation

start minikube

minikube start

Checkout the code

https://github.com/bibinss/sidecar

This has the API app under ‘api’ folder and proxy app under ‘proxy’ folder.

API app is a simple hello world spring boot app exposing only one ‘/hello’ API endpoint. We want to secure this endpoint using the proxy.

Proxy app is a spring boot application using netflix-zuul proxy.

Build docker image for api application

cd api

eval $(minikube docker-env)

mvn clean package

mvn dockerfile:build

Build docker image for proxy application

cd proxy

eval $(minikube docker-env)

mvn clean package

mvn dockerfile:build

Deploy the docker images in minikube

From the ‘sidecar’ folder run,

kubectl create -f sidecar-deploy.yml

Expose the proxy outside the pod via NodePort

kubectl expose pod api -n my-apps — type=NodePort — port 8081

Go to minikube console and ensure that application containers are deployed properly

minikube dashboard

Get the NodePort exposed IP and Port

minikube service api -n my-apps

This should open a browser window with Nodeport IP and Port

Get the access token

curl -X POST \
http://<IP>:<Port>/oauth/token \
-H ‘Authorization: Basic dGVzdC1jbGllbnQ6Y2xpZW50LXNlY3JldA==’ \
-d ‘grant_type=client_credentials’

dGVzdC1jbGllbnQ6Y2xpZW50LXNlY3JldA== is the base64 encoded client credentials configured in the Auth server (test-client:client-secret)

For example, below shows the how we receive an access token

Invoke the API using the access token

curl -X GET \
http://<IP>:<Port>/api/hello \
-H ‘Accept: application/json, text/plain, */*’ \
-H ‘Authorization: Bearer <Access token>’

Our API ‘api/hello’ returns a JSON response when invoked successfully. See it in action below for a successful invocation

Try to hit the same API without the access token or with a wrong token, you will get an Authorisation error.

--

--