When Kalix services are exposed to the internet using routes, all requests are served using Transport Layer Security (TLS). By default Kalix will automatically provision a server certificate for you using Let’s Encrypt.
Using TLS ensures that a client can trust that the server they are connecting to is the server that they intended to connect to, and ensures that the connection is encrypted and can’t be tampered with. However, the default configuration doesn’t offer the server any guarantees about the identity of the client. By default, anyone on the internet can connect to your exposed services.
Kalix offers the ability to require clients to supply a valid certificate, as well as the ability to use a custom server provisioned certificate, rather than a certificate automatically provisioned by Let’s Encrypt.
Kalix’s client certificate support, also known as Mutual TLS (mTLS) support, allows you to configure routes to require a client certificate. The supplied certificates will be validated using a trusted Certificate Authority that you supply.
Client certificates allow you to control who can connect to your services, by requiring all clients to present a certificate when they connect. This is a very course grained level of authentication, and is ideal for situations where you only want your service to be accessible to other services that you control.
To enable this, you will need a Certificate Authority (CA) that is capable of issuing client certificates to the clients that you want to consume your Kalix services. Kalix will trust any client certificates issued by that CA, so it’s important to only issue certificates to people or services that you trust.
Many organisations will already have a CA that they can use for this, perhaps using products like HashiCorp Vault or Kubernetes cert-manager. If you already have a way of issuing client certificates from a CA, then to enable this feature, you just need that CA’s certificate, and you can skip the next step.
If you don’t have a mechanism for issuing client certificates with a CA, this guide will walk you through the process. We will use the smallstep CLI, a tool that makes it very easy.
First you will need to install the CLI using the instructions linked above.
Then we’ll create a CA certificate and key:
step certificate create --profile root-ca "My Root CA" \ my-root-ca.crt my-root-ca.key --insecure --no-password
Now that we have the CA, we’ll also create a client certificate. We don’t actually need this to configure the client certificate support in Kalix. Only the CA certificate is needed for that. The client certificate will be used by our client when we try to connect to the service:
step certificate create "My Client" my-client.crt my-client.key \ --ca my-root-ca.crt --ca-key my-root-ca.key --insecure --no-password
Now that we have a CA certificate, we can configure it as a secret in Kalix. The type of secret we’re creating is called a TLS CA secret:
kalix secret create tls-ca my-root-ca --cert ./my-root-ca.crt
We now need to configure a route to use a secret. Routes can be created by following the instructions in exposing services to the internet. If you haven’t yet created your route, then using the
kalix route create command, you can pass the flag
--client-ca-secret my-root-ca when you create it. Otherwise, you can update it:
kalix route update my-route --client-ca-secret my-root-ca
Your service should now be secured. You can test that it’s secured using curl. Let’s say the URL that your service is exposed on is
spring-tooth-3406.us-east1.kalix.app. Try issuing a simple curl request on it:
$ curl https://spring-tooth-3406.us-east1.kalix.app -I curl: (56) OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
You can see that curl is reporting that a certificate is required to connect to this service. Now if you have a client certificate issued by the CA handy, like the one created above using smallstep, you can try the same request with the client certificate:
$ curl https://spring-tooth-3406.us-east1.kalix.app -I --key my-client.key --cert my-client.crt HTTP/2 404 content-length: 0 date: Wed, 10 Nov 2021 05:00:59 GMT server: envoy x-envoy-upstream-service-time: 19
Unless you have defined HTTP transcoding rules for the root path, your service is expected to respond with 404, as shown above. This verifies that the client certificate was accepted and the service is secured.
There may be multiple reasons why you don’t want to use the TLS certificates automatically provisioned by Let’s Encrypt:
The domain you want to provision the certificates at has a Certification Authority Authorization (CAA) policy configured in DNS, which does not permit Let’s Encrypt to provision certificates for hostnames at it’s domain, and you don’t want to or can’t change this policy.
You want to use certificates that are not publicly trusted, but rather are explicitly configured in your client and server.
To configure a custom server TLS secret, you will need the key and certificate for the servers hostname in unencrypted PEM format. Once that has been provisioned, create it by running:
kalix secret create tls my-tls-cert --key ./my-key.pem --cert ./my-cert.pem