Merge remote-tracking branch 'upstream/main' into dev-1.24

This commit is contained in:
Nate W
2022-02-15 08:28:12 -08:00
82 changed files with 4905 additions and 1675 deletions
@@ -1,6 +1,8 @@
---
reviewers:
- bryk
- floreks
- maciaszczykm
- shu-mutou
- mikedanese
title: Deploy and Access the Kubernetes Dashboard
description: >-
@@ -35,7 +37,7 @@ Dashboard also provides information on the state of Kubernetes resources in your
The Dashboard UI is not deployed by default. To deploy it, run the following command:
```
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
```
## Accessing the Dashboard UI
@@ -1,7 +1,7 @@
---
title: Encrypting Secret Data at Rest
reviewers:
- smarterclayton
title: Encrypting Secret Data at Rest
content_type: task
min-kubernetes-server-version: 1.13
---
@@ -9,27 +9,26 @@ min-kubernetes-server-version: 1.13
<!-- overview -->
This page shows how to enable and configure encryption of secret data at rest.
## {{% heading "prerequisites" %}}
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
* etcd v3.0 or later is required
<!-- steps -->
## Configuration and determining whether encryption at rest is already enabled
The `kube-apiserver` process accepts an argument `--encryption-provider-config`
that controls how API data is encrypted in etcd. An example configuration
is provided below.
that controls how API data is encrypted in etcd.
The configuration is provided as an API named
[`EncryptionConfiguration`](/docs/reference/config-api/apiserver-encryption.v1/).
An example configuration is provided below.
{{< caution >}}
**IMPORTANT:** For multi-master configurations (with two or more control plane nodes) the encryption configuration file must be the same!
Otherwise, the kube-apiserver can't decrypt data stored inside the key-value store.
**IMPORTANT:** For high-availability configurations (with two or more control plane nodes), the
encryption configuration file must be the same! Otherwise, the `kube-apiserver` component cannot
decrypt data stored in the etcd.
{{< /caution >}}
## Understanding the encryption at rest configuration.
@@ -39,39 +38,44 @@ apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- secrets
providers:
- identity: {}
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
- identity: {}
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
```
Each `resources` array item is a separate config and contains a complete configuration. The
`resources.resources` field is an array of Kubernetes resource names (`resource` or `resource.group`)
that should be encrypted. The `providers` array is an ordered list of the possible encryption
providers. Only one provider type may be specified per entry (`identity` or `aescbc` may be provided, but not both in the same item).
providers.
The first provider in the list is used to encrypt resources going into storage. When reading
resources from storage each provider that matches the stored data attempts to decrypt the data in
order. If no provider can read the stored data due to a mismatch in format or secret key, an error
Only one provider type may be specified per entry (`identity` or `aescbc` may be provided,
but not both in the same item).
The first provider in the list is used to encrypt resources written into the storage. When reading
resources from storage, each provider that matches the stored data attempts in order to decrypt the
data. If no provider can read the stored data due to a mismatch in format or secret key, an error
is returned which prevents clients from accessing that resource.
For more detailed information about the `EncryptionConfiguration` struct, please refer to the
[encryption configuration API](/docs/reference/config-api/apiserver-encryption.v1/).
{{< caution >}}
**IMPORTANT:** If any resource is not readable via the encryption config (because keys were changed),
If any resource is not readable via the encryption config (because keys were changed),
the only recourse is to delete that key from the underlying etcd directly. Calls that attempt to
read that resource will fail until it is deleted or a valid decryption key is provided.
{{< /caution >}}
@@ -90,15 +94,24 @@ Name | Encryption | Strength | Speed | Key Length | Other Considerations
Each provider supports multiple keys - the keys are tried in order for decryption, and if the provider
is the first provider, the first key is used for encryption.
__Storing the raw encryption key in the EncryptionConfig only moderately improves your security posture, compared to no encryption.
Please use `kms` provider for additional security.__ By default, the `identity` provider is used to protect secrets in etcd, which
provides no encryption. `EncryptionConfiguration` was introduced to encrypt secrets locally, with a locally managed key.
Encrypting secrets with a locally managed key protects against an etcd compromise, but it fails to protect against a host compromise.
Since the encryption keys are stored on the host in the EncryptionConfig YAML file, a skilled attacker can access that file and
extract the encryption keys.
{{< caution >}}
Storing the raw encryption key in the EncryptionConfig only moderately improves your security
posture, compared to no encryption. Please use `kms` provider for additional security.
{{< /caution >}}
Envelope encryption creates dependence on a separate key, not stored in Kubernetes. In this case, an attacker would need to compromise etcd, the kubeapi-server, and the third-party KMS provider to retrieve the plaintext values, providing a higher level of security than locally-stored encryption keys.
By default, the `identity` provider is used to protect Secrets in etcd, which provides no
encryption. `EncryptionConfiguration` was introduced to encrypt Secrets locally, with a locally
managed key.
Encrypting Secrets with a locally managed key protects against an etcd compromise, but it fails to
protect against a host compromise. Since the encryption keys are stored on the host in the
EncryptionConfiguration YAML file, a skilled attacker can access that file and extract the encryption
keys.
Envelope encryption creates dependence on a separate key, not stored in Kubernetes. In this case,
an attacker would need to compromise etcd, the `kubeapi-server`, and the third-party KMS provider to
retrieve the plaintext values, providing a higher level of security than locally stored encryption keys.
## Encrypting your data
@@ -109,113 +122,122 @@ apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
- identity: {}
- aescbc:
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
- identity: {}
```
To create a new secret perform the following steps:
To create a new Secret, perform the following steps:
1. Generate a 32 byte random key and base64 encode it. If you're on Linux or macOS, run the following command:
1. Generate a 32-byte random key and base64 encode it. If you're on Linux or macOS, run the following command:
```shell
head -c 32 /dev/urandom | base64
```
2. Place that value in the secret field.
3. Set the `--encryption-provider-config` flag on the `kube-apiserver` to point to the location of the config file.
4. Restart your API server.
1. Place that value in the `secret` field of the `EncryptionConfiguration` struct.
1. Set the `--encryption-provider-config` flag on the `kube-apiserver` to point to
the location of the config file.
1. Restart your API server.
{{< caution >}}
Your config file contains keys that can decrypt content in etcd, so you must properly restrict permissions on your masters so only the user who runs the kube-apiserver can read it.
Your config file contains keys that can decrypt the contents in etcd, so you must properly restrict
permissions on your control-plane nodes so only the user who runs the `kube-apiserver` can read it.
{{< /caution >}}
## Verifying that data is encrypted
Data is encrypted when written to etcd. After restarting your `kube-apiserver`, any newly created or
updated secret should be encrypted when stored. To check, you can use the `etcdctl` command line
program to retrieve the contents of your secret.
updated Secret should be encrypted when stored. To check this, you can use the `etcdctl` command line
program to retrieve the contents of your Secret.
1. Create a new secret called `secret1` in the `default` namespace:
1. Create a new Secret called `secret1` in the `default` namespace:
```shell
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
```
2. Using the etcdctl commandline, read that secret out of etcd:
1. Using the `etcdctl` command line, read that Secret out of etcd:
`ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C`
where `[...]` must be the additional arguments for connecting to the etcd server.
3. Verify the stored secret is prefixed with `k8s:enc:aescbc:v1:` which indicates the `aescbc` provider has encrypted the resulting data.
1. Verify the stored Secret is prefixed with `k8s:enc:aescbc:v1:` which indicates
the `aescbc` provider has encrypted the resulting data.
4. Verify the secret is correctly decrypted when retrieved via the API:
1. Verify the Secret is correctly decrypted when retrieved via the API:
```shell
kubectl describe secret secret1 -n default
```
should match `mykey: bXlkYXRh`, mydata is encoded, check [decoding a secret](/docs/tasks/configmap-secret/managing-secret-using-kubectl/#decoding-secret) to
completely decode the secret.
The output should contain `mykey: bXlkYXRh`, with contents of `mydata` encoded, check
[decoding a Secret](/docs/tasks/configmap-secret/managing-secret-using-kubectl/#decoding-secret)
to completely decode the Secret.
## Ensure all Secrets are encrypted
## Ensure all secrets are encrypted
Since secrets are encrypted on write, performing an update on a secret will encrypt that content.
Since Secrets are encrypted on write, performing an update on a Secret will encrypt that content.
```shell
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
```
The command above reads all secrets and then updates them to apply server side encryption.
The command above reads all Secrets and then updates them to apply server side encryption.
{{< note >}}
If an error occurs due to a conflicting write, retry the command.
For larger clusters, you may wish to subdivide the secrets by namespace or script an update.
{{< /note >}}
## Rotating a decryption key
Changing the secret without incurring downtime requires a multi step operation, especially in
the presence of a highly available deployment where multiple `kube-apiserver` processes are running.
Changing a Secret without incurring downtime requires a multi-step operation, especially in
the presence of a highly-available deployment where multiple `kube-apiserver` processes are running.
1. Generate a new key and add it as the second key entry for the current provider on all servers
2. Restart all `kube-apiserver` processes to ensure each server can decrypt using the new key
3. Make the new key the first entry in the `keys` array so that it is used for encryption in the config
4. Restart all `kube-apiserver` processes to ensure each server now encrypts using the new key
5. Run `kubectl get secrets --all-namespaces -o json | kubectl replace -f -` to encrypt all existing secrets with the new key
6. Remove the old decryption key from the config after you back up etcd with the new key in use and update all secrets
With a single `kube-apiserver`, step 2 may be skipped.
1. Restart all `kube-apiserver` processes to ensure each server can decrypt using the new key
1. Make the new key the first entry in the `keys` array so that it is used for encryption in the config
1. Restart all `kube-apiserver` processes to ensure each server now encrypts using the new key
1. Run `kubectl get secrets --all-namespaces -o json | kubectl replace -f -` to encrypt all
existing Secrets with the new key
1. Remove the old decryption key from the config after you have backed up etcd with the new key in use
and updated all Secrets
When running a single `kube-apiserver` instance, step 2 may be skipped.
## Decrypting all data
To disable encryption at rest place the `identity` provider as the first entry in the config:
To disable encryption at rest, place the `identity` provider as the first entry in the config
and restart all `kube-apiserver` processes.
```yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- secrets
providers:
- identity: {}
- aescbc:
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
- identity: {}
- aescbc:
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
```
and restart all `kube-apiserver` processes. Then run:
Then run the following command to force decrypt
all Secrets:
```shell
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
```
to force all secrets to be decrypted.
## {{% heading "whatsnext" %}}
* Learn more about the [EncryptionConfiguration configuration API (v1)](/docs/reference/config-api/apiserver-encryption.v1/).
@@ -10,7 +10,9 @@ weight: 10
{{< feature-state for_k8s_version="v1.15" state="stable" >}}
Client certificates generated by [kubeadm](/docs/reference/setup-tools/kubeadm/) expire after 1 year. This page explains how to manage certificate renewals with kubeadm.
Client certificates generated by [kubeadm](/docs/reference/setup-tools/kubeadm/) expire after 1 year.
This page explains how to manage certificate renewals with kubeadm. It also covers other tasks related
to kubeadm certificate management.
## {{% heading "prerequisites" %}}
@@ -126,13 +128,13 @@ command. In that case, you should explicitly set `--certificate-renewal=true`.
You can renew your certificates manually at any time with the `kubeadm certs renew` command.
This command performs the renewal using CA (or front-proxy-CA) certificate and key stored in `/etc/kubernetes/pki`.
This command performs the renewal using CA (or front-proxy-CA) certificate and key stored in `/etc/kubernetes/pki`.
After running the command you should restart the control plane Pods. This is required since
dynamic certificate reload is currently not supported for all components and certificates.
[Static Pods](/docs/tasks/configure-pod-container/static-pod/) are managed by the local kubelet
and not by the API Server, thus kubectl cannot be used to delete and restart them.
To restart a static Pod you can temporarily remove its manifest file from `/etc/kubernetes/manifests/`
To restart a static Pod you can temporarily remove its manifest file from `/etc/kubernetes/manifests/`
and wait for 20 seconds (see the `fileCheckFrequency` value in [KubeletConfiguration struct](/docs/reference/config-api/kubelet-config.v1beta1/).
The kubelet will terminate the Pod if it's no longer in the manifest directory.
You can then move the file back and after another `fileCheckFrequency` period, the kubelet will recreate
@@ -289,3 +291,52 @@ Such a controller is not a secure mechanism unless it not only verifies the Comm
in the CSR but also verifies the requested IPs and domain names. This would prevent
a malicious actor that has access to a kubelet client certificate to create
CSRs requesting serving certificates for any IP or domain name.
## Generating kubeconfig files for additional users {#kubeconfig-additional-users}
During cluster creation, kubeadm signs the certificate in the `admin.conf` to have
`Subject: O = system:masters, CN = kubernetes-admin`.
[`system:masters`](/docs/reference/access-authn-authz/rbac/#user-facing-roles)
is a break-glass, super user group that bypasses the authorization layer (e.g. RBAC).
Sharing the `admin.conf` with additional users is **not recommended**!
Instead, you can use the [`kubeadm kubeconfig user`](/docs/reference/setup-tools/kubeadm/kubeadm-kubeconfig)
command to generate kubeconfig files for additional users.
The command accepts a mixture of command line flags and
[kubeadm configuration](/docs/reference/config-api/kubeadm-config.v1beta3/) options.
The generated kubeconfig will be written to stdout and can be piped to a file
using `kubeadm kubeconfig user ... > somefile.conf`.
Example configuration file that can be used with `--config`:
```yaml
# example.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
# Will be used as the target "cluster" in the kubeconfig
clusterName: "kubernetes"
# Will be used as the "server" (IP or DNS name) of this cluster in the kubeconfig
controlPlaneEndpoint: "some-dns-address:6443"
# The cluster CA key and certificate will be loaded from this local directory
certificatesDir: "/etc/kubernetes/pki"
```
Make sure that these settings match the desired target cluster settings.
To see the settings of an existing cluster use:
```shell
kubectl get cm kubeadm-config -n kube-system -o=jsonpath="{.data.ClusterConfiguration}"
```
The following example will generate a kubeconfig file with credentials valid for 24 hours
for a new user `johndoe` that is part of the `appdevs` group:
```shell
kubeadm kubeconfig user --config example.yaml --org appdevs --client-name johndoe --validity-period 24h
```
The following example will generate a kubeconfig file with administrator credentials valid for 1 week:
```shell
kubeadm kubeconfig user --config example.yaml --client-name admin --validity-period 168h
```
@@ -13,7 +13,7 @@ This page shows how to configure default memory requests and limits for a
{{< glossary_tooltip text="namespace" term_id="namespace" >}}.
A Kubernetes cluster can be divided into namespaces. Once you have a namespace that
that has a default memory
has a default memory
[limit](/docs/concepts/configuration/manage-resources-containers/#requests-and-limits),
and you then try to create a Pod with a container that does not specify its own memory
limit its own memory limit, then the
@@ -138,7 +138,8 @@ The sum of their values will account for the total amount of reserved memory.
A new `--reserved-memory` flag was added to Memory Manager to allow for this total reserved memory
to be split (by a node administrator) and accordingly reserved across many NUMA nodes.
The flag specifies a comma-separated list of memory reservations per NUMA node.
The flag specifies a comma-separated list of memory reservations of different memory types per NUMA node.
Memory reservations across multiple NUMA nodes can be specified using semicolon as separator.
This parameter is only useful in the context of the Memory Manager feature.
The Memory Manager will not use this reserved memory for the allocation of container workloads.
@@ -180,6 +181,10 @@ or
`--reserved-memory 0:memory=1Gi --reserved-memory 1:memory=2Gi`
or
`--reserved-memory '0:memory=1Gi;1:memory=2Gi'`
When you specify values for `--reserved-memory` flag, you must comply with the setting that
you prior provided via Node Allocatable Feature flags.
That is, the following rule must be obeyed for each memory type:
@@ -215,7 +220,7 @@ Here is an example of a correct configuration:
--kube-reserved=cpu=4,memory=4Gi
--system-reserved=cpu=1,memory=1Gi
--memory-manager-policy=Static
--reserved-memory 0:memory=3Gi --reserved-memory 1:memory=2148Mi
--reserved-memory '0:memory=3Gi;1:memory=2148Mi'
```
Let us validate the configuration above:
@@ -0,0 +1,154 @@
---
title: "Changing the Container Runtime on a Node from Docker Engine to containerd"
weight: 8
content_type: task
---
This task outlines the steps needed to update your container runtime to containerd from Docker. It is applicable for cluster operators running Kubernetes 1.23 or earlier. Also this covers an example scenario for migrating from dockershim to containerd and alternative container runtimes can be picked from this [page](https://kubernetes.io/docs/setup/production-environment/container-runtimes/).
## {{% heading "prerequisites" %}}
{{% thirdparty-content %}}
Install containerd. For more information see, [containerd's installation documentation](https://containerd.io/docs/getting-started/) and for specific prerequisite follow [this](/docs/setup/production-environment/container-runtimes/#containerd).
## Drain the node
```
# replace <node-to-drain> with the name of your node you are draining
kubectl drain <node-to-drain> --ignore-daemonsets
```
## Stop the Docker daemon
```shell
systemctl stop kubelet
systemctl disable docker.service --now
```
## Install Containerd
This [page](/docs/setup/production-environment/container-runtimes/#containerd) contains detailed steps to install containerd.
{{< tabs name="tab-cri-containerd-installation" >}}
{{% tab name="Linux" %}}
1. Install the `containerd.io` package from the official Docker repositories.
Instructions for setting up the Docker repository for your respective Linux distribution and installing the `containerd.io` package can be found at
[Install Docker Engine](https://docs.docker.com/engine/install/#server).
2. Configure containerd:
```shell
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
```
3. Restart containerd:
```shell
sudo systemctl restart containerd
```
{{% /tab %}}
{{% tab name="Windows (PowerShell)" %}}
Start a Powershell session, set `$Version` to the desired version (ex: `$Version="1.4.3"`), and then run the following commands:
1. Download containerd:
```powershell
curl.exe -L https://github.com/containerd/containerd/releases/download/v$Version/containerd-$Version-windows-amd64.tar.gz -o containerd-windows-amd64.tar.gz
tar.exe xvf .\containerd-windows-amd64.tar.gz
```
2. Extract and configure:
```powershell
Copy-Item -Path ".\bin\" -Destination "$Env:ProgramFiles\containerd" -Recurse -Force
cd $Env:ProgramFiles\containerd\
.\containerd.exe config default | Out-File config.toml -Encoding ascii
# Review the configuration. Depending on setup you may want to adjust:
# - the sandbox_image (Kubernetes pause image)
# - cni bin_dir and conf_dir locations
Get-Content config.toml
# (Optional - but highly recommended) Exclude containerd from Windows Defender Scans
Add-MpPreference -ExclusionProcess "$Env:ProgramFiles\containerd\containerd.exe"
```
3. Start containerd:
```powershell
.\containerd.exe --register-service
Start-Service containerd
```
{{% /tab %}}
{{< /tabs >}}
## Configure the kubelet to use containerd as its container runtime
Edit the file `/var/lib/kubelet/kubeadm-flags.env` and add the containerd runtime to the flags. `--container-runtime=remote` and `--container-runtime-endpoint=unix:///run/containerd/containerd.sock"`
For users using kubeadm should consider the following:
The `kubeadm` tool stores the CRI socket for each host as an annotation in the Node object for that host.
To change it you must do the following:
Execute `kubectl edit no <NODE-NAME>` on a machine that has the kubeadm `/etc/kubernetes/admin.conf` file.
This will start a text editor where you can edit the Node object.
To choose a text editor you can set the `KUBE_EDITOR` environment variable.
- Change the value of `kubeadm.alpha.kubernetes.io/cri-socket` from `/var/run/dockershim.sock`
to the CRI socket path of your choice (for example `unix:///run/containerd/containerd.sock`).
Note that new CRI socket paths must be prefixed with `unix://` ideally.
- Save the changes in the text editor, which will update the Node object.
## Restart the kubelet
```shell
systemctl start kubelet
```
## Verify that the node is healthy
Run `kubectl get nodes -o wide` and containerd appears as the runtime for the node we just changed.
## Remove Docker Engine
{{% thirdparty-content %}}
Finally if everything goes well remove docker
{{< tabs name="tab-remove-docker-enigine" >}}
{{% tab name="CentOS" %}}
```shell
sudo yum remove docker-ce docker-ce-cli
```
{{% /tab %}}
{{% tab name="Debian" %}}
```shell
sudo apt-get purge docker-ce docker-ce-cli
```
{{% /tab %}}
{{% tab name="Fedora" %}}
```shell
sudo dnf remove docker-ce docker-ce-cli
```
{{% /tab %}}
{{% tab name="Ubuntu" %}}
```shell
sudo apt-get purge docker-ce docker-ce-cli
```
{{% /tab %}}
{{< /tabs >}}
@@ -5,7 +5,8 @@ content_type: task
<!--overview-->
This page shows you how to specify the type of [cascading deletion](/docs/concepts/workloads/controllers/garbage-collection/#cascading-deletion)
This page shows you how to specify the type of
[cascading deletion](/docs/concepts/architecture/garbage-collection/#cascading-deletion)
to use in your cluster during {{<glossary_tooltip text="garbage collection" term_id="garbage-collection">}}.
## {{% heading "prerequisites" %}}
@@ -26,7 +27,7 @@ kubectl get pods -l app=nginx --output=yaml
The output has an `ownerReferences` field similar to this:
```
```yaml
apiVersion: v1
...
ownerReferences:
@@ -41,7 +42,7 @@ apiVersion: v1
## Use foreground cascading deletion {#use-foreground-cascading-deletion}
By default, Kubernetes uses [background cascading deletion](/docs/concepts/workloads/controllers/garbage-collection/#background-deletion)
By default, Kubernetes uses [background cascading deletion](/docs/concepts/architecture/garbage-collection/#background-deletion)
to delete dependents of an object. You can switch to foreground cascading deletion
using either `kubectl` or the Kubernetes API, depending on the Kubernetes
version your cluster runs. {{<version-check>}}
@@ -64,9 +65,9 @@ kubectl delete deployment nginx-deployment --cascade=foreground
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
@@ -80,19 +81,19 @@ kubectl delete deployment nginx-deployment --cascade=foreground
like this:
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "nginx-deployment",
"namespace": "default",
"uid": "d1ce1b02-cae8-4288-8a53-30e84d8fa505",
"resourceVersion": "1363097",
"creationTimestamp": "2021-07-08T20:24:37Z",
"deletionTimestamp": "2021-07-08T20:27:39Z",
"finalizers": [
"foregroundDeletion"
]
...
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "nginx-deployment",
"namespace": "default",
"uid": "d1ce1b02-cae8-4288-8a53-30e84d8fa505",
"resourceVersion": "1363097",
"creationTimestamp": "2021-07-08T20:24:37Z",
"deletionTimestamp": "2021-07-08T20:27:39Z",
"finalizers": [
"foregroundDeletion"
]
...
```
{{% /tab %}}
@@ -104,9 +105,9 @@ For details, read the [documentation for your Kubernetes version](/docs/home/sup
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
@@ -120,19 +121,19 @@ For details, read the [documentation for your Kubernetes version](/docs/home/sup
like this:
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "nginx-deployment",
"namespace": "default",
"uid": "d1ce1b02-cae8-4288-8a53-30e84d8fa505",
"resourceVersion": "1363097",
"creationTimestamp": "2021-07-08T20:24:37Z",
"deletionTimestamp": "2021-07-08T20:27:39Z",
"finalizers": [
"foregroundDeletion"
]
...
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "nginx-deployment",
"namespace": "default",
"uid": "d1ce1b02-cae8-4288-8a53-30e84d8fa505",
"resourceVersion": "1363097",
"creationTimestamp": "2021-07-08T20:24:37Z",
"deletionTimestamp": "2021-07-08T20:27:39Z",
"finalizers": [
"foregroundDeletion"
]
...
```
{{% /tab %}}
{{</tabs>}}
@@ -165,32 +166,32 @@ kubectl delete deployment nginx-deployment --cascade=background
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
```
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
```
The output is similar to this:
The output is similar to this:
```
"kind": "Status",
"apiVersion": "v1",
...
"status": "Success",
"details": {
"name": "nginx-deployment",
"group": "apps",
"kind": "deployments",
"uid": "cc9eefb9-2d49-4445-b1c1-d261c9396456"
}
```
```
"kind": "Status",
"apiVersion": "v1",
...
"status": "Success",
"details": {
"name": "nginx-deployment",
"group": "apps",
"kind": "deployments",
"uid": "cc9eefb9-2d49-4445-b1c1-d261c9396456"
}
```
{{% /tab %}}
{{% tab name="Versions prior to Kubernetes 1.20.x" %}}
Kubernetes uses background cascading deletion by default, and does so
@@ -211,32 +212,32 @@ kubectl delete deployment nginx-deployment --cascade=true
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
```
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
```
The output is similar to this:
The output is similar to this:
```
"kind": "Status",
"apiVersion": "v1",
...
"status": "Success",
"details": {
"name": "nginx-deployment",
"group": "apps",
"kind": "deployments",
"uid": "cc9eefb9-2d49-4445-b1c1-d261c9396456"
}
```
```
"kind": "Status",
"apiVersion": "v1",
...
"status": "Success",
"details": {
"name": "nginx-deployment",
"group": "apps",
"kind": "deployments",
"uid": "cc9eefb9-2d49-4445-b1c1-d261c9396456"
}
```
{{% /tab %}}
{{</tabs>}}
@@ -264,33 +265,33 @@ kubectl delete deployment nginx-deployment --cascade=orphan
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
```
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
```
The output contains `orphan` in the `finalizers` field, similar to this:
The output contains `orphan` in the `finalizers` field, similar to this:
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"namespace": "default",
"uid": "6f577034-42a0-479d-be21-78018c466f1f",
"creationTimestamp": "2021-07-09T16:46:37Z",
"deletionTimestamp": "2021-07-09T16:47:08Z",
"deletionGracePeriodSeconds": 0,
"finalizers": [
"orphan"
],
...
```
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"namespace": "default",
"uid": "6f577034-42a0-479d-be21-78018c466f1f",
"creationTimestamp": "2021-07-09T16:46:37Z",
"deletionTimestamp": "2021-07-09T16:47:08Z",
"deletionGracePeriodSeconds": 0,
"finalizers": [
"orphan"
],
...
```
{{% /tab %}}
{{% tab name="Versions prior to Kubernetes 1.20.x" %}}
@@ -309,33 +310,33 @@ kubectl delete deployment nginx-deployment --cascade=orphan
1. Start a local proxy session:
```shell
kubectl proxy --port=8080
```
```shell
kubectl proxy --port=8080
```
1. Use `curl` to trigger deletion:
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
```
```shell
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/deployments/nginx-deployment \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
```
The output contains `orphan` in the `finalizers` field, similar to this:
The output contains `orphan` in the `finalizers` field, similar to this:
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"namespace": "default",
"uid": "6f577034-42a0-479d-be21-78018c466f1f",
"creationTimestamp": "2021-07-09T16:46:37Z",
"deletionTimestamp": "2021-07-09T16:47:08Z",
"deletionGracePeriodSeconds": 0,
"finalizers": [
"orphan"
],
...
```
```
"kind": "Deployment",
"apiVersion": "apps/v1",
"namespace": "default",
"uid": "6f577034-42a0-479d-be21-78018c466f1f",
"creationTimestamp": "2021-07-09T16:46:37Z",
"deletionTimestamp": "2021-07-09T16:47:08Z",
"deletionGracePeriodSeconds": 0,
"finalizers": [
"orphan"
],
...
```
{{% /tab %}}
{{</tabs>}}
@@ -349,4 +350,4 @@ kubectl get pods -l app=nginx
* Learn about [owners and dependents](/docs/concepts/overview/working-with-objects/owners-dependents/) in Kubernetes.
* Learn about Kubernetes [finalizers](/docs/concepts/overview/working-with-objects/finalizers/).
* Learn about [garbage collection](/docs/concepts/workloads/controllers/garbage-collection/).
* Learn about [garbage collection](/docs/concepts/architecture/garbage-collection/).
@@ -14,21 +14,31 @@ A security context defines privilege and access control settings for
a Pod or Container. Security context settings include, but are not limited to:
* Discretionary Access Control: Permission to access an object, like a file, is based on
[user ID (UID) and group ID (GID)](https://wiki.archlinux.org/index.php/users_and_groups).
[user ID (UID) and group ID (GID)](https://wiki.archlinux.org/index.php/users_and_groups).
* [Security Enhanced Linux (SELinux)](https://en.wikipedia.org/wiki/Security-Enhanced_Linux): Objects are assigned security labels.
* [Security Enhanced Linux (SELinux)](https://en.wikipedia.org/wiki/Security-Enhanced_Linux):
Objects are assigned security labels.
* Running as privileged or unprivileged.
* [Linux Capabilities](https://linux-audit.com/linux-capabilities-hardening-linux-binaries-by-removing-setuid/): Give a process some privileges, but not all the privileges of the root user.
* [Linux Capabilities](https://linux-audit.com/linux-capabilities-hardening-linux-binaries-by-removing-setuid/):
Give a process some privileges, but not all the privileges of the root user.
* [AppArmor](/docs/tutorials/clusters/apparmor/): Use program profiles to restrict the capabilities of individual programs.
* [AppArmor](/docs/tutorials/security/apparmor/):
Use program profiles to restrict the capabilities of individual programs.
* [Seccomp](/docs/tutorials/clusters/seccomp/): Filter a process's system calls.
* [Seccomp](/docs/tutorials/security/seccomp/): Filter a process's system calls.
* AllowPrivilegeEscalation: Controls whether a process can gain more privileges than its parent process. This bool directly controls whether the [`no_new_privs`](https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt) flag gets set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged OR 2) has `CAP_SYS_ADMIN`.
* `allowPrivilegeEscalation`: Controls whether a process can gain more privileges than
its parent process. This bool directly controls whether the
[`no_new_privs`](https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt)
flag gets set on the container process.
`allowPrivilegeEscalation` is always true when the container:
* readOnlyRootFilesystem: Mounts the container's root filesystem as read-only.
- is run as privileged, or
- has `CAP_SYS_ADMIN`
* `readOnlyRootFilesystem`: Mounts the container's root filesystem as read-only.
The above bullets are not a complete set of security context settings -- please see
[SecurityContext](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#securitycontext-v1-core)
@@ -37,15 +47,10 @@ for a comprehensive list.
For more information about security mechanisms in Linux, see
[Overview of Linux Kernel Security Features](https://www.linux.com/learn/overview-linux-kernel-security-features)
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
<!-- steps -->
## Set the security context for a Pod
@@ -91,7 +96,7 @@ ps
The output shows that the processes are running as user 1000, which is the value of `runAsUser`:
```shell
```none
PID USER TIME COMMAND
1 1000 0:00 sleep 1h
6 1000 0:00 sh
@@ -108,7 +113,7 @@ ls -l
The output shows that the `/data/demo` directory has group ID 2000, which is
the value of `fsGroup`.
```shell
```none
drwxrwsrwx 2 root 2000 4096 Jun 6 20:08 demo
```
@@ -127,19 +132,26 @@ ls -l
The output shows that `testfile` has group ID 2000, which is the value of `fsGroup`.
```shell
```none
-rw-r--r-- 1 1000 2000 6 Jun 6 20:08 testfile
```
Run the following command:
```shell
$ id
id
```
The output is similar to this:
```none
uid=1000 gid=3000 groups=2000
```
You will see that gid is 3000 which is same as `runAsGroup` field. If the `runAsGroup` was omitted the gid would
remain as 0(root) and the process will be able to interact with files that are owned by root(0) group and that have
the required group permissions for root(0) group.
From the output, you can see that `gid` is 3000 which is same as the `runAsGroup` field.
If the `runAsGroup` was omitted, the `gid` would remain as 0 (root) and the process will
be able to interact with files that are owned by the root(0) group and groups that have
the required group permissions for the root (0) group.
Exit your shell:
@@ -159,11 +171,14 @@ slowing Pod startup. You can use the `fsGroupChangePolicy` field inside a `secur
to control the way that Kubernetes checks and manages ownership and permissions
for a volume.
**fsGroupChangePolicy** - `fsGroupChangePolicy` defines behavior for changing ownership and permission of the volume
before being exposed inside a Pod. This field only applies to volume types that support
`fsGroup` controlled ownership and permissions. This field has two possible values:
**fsGroupChangePolicy** - `fsGroupChangePolicy` defines behavior for changing ownership
and permission of the volume before being exposed inside a Pod.
This field only applies to volume types that support `fsGroup` controlled ownership and permissions.
This field has two possible values:
* _OnRootMismatch_: Only change permissions and ownership if permission and ownership of root directory does not match with expected permissions of the volume. This could help shorten the time it takes to change ownership and permission of a volume.
* _OnRootMismatch_: Only change permissions and ownership if permission and ownership of
root directory does not match with expected permissions of the volume.
This could help shorten the time it takes to change ownership and permission of a volume.
* _Always_: Always change permission and ownership of the volume when volume is mounted.
For example:
@@ -176,7 +191,6 @@ securityContext:
fsGroupChangePolicy: "OnRootMismatch"
```
{{< note >}}
This field has no effect on ephemeral volume types such as
[`secret`](/docs/concepts/storage/volumes/#secret),
@@ -238,7 +252,7 @@ kubectl exec -it security-context-demo-2 -- sh
In your shell, list the running processes:
```
```shell
ps aux
```
@@ -297,7 +311,7 @@ ps aux
The output shows the process IDs (PIDs) for the Container:
```shell
```
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4336 796 ? Ss 18:17 0:00 /bin/sh -c node server.js
root 5 0.1 0.5 772124 22700 ? Sl 18:17 0:00 node server.js
@@ -354,7 +368,7 @@ cat status
The output shows capabilities bitmap for the process:
```shell
```
...
CapPrm: 00000000aa0435fb
CapEff: 00000000aa0435fb
@@ -374,7 +388,10 @@ See [capability.h](https://github.com/torvalds/linux/blob/master/include/uapi/li
for definitions of the capability constants.
{{< note >}}
Linux capability constants have the form `CAP_XXX`. But when you list capabilities in your Container manifest, you must omit the `CAP_` portion of the constant. For example, to add `CAP_SYS_TIME`, include `SYS_TIME` in your list of capabilities.
Linux capability constants have the form `CAP_XXX`.
But when you list capabilities in your container manifest, you must
omit the `CAP_` portion of the constant.
For example, to add `CAP_SYS_TIME`, include `SYS_TIME` in your list of capabilities.
{{< /note >}}
## Set the Seccomp Profile for a Container
@@ -437,18 +454,19 @@ the Pod's Volumes when applicable. Specifically `fsGroup` and `seLinuxOptions` a
applied to Volumes as follows:
* `fsGroup`: Volumes that support ownership management are modified to be owned
and writable by the GID specified in `fsGroup`. See the
[Ownership Management design document](https://git.k8s.io/community/contributors/design-proposals/storage/volume-ownership-management.md)
for more details.
and writable by the GID specified in `fsGroup`. See the
[Ownership Management design document](https://git.k8s.io/community/contributors/design-proposals/storage/volume-ownership-management.md)
for more details.
* `seLinuxOptions`: Volumes that support SELinux labeling are relabeled to be accessible
by the label specified under `seLinuxOptions`. Usually you only
need to set the `level` section. This sets the
[Multi-Category Security (MCS)](https://selinuxproject.org/page/NB_MLS)
label given to all Containers in the Pod as well as the Volumes.
by the label specified under `seLinuxOptions`. Usually you only
need to set the `level` section. This sets the
[Multi-Category Security (MCS)](https://selinuxproject.org/page/NB_MLS)
label given to all Containers in the Pod as well as the Volumes.
{{< warning >}}
After you specify an MCS label for a Pod, all Pods with the same label can access the Volume. If you need inter-Pod protection, you must assign a unique MCS label to each Pod.
After you specify an MCS label for a Pod, all Pods with the same label can access the Volume.
If you need inter-Pod protection, you must assign a unique MCS label to each Pod.
{{< /warning >}}
## Clean up
@@ -462,11 +480,8 @@ kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4
```
## {{% heading "whatsnext" %}}
* [PodSecurityContext](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podsecuritycontext-v1-core)
* [SecurityContext](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#securitycontext-v1-core)
* [Tuning Docker with the newest security enhancements](https://github.com/containerd/containerd/blob/main/docs/cri/config.md)
@@ -19,15 +19,14 @@ Kubernetes node. `crictl` and its source are hosted in the
## {{% heading "prerequisites" %}}
`crictl` requires a Linux operating system with a CRI runtime.
<!-- steps -->
## Installing crictl
You can download a compressed archive `crictl` from the cri-tools [release
page](https://github.com/kubernetes-sigs/cri-tools/releases), for several
You can download a compressed archive `crictl` from the cri-tools
[release page](https://github.com/kubernetes-sigs/cri-tools/releases), for several
different architectures. Download the version that corresponds to your version
of Kubernetes. Extract it and move it to a location on your system path, such as
`/usr/local/bin/`.
@@ -85,6 +84,7 @@ List all pods:
```shell
crictl pods
```
The output is similar to this:
```
@@ -100,6 +100,7 @@ List pods by name:
```shell
crictl pods --name nginx-65899c769f-wv2gp
```
The output is similar to this:
```
@@ -112,6 +113,7 @@ List pods by label:
```shell
crictl pods --label run=nginx
```
The output is similar to this:
```
@@ -126,6 +128,7 @@ List all images:
```shell
crictl images
```
The output is similar to this:
```
@@ -141,6 +144,7 @@ List images by repository:
```shell
crictl images nginx
```
The output is similar to this:
```
@@ -153,6 +157,7 @@ Only list image IDs:
```shell
crictl images -q
```
The output is similar to this:
```
@@ -169,6 +174,7 @@ List all containers:
```shell
crictl ps -a
```
The output is similar to this:
```
@@ -181,9 +187,10 @@ CONTAINER ID IMAGE
List running containers:
```
```shell
crictl ps
```
The output is similar to this:
```
@@ -198,6 +205,7 @@ CONTAINER ID IMAGE
```shell
crictl exec -i -t 1f73f2d81bf98 ls
```
The output is similar to this:
```
@@ -211,6 +219,7 @@ Get all container logs:
```shell
crictl logs 87d3992f84f74
```
The output is similar to this:
```
@@ -224,6 +233,7 @@ Get only the latest `N` lines of logs:
```shell
crictl logs --tail=1 87d3992f84f74
```
The output is similar to this:
```
@@ -236,29 +246,29 @@ Using `crictl` to run a pod sandbox is useful for debugging container runtimes.
On a running Kubernetes cluster, the sandbox will eventually be stopped and
deleted by the Kubelet.
1. Create a JSON file like the following:
1. Create a JSON file like the following:
```json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"logDirectory": "/tmp",
"linux": {
}
}
```
```json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"logDirectory": "/tmp",
"linux": {
}
}
```
2. Use the `crictl runp` command to apply the JSON and run the sandbox.
2. Use the `crictl runp` command to apply the JSON and run the sandbox.
```shell
crictl runp pod-config.json
```
```shell
crictl runp pod-config.json
```
The ID of the sandbox is returned.
The ID of the sandbox is returned.
### Create a container
@@ -266,68 +276,73 @@ Using `crictl` to create a container is useful for debugging container runtimes.
On a running Kubernetes cluster, the sandbox will eventually be stopped and
deleted by the Kubelet.
1. Pull a busybox image
1. Pull a busybox image
```shell
crictl pull busybox
Image is up to date for busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
```
```shell
crictl pull busybox
```
```none
Image is up to date for busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
```
2. Create configs for the pod and the container:
2. Create configs for the pod and the container:
**Pod config**:
```yaml
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
```
**Pod config**:
**Container config**:
```yaml
{
"metadata": {
"name": "busybox"
},
"image":{
"image": "busybox"
},
"command": [
"top"
],
"log_path":"busybox.log",
"linux": {
}
}
```
```json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
```
3. Create the container, passing the ID of the previously-created pod, the
container config file, and the pod config file. The ID of the container is
returned.
**Container config**:
```shell
crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.json
```
```json
{
"metadata": {
"name": "busybox"
},
"image":{
"image": "busybox"
},
"command": [
"top"
],
"log_path":"busybox.log",
"linux": {
}
}
```
4. List all containers and verify that the newly-created container has its
state set to `Created`.
3. Create the container, passing the ID of the previously-created pod, the
container config file, and the pod config file. The ID of the container is
returned.
```shell
crictl ps -a
```
The output is similar to this:
```shell
crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.json
```
4. List all containers and verify that the newly-created container has its
state set to `Created`.
```shell
crictl ps -a
```
The output is similar to this:
```
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox 32 seconds ago Created busybox 0
```
```
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox 32 seconds ago Created busybox 0
```
### Start a container
@@ -336,6 +351,7 @@ To start a container, pass its ID to `crictl start`:
```shell
crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
```
The output is similar to this:
```
@@ -350,13 +366,12 @@ crictl ps
The output is similar to this:
```
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox About a minute ago Running busybox 0
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox About a minute ago Running busybox 0
```
## {{% heading "whatsnext" %}}
* [Learn more about `crictl`](https://github.com/kubernetes-sigs/cri-tools).
* [Map `docker` CLI commands to `crictl`](/reference/tools/map-crictl-dockercli/).
* [Map `docker` CLI commands to `crictl`](/docs/reference/tools/map-crictl-dockercli/).
<!-- discussion -->
@@ -58,7 +58,8 @@ Again, the information from `kubectl describe ...` should be informative. The m
* Make sure that you have the name of the image correct.
* Have you pushed the image to the registry?
* Run a manual `docker pull <image>` on your machine to see if the image can be pulled.
* Try to manually pull the image to see if the image can be pulled. For example,
if you use Docker on your PC, run `docker pull <image>`.
#### My pod is crashing or otherwise unhealthy
@@ -86,8 +86,8 @@ worker node, but it can't run on that machine. Again, the information from
* Make sure that you have the name of the image correct.
* Have you pushed the image to the repository?
* Run a manual `docker pull <image>` on your machine to see if the image can be
pulled.
* Try to manually pull the image to see if it can be pulled. For example, if you
use Docker on your PC, run `docker pull <image>`.
### My pod is crashing or otherwise unhealthy
@@ -45,8 +45,9 @@ and command-line interfaces (CLIs), such as [`kubectl`](/docs/reference/kubectl/
Someone else from the community may have already asked a similar question or may
be able to help with your problem. The Kubernetes team will also monitor
[posts tagged Kubernetes](https://stackoverflow.com/questions/tagged/kubernetes).
If there aren't any existing questions that help, please
[ask a new one](https://stackoverflow.com/questions/ask?tags=kubernetes)!
If there aren't any existing questions that help, **please [ensure that your question is on-topic on Stack Overflow](https://stackoverflow.com/help/on-topic)
and that you read through the guidance on [how to ask a new question](https://stackoverflow.com/help/how-to-ask)**,
before [asking a new one](https://stackoverflow.com/questions/ask?tags=kubernetes)!
### Slack
@@ -88,7 +88,7 @@ or the custom metrics API (for all other metrics).
The common use for HorizontalPodAutoscaler is to configure it to fetch metrics from
{{< glossary_tooltip text="aggregated APIs" term_id="aggregation-layer" >}}
(`metrics.k8s.io`, `custom.metrics.k8s.io`, or `external.metrics.k8s.io`). The `metrics.k8s.io` API is
usually provided by an add on named Metrics Server, which needs to be launched separately.
usually provided by an add-on named Metrics Server, which needs to be launched separately.
For more information about resource metrics, see
[Metrics Server](/docs/tasks/debug-application-cluster/resource-metrics-pipeline/#metrics-server).
@@ -329,7 +329,7 @@ APIs, cluster administrators must ensure that:
* The corresponding APIs are registered:
* For resource metrics, this is the `metrics.k8s.io` API, generally provided by [metrics-server](https://github.com/kubernetes-sigs/metrics-server).
It can be launched as a cluster addon.
It can be launched as a cluster add-on.
* For custom metrics, this is the `custom.metrics.k8s.io` API. It's provided by "adapter" API servers provided by metrics solution vendors.
Check with your metrics pipeline to see if there is a Kubernetes metrics adapter available.
@@ -514,7 +514,7 @@ Finally, you can delete an autoscaler using `kubectl delete hpa`.
In addition, there is a special `kubectl autoscale` command for creating a HorizontalPodAutoscaler object.
For instance, executing `kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80`
will create an autoscaler for replication set *foo*, with target CPU utilization set to `80%`
will create an autoscaler for ReplicaSet *foo*, with target CPU utilization set to `80%`
and the number of replicas between 2 and 5.
## Implicit maintenance-mode deactivation
@@ -538,7 +538,7 @@ desired and could be troublesome when an HPA is active.
Keep in mind that the removal of `spec.replicas` may incur a one-time
degradation of Pod counts as the default value of this key is 1 (reference
[Deployment Replicas](/docs/concepts/workloads/controllers/deployment#replicas).
[Deployment Replicas](/docs/concepts/workloads/controllers/deployment#replicas)).
Upon the update, all Pods except 1 will begin their termination procedures. Any
deployment application afterwards will behave as normal and respect a rolling
update configuration as desired. You can avoid this degradation by choosing one of the following two
@@ -29,13 +29,18 @@ these certificates will validate against the cluster root CA.
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
{{< include "task-tutorial-prereqs.md" >}}
You need the `cfssl` tool. You can download `cfssl` from
[https://github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases).
Some steps in this page use the `jq` tool. If you don't have `jq`, you can
install it via your operating system's software sources, or fetch it from
[https://stedolan.github.io/jq/](https://stedolan.github.io/jq/).
<!-- steps -->
## Trusting TLS in a Cluster
## Trusting TLS in a cluster
Trusting the custom CA from an application running as a pod usually requires
some extra application configuration. You will need to add the CA certificate
@@ -48,7 +53,7 @@ You can distribute the CA certificate as a
[ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap) that your
pods have access to use.
## Requesting a Certificate
## Requesting a certificate
The following section demonstrates how to create a TLS certificate for a
Kubernetes service accessed through DNS.
@@ -57,12 +62,7 @@ Kubernetes service accessed through DNS.
This tutorial uses CFSSL: Cloudflare's PKI and TLS toolkit [click here](https://blog.cloudflare.com/introducing-cfssl/) to know more.
{{< /note >}}
## Download and install CFSSL
The cfssl tools used in this example can be downloaded at
[https://github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases).
## Create a Certificate Signing Request
## Create a certificate signing request
Generate a private key and certificate signing request (or CSR) by running
the following command:
@@ -98,14 +98,14 @@ is the pod's DNS name. You should see the output similar to:
```
This command generates two files; it generates `server.csr` containing the PEM
encoded [pkcs#10](https://tools.ietf.org/html/rfc2986) certification request,
encoded [PKCS#10](https://tools.ietf.org/html/rfc2986) certification request,
and `server-key.pem` containing the PEM encoded key to the certificate that
is still to be created.
## Create a Certificate Signing Request object to send to the Kubernetes API
## Create a CertificateSigningRequest object to send to the Kubernetes API
Generate a CSR yaml blob and send it to the apiserver by running the following
command:
Generate a CSR manifest (in YAML), and send it to the API server. You can do that by
running the following command:
```shell
cat <<EOF | kubectl apply -f -
@@ -124,7 +124,7 @@ EOF
```
Notice that the `server.csr` file created in step 1 is base64 encoded
and stashed in the `.spec.request` field. We are also requesting a
and stashed in the `.spec.request` field. You are also requesting a
certificate with the "digital signature", "key encipherment", and "server
auth" key usages, signed by an example `example.com/serving` signer.
A specific `signerName` must be requested.
@@ -157,7 +157,7 @@ Subject Alternative Names:
Events: <none>
```
## Get the Certificate Signing Request Approved
## Get the CertificateSigningRequest approved {#get-the-certificate-signing-request-approved}
Approving the [certificate signing request](/docs/reference/access-authn-authz/certificate-signing-requests/)
is either done by an automated approval process or on a one off basis by a cluster
@@ -186,16 +186,18 @@ my-svc.my-namespace 10m example.com/serving yourname@example.com <none>
This means the certificate request has been approved and is waiting for the
requested signer to sign it.
## Sign the Certificate Signing Request
## Sign the CertificateSigningRequest {#sign-the-certificate-signing-request}
Next, you'll play the part of a certificate signer, issue the certificate, and upload it to the API.
A signer would typically watch the Certificate Signing Request API for objects with its `signerName`,
check that they have been approved, sign certificates for those requests,
A signer would typically watch the CertificateSigningRequest API for objects with its `signerName`,
check that they have been approved, sign certificates for those requests,
and update the API object status with the issued certificate.
### Create a Certificate Authority
You need an authority to provide the digital signature on the new certificate.
First, create a signing certificate by running the following:
```shell
@@ -210,7 +212,7 @@ cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
EOF
```
You should see the output similar to:
You should see output similar to:
```none
2022/02/01 11:50:39 [INFO] generating a new CA key and certificate from CSR
@@ -223,7 +225,7 @@ You should see the output similar to:
This produces a certificate authority key file (`ca-key.pem`) and certificate (`ca.pem`).
### Issue a Certificate
### Issue a certificate
{{< codenew file="tls/server-signing-config.json" >}}
@@ -245,7 +247,7 @@ You should see the output similar to:
This produces a signed serving certificate file, `ca-signed-server.pem`.
### Upload the Signed Certificate
### Upload the signed certificate
Finally, populate the signed certificate in the API object's status:
@@ -256,24 +258,27 @@ kubectl get csr my-svc.my-namespace -o json | \
```
{{< note >}}
This uses the command line tool [jq](https://stedolan.github.io/jq/) to populate the base64-encoded content in the `.status.certificate` field.
If you do not have `jq`, you can also save the JSON output to a file, populate this field manually, and upload the resulting file.
This uses the command line tool [`jq`](https://stedolan.github.io/jq/) to populate the base64-encoded
content in the `.status.certificate` field.
If you do not have `jq`, you can also save the JSON output to a file, populate this field manually, and
upload the resulting file.
{{< /note >}}
Once the CSR is approved and the signed certificate is uploaded you should see the following:
Once the CSR is approved and the signed certificate is uploaded, run:
```shell
kubectl get csr
```
The output is similar to:
```none
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-svc.my-namespace 20m example.com/serving yourname@example.com <none> Approved,Issued
```
## Download the Certificate and Use It
## Download the certificate and use it
Now, as the requesting user, you can download the issued certificate
Now, as the requesting user, you can download the issued certificate
and save it to a `server.crt` file by running the following:
```shell
@@ -281,37 +286,48 @@ kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
| base64 --decode > server.crt
```
Now you can populate `server.crt` and `server-key.pem` in a secret and mount
it into a pod to use as the keypair to start your HTTPS server:
Now you can populate `server.crt` and `server-key.pem` in a
{{< glossary_tooltip text="Secret" term_id="secret" >}}
that you could later mount into a Pod (for example, to use with a webserver
that serves HTTPS).
```shell
kubectl create secret tls server --cert server.crt --key server-key.pem
kubectl create secret tls server --cert server.crt --key server-key.pem
```
```none
secret/server created
```
Finally, you can populate `ca.pem` in a configmap and use it as the trust root
to verify the serving certificate:
Finally, you can populate `ca.pem` into a {< glossary_tooltip text="ConfigMap" term_id="configmap" >}}
and use it as the trust root to verify the serving certificate:
```shell
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
```
```none
configmap/example-serving-ca created
```
## Approving Certificate Signing Requests
## Approving CertificateSigningRequests {#approving-certificate-signing-requests}
A Kubernetes administrator (with appropriate permissions) can manually approve
(or deny) Certificate Signing Requests by using the `kubectl certificate
(or deny) CertificateSigningRequests by using the `kubectl certificate
approve` and `kubectl certificate deny` commands. However if you intend
to make heavy usage of this API, you might consider writing an automated
certificates controller.
Whether a machine or a human using kubectl as above, the role of the approver is
{{< caution >}}
The ability to approve CSRs decides who trusts whom within your environment. The
ability to approve CSRs should not be granted broadly or lightly.
You should make sure that you confidently understand both the verification requirements
that fall on the approver **and** the repercussions of issuing a specific certificate
before you grant the `approve` permission.
{{< /caution >}}
Whether a machine or a human using kubectl as above, the role of the _approver_ is
to verify that the CSR satisfies two requirements:
1. The subject of the CSR controls the private key used to sign the CSR. This
@@ -326,20 +342,15 @@ to verify that the CSR satisfies two requirements:
If and only if these two requirements are met, the approver should approve
the CSR and otherwise should deny the CSR.
## A Word of Warning on the Approval Permission
For more information on certificate approval and access control, read
the [Certificate Signing Requests](/docs/reference/access-authn-authz/certificate-signing-requests/)
reference page.
The ability to approve CSRs decides who trusts whom within your environment. The
ability to approve CSRs should not be granted broadly or lightly. The
requirements of the challenge noted in the previous section and the
repercussions of issuing a specific certificate should be fully understood
before granting this permission.
## Configuring your cluster to provide signing
## A Note to Cluster Administrators
This tutorial assumes that a signer is setup to serve the certificates API. The
This page assumes that a signer is setup to serve the certificates API. The
Kubernetes controller manager provides a default implementation of a signer. To
enable it, pass the `--cluster-signing-cert-file` and
`--cluster-signing-key-file` parameters to the controller manager with paths to
your Certificate Authority's keypair.