12 KiB
| title | authors | reviewers | approvers | editor | creation-date | last-updated | status | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Certificate Request CRD |
|
|
|
@joshvanl | 2019-07-08 | 2019-08-12 | implementable |
Certificate Request CRD
Table of Contents
Summary
Currently, certificates issued via cert-manager rely on the Certificate
resource being reconciled by the Certificate controller. This resource imposes
limitations on what issuers are able to honour the Certificate resource as
well as other opinionated implementation details.
This proposal adds a new custom resource CertificateRequest that contains an
x509 certificate signing request, a target issuer, and other metadata about the
request. Each issuer will have their own CertificateRequest controller to
watch for resources that are referencing them. The Certificate controller will
then rely on creating CertificateRequests to resolve its own Spec.
Motivation
Currently the required use of the Certificate resource means that users are
forced to:
- expose the signed certificate's private key to the API server
- be limited to the finite set of issuers as implemented into the cert-manager project, or, "in-tree"
- adhere to the
Certificatecontroller's opinionated implementation, limiting scope for integrations with other projects - rely on developers of the cert-manager project for reviews and approval of new issuers
Due to these issues, cert-manager can be often unsuitable for some use cases/integrations or users are unsatisfied with some behaviour. Lack of exposure of options that a raw x509 certificate signing request provides can also be a source of frustration.
With cert-manger maintainers ensuring that all issuers are always fully supported and tested, it becomes difficult for new issuers to become accepted. Some developers of new issuers would be happy to maintain these issuers themselves however is not possible with all issuers belonging in the same code base and repository.
Goals
- Introduce the
CertificateRequestresource. - Create a
CertificateRequestcontroller for each in-tree issuer to resolveCertificateRequest. - Change the implementation of the
Certificatecontroller to rely on theCertificateRequestresource to resolve the request. - Update documentation detailing this new behaviour and how it can be used to
develop out-of-tree implantations of an issuer
CertificateRequestcontroller. - Create a boilerplate/scaffolding example code to help quick start developers on creating a controller with best practices.
Non-Goals
- This proposal does not document or explore possible or planned integrations using this new functionality.
- This proposal will not investigate possible alignment or merging with the
Kubernetes internal
CertificateSigningRequestresource. Although is is of interest, the motivation is mostly in order to get a built-in approval workflow for CertificateRequests. The feasibility of being able to implement a solution using the built-in type in the near future however is small, so we'd rather 'trail-blaze' here and then try and fold our changes back upstream at a later date.
Proposal
API Changes
This proposal will create the following new API types in the
cert-manager.io group;
// CertificateRequestSpec defines the desired state of CertificateRequest
type CertificateRequestSpec struct {
// Requested certificate default Duration
// +optional
Duration *metav1.Duration `json:"duration,omitempty"`
// IssuerRef is a reference to the issuer for this CertificateRequest. If
// the 'kind' field is not set, or set to 'Issuer', an Issuer resource with
// the given name in the same namespace as the CertificateRequest will be
// used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with
// the provided name will be used. The 'name' field in this stanza is
// required at all times. The group field refers to the API group of the
// issuer which defaults to 'cert-manager.io' if empty.
IssuerRef ObjectReference `json:"issuerRef"`
// Byte slice containing the PEM encoded CertificateSigningRequest
CSRPEM []byte `json:"csr"`
// IsCA will mark the resulting certificate as valid for signing. This
// implies that the 'signing' usage is set
// +optional
IsCA bool `json:"isCA,omitempty"`
}
// CertificateStatus defines the observed state of CertificateRequest and
// resulting signed certificate.
type CertificateRequestStatus struct {
// +optional
Conditions []CertificateRequestCondition `json:"conditions,omitempty"`
// Byte slice containing a PEM encoded signed certificate resulting from the
// given certificate signing request.
// +optional
Certificate []byte `json:"certificate,omitempty"`
// Byte slice containing the PEM encoded certificate authority of the signed
// certificate.
// +optional
CA []byte `json:"ca,omitempty"`
// FailureTime stores the time that this CertificateRequest failed.
// This is used to influence garbage collection and back-off.
// +optional
FailureTime *metav1.Time `json:"failureTime,omitempty"`
}
The CertificateRequestCondition resembles much the same of the
CertificateRequestCondition.
The ObjectReference field type has had a new field Group added as follows:
// ObjectReference is a reference to an object with a given name, kind and group.
type ObjectReference struct {
Name string `json:"name"`
// +optional
Kind string `json:"kind,omitempty"`
// +optional
Group string `json:"group,omitempty"`
}
The group refers to the API group that the target Issuer belongs to. This enables namespacing of references to different issuers of external API groups.
Controller Behaviour
The philosophy for the CertificateRequest controllers are planned to be as
minimal as possible in that the single goal of them is to enable its owning
Issuer to create the resulting certificate. Once a sync on a
CertificateRequest has been observed, the general flow is as follows:
- Check the group belongs to the owning
Issuer, exit if not. - Check if
CertificateRequestis in a failed state, exit if true. TODO: more tightly define what a 'failed state' exactly is. - Check the
Issuertype is of the same type, exit if not. - Verify the Spec of the
CertificateRequest. - If a certificate exits then update the status if needed and exit.
- Sign the certificate via the Issuer using the contents of Spec.
It is worth noting that whether the certificate is invalid, out-of-date or
failed then the controller should take no further action on the resource. It is
the responsibility of a higher level controller such as the Certificate
controller to take further action to retry the certificate issuance through
managing the life cycle of the CertificateRequest resources.
With all Issuers updated with CertificateRequest controllers, the
Certificate controller will be migrated to begin to use and manage the life
cycle CertificateRequests to resolve it's Spec. Further concrete
implementation details TBD.
ACME
The CertificateRequest controller is responsible for creating Order
resources to fulfil ACME certificate requests. If the Order fails due to a
non-networking or other non-transient issue then the Order is marked as failed
- this means the
CertificateRequesttoo shall be marked as failed and no further processing will take place by theCertificateRequestcontroller on this resource.
Failure
The CertificateRequest resource has a FailureTime field in its Status. If
the CertificateRequest fails for any reason then this field is set to the
current time. This field can then be used by a higher order controller, such as
the Certificate controller, to take further action and facilitate a backoff.
The Certificate controller will retry all failed CertificateRequest resources
by creating a new request with an identical Spec, only when the FailureTime
field is a least 1 hour in the past. The old failed CertificateRequest will be
deleted and the new CertificateRequest resource will be created with the same
name.
Internal API Resource Behaviour
The group name of IssuerRef inside CertificateRequests is to be defaulted
to "cert-manager.io" if the field is empty, using a mutating webhook. This
means that if unspecified, CertificateRequest objects will be put into the
ownership of the default pool of issuers in the cert-manager project.
Until the mutating webhook is fully implemented, we will handle defaulting internally in the controller.
CertificateRequest Annotations
In order for CertificateRequest controllers to resolve requests, extra
information may be needed that is not present in the API Spec. To pass on this
information, a set of one or more annotations should be defined, with reliable
value pairs. These annotations should be considered optional. Any
CertificateRequest controller that relies on these to function should
fallback gracefully or be marked as failed in the event a required annotation is
missing. The currently defined annotations are:
cert-manager.io/private-key-secret-name: The name of the secret, in the same namespace as theCertificateRequest, that stores the private key which was used to sign the x509 certificate signing request. This is required by theSelfSigningissuer to sign its own certificate. If this annotation is missing or empty, theSelfSignCertificateRequestcontroller will mark the resource as failed and no further processing will take place on it. Currently theCertificatecontroller adds this annotation to allCertificateRequestresources it creates with the definedSecretNamein the Spec of theCertificate.
Test Plan
Standard unit and end-to-end tests will be used to verify new behaviour, as used
by cert-manager currently. Current end-to-end tests for Certificate resources
will also give a good signal for CertificateRequests once the controller has
migrated its implementation.
Risks and Mitigations
The introduction and consequently the reliance on this core resource for all cert-manager functions means it poses a high risk to bugs or unexpected behaviour appearing across the whole codebase. With this, it is key to ensure the change happens in incremental roll-outs and proper care is taken during testing.
The new resource could be potentially confusing for current cert-manager users. To mitigate this, proper documentation should be created to explain the changes. It should also be made clear that the resource is typically only to be consumed or managed by a more complex controller or system, not necessarily a human user.
Graduation Criteria
Alpha
- Creation of
CertificateRequestresource. - A CA issuer
CertificateRequestcontroller. - Exposing the single controller via a feature gated flag.
Alpha -> Beta Graduation
- All issuers have a
CertificateRequestcontroller. - All controllers are enabled by default.
- The
Certificatecontroller optionally makes use of theCertificateRequestresource to resolve certificates when a feature flag is enabled.
Beta -> GA Graduation
- The
CertificateRequestAPI resource should be considered stable. - The
Certificatecontroller makes use of theCertificateRequestresource to resolve certificates.