From 0ad51f71e19bbfadca3b91ec70de4d19eb5cb2e9 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Thu, 19 Mar 2020 13:35:23 +0000 Subject: [PATCH] Revise CertificateSigningRequest documentation (#19698) * Revise CertificateSigningRequest approval & rejection details API clients can deny CSRs. Document this and tidy the page. "There is currently not a mechanism for a signer implementation to report its inability to sign a request." seemed misleading; clients can set status. * Tidy page Co-Authored-By: Jordan Liggitt Co-authored-by: Jordan Liggitt --- .../certificate-signing-requests.md | 88 +++++++++++-------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/content/en/docs/reference/access-authn-authz/certificate-signing-requests.md b/content/en/docs/reference/access-authn-authz/certificate-signing-requests.md index b8e4f34bc2..95315eb29b 100644 --- a/content/en/docs/reference/access-authn-authz/certificate-signing-requests.md +++ b/content/en/docs/reference/access-authn-authz/certificate-signing-requests.md @@ -16,6 +16,7 @@ The Certificates API enables automation of [X.509](https://www.itu.int/rec/T-REC-X.509) credential provisioning by providing a programmatic interface for clients of the Kubernetes API to request and obtain X.509 {{< glossary_tooltip term_id="certificate" text="certificates" >}} from a Certificate Authority (CA). + A CertificateSigningRequest (CSR) resource is used to request that a certificate be signed by a denoted signer, after which the request may be approved or denied before finally being signed. @@ -25,29 +26,33 @@ finally being signed. {{% capture body %}} ## Request signing process -The _CertificateSigningRequest_ resource type allows a client to submit an x509 CSR (`spec.request`) -and request it be signed by a specific _signer_, denoted by the `spec.signerName` field. +The _CertificateSigningRequest_ resource type allows a client to ask for an X.509 certificate +be issued, based on a signing request. +The CertificateSigningRequest object includes a PEM-encoded PKCS#10 signing request in +the `spec.request` field. The CertificateSigningRequest denotes the _signer_ (the +recipient that the request is being made to) using the `spec.signerName` field. Once created, a CertificateSigningRequest must be approved before it can be signed. -Depending on the signer requested, a CertificateSigningRequest may be auto-approved by a -{{< glossary_tooltip text="controller" term_id="controller" >}}. +Depending on the signer selected, a CertificateSigningRequest may be automatically approved +by a {{< glossary_tooltip text="controller" term_id="controller" >}}. Otherwise, a CertificateSigningRequest must be manually approved either via the REST API (or client-go) -or via `kubectl certificate approve`. Likewise, a CertificateSigningRequest may also be denied, in which -case the configured signer must not sign the request. +or by running `kubectl certificate approve`. Likewise, a CertificateSigningRequest may also be denied, +which tells the configured signer that it must not sign the request. -Once approved, a signing controller must attempt to sign the request. A signer should apply its own policy -restrictions, similar to the approval process, on the request to ensure it never signs an invalid request. -There is currently not a mechanism for a signer implementation to report its inability to sign a request. -Once the signer has determined that a request should be signed, it must sign the request and store the -resulting certificate (and if appropriate, certificate chain) in the `status.certificate` field as PEM-encoded -certificates. +For certificates that have been approved, the next step is signing. The relevant signing controller +first validates that the signing conditions are met and then creates a certificate. +The signing controller then updates the CertificateSigningRequest, storing the new certificate into +the `status.certificate` field of the existing CertificateSigningRequest object. The +`status.certificate` field is either empty or contains a X.509 certificate, encoded in PEM format. +The CertificateSigningRequest `status.certificate` field is empty until the signer does this. Once the `status.certificate` field has been populated, the request has been completed and clients can now fetch the signed certificate PEM data from the CertificateSigningRequest resource. +Signers can instead deny certificate signing if the approval conditions are not met. In order to reduce the number of old CertificateSigningRequest resources left in a cluster, a garbage collection -controller runs periodically. Depending on the state of the request, it will automatically delete requests older -than a specified duration: +controller runs periodically. The garbage collection removes CertificateSigningRequests that have not changed +state for some duration: * Approved requests: automatically deleted after 1 hour * Denied requests: automatically deleted after 1 hour @@ -55,8 +60,6 @@ than a specified duration: ## Signers -### Signers should define... - All signers should provide information about how they work so that clients can predict what will happen to their CSRs. This includes: @@ -65,8 +68,9 @@ This includes: 1. **Permitted x509 extensions**: including IP subjectAltNames, DNS subjectAltNames, Email subjectAltNames, URI subjectAltNames etc, and behavior when a disallowed extension is requested. 1. **Permitted key usages / extended key usages**: any restrictions on and behavior when usages different than the signer-determined usages are specified in the CSR. 1. **Expiration/certificate lifetime**: whether it is fixed by the signer, configurable by the admin, determined by the CSR object etc and behavior if an expiration different than the signer-determined expiration is specified in the CSR. -1. **CA bit allowed/disallowed**: and behavior if a CSR contains a request a for a CA cert when the signer does not permit it. -1. **optional**: Information about the meaning of additional `CERTIFICATE` PEM blocks in `status.certificate`, if different from the standard behavior of treating the additional certificates as intermediates, and presenting them in TLS handshakes. +1. **CA bit allowed/disallowed**: and behavior if a CSR contains a request a for a CA certificate when the signer does not permit it. + +Commonly, the `status.certificate` field contains a single PEM-encoded X.509 certificate once the CSR is approved and the certificate is issued. Some signers store multiple certificates into the `status.certificate` field. In that case, the documentation for the signer should specify the meaning of additional certificates; for example, this might be certificate plus intermediates to be presented during TLS handshakes. ### Kubernetes signers @@ -78,7 +82,7 @@ Kubernetes provides built-in signers that each have a well-known `signerName`: 1. Permitted subjects - no subject restrictions, but approvers and signers may choose not to approve or sign. Certain subjects like cluster-admin level users or groups vary between distributions and installations, but deserve additional scrutiny before approval and signing. The `CertificateSubjectRestriction` admission plugin is available and enabled by default to restrict `system:masters`, but it is often not the only cluster-admin subject in a cluster. 1. Permitted x509 extensions - honors subjectAltName and key usage extensions and discards other extensions. 1. Permitted key usages - must include []string{"client auth"}. Must not include key usages beyond []string{"digital signature", "key encipherment", "client auth"} - 1. Expiration/cert lifetime - minimum of CSR signer or request. Sanity of the time is the concern of the signer. + 1. Expiration/certificate lifetime - minimum of CSR signer or request. The signer is responsible for checking that the certificate lifetime is valid and permissible. 1. CA bit allowed/disallowed - not allowed. 1. `kubernetes.io/kube-apiserver-client-kubelet`: signs client certificates that will be honored as client-certs by the @@ -89,7 +93,7 @@ Kubernetes provides built-in signers that each have a well-known `signerName`: 1. Permitted subjects - organizations are exactly `[]string{"system:nodes"}`, common name starts with `"system:node:"` 1. Permitted x509 extensions - honors key usage extensions, forbids subjectAltName extensions, drops other extensions. 1. Permitted key usages - exactly `[]string{"key encipherment", "digital signature", "client auth"}` - 1. Expiration/cert lifetime - minimum of CSR signer or request. Sanity of the time is the concern of the signer. + 1. Expiration/certificate lifetime - minimum of CSR signer or request. Sanity of the time is the concern of the signer. 1. CA bit allowed/disallowed - not allowed. 1. `kubernetes.io/kubelet-serving`: signs serving certificates that are honored as a valid kubelet serving certificate @@ -100,17 +104,17 @@ Kubernetes provides built-in signers that each have a well-known `signerName`: 1. Permitted subjects - organizations are exactly `[]string{"system:nodes"}`, common name starts with `"system:node:"` 1. Permitted x509 extensions - honors key usage and DNSName/IPAddress subjectAltName extensions, forbids EmailAddress and URI subjectAltName extensions, drops other extensions. At least one DNS or IP subjectAltName must be present. 1. Permitted key usages - exactly `[]string{"key encipherment", "digital signature", "server auth"}` - 1. Expiration/cert lifetime - minimum of CSR signer or request. + 1. Expiration/certificate lifetime - minimum of CSR signer or request. 1. CA bit allowed/disallowed - not allowed. 1. `kubernetes.io/legacy-unknown`: has no guarantees for trust at all. Some distributions may honor these as client - certs, but that behavior is not standard kubernetes behavior. + certs, but that behavior is not standard Kubernetes behavior. Never auto-approved by {{< glossary_tooltip term_id="kube-controller-manager" >}}. - 1. Trust distribution: None. There is no standard trust or distribution for this signer in a kubernetes cluster. + 1. Trust distribution: None. There is no standard trust or distribution for this signer in a Kubernetes cluster. 1. Permitted subjects - any 1. Permitted x509 extensions - honors subjectAltName and key usage extensions and discards other extensions. 1. Permitted key usages - any - 1. Expiration/cert lifetime - minimum of CSR signer or request. Sanity of the time is the concern of the signer. + 1. Expiration/certificate lifetime - minimum of CSR signer or request. Sanity of the time is the concern of the signer. 1. CA bit allowed/disallowed - not allowed. {{< note >}} @@ -222,16 +226,17 @@ rules: - sign ``` -## Approval/Rejection +## Approval & rejection -### kube-controller-manager auto-approval +### Control plane automated approval {#approval-rejection-control-plane} The kube-controller-manager ships with a built-in approver for certificates with a signerName of `kubernetes.io/kube-apiserver-client-kubelet` that delegates various permissions on CSRs for node credentials to authorization. -It does this by posting SubjectAccessReview resources to the API server. +The kube-controller-manager POSTs SubjectAccessReview resources to the API server +in order to check authorization for certificate approval. -### kubectl-based approver +### Approval & rejection using `kubectl` {#approval-rejection-kubectl} A Kubernetes administrator (with appropriate permissions) can manually approve (or deny) CertificateSigningRequests by using the `kubectl certificate @@ -249,15 +254,15 @@ Likewise, to deny a CSR: kubectl certificate deny ``` -### API-based approver +### Approval & rejection using the Kubernetes API {#approval-rejection-api-client} Users of the REST API can approve CSRs by submitting an UPDATE request to the `approval` subresource of the CSR to be approved. For example, you could write an {{< glossary_tooltip term_id="operator-pattern" text="operator" >}} that watches for a particular kind of CSR and then sends an UPDATE to approve them. -As part of this request, the `Approved` or `Denied` status condition should be set to the -desired state: +When you make an approval or rejection request, set either the `Approved` or `Denied` +status condition based on the state you determine: For `Approved` CSRs: @@ -269,7 +274,7 @@ status: conditions: - lastUpdateTime: "2020-02-08T11:37:35Z" message: Approved by my custom approver controller - reason: ApprovedByMyPolicy # this can be set to anything + reason: ApprovedByMyPolicy # You can set this to any string type: Approved ``` @@ -283,13 +288,18 @@ status: conditions: - lastUpdateTime: "2020-02-08T11:37:35Z" message: Denied by my custom approver controller - reason: DeniedByMyPolicy # this can be set to anything + reason: DeniedByMyPolicy # You can set this to any string type: Denied ``` +It's usual to set `status.condtions.reason` to a machine-friendly reason +code using TitleCase; this is a convention but you can set it to anything +you like. If you want to add a note just for human consumption, use the +`status.condtions.message` field. + ## Signing -### Control plane signer +### Control plane signer {#signer-control-plane} The Kubernetes control plane implements each of the [Kubernetes signers](/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers), as part of the kube-controller-manager. @@ -299,7 +309,7 @@ Prior to Kubernetes v1.18, the kube-controller-manager would sign any CSRs that were marked as approved. {{< /note >}} -### API-based signers +### API-based signers {#signer-api} Users of the REST API can sign CSRs by submitting an UPDATE request to the `status` subresource of the CSR to be signed. @@ -311,8 +321,10 @@ signed certificate. {{% capture whatsnext %}} -* kube-controller-manager built in [signer](https://github.com/kubernetes/kubernetes/blob/32ec6c212ec9415f604ffc1f4c1f29b782968ff1/pkg/controller/certificates/signer/cfssl_signer.go) -* kube-controller-manager built in [approver](https://github.com/kubernetes/kubernetes/blob/32ec6c212ec9415f604ffc1f4c1f29b782968ff1/pkg/controller/certificates/approver/sarapprove.go) -* [Manage TLS Certificates in a Cluster](https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/) +* Read [Manage TLS Certificates in a Cluster](https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/) +* View the source code for the kube-controller-manager built in [signer](https://github.com/kubernetes/kubernetes/blob/32ec6c212ec9415f604ffc1f4c1f29b782968ff1/pkg/controller/certificates/signer/cfssl_signer.go) +* View the source code for the kube-controller-manager built in [approver](https://github.com/kubernetes/kubernetes/blob/32ec6c212ec9415f604ffc1f4c1f29b782968ff1/pkg/controller/certificates/approver/sarapprove.go) +* For details of X.509 itself, refer to [RFC 5280](https://tools.ietf.org/html/rfc5280#section-3.1) section 3.1 +* For information on the syntax of PKCS#10 certificate signing requests, refer to [RFC 2986](https://tools.ietf.org/html/rfc2986) {{% /capture %}}