How-To: Manage EZCA Certificates with the EZCA Kubernetes Operator

Learn how to manage your EZCA certificates using the Keytos EZCA Kubernetes Operator. This guide will walk you through how to use the tool to manage your EZCA certificates in your Kubernetes cluster.

Overview - Manage Certificates in Your Kubernetes Cluster Using the EZCA Kubernetes Operator

The EZCA Kubernetes Operator is a tool that allows you to manage your EZCA certificates in your Kubernetes cluster. You store a certificate in a Kubernetes kubernetes.io/tls Secret. The controller watches it and, before it expires, renews it using EZCA and updates the Secret in place. Your workloads can continue to use the Secret without any downtime or expired certificates.

Prerequisites for Using the EZCA Kubernetes Operator

  1. You have an active EZCA plan.
  2. You have a Kubernetes cluster and Helm installed.

How to Create Your EZCA Kubernetes Operator and Issue a Certificate - Step by Step Guide

Step 1: How to Create an SSL Certificate in EZCA

In order to use the EZCA Kubernetes Operator, you will need to create an initial SSL certificate in EZCA. This can be done in several ways. Select the tab specific to your needs to create the certificate:

EZCA allows users to securely create a certificate in the browser by locally generating a private key in the browser and then requesting a certificate, following the PKI best practices of the private key never leaving the client’s computer.

  1. Navigate to https://portal.ezca.io/ (or your EZCA URL).

  2. Navigate to Domains.

    EZCA Cloud PKI portal My Domains page listing registered domains with Request Certificate buttons
  3. Click the Request Certificate button on the domain you want to request a certificate for. For the bootstrap certificate, this can be any domain.

    EZCA Cloud PKI My Domains page with Request Certificate button highlighted for a domain
  4. This will pre-populate the Subject Name and Subject Alternate Names with the selected domain.

    EZCA Cloud PKI Request New Certificate form with pre-filled subject name and DNS names fields
  5. By default, EZCA will request the certificate to be the maximum validity allowed by your administrators. If you want to decrease the lifetime of the certificate, adjust the validity slider.

    EZCA Cloud PKI Request New Certificate form with validity period slider highlighted at 30 days
  6. From the Certificate Location dropdown, select the Generate Locally option.

    EZCA Cloud PKI certificate form with Certificate Location set to Generate Locally option highlighted
  7. At the top right of the form, click the Request Certificate button.

    EZCA Cloud PKI Request New Certificate button highlighted to submit the certificate request
  8. Your Certificate has been created successfully.

    EZCA Cloud PKI Certificate Created Successfully page showing certificate and private key with download warning
  9. Click Download Full Certificate (.pem) to download the certificate and private key.

    EZCA Cloud PKI Certificate Created Successfully page showing button to download full certificate PEM
  10. Open the PEM file and separate the certificate and private key into two separate PEM files named bootstrap.crt and bootstrap.key, respectively. If you have openssl installed, this can be done with the following commands:

    openssl pkey -in <path-to-downloaded-pem> -out bootstrap.key
    openssl x509 -in <path-to-downloaded-pem> -out bootstrap.crt
    

The Keytos Terraform Provider lets you create the bootstrap certificate as code. Make sure to go over the detailed documentation and descriptions for each data source and resource to understand its parameters and intended behavior. For an example of a terraform integration for the Keytos Terraform Provider, see an end-to-end integration of the Keytos Terraform Provider and the EZCA Kubernetes Operator.

  1. To run your terraform, navigate to the directory holding your terraform configuration and run the following command:

    terraform init -upgrade
    
  2. Apply the terraform to create the certificate. Pass in the values file for the terraform provider:

    terraform apply -var-file=<path-to-var-file>
    
  3. After completion, run the following commands to output your certificate and private key:

    terraform output -raw cert_pem >bootstrap.crt
    terraform output -raw private_key_pem >bootstrap.key
    

Step 2: How to Create the Bootstrap Secret in Kubernetes

The bootstrap secret is the SSL certificate that will be used to authenticate your cluster and to rotate the certificate. The following commands will create a namespace in Kubernetes and add the certificate as a secret in the namespace.

kubectl create namespace ezca-cert-controller-system

# Pass in the path to your PEM cert and path to your PEM private key for the --cert and --key arguments
kubectl -n ezca-cert-controller-system create secret tls cluster-cert-identity \
  --cert=bootstrap.crt --key=bootstrap.key

Step 3: How to Configure your EZCA Kubernetes Operator

To configure the Kubernetes Operator, you will need to create a values.yaml file, which will be installed using Helm. Copy the following values.yaml file and fill in your values.

global:
  ezcaURL: https://portal.ezca.io

clusterIdentity:
  name: master-cert-identity-1
  certSecretName: cluster-cert-identity
  renewalThreshold: 20

NOTE: Ensure that the lifetime of the certificate is within range of the maximum certificate validity period of the CA itself. Otherwise, certificate issuance will fail.

NOTE: Ensure that you have created all the namespaces referenced in your values.yaml.

Step 4: How to Install the Kubernetes Operator

Next, run these command to install the Kubernetes Operator in your cluster.

helm pull oci://keytos-eqgzasb8bufxa0cd.azurecr.io/ezca/helm/ezca-cert-controller \
  --untar --destination /tmp/ezca-cert-controller

kubectl apply --server-side --force-conflicts \
  -f /tmp/ezca-cert-controller/ezca-cert-controller/crds/

helm upgrade --install ezca-cert-controller-system \
  oci://keytos-eqgzasb8bufxa0cd.azurecr.io/ezca/helm/ezca-cert-controller \
  --namespace ezca-cert-controller-system --create-namespace -f values.yaml

To view your new operator in your cluster, use the following commands:

helm list -n ezca-cert-controller-system
# Expected Output:
# NAME                            NAMESPACE                       REVISION     UPDATED    STATUS          CHART    APP VERSION
# ezca-cert-controller-system     ezca-cert-controller-system     9            ...        deployed        ...      ...
kubectl get cci
# Expected Output:
# NAME                     READY   EXPIRATION             THUMBPRINT                                 AGE
# master-cert-identity-1   True    2026-09-24T12:38:47Z   91A0220325F51684CA00D0CE36F7D8B6B1364C7A   3d21h
kubectl get secret -n ezca-cert-controller-system
# Expected Output:
# NAME                                                TYPE                 DATA   AGE
# cluster-cert-identity                               kubernetes.io/tls    2      3d22h
# sh.helm.release.v1.ezca-cert-controller-system.v1   helm.sh/release.v1   1      3d21h
# ...

Done! You should now have the EZCA Kubernetes Operator installed in your cluster. The operator will keep the certificate up to date by renewing it with EZCA before it expires.

How to Configure Multiple Certificates with the EZCA Kubernetes Operator

The EZCA Kubernetes Operator supports installing multiple certificates in different namespace by adding to your values.yaml file. To do this, repeat the steps above to create an SSL bootstrap certificate and add it to each namespace. Then, run the Helm commands to upgrade your Helm chart with the new values. Here is an example:

global:
  ezcaURL: https://portal.ezca.io

clusterIdentity:
  name: master-cert-identity-1
  certSecretName: cluster-cert-identity
  renewalThreshold: 20

appCerts:
  - name: cert-1
    namespace: my-namespace
    validityInDays: 30
    certSecretName: cert-1
  - name: cert-2
    namespace: my-namespace
    validityInDays: 30
    certSecretName: cert-2

Reference: What Values Can I Set for the EZCA Kubernetes Operator?

Your values.yaml can include many values to customize the EZCA Kubernetes Operator to fit your needs. See the chart below for details.

Key Default Description
global.cloud Public Azure sovereign cloud for Entra ID / Graph. One of Public, USGov.
global.ezcaURL https://portal.ezca.io Base URL of your EZCA instance. Required.
global.appInsightsConnString "" Optional App Insights connection string. When it is set, renewals/rotations/errors are reported.
clusterIdentity.name "" metadata.name of the ClusterCertIdentity. Blank → not created.
clusterIdentity.certSecretName cluster-cert-identity Name of the pre-existing kubernetes.io/tls Secret with the bootstrap certificate.
clusterIdentity.certSecretNamespace "" Namespace of that Secret. Blank → the release namespace.
clusterIdentity.renewalThreshold 20 Percent of lifetime remaining at/below which to renew (1-99).
appCerts[].name app-cert-<n> metadata.name of the Kubernetes resource.
appCerts[].namespace "" metadata.namespace; blank → release namespace.
appCerts[].validityInDays Requested lifetime in days. Unset → issuer default (90 days).
appCerts[].certSecretName entry’s name Name of the issued-cert Secret.
appCerts[].renewalThreshold 20 Percent of lifetime remaining at/below which to renew (1-99).

To view the appCerts, use the following command:

kubectl get mc -A
# Expected Output:
# NAMESPACE        NAME               READY   EXPIRATION             THUMBPRINT                                 AGE
# my-namespace-1   namespace-1-cert   True    2026-09-24T20:44:35Z   CD1465B9B4195FA7C0A1FBC41C01C8DC0A649159   3d15h
# my-namespace-2   namespace-2-cert   True    2026-09-24T20:44:38Z   18612084B05EC7522CA071FF2823FFA99D6CA209   3d15h

View the full schema for each subsection here or a more detailed example here.

How to Uninstall the EZCA Kubernetes Operator

To uninstall the Helm chart, run the following command:

helm uninstall ezca-cert-controller-system --namespace ezca-cert-controller-system

This will not delete the Custom Resource Definitions (CRDs) from your cluster. You must delete them manually. Use the following command:

kubectl delete crd certidentities.ezca.keytos.io clustercertidentities.ezca.keytos.io managedcredentials.ezca.keytos.io