design/20210209.certificates.k8s.io-adoption.md
In Kubernetes v1.19 the
CertificateSigningRequest
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-manager’s 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,
see).
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:
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.
CertificateSigningRequest signer controllers to cert-manager for all
Issuer typesCertificateRequest resource for CertificateSigningRequestCertificateRequest resource before CertificateSigningRequest is
fully supported and a migration path is in placeBelow 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 namespace. 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
RBAC 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 Conditions.
This will be done via a
SubjectAccessReview
against the UserInfo fields on the CertificateSigningRequest. The user must
hold the following permissions to reference a namespaced signer:
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
Until 1.22
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 whose value is a Go
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 fall back 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 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.
# Namespaced issuer reference
# e.g., `issuers.cert-manager.io/my-namespace.my-issuer
signerName: issuers.cert-manager.io/<namespace>.<issuer-name>
# Cluster scoped issuer reference
# e.g., `clusterissuers.cert-manager.io/my-issuer
signerName: clusterissuers.cert-manager.io/<clusterissuer-name>
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:
venafi.experimental.cert-manager.io/custom-fields annotation is set by
the user to request a Venafi certificate with custom fields.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
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:
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.