cert-manager issues certificates through an Issuer or ClusterIssuer of type vault, which calls the PKI secrets engine at <MOUNT>/sign/<ROLE>. Stronghold is API-compatible with Vault, so such an Issuer can be pointed at Stronghold. The <MOUNT>/sign/<ROLE> endpoint accepts the fields that cert-manager sends (csr, common_name, alt_names, ip_sans, uri_sans, other_sans, ttl).
In Deckhouse Platform, cert-manager is installed by the cert-manager module.
Goal
After the setup:
- cert-manager in the cluster issues and renews TLS certificates for
example.comsubdomains through the intermediate CA in Stronghold. - cert-manager logs in to Stronghold with the Kubernetes auth method, so no long-lived Stronghold credentials are stored in the cluster.
Prerequisites
Before you start, prepare the following:
- The PKI secrets engine at the
pki_intpath with an intermediate CA and theexample-comrole for theexample.comdomain, as in Internal PKI with Stronghold. - The Kubernetes auth method enabled in Stronghold for the cluster.
- cert-manager installed in the cluster.
- A Stronghold token with permissions to write policies and Kubernetes auth roles.
- The CA certificate that signed the Stronghold TLS certificate.
Step 1. Configure Stronghold
Allow cert-manager to sign certificate requests with the example-com role.
Create a policy that allows signing certificate requests for the role:
d8 stronghold policy write cert-manager-pki - <<'POLICY' path "pki_int/sign/example-com" { capabilities = ["create", "update"] } POLICYCreate a Kubernetes auth role for the
stronghold-issuerServiceAccount in themyappnamespace. Theaudienceparameter must match the token audience that cert-manager requests:vault://<NAMESPACE>/<ISSUER_NAME>for an Issuer,vault://<CLUSTER_ISSUER_NAME>for a ClusterIssuer:d8 stronghold write auth/kubernetes/role/cert-manager-myapp bound_service_account_names=stronghold-issuer bound_service_account_namespaces=myapp audience=vault://myapp/stronghold policies=cert-manager-pki ttl=20mIn DP in
Automaticmode, the Kubernetes auth method for the current cluster is created by the module at thekubernetes_localpath: in this case, useauth/kubernetes_localinstead ofauth/kubernetesin the commands and in the IssuermountPath. Theauth/kubernetespath applies to a manually enabled method.
Step 2. Configure cert-manager
Create an Issuer that calls Stronghold, and request a certificate.
Create a ServiceAccount and allow cert-manager to request tokens for it:
apiVersion: v1 kind: ServiceAccount metadata: name: stronghold-issuer namespace: myapp --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: stronghold-issuer-token namespace: myapp rules: - apiGroups: [""] resources: ["serviceaccounts/token"] resourceNames: ["stronghold-issuer"] verbs: ["create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: stronghold-issuer-token namespace: myapp roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: stronghold-issuer-token subjects: - kind: ServiceAccount name: cert-manager namespace: d8-cert-managerCreate the Issuer:
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: stronghold namespace: myapp spec: vault: server: https://stronghold.example.com path: pki_int/sign/example-com caBundle: <CA_BUNDLE_BASE64> auth: kubernetes: role: cert-manager-myapp mountPath: /v1/auth/kubernetes serviceAccountRef: name: stronghold-issuer<CA_BUNDLE_BASE64>is the base64-encoded CA certificate that signed the Stronghold TLS certificate.Request a certificate:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: www namespace: myapp spec: secretName: www-tls commonName: www.example.com dnsNames: - www.example.com duration: 72h renewBefore: 24h issuerRef: name: stronghold kind: Issuer
cert-manager stores the certificate and private key in the www-tls Secret and renews the certificate before it expires. The duration value must not exceed the max_ttl of the example-com role.
Other authentication methods
A vault Issuer also supports AppRole authentication (auth.appRole with roleId and a reference to a Secret with secret_id) and token authentication (auth.tokenSecretRef). With these methods, the secret_id or the token is stored in a Secret in the cluster. Kubernetes auth does not require storing long-lived credentials in the cluster.
Verification
Check the result:
Check that the Issuer is ready:
d8 k -n myapp get issuer strongholdThe
READYcolumn must showTrue.Check that the certificate is issued:
d8 k -n myapp get certificate wwwThe
READYcolumn must showTrue.Check the issuer and the expiry date of the certificate in the Secret:
d8 k -n myapp get secret www-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -issuer -enddateThe
issuerfield must contain the name of the intermediate CA frompki_int.
Cleanup
Delete the objects created in this guide.
Delete the Certificate, its Secret, the Issuer, and the ServiceAccount with its Role and RoleBinding:
d8 k -n myapp delete certificate www d8 k -n myapp delete secret www-tls d8 k -n myapp delete issuer stronghold d8 k -n myapp delete rolebinding stronghold-issuer-token d8 k -n myapp delete role stronghold-issuer-token d8 k -n myapp delete serviceaccount stronghold-issuerDelete the Kubernetes auth role and the policy in Stronghold:
d8 stronghold delete auth/kubernetes/role/cert-manager-myapp d8 stronghold policy delete cert-manager-pkiCertificates that were already issued stay valid until they expire. To revoke them, use
pki_int/revoke, as in Internal PKI with Stronghold.