Skip to content

jeroenr/api-gateway

Repository files navigation

Api Gateway Build Status License

The Api Gateway is the entry point of a microservice infrastructure (see api gateway pattern). The main problem it solves is "How do the clients of a Microservices-based application access the individual services?". It handles the first layer of authentication and routes the incoming requests (like a reverse proxy) to the corresponding service, based on the mapping in its service registry.

Contributions

This is a young but very active project and absolutely needs your help. Good ways to contribute include:

  • Raising bugs and feature requests
  • Fixing bugs
  • Improving the performance
  • Adding to the documentation

Requirements

  • Sbt 0.13.*

Running

$ sbt run

By default this will start the gateway interface on https://localhost:8080/api and the management interface on https://localhost:8081

Configuration

Most of the configurable options are available as environment variables. Below is a list with default values:

  • API_PREFIX=api
  • AUTH_HOST=localhost
  • AUTH_PORT=7070
  • K8S_API_HOST=localhost
  • K8S_API_PORT=8001
  • K8S_API_TOKEN=

For a Kubernetes configuration example see the sample descriptor file.

Pulling the docker image

$ docker pull jeroenrosenberg/api-gateway

Building a docker image

This project is using the Docker plugin of the Sbt Native Packager to generate a docker image using:

$ sbt docker:publishLocal

Then you can simply publish your docker image to your favorite docker repository. For instance for the Google Container Registry:

$ docker tag com.github.jeroenr/api-gateway eu.gcr.io/my-docker-registry/api-gateway
$ gcloud docker push eu.gcr.io/my-docker-registry/api-gateway

Deploying in Kubernetes

Since the Api gateway currently relies on the Kubernetes API for service discovery the first thing we would need is an access token. The easiest way to do this would be through service accounts. After that you need descriptor files for the Kubernetes deployment and service. Below is a quick walkthrough the steps. I assume you're familiar with Kubernetes' terminology and the kubectl commandline tool.

Create service account

The steps below will create a service account and associated secret to be used by the Api gateway pod.

$ kubectl create serviceaccount my-service-account
serviceaccount "my-service-account" created

Great, now a new service account has been created and under the hood also an associated secret which we can retrieve by:

$ kubectl get serviceaccounts my-service-account -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  # ...
secrets:
- name: my-service-account-token-1yvwg

As you can see in our example the generated secret is called "my-service-account-token-1yvwg". Depending on where you pull your docker image from you might also need to create another secret with credentials for the docker registry to be used as an image pull secret.

Now we can setup our K8s deployment and service descriptor. Here's an example config. Important to configure is:

  • The container image path (e.g. eu.gcr.io/my-docker-registry/api-gateway)
  • The image pull secret for the container registry (e.g. my-docker-registry-secret)
  • The secretKeyRef.name for the K8S_API_TOKEN env variable (e.g. my-service-account-token-1yvwg)
  • The AUTH_HOST and AUTH_PORT env variables to point to your backing authentication service

As a final step we can now create the k8s deployment and service:

$ kubectl apply -f k8s-descriptor.yaml
deployment "api-gateway" created
service "api-gateway-svc" created

Cool, now we're running the Api gateway in Kubernetes!

Deploying on other platforms

Currently the Api gateway relies on the services endpoint from the Kubernetes API to poll for service updates (see Automatic Service discovery section). If you want to deploy the Api gateway on a different platform you would have to:

  • Mock this endpoint and manually update the service registry (see (#manually-updating-the-service-registry). You could also rely on something like Consul and write a sync script.
  • Make a PR to add a flag in the configuration to disable automatic service discovery
  • Make a PR to support different pluggable service discovery modules
  • The k8s namespaces to watch for service updates. This can be configured through JVM params (e.g. -Dintegration.kubernetes.namespaces.0=my-env to only handle service updates on the 'my-env' namespace)

Features

Authentication

As mentioned the Api gateway is the first layer of the authentication flow. If a request is made to a secured route (i.e. a route which maps to a service with the flag "secured" set) it will request a JWT access token from an authentication service (e.g. https://github.com/cupenya/auth-service which retrieves a user claim based on a reference token in a domain cookie and generates a JWT token for this claim). If a valid JWT token is returned the call is forwarded to the corresponding service and the JWT token is passed in the request header as an Oauth bearer token for further authorization to be done by the backing service.

If no valid JWT token is returned the error response will be forwarded to the caller. This could happen when for instance the user session has expired. The user could then "login" again using the "/auth/login" endpoint as follows:

$ curl -X POST \
  https://localhost:8080/auth/login \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json'
  -d '{
    "username": "my-user",
    "password": "my-pass"
}'

This call is just forwarded to the authentication service.

Here's a Postman collection with all available Api calls

Automatic Service discovery

The Api gateway supports service discovery through the Kubernetes API using the k8s-svc-discovery module. It's polling the /api/v1/services endpoint for service and updates the routing / mapping based on the service metadata.

Manually updating the service registry

There's also a dashboard Api which can be used to manually update the service registry. For instance to add a service:

$ curl -X POST \
  https://localhost:8081/services \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json'
  -d '{
	"name": "my-user-service",
	"host": "localhost",
	"resource": "users",
	"port": 9090,
	"secured": false
}'

This will add a reverse proxy mapping from https://{api-gateway-host}:{api-gateway-port}/{api-gateway-prefix}/users to https://localhost:9090/users. If no 'port' is specified it will default to 80. The flag 'secured' determines whether the Api gateway performs authentication checks and passes on the authentication info to the corresponding service. See Authentication section for more information.

Here's a Postman collection with all available Api calls