Mesh Workload Certificates with SAN DNS and URI entries#
This section describes the process of having Aspen Mesh Citadel create X.509 certificates for workloads in your service mesh with extensions using SAN DNS names and URIs specified by you.
The default behavior in Aspen Mesh Citadel is to generate workload certificates using SPIFFE URIs as a SAN extension for services within the mesh. However, these do not meet the needs of many enterprise users that are familiar with traditional X.509 certificates with SAN DNS and URI extensions.
For instance, many enterprise customers often have a mixed set of applications scattered across legacy VMs and modernized Kubernetes platforms. Legacy applications on VMs are typically not in the mesh, as adding a sidecar proxy is not always feasible. These users still desire to have encrypted traffic between workloads in the mesh and legacy VM workloads, but their tooling typically does not support nontraditional X.509 certificates.
Setup#
Make sure to install Citadel before following this guide.
Tip
Checking URIs is done using Go url.Parse(). Use the Go playground to test any URIs.
Behavior#
Aspen Mesh Citadel creates X.509 certificates with SAN DNS and URI entries for workloads based on annotations added in service accounts:
Case 1: If the service account associated with a deployment contains the
certificate.aspenmesh.io/customFieldsannotation, for example:apiVersion: v1 kind: ServiceAccount metadata: name: SERVICE_ACCOUNT_NAME annotations: "certificate.aspenmesh.io/customFields": '{ "SAN": { "DNS": [ "YOUR_DOMAIN_HERE" ], "URI": [ "YOUR_URI_HERE" ] } }'
Then the workload certificate will contain an X.509 extension with a SAN DNS name of
YOUR_DOMAIN_HEREand a SAN URI ofYOUR_URI_HERE.Case 2: If the service account associated with a deployment does not contain the
certificate.aspenmesh.io/customFieldsannotation, the workload certificate will have an extension containing a SAN DNS entry forSERVICE_ACCOUNT_NAME.<service account namespace>.svc.cluster.local.Case 3: If no service account is associated with the deployment, the name of the default service account is used. This will create a certificate with a SAN DNS entry for
DNS: default.<namespace>.svc.cluster.local.
Note
You can specify multiple DNS and URI entries in the annotations above.
When upgrading, until the existing certificates are rotated, they won’t be updated to have the extension for SAN DNS and URI entries. If you wish to have default SAN DNS entries (case 2) you must restart the associated pods associated with the service account.
These generated certificates can be used with Aspen Mesh gateways as described in this guide.
Example deployment#
Here we will deploy a copy of httpbin from the samples directory in the Aspen Mesh install and inspect the certificate generated from its service account. These steps assume that Aspen Mesh has been installed into the cluster
and that the current directory is the Aspen Mesh release directory.
Enable automatic sidecar injection in the default namespace:
$ kubectl label namespace default istio-injection=enabled
Deploy the
httpbinsample application:$ kubectl apply -f samples/httpbin/httpbin.yaml
Store the
httpbinpod name as a variable:$ export HTTPBIN_POD=$(kubectl get pod -l app=httpbin -o jsonpath='{.items[0].metadata.name}')
Verify that the certificate has only an extension for a SPIFFE URI:
$ istioctl proxy-config secret $HTTPBIN_POD -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
Output:
Certificate: Data: ... X509v3 Subject Alternative Name: critical URI:spiffe://cluster.local/ns/default/sa/httpbin
Open your Aspen Mesh override values file (for example,
aspen-mesh-override-values.yaml) in a text editor.To enable the SAN DNS and URI extensions, copy the following information and paste it into the file:
global: certificateCustomFields: true
Save and close the file.
Deploy the new value to the cluster via a Helm upgrade:
$ helm upgrade istiod manifests/charts/istio-control/istio-discovery \ --namespace=istio-system \ --values <aspenMeshOverrideValuesFilename>
Make a copy of
httpbin.yamlnamedhttpbin-san-dns.yamlin the current directory:$ cp samples/httpbin/httpbin.yaml httpbin-san-dns.yaml
Open
httpbin-san-dns.yamlin a text editor.Add the
certificate.aspenmesh.io/customFieldsannotation:apiVersion: v1 kind: ServiceAccount metadata: name: httpbin annotations: "certificate.aspenmesh.io/customFields": '{ "SAN": { "DNS": [ "test.example.com", "httpbin.example.com" ], "URI": [ "com.example.uuid:cc1bf660-9e35-4169-9bbf-2a893ea2fa5d", "http://test.example.com/get" ] } }'
Save and close the file.
Apply the
httpbin-san-dns.yamlfile:$ kubectl apply -f httpbin-san-dns.yaml
Delete the
httpbinpod to get a new certificate for the workload:$ kubectl delete pod -l app=httpbin
Store the new
httpbinpod name as a variable:$ export HTTPBIN_POD=$(kubectl get pod -l app=httpbin -o jsonpath='{.items[0].metadata.name}')
Verify that the certificate now includes the specified SAN DNS and URI extensions:
$ istioctl proxy-config secret $HTTPBIN_POD -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
Output:
Certificate: Data: ... X509v3 Subject Alternative Name: critical DNS:httpbin.example.com, URI:spiffe://cluster.local/ns/default/sa/httpbin, DNS:test.example.com, URI:com.example.uuid:cc1bf660-9e35-4169-9bbf-2a893ea2fa5d, URI:http://test.example.com/get