TLS certificates
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.
Client certificates
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. If this CA is used to issue certificates to more than just the services you want to invoke your service, such as if using a public CA, you will also need to configure Client certificate validation. Otherwise, Kalix will trust any client that presents a certificate issued by that CA.
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.
Creating your own CA
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 rootca.acme.org \
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 client.acme.org my-client.crt my-client.key \
--ca my-root-ca.crt --ca-key my-root-ca.key --insecure --no-password
Configuring the CA secret
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
Configuring a route to use the secret
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.
- CLI with command line arguments
-
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
- CLI with a descriptor
-
-
Using either the
kalix route edit
command or updating the route descriptor:host: ecommerce.acme.org tls: clientValidationCa: name: my-root-ca routes: - prefix: / route: service: shopping-cart
-
Testing that the service is secured
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.
Client certificate validation
If you wish to validate more than just that the certificate was signed by your configured CA, and what to validate the identity attached to the certificate, you can do that by specifying assertions to run against the subject of the client certificate. The client certificates subject can either be the Common Name (CN) in the Subject field of the certificate, or a DNS Subject Alternative Name in the certificate.
Configuration client certificate validation can be done either with command line arguments or route descriptors, though route descriptors are a little more powerful:
- CLI with command line arguments
-
If you haven’t yet created your route, then using the
kalix route create
command, you can pass the flag--client-certificate-subject some.client.name
when you create it. Otherwise, you can update it:kalix route update my-route --client-certificate-subject client.acme.org
You can supply multiple
--client-certificate-subject
arguments to match multiple certificate subject names. Additionally, if the argument starts with a, a suffix match will be done, and if it ends with a
, a prefix match will be done. For example:
kalix route update my-route --client-certificate-subject *.acme.org
Will match any subject name under the
acme.org
domain name. - CLI with a descriptor
-
Using either the
kalix route edit
command or updating the route descriptor:host: ecommerce.acme.org tls: clientValidationCa: name: my-root-ca validation: clientCertificate: subjectMatches: - exact: client.acme.org routes: - prefix: / route: service: shopping-cart
Multiple subject matchers can be defined.
hasPrefix
,hasSuffix
andregex
can also be used to match the subject. For example, this will allow any certificate subject name under the domainacme.org
:host: ecommerce.acme.org tls: clientValidationCa: name: my-root-ca validation: clientCertificate: subjectMatches: - hasSuffix: .acme.org routes: - prefix: / route: service: shopping-cart
Custom server certificates
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.
Configuring a TLS secret
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
Configuring a route to use the secret
Now that you’ve created the secret, you can update or create your route to use it:
- CLI with command line arguments
-
If you haven’t yet created your route, then using the
kalix route create
command, you can pass the flag--server-certificate-secret my-tls-cert
when you create it. Otherwise, you can update it:kalix route update my-route --server-certificate-secret my-tls-cert
- CLI with a descriptor
-
Using either the
kalix route edit
command or updating the route descriptor:host: ecommerce.acme.org tls: serverCertificate: name: my-tls-cert routes: - prefix: / route: service: shopping-cart