Project: cert-manager (Provisioning / Security & Compliance)
File: 20210209.certificates.k8s.io-adoption.md

title: certificates.k8s.io Adoption authors: "@joshvanl" reviewers: "@joshvanl" approvers: "@munnerz" @jetstack/team-cert-manager editor: "@joshvanl" creation-date: 2021-02-09 last-updated: 2021-07-26 status: implemented <!-- toc --> * * * * * * * * * <!-- /toc --> In Kubernetes v1.19 the resource graduated to `certificates.k8s.io/v1`. This makes the concept of requesting, signing, and consuming certificates in Kubernetes first-class objects. cert-manager is well placed to serve this resource type as it becomes more popular in the wider community, whilst preserving all the features and extensions that cert-manager has to offer. With the extensiveness of cert-managers ecosystem, it is well placed to manage the core Kubernetes resource type. This gives cert-manager the ability to integrate with components that it otherwise wouldn't have, without changes to the third-party project. Having the "request" resource managed inside the API server has a better security profile (i.e. `UserInfo` fields are managed by the API server rather than a configurable webhook, ). Consumers of the certificates.k8s.io `CertificateRequest` do not require cert-manager as a hard dependency. cert-manager can cause issues with the order of operation scenarios during installation or upgrades. For example, the `CertificateRequest` resource needs to be installed and the webhook ready for consumers/clients of this API to make requests. In some set-ups, the cert-manager installation is handled by two separate teams: The cert-manager CRDs and webhook are installed and managed by the operations team, which allows the operations team to enforce cluster policies; The cert-manager controller, cainjector and acmesolver are installed and managed by the developer team. By supporting the built-in `CertificateSigningRequest` resource, we decrease the coupling between the operations team and the developer team. Since the `CertificateSigningRequest` resource is built-in, it does not need any `CustomResourceDefinition` installation, and the webhook for this resource is integrated to the API server. Support for the `CertificateSigningRequest` resource in cert-manager is a stepping stone to migrating to this resource instead of the `CertificateRequest` resource, if the project does indeed want to migrate. Add `CertificateSigningRequest` signer controllers to cert-manager for all `Issuer` types Pave a way for replacement of the `CertificateRequest` resource for `CertificateSigningRequest` Remove the `CertificateRequest` resource before `CertificateSigningRequest` is fully supported and a migration path is in place Below are a summary of properties of the `CertificateSigningRequest` which cause issues or caveats which need to be addressed when adding support for the resource. `CertificateSigningRequests` are cluster scoped resources, whereas `CertificateRequests` are not. This means that in order for users to have the same debugging and usage capabilities of the `CertificateRequest`, users will have the ability to list all requests in the cluster, rather than being scoped to specific namespaces. This is a regression in certificate privacy. Whilst this is a regression in privacy, it could be an accepted limitation where the real world consequences are minimal. `CertificateSigningRequests` are cluster scoped resources, whereas `CertificateRequests` are not. cert-manager has the concept of namespaced issuers that may only be referenced by `CertificateRequests` that reside in the same

Since `CertificateSigningRequests` can reference any namespaced `Issuer`, there must be some mechanism to prevent privilege escalation (Alice references an issuer in Bob's namespace). cert-manager will enforce an noun and verb whereby the requester must have this role bound to them in order for the `CertificateSigningRequest` referencing a namespaced `Issuer` be approved by the cert-manager controller. See . This will be done via a against the `UserInfo` fields on the `CertificateSigningRequest`. The user must hold the following permissions to reference a namespaced signer: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: cert-manager-referencer:my-issuer namespace: sandbox rules: apiGroups: ["cert-manager.io"] resources: ["signers"] verbs: ["reference"] resourceNames: "my-issuer" # To give permission to only reference Issuers with the name 'my-issuer' "*" # To give permission to reference Issuers with any name in this namespace ``` `CertificateSigningRequests` did not include a `duration` field. To have parity with the `CertificateRequest` resource, the duration field will be moved to the annotation `experimental.cert-manager.io/request-duration` who's value is a [Go time duration string](https://golang.org/pkg/time/#Duration.String). When 1.22 is released, cert-manager can optimistically read the `expirationSeconds` `CertificateSigningRequest` field to discover the requested duration. If this field hasn't been set or the user is using an older version of Kubernetes, cert-manager can fallback to this annotation. `CertificateSigningRequests` do not include a `ca` field. This field has been proven to be problematic in cert-manager and controversial as it can encourage TLS anti-patterns. Attempting to add a `ca` style field to `CertificateSigningRequests` in the form of an annotation also causes issues in controller reconciliation, since updating the status and metadata fields are separate endpoints; if a successful status update occurs but the annotation update fails, the `CertificateSigningRequest` is left in a bad state with no way of recovery. For these reasons, the `ca` field has been omitted with no intention of including it. Users are advised to share CA data out of band to the `CertificateSigningRequest` resource. All current [external issuers](https://cert-manager.io/docs/configuration/external/) are built for the `CertificateRequest` resource. The project should continue to support this resource indefinitely, and provide an example project for creating external signers if and when the migration to `CertificateSigningRequests` occurs. cert-manager will support both `CertificateRequest` and `CertificateSigningRequest` types until, and if, the project completely migrates to the `CertificateSigningRequest` resource. The `Certificates` controller will continue to create `CertificateRequest` resources. The `Certificates` controller could be changed in future to be optionally configured to create `CertificateSigningRequests`. The cert-manager controller will not enable the `CertificateSigningRequest` controllers unless the `ExperimentalCertificateSigningRequestControllers=true` environment variable is present on the cert-manager controller. This could be changed in future by optimistically discovering whether the `CertificateSigningRequest` resource is available and starting the controllers. Instead of the concept of an `IssuerRef` for `CertificateRequests`, `CertificateSigningRequests` have the concept of a `SignerName`. Since `CertificateSigningRequests` are cluster scoped resources, the signer name must include the namespace if the referenced `Issuer` is namespaced. The signer name for cert-manager signers will be prefixed with `cert-manager.io` to prevent conflicts with other external signer projects. ```yaml signerName: issuers.cert-manager.io/<namespace>.<issuer-name> signerName:

``` Using the same approach of referencing by just name, rather than issuer type (e.g. CA, Vault etc.), keeps the behaviour of this resource in line with `CertificateRequests` for end users. Each `CertificateSigningRequest` controller will behave in the same way as the existing `CertificateRequest` resource, by getting the referenced signer, and attempting to sign. If the issuer type is not managed by this controller, do nothing, else sign. Some special cases for some `[Cluster]Issuers` that need to be addressed: SelfSigned: The `experimental.cert-manager.io/private-key-secret-name` annotation is used to reference a secret containing the private key of the self-signed certificate. The Secret must reside in either the namespace of the reference Issuer, or the cluster resource namespace in the case of a ClusterIssuer. Venafi: The `venafi.experimental.cert-manager.io/custom-fields` annotation is set by the user to request a Venafi certificate with custom fields. The `venafi.experimental.cert-manager.io/pickup-id` annotation is used by the cert-manager Venafi signer to keep track of the request against the Venafi API. ACME: The ACME controller creates sub-resources (`Orders`). Since `CertificateSigningRequests` are cluster scoped resources, when referencing a ClusterIssuer we should create Orders in the cluster resource namespace, else the namespace of the referenced Issuer. The `CertificateSigningRequest` has [well-known condition types](https://github.com/kubernetes/api/blob/4a626d306b987a4096cf0784ec01af1be2f6d67f/certificates/v1/types.go#L222) of `Approved`, `Denied`, and `Failed`. `CertificateSigningRequest` signer controllers should not begin computation of the request until the resource has the `Approved` condition set to `True`. It was found that nearly all users testing out these signers forgot about needing to manually add the Approved condition. An event is fired on `CertificateSigningRequest` which have neither a Denied or Approved condition. This is to aid consumers in knowing that the resource has been observed, but is waiting for the Approved condition. If a signer fails when processing a `CertificateSigningRequest`, the well-known `Failed` condition should be set to `True`. No signer controllers should process the request again. When the request has been successfully signed, the `status.Certificate` field will be updated with the sign certificate. IsCA: The `experimental.cert-manager.io/request-is-ca` annotation is used to request a certificate with the X.509 `IsCA` flag set. Duration: The `experimental.cert-manager.io/request-duration` annotation is used to request a certificate with a particular duration. Accepts a Go time duration string. Namespaced issuers: requesters must have the following RBAC in the same namespace to allow them to request from a namespaced issuer: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: cert-manager-referencer:my-issuer namespace: sandbox rules: apiGroups: ["cert-manager.io"] resources: ["signers"] verbs: ["reference"] resourceNames: "my-issuer" # To give permission to only reference Issuers with the name 'my-issuer' "*" # To give permission to reference Issuers with any name in this namespace ``` No effect to upgrades as only additional controllers added. No CRD API changes. Below is each level of graduation for support of `CertificateSigningRequest` in cert-manager. Create signer implementations for each cert-manager.io issuer types. These controllers are active in a default cert-manager installation, though `CertificateRequests` are the resource created from `Certificate` resources. [TBD] Swap `CertificateRequests` for `CertificateSigningRequests` as the resource created from `Certificates`. [TBD] Remove the `CertificateRequest` resource from the cert-manager project, in favour of the `CertificateSigningRequest` resource.