Use a custom Certificate Authority with Istio

This guide demonstrates how to modify the default IstioControlPlane Custom Resource (CR) provided by Streaming Data Manager to provision workload certificates using a custom certificate authority (CA) which integrates with the Kubernetes Certificate Signing Request (CSR) API.

Load the CA’s root certificate

Load the CA’s root certificate into a secret that istiod can access.

$ cat <<EOF > ./external-ca-secret.yaml
  apiVersion: v1
  kind: Secret
  metadata:
    name: external-ca-cert
    namespace: istio-system
  data:
    root-cert.pem: <tls.cert>
  EOF
$ kubectl apply -f external-ca-secret.yaml

Replace <tls.cert> with the CA’s base64 encoded public key (without line wrapping). This step is necessary for Istio to verify that the workload certificates have been signed by the correct certificate authority and to add the root-cert to the trust bundle for mTLS to work.

Modify the IstioControlPlane CR

  1. Add the EXTERNAL_CA and K8S_SIGNER environment variables to the spec.istiod.deployment section of the IstioControlPlane CR. These configure istiod to use an external signer and specify the name of the signer to use.

    apiVersion: servicemesh.cisco.com/v1alpha1
    kind: IstioControlPlane
    metadata:
      name: istio-sample-v115x
      ...
    spec:
      ...
      istiod:
        deployment:
          image: "033498657557.dkr.ecr.us-east-2.amazonaws.com/banzaicloud/istio-pilot:v1.15.3-bzc"
          env:
          # Indicate to Istiod that we use an external signer
          - name: EXTERNAL_CA
            value: ISTIOD_RA_KUBERNETES_API
          # Indicate to Istiod the external K8S Signer Name
          - name: K8S_SIGNER
            value: csr.banzaicloud.io/privateca
      ...
    
  2. Mount an overlay patch to inject the secret created above into Istio. Add this modification to the IstioControlPlane CR:

    k8sResourceOverlays:
    - groupVersionKind:
      group: apps
      kind: Deployment
      version: v1
    objectKey:
      name: istiod-<icp-name>
    patches:
    - parseValue: true
      path: /spec/template/spec/volumes/-
      type: replace
      value: |
        name: external-ca-cert
        secret:
          secretName: external-ca-cert
          optional: true    
    - parseValue: true
      path: /spec/template/spec/containers/name=discovery/volumeMounts/-
      type: replace
      value: |
        name: external-ca-cert
        mountPath: /etc/external-ca-cert
        readOnly: true    
    

    Replace <icp-name> above with the name of the IstioControlPlane CR. For example, if the name field in the IstioControlPlane CR is set to istio-sample-v115x, this should be istiod-istio-sample-v115x.

  3. Patch the istiod ClusterRole to give it permission to approve Certificate Signing Requests with the csr.banzaicloud.io/privateca signer name. Add this section to the IstioControlPlane CR as well:

    k8sResourceOverlays:
    - groupVersionKind:
      group: rbac.authorization.k8s.io
      kind: ClusterRole
      version: v1
    objectKey:
      name: <istiod-clusterrole-name>
    patches:
    - parseValue: true
      path: /rules/-
      type: replace
      value: |
        apiGroups:
        - certificates.k8s.io
        resourceNames:
        - csr.banzaicloud.io/privateca
        resources:
        - signers
        verbs:
        - approve    
    

    Replace <istiod-clusterrole-name> above with the name of the Istiod ClusterRole object. For example, if the name and the namespace field in the IstioControlplane CR are set to istio-sample-v115x and istio-system,respectively, this should be istiod-istio-sample-v115x-istio-system.

  4. Deploy the modified IstioControlPlane CR into your cluster and verify that the istiod-istio-sample-v115x-istio-system ClusterRole has permission to approve certificatesigningrequests.certificates.k8s.io resources.

Test the modified IstioControlPlane CR

To test the IstioControlPlane CR modifications you can deploy any pod to a namespace where injection is enabled. For example, to deploy a test image you can use the following spec:

apiVersion: v1
kind: Pod
metadata:
  name: connect-test
spec:
  containers:
  - name: kafka-test
    image: ubuntu:latest
    # Just spin and wait forever
    command: ["bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 3000; done;" ]

If the connect-test pod is up and running, your custom CA has been successfully integrated with Istio.