Encrypt Service Traffic with OpenShift CA

Did you know that you can make use of the OpenShift CA to encrypt traffic between services or between a route and the service? I know you think service mesh, but there is also a small-scale solution available if you don’t have a service mesh you can use.

Encrypt Ingress Traffic

So let’s say that you want to deploy a web app, and you need to encrypt the traffic between HAProxy as the route entry point and a web app. Usually, the OpenShift operations team has you covered, and they have configured HAProxy with TLS, so you don’t have to worry about public TLS. But once you are past the route as an entry point to OpenShift, you will get HTTP without TLS.

Default setup with not encrypted cluster internal communication

So let’s see what we can do with standard OpenShift to encrypt the traffic between the route and webapp.

Every OpenShift Container Platform cluster has a service-ca operator. The service-ca operator hosts a self-signed certificate authority, from which you can request private keys and certificates. You can use those to encrypt traffic internal to OpenShift.

To request a certificate and private key for our web application, you need to add the annotation service.beta.openshift.io/serving-cert-secret-name: <secret name> to the service resource:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.openshift.io/serving-cert-secret-name: webapp-tls
  name: webapp
spec:
  selector:
    app: webapp
    # ..

The operator will pick up the annotation and store our service’s TLS private key and certificate in secret webapp-tls. To use the certificate and private key in our pod, we need to mount the secret, and import it into the web application. Please check what you need to do because the steps required depend on your web applications tech stack.

After we have configured the pod, we need to change the route settings. The default configuration of the route is insecure. To encrypt the communication between the route and the pod, we need to set TLS termination to reencrypt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
kind: Route
apiVersion: route.openshift.io/v1
metadata:
  name: webapp
  labels:
    app: webapp
spec:
  to:
    kind: Service
    name: webapp
    weight: 100
  port:
    targetPort: https
  tls:
    termination: reencrypt
  wildcardPolicy: None

With that, we now have two spheres of trust.

  1. The external traffic is encrypted with a certificate issued by a public CA, which the browser trusts.
  2. The internal traffic is encrypted with a certificate issued by the OpenShift internal CA, which the route trusts.
Certificate Chains

You can find a working sample in my GitHub Repository blog-coding-samples .

Certificate Validity

The internal OpenShift CA has a validity of 26 months, and after 13 months, the CA is automatically rotated. To smoothen the CA rollover, the new CA maintains trust in the previous CA. In my experience, the transition period is more than enough so that all pods were restarted and consequently updated their certificates.

Conclusion

The best practice for larger deployments is, in most cases, a service mesh. In this scenario, the sidecar proxy is responsible for encrypting and decrypting the communication. As a result, your application does not have to import a certificate and private keys, making a developer’s life a little easier.

However, internal OpenShift CA provides an entry to encrypting and decrypting the cluster-internal communication for small-scale solutions. OpenShift hides much of the burden to manage your own CA as far as possible. However, please keep in mind that this approach is rather suitable for a small-scale setup.