Thursday, March 23, 2017

Oracle Cloud - Architecture Blueprint - microservices transport protocol encryption

The default way microservices communicate with each other is based upon the http protocol. When one microservice needs to call another microservice it will initiate a service call based upon a HTTP request. The HTTP request can be all of the standard methods defined in the HTTP standard such as GET, POST and PUT. In effect this is a good mechanism and enables you to use all of the standards defined within HTTP. The main issue with HTTP is that it is clear text and by default will not have encryption enabled.

The reality one has to deal with is that the number of instances of microservices can be enormous and the possible connections can be enormous in a complex landscape. This also means that each possible path, each network connection can be a potentially be intercepted. Having no HTTPS SSL encryption implemented makes intercepting network traffic much more easy.



It is a best practice to ensure all of your connections are by default enabled, to do so it will be needed to make use of HTTPS instead of HTTP. Building your microservices deployment to only work with HTTPS and not with HTTP bring in a couple of additional challenges.

The challenge of scaling environments
In a microservices oriented deployment containers or virtual machines that provide instances of a microservice will be provisioned and de-provisioned in a matter of seconds. The issue that comes with this in relation to using HTTPS instead of HTTP is that you want to ensure that all HTTPS connections between the systems are baed upon valid certificates which are being created and controlled by a central certificate authority.

Even though it is a possibility that you have each service that is provisioned generate and sign its own certificate this is not advisable. using self signed certificates is considered in general as a not secure way of doing things. Most standard implementations of negotiating encryption between two parties do not see a self-signed certificate as a valid level of security. Even though you can force your code to accept a self-signed certificate and make it work you will be able to ensure encryption on the protocol level is negotiated and used, however, you will not be able to fully be assured that the other party is not a malicious node owned by an intruder.

To ensure that all instances can verify that the other instance they call is indeed a trusted party and to ensure that encryption is used in the manner it is intended you will have to make use of a certificate authority. A certificate authority is a central "bookkeeper" that will provide certificates to parties needing one and the certificate authority will provide the means to verify that a certificate that is offered during encryption negotiation is indeed a valid certificate and belongs to the instance that provides this certificate.

The main issue with using a certificate authority to provide signed certificates is that you will have to ensure that you have a certificate authority service in your landscape capable of generating and providing new certificates directly when this is needed.

In general, as we look at the common way certificates are signed and handed out, it is a tiresome process which might involve third parties and/or manual processing. Within a environment where signed certificates are needed directly and on the fly this is not a real option. This means, requesting signed certificates from the certificate authority needs to be direct and preferably based upon a REST API.

Certificate authority as a service
When designing your microservices deployment while making use of HTTPS and certificates signed by a certificate authority you will need to have the certificate authority as a service. The certificate authority as a service should enable services to request a new certificate when they are initialized. A slightly other alternative is that your orchestration tooling is requesting the certificate on behalf of the service that needs to be provisioned and provides the certificate during the provisioning phase.

In both cases you will need to have the option to request a new certificate, or request a certificate revocation when the service is terminated, via a REST API.

The below diagram shows on a high level the implementation of a certification authority as a service which enables (in this example) a service instance to request a signed certificate to be used to ensure the proper way of initiating HTTPS connections with assured protocol level encryption.


To ensure a decoupling between the microservices and the certificate authority we do not allow direct interaction between the microservice instances and the certificate authority. From a security point of view and a decoupling and compartmentalizing point of view this is a good practice and adds additional layers of security within the overall footprint.

When a new instance of a microservice is being initialized, this can be as a docker container in the Oracle Container Cloud Service or this can be as a virtual machine instance in the Oracle Compute Cloud Service, the initialization will request the certificate microservice for a new and signed certificate.

The certificate microservice will request a new certificate by calling the certificate authority server REST API on behalf of the initiating microservice. The answer provided back by the certificate authority is passed through by the certificate microservice towards the requesting party. In addition to, just being a proxy, it is good practice to ensure you certificate microservice will do a number of additional verification to see if the requesting party is authorized to request a certificate and to ensure the right level of auditing and logging is done to provide a audit trail.

Giving the CA a REST API
When exploring certificate authority implementations and solutions it will become apparent that they have been developed, in general, without the need for a REST API in mind. As the concept of the certificate authority is already in place long before microservice concepts came into play you will find that the integration options are not that well available.

An exception to this is the CFSSL, CloudFlare Secure Socket Layer, project on Github. The CFSSL project provides an opensource and free PKI toolkit which provides a full set of rich REST API's to undertake all required actions in a controlled manner.

As an example, the creation of a new certificate can be done by sending a JSON payload to the CFSSL REST API, the return message will consist out of a JSON file which contains the cryptographic materials needed to ensure the requesting party can enable HTTPS. Below you will notice the JSON payload you can send to the REST API. This is a specific request for a certificate for the ms001253 instance located in the Oracle Compute Cloud Service.

{
 "request": {
  "CN": "ms001253.compute-acme.oraclecloud.internal",
  "hosts": ["ms001253.compute-acme.oraclecloud.internal"],
  "key": {
   "algo": "rsa",
   "size": 2048
  },
  "names": [{
   "C": "NL",
   "ST": "North-Holland",
   "L": "Amsterdam",
   "O": "ACME Inc."
  }]
 }
}

As a result you will be given back a JSON payload containing all the required information. Due to the way CFSSL is build you will have the response almost instantly. The combiantion of having the option to request a certificate via a call to a REST API and getting the result back directly makes it very usable for cloud implementations where you scale the number of instances (VM's, containers,..) up or down all the time.

{
 "errors": [],
 "messages": [],
 "result": {
  "certificate": "-----BEGIN CERTIFICATE-----\nMIIDRzCCAjGgAwIBAg2 --SNIP-- 74m1d6\n-----END CERTIFICATE-----\n",
  "certificate_request": "-----BEGIN CERTIFICATE REQUEST-----\nMIj --SNIP-- BqMtkb\n-----END CERTIFICATE REQUEST-----\n",
  "private_key": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIJfVVIvN --SNIP-- hYYg==\n-----END EC PRIVATE KEY-----\n",
  "sums": {
   "certificate": {
    "md5": "E9308D1892F1B77E6721EA2F79C026BE",
    "sha-1": "4640E6DEC2C40B74F46C409C1D31928EE0073D25"
   },
   "certificate_request": {
    "md5": "AA924136405006E36CEE39FED9CBA5D7",
    "sha-1": "DF955A43DF669D38E07BF0479789D13881DC9024"
   }
  }
 },
 "success": true
}

The API endpoint for creating a new certificate will be /api/v1/cfssl/newcert however CFSSL provides a lot more API calls to undertake a number of actions. One of the reasons the implementation of the intermediate microservice is that it can ensure that clients cannot initiate some of those API calls whithout having the need to change the way CFSSL is build.

The below overview shows the main API endpoints that are provided by CFSSL. A full set of documentation on the endpoints can be found in the CFSSL documentation on Github.

  • /api/v1/cfssl/authsign
  • /api/v1/cfssl/bundle
  • /api/v1/cfssl/certinfo
  • /api/v1/cfssl/crl
  • /api/v1/cfssl/info
  • /api/v1/cfssl/init_ca
  • /api/v1/cfssl/newcert
  • /api/v1/cfssl/newkey
  • /api/v1/cfssl/revoke
  • /api/v1/cfssl/scan
  • /api/v1/cfssl/scaninfo
  • /api/v1/cfssl/sign


Certificate verification
One of the main reasons we stated one should ensure that you do not use self-signed certificates and why you should use certificates from a certificate authority is that you want to have the option of verification.

When conducting a verification of a certificate, checking if the certificate is indeed valid and by doing so getting an additional level of trust you will have to verify the certificate received from the other party with the certificate authority. This is done based upon OCSP or Online Certificate Status Protocol. A simple high level example of this is shown in the below diagram;

Within the high level diagram as shown above you can see that:

  • A service will request a certificate from the certificate microservice during the initialization phase
  • The certificate microservice requests a ceretificate on behalf at the certificate authority
  • The certificate authority sends the certificate back to the certificate microservice after which it is send to the requesting party
  • The requesting party uses the response to include the certificate in the configuration to allow HTTPS traffic


As soon as the instance is up and running it is eligible to receive requests from other services. As an example; if example service 0 would call example service 2 the first response during encryption negotiation would be that example service 2 sends back a certificate. If you have a OCSP responder in your network example service 1 can contact the OCSP responder check the validity of the certificate received from example service 2. If the response indicates that the certificate is valid one can assume that a secured connection can be made and the other party can be trusted

Conclusion
implementing and enforcing that only encrypted connections are used between services is a good practice and should be on the top of your list when desiging your microservices based solution. One should include this int he first stage and within the core of the architecture. Trying to implement a core security functionality at a later stage is commonly a cumbersome task.

Ensuring you have all the right tools and services in place to ensure you can easily scale up and down while using certificates is something that is vital to be successful.

Even though it might sounds relative easy to ensure https is used everywhere and in the right manner it will require effort to ensure it is done in the right way and it will become and asset and not a liability.

When done right it a ideal addition to a set of design decisions for ensuring a higher level of security in microservice based deployments.

No comments: