Istio and cert-manager integration
Istio provides different mechanisms to sign workload certificates for the purpose of mutual TLS (mTLS). The options include:
- Istio Certificate Authority (CA) uses a self-signed root certificate
- Istio CA uses an administrator-specified certificate and key with an administrator-specified root certificate
- Custom CA issues keys and certificate files mounted into the sidecars
- Custom CA integration uses Kubernetes CSR API
- External CA uses Istio CA gRPC API (either through the Istiod Registration Authority (RA) model or directly authenticating workloads and validating Subject Alternative Name (SAN))
This guide explains how to integrate with cert-manager.
cert-manager CA Integration
This task shows how to provision Control Plane and Workload Certificates with an external Certificate Authority using cert-manager. cert-manager is a x509 certificate operator for Kubernetes that supports a number of Issuers, representing Certificate Authorities that can sign certificates. The istio-csr project installs an agent that is responsible for verifying incoming certificate signing requests from Istio mesh workloads, and signs them through cert-manager via a configured Issuer.
Install cert-manager
First, cert-manager must be installed on the cluster using your preferred method.
helm repo add jetstack https://charts.jetstack.io
helm repo update
kubectl create namespace cert-manager
helm install -n cert-manager cert-manager jetstack/cert-manager --set installCRDs=trueVerify the cert-manager deployments have successfully rolled-out.
for i in cert-manager cert-manager-cainjector cert-manager-webhook; \
do kubectl rollout status deploy/$i -n cert-manager; doneConfigure cert-manager
An Issuer must be created in the
istio-system
namespace to sign Istiod and mesh workload certificates. We will use a SelfSigned Issuer, though any supported Issuer can be used.Use a Private CAPublicly trusted certificates are strongly discouraged from being used, including ACME certificates.
kubectl create namespace istio-system
kubectl apply -n istio-system -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: istio-ca
spec:
isCA: true
duration: 2160h # 90d
secretName: istio-ca
commonName: istio-ca
subject:
organizations:
- cert-manager
issuerRef:
name: selfsigned
kind: Issuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: istio-ca
spec:
ca:
secretName: istio-ca
EOFVerify the "istio-ca" and "self-signed"
issuers
are present and reportREADY=True
:kubectl get issuers -n istio-system
Once the
issuers
have become ready, istio-csr can be installed into the cluster.Install istio-csr
helm install -n cert-manager cert-manager-istio-csr jetstack/cert-manager-istio-csr
Verify the istio-csr deployment has successfully rolled-out.
kubectl rollout status deploy/cert-manager-istio-csr -n cert-manager
Certificates
istio-ca
andistiod
should be present and reportREADY=True
.kubectl get certificates -n istio-system
Install Istio
Istio must be configured to use cert-manager as the CA server for both workload and Istio control plane components. The following configuration uses the IstioOperator resource to install Istio with cert-manager integration:
istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
values:
global:
# Changes the certificate provider to Cert Manager istio-csr
caAddress: cert-manager-istio-csr.cert-manager.svc:443
components:
pilot:
k8s:
env:
# Disables istiod CA Server functionality
- name: ENABLE_CA_SERVER
value: "false"
overlays:
- apiVersion: apps/v1
kind: Deployment
name: istiod
patches:
# Mounts istiod serving and webhook certificates from Secret
- path: spec.template.spec.containers.[name:discovery].args[-1]
value: "--tlsCertFile=/etc/cert-manager/tls/tls.crt"
- path: spec.template.spec.containers.[name:discovery].args[-1]
value: "--tlsKeyFile=/etc/cert-manager/tls/tls.key"
- path: spec.template.spec.containers.[name:discovery].args[-1]
value: "--caCertFile=/etc/cert-manager/ca/root-cert.pem"
- path: spec.template.spec.containers.[name:discovery].volumeMounts[-1]
value:
name: cert-manager
mountPath: "/etc/cert-manager/tls"
readOnly: true
- path: spec.template.spec.containers.[name:discovery].volumeMounts[-1]
value:
name: ca-root-cert
mountPath: "/etc/cert-manager/ca"
readOnly: true
- path: spec.template.spec.volumes[-1]
value:
name: cert-manager
secret:
secretName: istiod-tls
- path: spec.template.spec.volumes[-1]
value:
name: ca-root-cert
configMap:
defaultMode: 420
name: istio-ca-root-cert
EOFThe installation should complete, and the Istio control plane should become in a ready state.
kubectl get pods -n istio-system
Test mTLS
All workload certificates will now be requested through cert-manager using the configured Issuer. Let's run an example workload to test mTLS. First, create a namespace and configure it for automatic sidecar injection:
kubectl create ns foo
kubectl label ns/foo istio-injection=enabledRun the sample sleep and
httpbin
workloads.ISTIO_VERSION=1.18
kubectl apply -n foo -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION/samples/sleep/sleep.yaml
kubectl apply -n foo -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION/samples/httpbin/httpbin.yamlVerify the sleep and
httpbin
deployments have successfully rolled-out.for i in sleep httpbin; do kubectl rollout status -n foo deploy/$i; done
Verify the sidecar proxy was injected for each workload. Each workload pod should show
2/2
containers areREADY
.for i in sleep httpbin; do kubectl get po -n foo -l app=$i; done
By default, Istio configures destination workloads using
PERMISSIVE
mode. This mode means a service can accept both plain text and mTLS connections. To ensure mTLS is being used between sleep andhttpbin
workloads, set the mode toSTRICT
for namespace "foo".kubectl apply -n foo -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "default"
spec:
mtls:
mode: STRICT
EOFTest mTLS from the sleep pod to the
httpbin
pod.kubectl -n foo exec -it deploy/sleep -c sleep -- curl -o /dev/null -s -w '%{http_code}\n' http://httpbin.foo:8000/headers
You should receive an
200
response code.Visualize mTLS
Optionally, you can run Kiali to visualize the mTLS connections.
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION/samples/addons/kiali.yamlVerify the Kiali and Prometheus deployments successfully rolled-out.
for i in prometheus kiali; do kubectl rollout status -n istio-system deploy/$i; done
Open the Kiali dashboard.
istioctl dashboard kiali
Navigate to Workloads > Namespace:foo >
httpbin
. You should see the connection graph with padlocks to indicate mTLS is being used. If the graph is empty, adjust the "traffic metrics per refresh" dropdown list in the upper right-hand corner or regenerate connections.
Congratulations! You have successfully configured Istio to use cert-manager as a CA for mesh mTLS authentication.