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/customFields annotation, 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_HERE and a SAN URI of YOUR_URI_HERE.

  • Case 2: If the service account associated with a deployment does not contain the certificate.aspenmesh.io/customFields annotation, the workload certificate will have an extension containing a SAN DNS entry for SERVICE_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.

Note

This section assumes yq and jq are installed.

  1. Enable automatic sidecar injection in the default namespace:

    $ kubectl label namespace default istio-injection=enabled
    
  2. Deploy the httpbin sample application:

    $ kubectl apply -f samples/httpbin/httpbin.yaml
    
  3. Store the httpbin pod name as a variable:

    $ export HTTPBIN_POD=$(kubectl get pod -l app=httpbin -o jsonpath='{.items[0].metadata.name}')
    
  4. 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
    
  5. Open your Aspen Mesh override values file (for example, aspen-mesh-override-values.yaml) in a text editor.

  6. To enable the SAN DNS and URI extensions, copy the following information and paste it into the file:

    global:
       certificateCustomFields: true
    
  7. Save and close the file.

  8. 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>
    
  9. Make a copy of httpbin.yaml named httpbin-san-dns.yaml in the current directory:

    $ cp samples/httpbin/httpbin.yaml httpbin-san-dns.yaml
    
  10. Open httpbin-san-dns.yaml in a text editor.

  11. Add the certificate.aspenmesh.io/customFields annotation:

    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" ] } }'
    
  12. Save and close the file.

  13. Apply the httpbin-san-dns.yaml file:

    $ kubectl apply -f httpbin-san-dns.yaml
    
  14. Delete the httpbin pod to get a new certificate for the workload:

    $ kubectl delete pod -l app=httpbin
    
  15. Store the new httpbin pod name as a variable:

    $ export HTTPBIN_POD=$(kubectl get pod -l app=httpbin -o jsonpath='{.items[0].metadata.name}')
    
  16. 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