Skip to content

Commit f72ccf8

Browse files
committed
Pod Certificates: Narrow documentation of new feature
The "Certificates" page is creaking under its own weight, and is due to be split up. This is being pursued in a separate PR: #51487
1 parent 4ac5340 commit f72ccf8

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

content/en/docs/concepts/storage/projected-volumes.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Currently, the following types of volume sources can be projected:
2525
* [`configMap`](/docs/concepts/storage/volumes/#configmap)
2626
* [`serviceAccountToken`](#serviceaccounttoken)
2727
* [`clusterTrustBundle`](#clustertrustbundle)
28+
* [`podCertificate`](#podcertificate)
2829

2930
All sources are required to be in the same namespace as the Pod. For more details,
3031
see the [all-in-one volume](https://git.k8s.io/design-proposals-archive/node/all-in-one-volume.md) design document.
@@ -96,6 +97,62 @@ By default, the kubelet will prevent the pod from starting if the named ClusterT
9697

9798
{{% code_sample file="pods/storage/projected-clustertrustbundle.yaml" %}}
9899

100+
101+
## podCertificate projected volumes {#podcertificate}
102+
103+
{{< feature-state feature_gate_name="PodCertificateRequest" >}}
104+
105+
{{< note >}}
106+
In Kubernetes {{< skew currentVersion >}}, you must enable support for Pod
107+
Certificates using the `PodCertificateRequest` [feature
108+
gate](/docs/reference/command-line-tools-reference/feature-gates/) and the
109+
`--runtime-config=certificates.k8s.io/v1alpha1/podcertificaterequests=true`
110+
kube-apiserver flag.
111+
{{< /note >}}
112+
113+
The `podCertificate` projected volumes source securely provisions a private key
114+
and X.509 certificate chain for pod to use as client or server credentials.
115+
Kubelet will then handle refreshing the private key and certificate chain when
116+
they get close to expiration. The application just has to make sure that it
117+
reloads the file promptly when it changes, with a mechanism like `inotify` or
118+
polling.
119+
120+
Each `podCertificate` projection supports the following configuration fields:
121+
* `signerName`: The
122+
[signer](/docs/reference/access-authn-authz/certificate-signing-requests#signers)
123+
you want to issue the certificate. Note that signers may have their own
124+
access requirements, and may refuse to issue certificates to your pod.
125+
* `keyType`: The type of private key that should be generated. Valid values are
126+
`ED25519`, `ECDSAP256`, `ECDSAP384`, `ECDSAP521`, `RSA3072`, and `RSA4096`.
127+
* `maxExpirationSeconds`: The maximum lifetime you will accept for the
128+
certificate issued to the pod. If not set, will be defaulted to `86400` (24
129+
hours). Must be at least `3600` (1 hour), and at most `7862400` (91 days).
130+
Kubernetes built-in signers are restricted to a max lifetime of `86400` (1
131+
day). The signer is allowed to issue a certificate with a lifetime shorter
132+
than what you've specified.
133+
* `credentialBundlePath`: Relative path within the projection where the
134+
credential bundle should be written. The credential bundle is a PEM-formatted
135+
file, where the first block is a "PRIVATE KEY" block that contains a
136+
PKCS#8-serialized private key, and the remaining blocks are "CERTIFICATE"
137+
blocks that comprise the certificate chain (leaf certificate and any
138+
intermediates).
139+
* `keyPath` and `certificateChainPath`: Separate paths where Kubelet should
140+
write *just* the private key or certificate chain.
141+
142+
{{< note >}}
143+
144+
Most applications should prefer using `credentialBundlePath` unless they need
145+
the key and certificates in separate files for compatibility reasons. Kubelet
146+
uses an atomic writing strategy based on symlinks to make sure that when you
147+
open the files it projects, you read either the old content or the new content.
148+
However, if you read the key and certificate chain from separate files, Kubelet
149+
may rotate the credentials after your first read and before your second read,
150+
resulting in your application loading a mismatched key and certificate.
151+
152+
{{< /note >}}
153+
154+
{{% code_sample file="pods/storage/projected-podcertificate.yaml" %}}
155+
99156
## SecurityContext interactions
100157

101158
The [proposal](https://git.k8s.io/enhancements/keps/sig-storage/2451-service-account-token-volumes#proposal) for file permission handling in projected service account volume enhancement introduced the projected files having the correct owner permissions set.

content/en/docs/reference/access-authn-authz/certificate-signing-requests.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,97 @@ you like. If you want to add a note for human consumption, use the
376376
`status.conditions.message` field.
377377

378378

379+
## PodCertificateRequests {#pod-certificate-requests}
380+
381+
{{< feature-state feature_gate_name="PodCertificateRequest" >}}
382+
383+
{{< note >}}
384+
In Kubernetes {{< skew currentVersion >}}, you must enable support for Pod
385+
Certificates using the `PodCertificateRequest` [feature
386+
gate](/docs/reference/command-line-tools-reference/feature-gates/) and the
387+
`--runtime-config=certificates.k8s.io/v1alpha1/podcertificaterequests=true`
388+
kube-apiserver flag.
389+
{{< /note >}}
390+
391+
PodCertificateRequests are API objects tailored to provisioning certificates to
392+
workloads running as Pods within a cluster. The user typically does not
393+
interact with PodCertificateRequests directly, but uses [podCertificate
394+
projected volume sources](
395+
/docs/concepts/storage/projected-volumes#podcertificate), which are a `kubelet`
396+
feature that handles secure key provisioning and automatic certificate refresh.
397+
The application inside the pod only needs to know how to read the certificates
398+
from the filesystem.
399+
400+
PodCertificateRequests are similar to CertificateSigningRequests, but have a
401+
simpler format enabled by their narrower use case.
402+
403+
A PodCertificateRequest has the following spec fields:
404+
* `signerName`: The signer to which this request is addressed.
405+
* `podName` and `podUID`: The Pod that Kubelet is requesting a certificate for.
406+
* `serviceAccountName` and `serviceAccountUID`: The ServiceAccount corresponding to the Pod.
407+
* `nodeName` and `nodeUID`: The Node corresponding to the Pod.
408+
* `maxExpirationSeconds`: The maximum lifetime that the workload author will
409+
accept for this certificate. Defaults to 24 hours if not specified.
410+
* `pkixPublicKey`: The public key for which the certificate should be issued.
411+
* `proofOfPossession`: A signature demonstrating that the requester controls the
412+
private key corresponding to `pkixPublicKey`.
413+
414+
Nodes automatically receive permissions to create PodCertificateRequests and
415+
read PodCertificateRequests related to them (as determined by the
416+
`spec.nodeName` field). The `NodeRestriction` admission plugin, if enabled,
417+
ensures that nodes can only create PodCertificateRequests that correspond to a
418+
real pod that is currently running on the node.
419+
420+
After creation, the `spec` of a PodCertificateRequest is immutable.
421+
422+
Unlike CSRs, PodCertificateRequests do not have an
423+
approval phase. Once the PodCertificateRequest is created, the signer's
424+
controller directly decides to issue or deny the request. It also has the
425+
option to mark the request as failed, if it encountered a permanent error when
426+
attempting to issue the request.
427+
428+
To take any of these actions, the signing controller needs to have the
429+
appropriate permissions on both the PodCertificateRequest type, as well as on
430+
the signer name:
431+
* Verbs: **update**, group: `certificates.k8s.io`, resource:
432+
`podcertificaterequests/status`
433+
* Verbs: **sign**, group: `certificates.k8s.io`, resource: `signers`,
434+
resourceName: `<signerNameDomain>/<signerNamePath>` or `<signerNameDomain>/*`
435+
436+
The signing controller is free to consider other information beyond what's
437+
contained in the request, but it can rely on the information in the request to
438+
be accurate. For example, the signing controller might load the Pod and read
439+
annotations set on it, or perform a SubjectAccessReview on the ServiceAccount.
440+
441+
To issue a certificate in response to a request, the signing controller:
442+
* Adds an `Issued` condition to `status.conditions`.
443+
* Puts the issued certificate in `status.certificateChain`
444+
* Puts the `NotBefore` and `NotAfter` fields of the certificate in the
445+
`status.notBefore` and `status.notAfter` fields &mdash; these fields are
446+
denormalized into the Kubernetes API in order to aid debugging
447+
* Suggests a time to begin attempting to refresh the certificate using
448+
`status.beginRefreshAt`.
449+
450+
To deny a request, the signing controller adds a "Denied" condition to
451+
`status.conditions[]`.
452+
453+
To mark a request failed, the signing controller adds a "Failed" condition to
454+
`status.conditions[]`.
455+
456+
All of these conditions are mutually-exclusive, and must have status "True". No
457+
other condition types are permitted on PodCertificateRequests. In addition,
458+
once any of these conditions are set, the `status` field becomes immutable.
459+
460+
Like all conditions, the `status.conditions[].reason` field is meant to contain
461+
a machine-readable code describing the condition in TitleCase. The
462+
`status.conditions[].message` field is meant for a free-form explanation for
463+
human consumption.
464+
465+
To ensure that terminal PodCertificateRequests do not build up in the cluster, a
466+
`kube-controller-manager` controller deletes all PodCertificateRequests older
467+
than 15 minutes. All certificate issuance flows are expected to complete within
468+
this 15-minute limit.
469+
379470
## Cluster trust bundles {#cluster-trust-bundles}
380471

381472
{{< feature-state feature_gate_name="ClusterTrustBundle" >}}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: PodCertificateRequest
3+
content_type: feature_gate
4+
_build:
5+
list: never
6+
render: false
7+
8+
stages:
9+
- stage: alpha
10+
defaultValue: false
11+
fromVersion: "1.34"
12+
toVersion: "1.37"
13+
---
14+
Enable PodCertificateRequest objects and podCertificate projected volume
15+
sources.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Sample Pod spec that uses a podCertificate projection to request an ED25519
2+
# private key, a certificate from the `coolcert.example.com/foo` signer, and
3+
# write the results to `/var/run/my-x509-credentials/credentialbundle.pem`.
4+
apiVersion: v1
5+
kind: Pod
6+
metadata:
7+
namespace: default
8+
name: podcertificate-pod
9+
spec:
10+
serviceAccountName: default
11+
containers:
12+
- image: debian
13+
name: main
14+
command: ["sleep", "infinity"]
15+
volumeMounts:
16+
- name: my-x509-credentials
17+
mountPath: /var/run/my-x509-credentials
18+
volumes:
19+
- name: my-x509-credentials
20+
projected:
21+
defaultMode: 420
22+
sources:
23+
- podCertificate:
24+
keyType: ED25519
25+
signerName: coolcert.example.com/foo
26+
credentialBundlePath: credentialbundle.pem

0 commit comments

Comments
 (0)