IBM Bluemix, based on Cloud Foundry, makes it easy to host applications “in the Cloud”. At first glance creating a number of small RESTful services and aggregating them on the client (either browser or mobile native) seems too trivial to even mention. However, when you proceed beyond the trivial examples and think of concerns an enterprise will encounter, things are less obvious.
Let’s start with looking under the covers of how a request to a Bluemix hosted application is processed.
This diagram depicts two inbound paths. The bottom is the typical flow of a request through to a Bluemix hosted application. As you can see HTTP and HTTPS requests can be made to the public route assigned to the app. However all SSL is terminated at the security gateway before being passed into Cloud Foundry (CF). As a result the application itself will only ever see unencrypted HTTP traffic. Since CF apps may only ever have a single port assigned the application process must run an HTTP listener. Instead if it runs a HTTPS listener the application will never successfully complete an SSL handshake since SSL has already been terminated upstream. However, while the application only sees HTTP traffic, the security gateway does send an X-Forwarded-Proto header. The value of this header (http|https) will indicate the original protocol of the client request. This way the application may decide to return a redirect the client to force HTTPS if it sees that the client initially made an unencrypted request.
- Provides a universally trusted server certificate for HTTPS clients without the expense of purchasing your own certificate (applying your own certificate and domain is supported).
- Applications simply handle HTTP traffic and do not need to handle multiple inbound ports or manage their own server certificates.
- Between the point of SSL termination and your application, network traffic is in the clear in a multi-tenant environment.
- Mutual SSL authentication (client certificates) between a client and the CF application is not possible.
- All CF routes are public. Due to the design of Cloud Foundry it is not possible to provide a private HTTP/S application only reachable by your own applications (say scoped to your Organization or Space). To receive HTTP/S traffic the application will always be publicly reachable.
All of these problems can be overcome if the application is packaged as a Docker image and deployed as a single IBM Container. In the diagram above the top path depicts the request traffic to a single container. As you can see that traffic is not SSL terminated, nor is it subject to the Cloud Foundry router. However single container instances are playthings and should never be seriously considered for any kind of production scenarios. This is because they are essentially unmanaged. Unlike CF apps, there is no Health Manager to look after them or log aggregator to collect status, nor is there any out of the box means to scale. Furthermore service discovery is awkward since a zero-runtime “bridge app” is required to convey the VCAP_SERVICES details into the container environment. In short you end up having to build out this supporting infrastructure yourself in a series of single instance containers. Bluemix does this already in Container Groups, but unfortunately a public route is the only way to send requests to the cluster of containers. The request ends up taking the same path to the container group as it would to a CF hosted app, so it too would be subjected to all the cons listed above.
In a simple scenario, each CF app implements a microservice and is assigned a public route. No service has any back-channel communication with other services. In Cloud Foundry each service is hosted on its own subdomain. This means a client would need to connect with multiple subdomains. For browser based clients, CORS would need to be used to overcome the Same Origin Policy (SOP) security restriction.
A more sophisticated example involves service composition. This is where one service requires the capabilities of several other services in order to fulfill its own requirements. In Cloud Foundry this is done through the use of Services. Services are simply applications that implement the CF Service Broker API. As part of that contract each Service must enforce basic authentication.
So while a Service does have a public route assigned, without the basic auth credentials external requests are not processed. Only CF apps that have been bound to the Service have the credentials via VCAP_SERVICES. This allows the Services to expose internal APIs not meant to be consumed by the end-users directly. This configuration represents the intent of how Bluemix/Cloud Foundry is meant to be used. However, it is not without its issues:
- Each “private” microservice is still publicly routable and therefore must be secured against unintended use. By Service Broker contract each Service must implement basic auth, but because of SSL termination credentials will be in the clear before reaching the application.
- Each “private” microservice has the additional burden of implementing the Service Broker REST API. This is so an instance of the Service can be provisioned by Cloud Foundry and bound to an application. It is through binding that service discovery is achieved.
In part 2 I will explore whether non-routable applications can be used to avoid the problems above.
In part 3 I will discuss how the IBM API Management service can be (redundantly!) used to secure your Bluemix hosted microservices.