Concept

The Infisical PKI Issuer is an installable Kubernetes cert-manager controller that uses Infisical PKI to sign certificate requests. The issuer is perfect for getting X.509 certificates for ingresses and other Kubernetes resources and capable of automatically renewing certificates as needed.

As part of the workflow, you install cert-manager, the Infisical PKI Issuer, and configure resources to represent the connection details to your Infisical PKI and the certificates you wish to issue. Each issued certificate and corresponding private key is made available in a Kubernetes secret.

We recommend reading the cert-manager documentation for a fuller understanding of all the moving parts.

Workflow

A typical workflow for using the Infisical PKI Issuer to issue certificates for your Kubernetes resources consists of the following steps:

  1. Creating a machine identity in Infisical.
  2. Creating a Kubernetes secret to store the credentials of the machine identity.
  3. Installing cert-manager into your Kubernetes cluster.
  4. Installing the Infisical PKI Issuer controller into your Kubernetes cluster.
  5. Creating an Issuer or ClusterIssuer resource in your Kubernetes cluster to represent the Infisical PKI issuer you wish to use.
  6. Creating a Certificate resource in your Kubernetes cluster to represent a certificate you wish to issue. As part of this step, you specify the Kubernetes Secret to create and store the issued certificate and private key.
  7. Consuming the issued certificate across your Kubernetes resources from the specified Kubernetes Secret.

Guide

In the following steps, we explore how to install the Infisical PKI Issuer using kubectl and use it to obtain certificates for your Kubernetes resources.

1

Create an identity in Infisical

Follow the instructions here to configure a machine identity in Infisical with Universal Auth.

By the end of this step, you should have a Client ID and Client Secret on hand as part of the Universal Auth configuration for the Infisical PKI Issuer to authenticate with Infisical; this will be useful in steps 4 and 5.

Currently, the Infisical PKI Issuer only supports authenticating with Infisical via the Universal Auth authentication method.

We’re planning to add support for Kubernetes Auth in the near future.

2

Install cert-manager

Install cert-manager into your Kubernetes cluster by following the instructions here or by running the following command:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml
3

Install the Issuer Controller

Install the Infisical PKI Issuer controller into your Kubernetes cluster by running the following command:

kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical-issuer/main/build/install.yaml
4

Create Kubernetes Secret for Infisical PKI Issuer

Start by creating a Kubernetes Secret containing the Client Secret from step 1. As mentioned previously, this will be used by the Infisical PKI issuer to authenticate with Infisical.

kubectl create secret generic issuer-infisical-client-secret \
    --namespace <namespace_you_want_to_issue_certificates_in> \
    --from-literal=clientSecret=<client_secret>
5

Create Infisical PKI Issuer

Next, create the Infisical PKI Issuer by filling out url, clientId, either caId or certificateTemplateId, and applying the following configuration file for the Issuer resource. This configuration file specifies the connection details to your Infisical PKI CA to be used for issuing certificates.

infisical-issuer.yaml
apiVersion: infisical-issuer.infisical.com/v1alpha1
kind: Issuer
metadata:
    name: issuer-infisical
    namespace: <namespace_you_want_to_issue_certificates_in>
spec:
    url: "https://app.infisical.com" # the URL of your Infisical instance
    caId: <ca_id> # the ID of the CA you want to use to issue certificates
    certificateTemplateId: <certificate_template_id> # the ID of the certificate template you want to use to issue certificates against
    authentication:
        universalAuth:
            clientId: <client_id> # the Client ID from step 1
            secretRef: # reference to the Secret created in step 4
                name: "issuer-infisical-client-secret"
                key: "clientSecret"
kubectl apply -f infisical-issuer.yaml

The Infisical PKI Issuer supports issuing certificates against a specific CA or a specific certificate template.

For this reason, you should only fill in the caId or the certificateTemplateId field but not both.

We recommend using the certificateTemplateId field to issue certificates against a specific certificate template since templates let you enforce constraints on issued certificates and may have alerting policies bound to them.

You can check that the issuer was created successfully by running the following command:

kubectl get issuers.infisical-issuer.infisical.com -n <namespace_of_issuer> -o wide
NAME               AGE
issuer-infisical   21h

An Issuer is a namespaced resource, and it is not possible to issue certificates from an Issuer in a different namespace. This means you will need to create an Issuer in each namespace you wish to obtain Certificates in.

If you want to create a single Issuer that can be consumed in multiple namespaces, you should consider creating a ClusterIssuer resource. This is almost identical to the Issuer resource, however is non-namespaced so it can be used to issue Certificates across all namespaces.

You can read more about the Issuer and ClusterIssuer resources here.

6

Create Certificate

Finally, create a Certificate by applying the following configuration file. This configuration file specifies the details of the (end-entity/leaf) certificate to be issued.

certificate-issuer.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
    name: certificate-by-issuer
    namespace: <namespace_you_want_to_issue_certificates_in>
spec:
    commonName: certificate-by-issuer.example.com # the common name for the certificate
    secretName: certificate-by-issuer # the name of the Kubernetes Secret to create and store the certificate and private key in
    issuerRef:
        name: issuer-infisical
        group: infisical-issuer.infisical.com
        kind: Issuer
    privateKey: # the algorithm and key size to use
        algorithm: ECDSA
        size: 256
    duration: 48h # the ttl for the certificate
    renewBefore: 12h # the time before the certificate expiry that the certificate should be automatically renewed

The above sample configuration file specifies a certificate to be issued with the common name certificate-by-issuer.example.com and ECDSA private key using the P-256 curve, valid for 48 hours; the certificate will be automatically renewed by cert-manager 12 hours before expiry. The certificate is issued by the issuer issuer-infisical created in the previous step and the resulting certificate and private key will be stored in a secret named certificate-by-issuer.

Note that the full list of the fields supported on the Certificate resource can be found in the API reference documentation here.

You can check that the certificate was created successfully by running the following command:

kubectl get certificates -n <namespace_of_your_certificate> -o wide
NAME                    READY   SECRET                  ISSUER             STATUS                                          AGE
certificate-by-issuer   True    certificate-by-issuer   issuer-infisical   Certificate is up to date and has not expired   20h
7

Use Certificate in Kubernetes Secret

Since the actual certificate and private key are stored in a Kubernetes secret, we can check that the secret was created successfully by running the following command:

kubectl get secret certificate-by-issuer -n <namespace_of_your_certificate>
NAME                    TYPE                DATA   AGE
certificate-by-issuer   kubernetes.io/tls   2      26h

We can describe the secret to get more information about it:

kubectl describe secret certificate-by-issuer -n default
Name:         certificate-by-issuer
Namespace:    default
Labels:       controller.cert-manager.io/fao=true
Annotations:  cert-manager.io/alt-names: 
            cert-manager.io/certificate-name: certificate-by-issuer
            cert-manager.io/common-name: certificate-by-issuer.example.com
            cert-manager.io/ip-sans: 
            cert-manager.io/issuer-group: infisical-issuer.infisical.com
            cert-manager.io/issuer-kind: Issuer
            cert-manager.io/issuer-name: issuer-infisical
            cert-manager.io/uri-sans: 

Type:  kubernetes.io/tls

Data
====
ca.crt: 1306 bytes
tls.crt: 2380 bytes
tls.key:  227 bytes

Here, ca.crt is the Root CA certificate, tls.crt is the requested certificate followed by the certificate chain, and tls.key is the private key for the certificate.

We can decode the certificate and print it out using openssl:

kubectl get secret certificate-by-issuer -n default -o jsonpath='{.data.tls\.crt}' | base64 --decode | openssl x509 -text -noout

In any case, the certificate is ready to be used as Kubernetes Secret by your Kubernetes resources.

FAQ