Secure backend with the Tribestream API Gateway

Introduction

Time

12 minutes

Learning objectives

  • Secure the access to multiple backend microservices.

  • Understand the difference between user (people) and client (software) accounts.

  • Decouple one application into 2 microservices.

  • How Security Profiles, API connections, User Accounts, Client Accounts and Routes work together.

Prerequisites

  • Docker installed and the daemon is running on your computer.

  • Git command line tool.

  • This is an advanced guide. It’s helpful if you have seen already the following guides:

    • Quickstart

    • Secure Microservices with OAuth 2.0 & JWT

    • Route Services with mod_rewrite

The Architecture

We have one important requirement: All HTTP requests must be authenticated.

This means the HTTP requests for both the frontend users and the backend services will be authenticated.

We are using 2 backend services to demonstrate how the calls between them should be setup.

Why backend authentication?

A significant number of organizations simply assume the intranet where the backend services are running is secure. With that in mind, they usually don’t require authentication between services. Services can call each other without limitations.

What if someone gains access to that intranet and is able to query all the REST APIs without limitations? There are a few famous data breaches that were performed by employees or contractors.

What about IP whitelisting? Someone from the outside, exploiting a vulnerability, can gain access to a trusted machine, leading also to data breaches.

no backend security
Figure 1. No Backend Authentication

In parallel to these attack vectors, as organizations grow, and you keep increasing the number of services and developer teams, you will want to keep an eye on how’s executing which services and why. You want to keep track on who’s generating more load and even disable a particular service.

In this guide we assume the organization isolates all the services. All requests must go trough the API gateway. There is merit in centralising credentials management. Imagine what you have an environment with 10 microservices and you add a new one used by half of them…​ You need to propagate your credentials through 5 different teams. The more people have access to the credentials, the higher the chance of a breach.

To each service, two sets of credentials will be given:

  • Inbound credentials for the received requests.

  • Outbound credentials for all requests that service needs to perform.

No one, apart from the TAG and a particular service, will know the credentials. If at some point a misbehaved microservice needs to be isolated by the support team, because it has a bug doing calls in a loop, you can immediately disable its credentials.

To wrap it up, we need backend authentication because:

  • The intranet is not that secure.

  • HTTP requests can only bee processed from authenticated sources.

  • We can revoke access to misbehaved microservices at any time.

Our setup

Remember the Movie application from previous guides? It turns out we were asked to split it…​ For some super clever reason we had to extract the ratings into a separated microservice.

Now we have the movie-back and the ratings-app microservices. The movie-back will need, from now on, to do an HTTP request to the ratings-app to know the rating of each movie.

Frontend users will still see it as movie and will need to use OAuth 2.0 authentication.

The requests are then forward to the movie-back microservice using Basic authentication. In order to call the ratings_app we also need to use Basic authentication, and remember, ony the TAG knows the credentials of all the microservices.

architecture
Figure 2. Our Architecture

An additional architectural advantage of having the TAG, but we are not showing today is that the endpoints are normalised and resilient to changes. The endpoints of the microservices themselves can change without impacting who’s using them.

Much more

In this case we are using Basic authentication without HTTPS. Don’t do that in production.

Basic authentication cannot prevent replay attacks.

Ideally, the backed requests should be secured using HTTP Signatures. We are not doing in this guide to keep the client applications simpler. If you haven’t seen it yet, take a look at the HTTP Signatures guide.

Code changes

We renamed the original movie-app to movie-back, for backend. Then we extracted the ratings logic into a new microservice having it’s own REST API, with one endpoint published at:

CXF HTTP Client

In order to do HTTP requests, we had to add a new library to the movie-back pom.xml file:

<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-client</artifactId>
  <version>3.1.13</version>
  <scope>provided</scope>
</dependency>

The requests are made in the MovieBean class:

//Instantiate the client:
private final String ratingsUser = System.getProperty("api.access.user");
private final String ratingsPassword = System.getProperty("api.access.password");

private final WebClient webClient = WebClient.create("http://localhost:8080", ratingsUser, ratingsPassword, null);

/**
 * Get the rating of a movie.
 *
 * @param id the movie ID
 * @return an int between 0 (avoid) to 10 (masterpiece)
 */
private int getRating(final long id) {
    return webClient.reset()
            .path(RATING_PATH, id)
            .get(Integer.class);
}

Because the microservices use TomEE, we can store the client credentials on the system.properties file at tomee/conf:

Activate basic auth on the Microservices

Both microservices use TomEE, for Basic auth we simply need to add a tomcat-users.xml file at tomee/conf:

The Demo

Start the Tribestream API Gateway (TAG)

To start the TAG, execute the following command according to your operating system:

We can reuse the TAG docker container we created from the Tribe quickstart guide. To start TAG execute the following command:

docker start tag

If this is the first time you run TAG, open a terminal execute the following command according to your operating system:

For linux:

docker run --net="host" -de LICENSE=accept --name tag tomitribe/tribestream-api-gateway

For OsX:

docker run -de LICENSE=accept --name tag -p 8080:8080  tomitribe/tribestream-api-gateway

To see the TAG starting process log you can execute the following command:

docker logs -f tag

Open the TAG

Open a browser and navigate to: http://localhost:8080/tag

Login into the TAG dashboard using the following credentials:

  • username:admin

  • password:admin

loginGif
Figure 3. TAG login and dashboard

Start the movie backend microservice

In order to run our demo Microservice we need to open a terminal and execute the following command:

If we already have used the movie-back:

docker start movie-back

For the first time:

docker run -d --net="host" --name movie-back  tomitribedev/movie-back

We can validate that our microservice is up and running by executing the following command:

curl -i http://localhost:9080/movie-back/api/movies

You must get a 401 error for unouthorized.

start the ratings app microservice

In order to run our demo Microservice we need to open a terminal and execute the following command:

If we already have used the ratings-app:

docker start ratings-app

For the first time:

docker run -d -p 9070:9070 --name ratings-app  tomitribedev/ratings-app

We can validate that our microservice is up and running by executing the following command:

curl -i http://localhost:9070/rating-app/api/ratings

You must get a 401 error for unouthorized.

Configure the TAG

We are going to add 2 user accounts, a client account, an OAuth 2.0 security profile, 2 API Connections and 2 routes to our microservices. Please checkout this github project:

git clone https://github.com/tomitribe/demo-secure-backend.git

Change to the demo-secure-backend folder:

cd demo-secure-backend

And execute this script for Linux:

./setup_data_linux.sh

Or this one for OsX or Windows:

./setup_data_osx.sh

The difference relates to how Docker sees the host computer network.

Test request will fail

The base setup assumes you only had the old microservice on, hence, it only has the user’s OAuth profile, the route and its API connection to can the movie-back microservice:

movie back
Figure 4. User Route forwards request to the Movie microservice

Because we now have the rating-app, we need to:

  • Create the new routings-app API Connection

  • Use that API Connection in the new Ratings Route

  • Add a client secret to the movie-backend client account. This will allow the service make calls to the Ratings Route, which is protected with Basic auth

movie backend account
Figure 5. Movie calls the Ratings Route

Add API connection

On the Dashboard, click connections. Then, in the menu, click add API Connection. The modal view will popup:

api connections popup
Figure 6. Add Ratings API Connection

Because of how Docker works the location to insert is different for:

After clicking Save, the details page will be shown and, in the menu, you can add the Basic auth authentication:

api connections menu
Figure 7. The API Connection Menu - Add Basic Auth

A new section will be shown and you can add the necessary credentials to call the ratings-app. They have to match what you put in the tomcat-users.xml of that app: username: rating; password: password.

api connection basic auth
Figure 8. The API Connection Menu - Add Basic Auth

Add new Ratings Route

On the Dashboard, click Routes. Then, in the menu, click add Mod_Rewrite Route. The modal view will popup:

route creation
Figure 9. Add Ratings Route

Add the name and the following rule:

RewriteRule ^/?ratings(.*) %{API:ratings-app}/rating-app/api/ratings$1 [P,NE,auth]

Where %{API:ratings-app} will use the previously created API Connection and the auth flag will open up the section where you can add the Basic profile. This will require all connection to this route to be authenticated with basic auth.

Add movie-backend client secret

We’ve already added the movie cliente account, we just need to add a client secret to it.

User accounts use passwords, software applications use client secrets.

On the Dashboard, click Accounts and on the Movie Client Access client Account:

account menu
Figure 10. Account details menu

The modal will popup:

account add secret
Figure 11. Add client secret

We could also use OAuth 2.0 authentication. That capability if on, but we will not use it in this guide. Save it.

Test the setup

Let’s simulate a user request by using the routes test window. Go to the Dashboard and select Routes. From the list click on the user-route. On the menu, click Test:

test window
Figure 12. Making a test

We use the Resource URL: /movie/movies we add OAuth 2.0 authentication with username: bob; password: superpassword.

When we click test we can see the 200 OK and the movies list shown in the payload section at the bottom.

Stop all

Since both the TAG and the microservice were created with a specific container name, you can now stop both containers, from the command line execute the following command.

Stopping TAG:OAuth 2.0

docker stop tag

Stopping the movie backend microservice:

docker stop movie-back

Stopping the ratings app microservice:

docker stop ratings-app

That’s it

Thanks for reading this guide.