From 8377a675cd4beef6da89eba9829a05c14b19a60f Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Thu, 16 Mar 2023 13:00:31 -0700 Subject: [PATCH 1/2] ClusterTrustBundles: Add section to certificates page Document the API types as they exist today, plus a hint of the future integrations that will be available. Co-Authored-By: Taahir Ahmed --- .../certificate-signing-requests.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) 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 aa95223bb0..ed61a6e3c5 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 @@ -459,6 +459,95 @@ status: certificate: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JS..." ``` +## ClusterTrustBundles (Alpha Feature) {#ctb} + +{{< feature-state for_k8s_version="v1.27" state="alpha" >}} + +{{< note >}} +Gated by the `ClusterTrustBundles` feature gate. +{{< /note >}} + +ClusterTrustBundles are a cluster-scoped object for distributing X.509 trust +anchors (root certificates) to workloads within the cluster. They're designed +to work well with the existing signer concept. + +Future Kubernetes releases will build on them with integrations like the ability +to project their contents into the pod filesystem. + +ClusterTrustBundles can be used in two modes: signer-linked and signer-unlinked. + +### Common properties and validation {#ctb-common} + +All ClusterTrustBundle objects have strong validation on the contents of their +`trustBundle` field. It must contain one or more X.509 certificates, +DER-serialized, each wrapped in a PEM `CERTIFICATE` block. The certificates +must parse as valid X.509 certificates. + +Esoteric PEM features like inter-block data and intra-block headers are either +rejected during object validation, or filtered by consumers of the object +(primarily Kubelet). Additionally, consumers will reorder the certificates in +the bundle with their own arbitrary but stable ordering. + +ClusterTrustBundle objects should be considered world-readable within the +cluster. All serviceaccounts have a default RBAC grant to get, list, and watch +all ClusterTrustBundle objects. + +### Signer-linked ClusterTrustBundles {#ctb-signer-linked} + +Signer-linked ClusterTrustBundles are associated with a signer name, like this: + +```yaml +apiVersion: certificates.k8s.io/v1alpha1 +kind: ClusterTrustBundle +metadata: + name: example.com:mysigner:foo +spec: + signerName: example.com/mysigner + trustBundle: "<... PEM data ...>" +``` + +These ClusterTrustBundles are intended to be maintained by a signer-specific +controller in the cluster, so they have several security features: + +* To create or update a signer-linked ClusterTrustBundle, you must have the + `attest` verb on the signer (verbs: `attest`, group: `certificates.k8s.io`, + resource: `signers`, resourceName: `/` or + `/*`). +* Signer-linked ClusterTrustBundles must be named with a prefix derived from + their `spec.signerName` field. Slashes (`/`) are replaced with colons (`:`), + and a final colon is appended. This is followed by an arbitary name. For + example, the signer `example.com/mysigner` becomes + `example.com:mysigner:`. + +Signer-linked ClusterTrustBundles will be consumed in workloads by a combination +of field selector on the signer name and a label selector. If this query +matches multiple ClusterTrustBundle objects, their contents will be merged, +deduplicated, and sorted before being provided to the workload. + +### Signer-unlinked ClusterTrustBundles {#ctb-signer-unlinked} + +Signer-unlinked ClusterTrustBundles have an empty `spec.signerName` field, like this: + +```yaml +apiVersion: certificates.k8s.io/v1alpha1 +kind: ClusterTrustBundle +metadata: + name: foo +spec: + signerName: "" + trustBundle: "<... PEM data ...>" +``` + +They are primarily intended for cluster configuration use cases. Each +signer-unlinked ClusterTrustBundle is an independent object, in contrast to the +customary grouping behavior of signer-linked ClusterTrustBundles. + +Signer-unlinked ClusterTrustBundles have no `attest` verb requirement. Instead, +control access to them using the standard RBAC verbs. + +To distinguish them from signer-linked ClusterTrustBundles, the names of +signer-unlinked ClusterTrustBundles must not contain a colon (`:`). + ## {{% heading "whatsnext" %}} * Read [Manage TLS Certificates in a Cluster](/docs/tasks/tls/managing-tls-in-a-cluster/) From e95deae997ac01540211e0666e2b453a3829f3b2 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Sun, 9 Apr 2023 18:17:50 +0100 Subject: [PATCH 2/2] Update CSR page to encompass CSRs and trust bundles Rather than mention trust bundles as a subtopic of certificate signing requests, reshape the page so that: - it's clear that CSRs are stable but ClusterTrustBundles are alpha - the task for issuing a certificate to a user stands separately from the concepts explained elsewhere in the page - it's clear that signers are relevant to both CSRs and ClusterTrustBundles --- .../certificate-signing-requests.md | 517 ++++++++++-------- 1 file changed, 278 insertions(+), 239 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 ed61a6e3c5..4ce299e5fb 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 @@ -4,27 +4,33 @@ reviewers: - mikedanese - munnerz - enj -title: Certificate Signing Requests +title: Certificates and Certificate Signing Requests content_type: concept weight: 25 --- -{{< feature-state for_k8s_version="v1.19" state="stable" >}} - -The Certificates API enables automation of +Kubernetes certificate and trust bundle APIs enable 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). +There is also experimental (alpha) support for distributing [trust bundles](#cluster-trust-bundles). + + + +## Certificate signing requests + +{{< feature-state for_k8s_version="v1.19" state="stable" >}} + + 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. - -## Request signing process +### Request signing process The CertificateSigningRequest resource type allows a client to ask for an X.509 certificate be issued, based on a signing request. @@ -64,12 +70,46 @@ state for some duration: * Pending requests: automatically deleted after 24 hours * All requests: automatically deleted after the issued certificate has expired +### Certificate signing authorization {#authorization} + +To allow creating a CertificateSigningRequest and retrieving any CertificateSigningRequest: + +* Verbs: `create`, `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` + +For example: + +{{< codenew file="access/certificate-signing-request/clusterrole-create.yaml" >}} + +To allow approving a CertificateSigningRequest: + +* Verbs: `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` +* Verbs: `update`, group: `certificates.k8s.io`, resource: `certificatesigningrequests/approval` +* Verbs: `approve`, group: `certificates.k8s.io`, resource: `signers`, resourceName: `/` or `/*` + +For example: + +{{< codenew file="access/certificate-signing-request/clusterrole-approve.yaml" >}} + +To allow signing a CertificateSigningRequest: + +* Verbs: `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` +* Verbs: `update`, group: `certificates.k8s.io`, resource: `certificatesigningrequests/status` +* Verbs: `sign`, group: `certificates.k8s.io`, resource: `signers`, resourceName: `/` or `/*` + +{{< codenew file="access/certificate-signing-request/clusterrole-sign.yaml" >}} + + ## Signers -Custom signerNames can also be specified. All signers should provide information about how they work so that clients can predict what will happen to their CSRs. +Signers abstractly represent the entity or entities that might sign, or have +signed, a security certificate. + +Any signer that is made available for outside a particular cluster should provide information +about how the signer works, so that consumers can understand what that means for CertifcateSigningRequests +and (if enabled) [ClusterTrustBundles](#cluster-trust-bundles). This includes: -1. **Trust distribution**: how trust (CA bundles) are distributed. +1. **Trust distribution**: how trust anchors (CA certificates or certificate bundles) are distributed. 1. **Permitted subjects**: any restrictions on and behavior when a disallowed subject is requested. 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. @@ -77,13 +117,17 @@ This includes: and the behavior when the signer-determined expiration is different from the CSR `spec.expirationSeconds` field. 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 +Commonly, the `status.certificate` field of a CertificateSigningRequest 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 the certificate plus intermediates to be presented during TLS handshakes. +If you want to make the _trust anchor_ (root certificate) available, this should be done +separately from a CertificateSigningRequest and its `status.certificate` field. For example, +you could use a ClusterTrustBundle. + The PKCS#10 signing request format does not have a standard mechanism to specify a certificate expiration or lifetime. The expiration or lifetime therefore has to be set through the `spec.expirationSeconds` field of the CSR object. The built-in signers @@ -153,9 +197,8 @@ Kubernetes provides built-in signers that each have a well-known `signerName`: of the `--cluster-signing-duration` option or, if specified, the `spec.expirationSeconds` field of the CSR object. 1. CA bit allowed/disallowed - not allowed. -{{< note >}} -Failures for all of these are only reported in kube-controller-manager logs. -{{< /note >}} +The kube-controller-manager implements [control plane signing](#signer-control-plane) for each of the built in +signers. Failures for all of these are only reported in kube-controller-manager logs. {{< note >}} The `spec.expirationSeconds` field was added in Kubernetes v1.22. Earlier versions of Kubernetes do not honor this field. @@ -168,156 +211,89 @@ kube-apiserver, but this is not a standard. None of these usages are related to ServiceAccount token secrets `.data[ca.crt]` in any way. That CA bundle is only guaranteed to verify a connection to the API server using the default service (`kubernetes.default.svc`). -## Authorization +### Custom signers -To allow creating a CertificateSigningRequest and retrieving any CertificateSigningRequest: +You can also introduce your own custom signer, which should have a similar prefixed name but using your +own domain name. For example, if you represent an open source project that uses the domain `open-fictional.example` +then you might use `issuer.open-fictional.example/service-mesh` as a signer name. -* Verbs: `create`, `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` +A custom signer uses the Kubernetes API to issue a certificate. See [API-based signers](#signer-api). -For example: +## Signing -{{< codenew file="access/certificate-signing-request/clusterrole-create.yaml" >}} +### Control plane signer {#signer-control-plane} -To allow approving a CertificateSigningRequest: +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. -* Verbs: `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` -* Verbs: `update`, group: `certificates.k8s.io`, resource: `certificatesigningrequests/approval` -* Verbs: `approve`, group: `certificates.k8s.io`, resource: `signers`, resourceName: `/` or `/*` +{{< note >}} +Prior to Kubernetes v1.18, the kube-controller-manager would sign any CSRs that +were marked as approved. +{{< /note >}} -For example: +{{< note >}} +The `spec.expirationSeconds` field was added in Kubernetes v1.22. Earlier versions of Kubernetes do not honor this field. +Kubernetes API servers prior to v1.22 will silently drop this field when the object is created. +{{< /note >}} -{{< codenew file="access/certificate-signing-request/clusterrole-approve.yaml" >}} +### API-based signers {#signer-api} -To allow signing a CertificateSigningRequest: +Users of the REST API can sign CSRs by submitting an UPDATE request to the `status` +subresource of the CSR to be signed. -* Verbs: `get`, `list`, `watch`, group: `certificates.k8s.io`, resource: `certificatesigningrequests` -* Verbs: `update`, group: `certificates.k8s.io`, resource: `certificatesigningrequests/status` -* Verbs: `sign`, group: `certificates.k8s.io`, resource: `signers`, resourceName: `/` or `/*` +As part of this request, the `status.certificate` field should be set to contain the +signed certificate. This field contains one or more PEM-encoded certificates. -{{< codenew file="access/certificate-signing-request/clusterrole-sign.yaml" >}} +All PEM blocks must have the "CERTIFICATE" label, contain no headers, +and the encoded data must be a BER-encoded ASN.1 Certificate structure +as described in [section 4 of RFC5280](https://tools.ietf.org/html/rfc5280#section-4.1). -## Normal user +Example certificate content: -A few steps are required in order to get a normal user to be able to -authenticate and invoke an API. First, this user must have a certificate issued -by the Kubernetes cluster, and then present that certificate to the Kubernetes API. - -### Create private key - -The following scripts show how to generate PKI private key and CSR. It is -important to set CN and O attribute of the CSR. CN is the name of the user and -O is the group that this user will belong to. You can refer to -[RBAC](/docs/reference/access-authn-authz/rbac/) for standard groups. - -```shell -openssl genrsa -out myuser.key 2048 -openssl req -new -key myuser.key -out myuser.csr +``` +-----BEGIN CERTIFICATE----- +MIIDgjCCAmqgAwIBAgIUC1N1EJ4Qnsd322BhDPRwmg3b/oAwDQYJKoZIhvcNAQEL +BQAwXDELMAkGA1UEBhMCeHgxCjAIBgNVBAgMAXgxCjAIBgNVBAcMAXgxCjAIBgNV +BAoMAXgxCjAIBgNVBAsMAXgxCzAJBgNVBAMMAmNhMRAwDgYJKoZIhvcNAQkBFgF4 +MB4XDTIwMDcwNjIyMDcwMFoXDTI1MDcwNTIyMDcwMFowNzEVMBMGA1UEChMMc3lz +dGVtOm5vZGVzMR4wHAYDVQQDExVzeXN0ZW06bm9kZToxMjcuMC4wLjEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDne5X2eQ1JcLZkKvhzCR4Hxl9+ZmU3 ++e1zfOywLdoQxrPi+o4hVsUH3q0y52BMa7u1yehHDRSaq9u62cmi5ekgXhXHzGmm +kmW5n0itRECv3SFsSm2DSghRKf0mm6iTYHWDHzUXKdm9lPPWoSOxoR5oqOsm3JEh +Q7Et13wrvTJqBMJo1GTwQuF+HYOku0NF/DLqbZIcpI08yQKyrBgYz2uO51/oNp8a +sTCsV4OUfyHhx2BBLUo4g4SptHFySTBwlpRWBnSjZPOhmN74JcpTLB4J5f4iEeA7 +2QytZfADckG4wVkhH3C2EJUmRtFIBVirwDn39GXkSGlnvnMgF3uLZ6zNAgMBAAGj +YTBfMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMB +Af8EAjAAMB0GA1UdDgQWBBTREl2hW54lkQBDeVCcd2f2VSlB1DALBgNVHREEBDAC +ggAwDQYJKoZIhvcNAQELBQADggEBABpZjuIKTq8pCaX8dMEGPWtAykgLsTcD2jYr +L0/TCrqmuaaliUa42jQTt2OVsVP/L8ofFunj/KjpQU0bvKJPLMRKtmxbhXuQCQi1 +qCRkp8o93mHvEz3mTUN+D1cfQ2fpsBENLnpS0F4G/JyY2Vrh19/X8+mImMEK5eOy +o0BMby7byUj98WmcUvNCiXbC6F45QTmkwEhMqWns0JZQY+/XeDhEcg+lJvz9Eyo2 +aGgPsye1o3DpyXnyfJWAWMhOz7cikS5X2adesbgI86PhEHBXPIJ1v13ZdfCExmdd +M1fLPhLyR54fGaY+7/X8P9AZzPefAkwizeXwe9ii6/a08vWoiE4= +-----END CERTIFICATE----- ``` -### Create CertificateSigningRequest +Non-PEM content may appear before or after the CERTIFICATE PEM blocks and is unvalidated, +to allow for explanatory text as described in [section 5.2 of RFC7468](https://www.rfc-editor.org/rfc/rfc7468#section-5.2). -Create a CertificateSigningRequest and submit it to a Kubernetes Cluster via kubectl. Below is a script to generate the CertificateSigningRequest. +When encoded in JSON or YAML, this field is base-64 encoded. +A CertificateSigningRequest containing the example certificate above would look like this: -```shell -cat < myuser.crt -``` - -### Create Role and RoleBinding - -With the certificate created it is time to define the Role and RoleBinding for -this user to access Kubernetes cluster resources. - -This is a sample command to create a Role for this new user: - -```shell -kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods -``` - -This is a sample command to create a RoleBinding for this new user: - -```shell -kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser -``` - -### Add to kubeconfig - -The last step is to add this user into the kubeconfig file. - -First, you need to add new credentials: - -```shell -kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true - -``` - -Then, you need to add the context: - -```shell -kubectl config set-context myuser --cluster=kubernetes --user=myuser -``` - -To test it, change the context to `myuser`: - -```shell -kubectl config use-context myuser +... +status: + certificate: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JS..." ``` ## Approval or rejection {#approval-rejection} +Before a [signer](#signers) issues a certificate based on a CertificateSigningRequest, +the signer typically checks that the issuance for that CSR has been _approved_. + ### Control plane automated approval {#approval-rejection-control-plane} The kube-controller-manager ships with a built-in approver for certificates with @@ -389,112 +365,49 @@ code using TitleCase; this is a convention but you can set it to anything you like. If you want to add a note for human consumption, use the `status.conditions.message` field. -## Signing -### 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. - -{{< note >}} -Prior to Kubernetes v1.18, the kube-controller-manager would sign any CSRs that -were marked as approved. -{{< /note >}} - -{{< note >}} -The `spec.expirationSeconds` field was added in Kubernetes v1.22. Earlier versions of Kubernetes do not honor this field. -Kubernetes API servers prior to v1.22 will silently drop this field when the object is created. -{{< /note >}} - -### 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. - -As part of this request, the `status.certificate` field should be set to contain the -signed certificate. This field contains one or more PEM-encoded certificates. - -All PEM blocks must have the "CERTIFICATE" label, contain no headers, -and the encoded data must be a BER-encoded ASN.1 Certificate structure -as described in [section 4 of RFC5280](https://tools.ietf.org/html/rfc5280#section-4.1). - -Example certificate content: - -``` ------BEGIN CERTIFICATE----- -MIIDgjCCAmqgAwIBAgIUC1N1EJ4Qnsd322BhDPRwmg3b/oAwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCeHgxCjAIBgNVBAgMAXgxCjAIBgNVBAcMAXgxCjAIBgNV -BAoMAXgxCjAIBgNVBAsMAXgxCzAJBgNVBAMMAmNhMRAwDgYJKoZIhvcNAQkBFgF4 -MB4XDTIwMDcwNjIyMDcwMFoXDTI1MDcwNTIyMDcwMFowNzEVMBMGA1UEChMMc3lz -dGVtOm5vZGVzMR4wHAYDVQQDExVzeXN0ZW06bm9kZToxMjcuMC4wLjEwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDne5X2eQ1JcLZkKvhzCR4Hxl9+ZmU3 -+e1zfOywLdoQxrPi+o4hVsUH3q0y52BMa7u1yehHDRSaq9u62cmi5ekgXhXHzGmm -kmW5n0itRECv3SFsSm2DSghRKf0mm6iTYHWDHzUXKdm9lPPWoSOxoR5oqOsm3JEh -Q7Et13wrvTJqBMJo1GTwQuF+HYOku0NF/DLqbZIcpI08yQKyrBgYz2uO51/oNp8a -sTCsV4OUfyHhx2BBLUo4g4SptHFySTBwlpRWBnSjZPOhmN74JcpTLB4J5f4iEeA7 -2QytZfADckG4wVkhH3C2EJUmRtFIBVirwDn39GXkSGlnvnMgF3uLZ6zNAgMBAAGj -YTBfMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMB -Af8EAjAAMB0GA1UdDgQWBBTREl2hW54lkQBDeVCcd2f2VSlB1DALBgNVHREEBDAC -ggAwDQYJKoZIhvcNAQELBQADggEBABpZjuIKTq8pCaX8dMEGPWtAykgLsTcD2jYr -L0/TCrqmuaaliUa42jQTt2OVsVP/L8ofFunj/KjpQU0bvKJPLMRKtmxbhXuQCQi1 -qCRkp8o93mHvEz3mTUN+D1cfQ2fpsBENLnpS0F4G/JyY2Vrh19/X8+mImMEK5eOy -o0BMby7byUj98WmcUvNCiXbC6F45QTmkwEhMqWns0JZQY+/XeDhEcg+lJvz9Eyo2 -aGgPsye1o3DpyXnyfJWAWMhOz7cikS5X2adesbgI86PhEHBXPIJ1v13ZdfCExmdd -M1fLPhLyR54fGaY+7/X8P9AZzPefAkwizeXwe9ii6/a08vWoiE4= ------END CERTIFICATE----- -``` - -Non-PEM content may appear before or after the CERTIFICATE PEM blocks and is unvalidated, -to allow for explanatory text as described in [section 5.2 of RFC7468](https://www.rfc-editor.org/rfc/rfc7468#section-5.2). - -When encoded in JSON or YAML, this field is base-64 encoded. -A CertificateSigningRequest containing the example certificate above would look like this: - -```yaml -apiVersion: certificates.k8s.io/v1 -kind: CertificateSigningRequest -... -status: - certificate: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JS..." -``` - -## ClusterTrustBundles (Alpha Feature) {#ctb} +## Cluster trust bundles {#cluster-trust-bundles} {{< feature-state for_k8s_version="v1.27" state="alpha" >}} {{< note >}} -Gated by the `ClusterTrustBundles` feature gate. +In Kubernetes {{< skew currentVersion >}}, you must enable the `ClusterTrustBundles` +[feature gate](/docs/reference/command-line-tools-reference/feature-gates/) +_and_ the `certificates.k8s.io/v1alpha1` +{{< glossary_tooltip text="API group" term_id="api-group" >}} in order to use +this API. {{< /note >}} -ClusterTrustBundles are a cluster-scoped object for distributing X.509 trust +A ClusterTrustBundles is a cluster-scoped object for distributing X.509 trust anchors (root certificates) to workloads within the cluster. They're designed -to work well with the existing signer concept. +to work well with the [signer](#signers) concept from CertificateSigningRequests. -Future Kubernetes releases will build on them with integrations like the ability -to project their contents into the pod filesystem. - -ClusterTrustBundles can be used in two modes: signer-linked and signer-unlinked. +ClusterTrustBundles can be used in two modes: +[signer-linked](#ctb-signer-linked) and [signer-unlinked](#ctb-signer-unlinked). ### Common properties and validation {#ctb-common} All ClusterTrustBundle objects have strong validation on the contents of their -`trustBundle` field. It must contain one or more X.509 certificates, +`trustBundle` field. That field must contain one or more X.509 certificates, DER-serialized, each wrapped in a PEM `CERTIFICATE` block. The certificates must parse as valid X.509 certificates. Esoteric PEM features like inter-block data and intra-block headers are either -rejected during object validation, or filtered by consumers of the object -(primarily Kubelet). Additionally, consumers will reorder the certificates in +rejected during object validation, or can be ignored by consumers of the object. +Additionally, consumers are allowed to reorder the certificates in the bundle with their own arbitrary but stable ordering. ClusterTrustBundle objects should be considered world-readable within the -cluster. All serviceaccounts have a default RBAC grant to get, list, and watch -all ClusterTrustBundle objects. +cluster. If your cluster uses [RBAC](/docs/reference/access-authn-authz/rbac/) +authorization, all ServiceAccounts have a default grant that allows them to +**get**, **list**, and **watch** all ClusterTrustBundle objects. +If you use your own authorization mechanism and you have enabled +ClusterTrustBundles in your cluster, you should set up an equivalent rule to +make these objects public within the cluster, so that they work as intended. ### Signer-linked ClusterTrustBundles {#ctb-signer-linked} -Signer-linked ClusterTrustBundles are associated with a signer name, like this: +Signer-linked ClusterTrustBundles are associated with a _signer name_, like this: ```yaml apiVersion: certificates.k8s.io/v1alpha1 @@ -509,20 +422,22 @@ spec: These ClusterTrustBundles are intended to be maintained by a signer-specific controller in the cluster, so they have several security features: -* To create or update a signer-linked ClusterTrustBundle, you must have the - `attest` verb on the signer (verbs: `attest`, group: `certificates.k8s.io`, - resource: `signers`, resourceName: `/` or - `/*`). -* Signer-linked ClusterTrustBundles must be named with a prefix derived from +* To create or update a signer-linked ClusterTrustBundle, you must be permitted + to **attest** on the signer (custom authorization verb `attest`, + API group `certificates.k8s.io`; resource path `signers`). You can configure + authorization for the specific resource name + `/` or match a pattern such as + `/*`. +* Signer-linked ClusterTrustBundles **must** be named with a prefix derived from their `spec.signerName` field. Slashes (`/`) are replaced with colons (`:`), and a final colon is appended. This is followed by an arbitary name. For - example, the signer `example.com/mysigner` becomes - `example.com:mysigner:`. + example, the signer `example.com/mysigner` can be linked to a + ClusterTrustBundle `example.com:mysigner:`. -Signer-linked ClusterTrustBundles will be consumed in workloads by a combination -of field selector on the signer name and a label selector. If this query -matches multiple ClusterTrustBundle objects, their contents will be merged, -deduplicated, and sorted before being provided to the workload. +Signer-linked ClusterTrustBundles will typically be consumed in workloads +by a combination of a +[field selector](/docs/concepts/overview/working-with-objects/field-selectors/) on the signer name, and a separate +[label selector](/docs/concepts/overview/working-with-objects/labels/#label-selectors). ### Signer-unlinked ClusterTrustBundles {#ctb-signer-unlinked} @@ -534,7 +449,7 @@ kind: ClusterTrustBundle metadata: name: foo spec: - signerName: "" + # no signerName specified, so the field is blank trustBundle: "<... PEM data ...>" ``` @@ -542,11 +457,135 @@ They are primarily intended for cluster configuration use cases. Each signer-unlinked ClusterTrustBundle is an independent object, in contrast to the customary grouping behavior of signer-linked ClusterTrustBundles. -Signer-unlinked ClusterTrustBundles have no `attest` verb requirement. Instead, -control access to them using the standard RBAC verbs. +Signer-unlinked ClusterTrustBundles have no `attest` verb requirement. +Instead, you control access to them directly using the usual mechanisms, +such as role-based access control. To distinguish them from signer-linked ClusterTrustBundles, the names of -signer-unlinked ClusterTrustBundles must not contain a colon (`:`). +signer-unlinked ClusterTrustBundles **must not** contain a colon (`:`). + + +## How to issue a certificate for a user {#normal-user} + +A few steps are required in order to get a normal user to be able to +authenticate and invoke an API. First, this user must have a certificate issued +by the Kubernetes cluster, and then present that certificate to the Kubernetes API. + +### Create private key + +The following scripts show how to generate PKI private key and CSR. It is +important to set CN and O attribute of the CSR. CN is the name of the user and +O is the group that this user will belong to. You can refer to +[RBAC](/docs/reference/access-authn-authz/rbac/) for standard groups. + +```shell +openssl genrsa -out myuser.key 2048 +openssl req -new -key myuser.key -out myuser.csr +``` + +### Create a CertificateSigningRequest {#create-certificatessigningrequest} + +Create a CertificateSigningRequest and submit it to a Kubernetes Cluster via kubectl. Below is a script to generate the CertificateSigningRequest. + +```shell +cat < myuser.crt +``` + +### Create Role and RoleBinding + +With the certificate created it is time to define the Role and RoleBinding for +this user to access Kubernetes cluster resources. + +This is a sample command to create a Role for this new user: + +```shell +kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods +``` + +This is a sample command to create a RoleBinding for this new user: + +```shell +kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser +``` + +### Add to kubeconfig + +The last step is to add this user into the kubeconfig file. + +First, you need to add new credentials: + +```shell +kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true + +``` + +Then, you need to add the context: + +```shell +kubectl config set-context myuser --cluster=kubernetes --user=myuser +``` + +To test it, change the context to `myuser`: + +```shell +kubectl config use-context myuser +``` + ## {{% heading "whatsnext" %}}