mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 15:29:46 +00:00
305 lines
16 KiB
Plaintext
305 lines
16 KiB
Plaintext
---
|
|
title: "Kubernetes cert-manager"
|
|
description: "Learn how to automatically provision and manage TLS certificates in Kubernetes using Infisical PKI"
|
|
---
|
|
|
|
## Concept
|
|
|
|
The Infisical PKI provides [ACME (Automated Certificate Management Environment)](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment) integration for various of ACME clients to issue and renew certificates automatically.
|
|
Under Kubernetes environment, [cert-manager](https://cert-manager.io) is the most popular issuer to issue certificates via ACME.
|
|
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` 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](https://cert-manager.io/docs/) for a fuller understanding of all the moving parts.
|
|
For the ACME part, please reference to the [ACME](https://cert-manager.io/docs/configuration/acme/) section.
|
|
|
|
## 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 certificate profile with ACME as the enrollment method in Infisical.
|
|
2. Installing `cert-manager` into your Kubernetes cluster.
|
|
3. Creating a Kubernetes secret to store the EAB (External Account Binding) credentials of the ACME certificate profile.
|
|
4. Creating an `Issuer` or `ClusterIssuer` resource in your Kubernetes cluster to connect to the Infisical PKI certificate profile you wish to use.
|
|
5. Create the approver policy to accept certificate request.
|
|
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](https://github.com/kubernetes/kubectl) and use it to obtain certificates for your Kubernetes resources.
|
|
|
|
<Steps>
|
|
<Step title="Create a certificate profile with ACME as the enrollment method in Infisical">
|
|
|
|
Follow the instructions [here](/documentation/platform/pki/enrollment-methods/acme) to create a certificate profile with ACME as the enrollment method.
|
|
|
|
By the end of this step, you should have a **ACME Directory URL**, **EAB KID** and **EAB Secret** on hand as part of the credentials for the Infisical PKI ACME server to authenticate with Infisical; this will be useful in steps 4 and 5.
|
|
|
|
<Note>
|
|
Currently, the Infisical PKI ACME server only supports authenticating with Infisical via the dedicated EAB credentials generated for each certificate profile as the authentication method.
|
|
|
|
We're planning to add support for [Kubernetes Auth](/documentation/platform/identities/kubernetes-auth) in the near future.
|
|
</Note>
|
|
</Step>
|
|
<Step title="Install cert-manager">
|
|
Install `cert-manager` into your Kubernetes cluster by following the instructions [here](https://cert-manager.io/docs/installation/) or by running the following command:
|
|
|
|
```bash
|
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml
|
|
```
|
|
</Step>
|
|
<Step title="Create Kubernetes Secret for the EAB secret of Infisical ACME server">
|
|
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.
|
|
|
|
<Tabs>
|
|
<Tab title="kubectl command">
|
|
```bash
|
|
kubectl create secret generic infisical-acme-eab-secret \
|
|
--namespace <namespace_you_want_to_issue_certificates_in> \
|
|
--from-literal=eabSecret=<eab_secret>
|
|
```
|
|
</Tab>
|
|
<Tab title="Configuration file">
|
|
```yaml acme-eab-secret.yaml
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: infisical-acme-eab-secret
|
|
namespace: <namespace_you_want_to_issue_certificates_in>
|
|
data:
|
|
eabSecret: <eab_secret>
|
|
```
|
|
|
|
```bash
|
|
kubectl apply -f acme-eab-secret.yaml
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
</Step>
|
|
<Step title="Create the cert-manager Issuer connecting to Infisical ACME server">
|
|
Next, create the cert-manager Issuer or ClusterIssuer by filling out `acme_server_url`, `your_email`, `acme_eab_kid`, 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.
|
|
|
|
```yaml infisical-issuer.yaml
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Issuer
|
|
metadata:
|
|
name: issuer-infisical
|
|
spec:
|
|
acme:
|
|
# the URL of your Infisical certificate profile with
|
|
# ACME enrollment method from step 1
|
|
server: <acme_server_url>
|
|
# your email address, any email could work.
|
|
# currently we just ignore the value
|
|
email: <your_email>
|
|
externalAccountBinding:
|
|
keyID: <acme_eab_kid> # the EAB secret value from step 1
|
|
keySecretRef: # reference to the Secret created in step 3
|
|
name: "issuer-infisical-client-secret"
|
|
key: "clientSecret"
|
|
privateKeySecretRef:
|
|
name: issuer-infisical-account-key
|
|
solvers:
|
|
- http01:
|
|
ingress:
|
|
# this doesn't need to be nginx, you can use any
|
|
# ingressClassName available in your Kubernetes cluster
|
|
ingressClassName: nginx
|
|
```
|
|
|
|
```
|
|
kubectl apply -f infisical-issuer.yaml
|
|
```
|
|
|
|
You can check that the issuer was created successfully by running the following command:
|
|
|
|
```bash
|
|
kubectl get issuers.cert-manager.io -n <namespace_of_issuer> -o wide
|
|
```
|
|
|
|
```bash
|
|
NAME AGE
|
|
issuer-infisical 21h
|
|
```
|
|
|
|
<Note>
|
|
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](https://cert-manager.io/docs/configuration/).
|
|
|
|
Also, currently Infisical ACME server only supports HTTP-01 and requires all the certificate orders passing the challenge before issuing certificates.
|
|
We will allow users to opt-out challenge in the near future and also provide support DNS-01 as well.
|
|
</Note>
|
|
</Step>
|
|
<Step title="Create Approver Policy">
|
|
If you create a `CertificateRequest` now, you'll notice it's neither approved nor denied. This is expected because by default cert-manager approver controller requires an approver-policy.
|
|
|
|
To enable approval, create the following YAML file and apply it:
|
|
|
|
```yaml infisical-approver-policy.yaml
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRole
|
|
metadata:
|
|
name: infisical-issuer-approver
|
|
rules:
|
|
# Permission to approve or deny CertificateRequests for signers in cert-manager.io API group
|
|
- apiGroups: ['cert-manager.io']
|
|
resources: ['signers']
|
|
verbs: ['approve']
|
|
resourceNames:
|
|
# Grant approval permissions for namespaced issuers
|
|
- "issuers.infisical-issuer.infisical.com/default.issuer-infisical"
|
|
# Grant approval permissions for cluster-scoped issuers
|
|
- "clusterissuers.infisical-issuer.infisical.com/clusterissuer-infisical"
|
|
---
|
|
# Bind the cert-manager service account to the new role
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: infisical-issuer-approver-binding
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: cert-manager
|
|
namespace: cert-manager
|
|
roleRef:
|
|
apiGroup: rbac.authorization.k8s.io
|
|
kind: ClusterRole
|
|
name: infisical-issuer-approver
|
|
```
|
|
|
|
```
|
|
kubectl apply -f infisical-approver-policy.yaml
|
|
```
|
|
|
|
This configuration creates a `ClusterRole` named `infisical-issuer-approver` that grants approval permissions for specific Infisical issuer types. It then binds this role to the cert-manager service account, allowing it to approve certificate requests from your Infisical issuers.
|
|
|
|
For information, check out [cert manager approval policy doc](https://cert-manager.io/docs/policy/approval/approver-policy/).
|
|
</Step>
|
|
<Step title="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.
|
|
|
|
```yaml 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](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec).
|
|
|
|
You can check that the certificate was created successfully by running the following command:
|
|
|
|
```bash
|
|
kubectl get certificates -n <namespace_of_your_certificate> -o wide
|
|
```
|
|
|
|
```bash
|
|
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
|
|
```
|
|
</Step>
|
|
<Step title="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:
|
|
|
|
```bash
|
|
kubectl get secret certificate-by-issuer -n <namespace_of_your_certificate>
|
|
```
|
|
|
|
```bash
|
|
NAME TYPE DATA AGE
|
|
certificate-by-issuer kubernetes.io/tls 2 26h
|
|
```
|
|
|
|
We can `describe` the secret to get more information about it:
|
|
|
|
```bash
|
|
kubectl describe secret certificate-by-issuer -n default
|
|
```
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```bash
|
|
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.
|
|
</Step>
|
|
|
|
</Steps>
|
|
|
|
## FAQ
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="What fields can be configured on the Certificate resource?">
|
|
The full list of the fields supported on the `Certificate` resource can be found in the API reference documentation [here](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec).
|
|
|
|
<Note>
|
|
Currently, not all fields are supported by the Infisical PKI Issuer.
|
|
</Note>
|
|
|
|
</Accordion>
|
|
<Accordion title="Can certificates be renewed automatically?">
|
|
Yes. `cert-manager` will automatically renew certificates according to the `renewBefore` threshold of expiry as
|
|
specified in the corresponding `Certificate` resource.
|
|
|
|
You can read more about the `renewBefore` field [here](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec).
|
|
|
|
</Accordion>
|
|
<Accordion title="Why is my CertificateRequest not being approved, showing 'CertificateRequest has not been approved yet. Ignoring.'?">
|
|
If you see log messages similar to:
|
|
```
|
|
"CertificateRequest has not been approved yet. Ignoring.","controller":"certificaterequest","controllerGroup":"cert-manager.io","controllerKind":"CertificateRequest","CertificateRequest":{"name":"skynet-infisical-rta-rsa2048-1","namespace":"infisical-system"},"namespace":"infisical-system","name":"skynet-infisical-rta-rsa2048-1","reconcileID":"bfb7cad9-d867-45b5-b3a3-0139e731b7a6"}
|
|
```
|
|
This indicates that the `CertificateRequest` has been created, but `cert-manager` has not yet approved it. This typically occurs because a necessary approver policy is missing. Refer to the documentation above to create an approver policy.
|
|
</Accordion>
|
|
</AccordionGroup>
|