Merge remote-tracking branch 'upstream/main' into dev-1.24
This commit is contained in:
@@ -86,12 +86,36 @@ The output is similar to this:
|
||||
|
||||
### Without kubectl proxy
|
||||
|
||||
Use `kubectl describe secret...` to get the token for the default service account with grep/cut:
|
||||
Use `kubectl apply` and `kubectl describe secret...` to create a token for the default service account with grep/cut:
|
||||
|
||||
First, create the Secret, requesting a token for the default ServiceAccount:
|
||||
|
||||
```shell
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: default-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: default
|
||||
type: kubernetes.io/service-account-token
|
||||
EOF
|
||||
```
|
||||
|
||||
Next, wait for the token controller to populate the Secret with a token:
|
||||
|
||||
```shell
|
||||
while ! kubectl describe secret default-token | grep -E '^token' >/dev/null; do
|
||||
echo "waiting for token..." >&2
|
||||
sleep 1
|
||||
done
|
||||
```
|
||||
|
||||
Capture and use the generated token:
|
||||
|
||||
```shell
|
||||
APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
|
||||
SECRET_NAME=$(kubectl get secrets | grep ^default | cut -f1 -d ' ')
|
||||
TOKEN=$(kubectl describe secret $SECRET_NAME | grep -E '^token' | cut -f2 -d':' | tr -d " ")
|
||||
TOKEN=$(kubectl describe secret default-token | grep -E '^token' | cut -f2 -d':' | tr -d " ")
|
||||
|
||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
```
|
||||
@@ -117,8 +141,7 @@ Using `jsonpath`:
|
||||
|
||||
```shell
|
||||
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
|
||||
SECRET_NAME=$(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}')
|
||||
TOKEN=$(kubectl get secret $SECRET_NAME -o jsonpath='{.data.token}' | base64 --decode)
|
||||
TOKEN=$(kubectl get secret default-token -o jsonpath='{.data.token}' | base64 --decode)
|
||||
|
||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
```
|
||||
|
||||
@@ -95,8 +95,25 @@ export CLUSTER_NAME="some_server_name"
|
||||
# Point to the API server referring the cluster name
|
||||
APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
|
||||
|
||||
# Gets the token value
|
||||
TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 --decode)
|
||||
# Create a secret to hold a token for the default service account
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: default-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: default
|
||||
type: kubernetes.io/service-account-token
|
||||
EOF
|
||||
|
||||
# Wait for the token controller to populate the secret with a token:
|
||||
while ! kubectl describe secret default-token | grep -E '^token' >/dev/null; do
|
||||
echo "waiting for token..." >&2
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Get the token value
|
||||
TOKEN=$(kubectl get secret default-token -o jsonpath='{.data.token}' | base64 --decode)
|
||||
|
||||
# Explore the API with TOKEN
|
||||
curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
@@ -119,26 +136,6 @@ The output is similar to this:
|
||||
}
|
||||
```
|
||||
|
||||
Using `jsonpath` approach:
|
||||
|
||||
```shell
|
||||
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
|
||||
TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode )
|
||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
|
||||
{
|
||||
"kind": "APIVersions",
|
||||
"versions": [
|
||||
"v1"
|
||||
],
|
||||
"serverAddressByClientCIDRs": [
|
||||
{
|
||||
"clientCIDR": "0.0.0.0/0",
|
||||
"serverAddress": "10.0.1.149:443"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The above example uses the `--insecure` flag. This leaves it subject to MITM
|
||||
attacks. When kubectl accesses the cluster it uses a stored root certificate
|
||||
and client certificates to access the server. (These are installed in the
|
||||
|
||||
@@ -361,3 +361,12 @@ We also recommend restarting any components (e.g. `kube-scheduler`,
|
||||
stale data. Note that in practice, the restore takes a bit of time. During the
|
||||
restoration, critical components will lose leader lock and restart themselves.
|
||||
{{< /note >}}
|
||||
|
||||
## Upgrading etcd clusters
|
||||
|
||||
|
||||
For more details on etcd upgrade, please refer to the [etcd upgrades](https://etcd.io/docs/latest/upgrades/) documentation.
|
||||
|
||||
{{< note >}}
|
||||
Before you start an upgrade, please back up your etcd cluster first.
|
||||
{{< /note >}}
|
||||
|
||||
@@ -46,7 +46,8 @@ management policies to determine some placement preferences on the node.
|
||||
### Configuration
|
||||
|
||||
The CPU Manager policy is set with the `--cpu-manager-policy` kubelet
|
||||
option. There are two supported policies:
|
||||
flag or the `cpuManagerPolicy` field in [KubeletConfiguration](/docs/reference/config-api/kubelet-config.v1beta1/).
|
||||
There are two supported policies:
|
||||
|
||||
* [`none`](#none-policy): the default policy.
|
||||
* [`static`](#static-policy): allows pods with certain resource characteristics to be
|
||||
@@ -68,6 +69,27 @@ and `CPUManagerPolicyBetaOptions` feature gates. Diverging from the Kubernetes s
|
||||
feature gates guard groups of options, because it would have been too cumbersome to add a feature
|
||||
gate for each individual option.
|
||||
|
||||
### Changing the CPU Manager Policy
|
||||
|
||||
Since the CPU manger policy can only be applied when kubelet spawns new pods, simply changing from
|
||||
"none" to "static" won't apply to existing pods. So in order to properly change the CPU manager
|
||||
policy on a node, perform the following steps:
|
||||
|
||||
1. [Drain](/docs/tasks/administer-cluster/safely-drain-node) the node.
|
||||
2. Stop kubelet.
|
||||
3. Remove the old CPU manager state file. The path to this file is
|
||||
`/var/lib/kubelet/cpu_manager_state` by default. This clears the state maintained by the
|
||||
CPUManager so that the cpu-sets set up by the new policy won’t conflict with it.
|
||||
4. Edit the kubelet configuration to change the CPU manager policy to the desired value.
|
||||
5. Start kubelet.
|
||||
|
||||
Repeat this process for every node that needs its CPU manager policy changed. Skipping this
|
||||
process will result in kubelet crashlooping with the following error:
|
||||
|
||||
```
|
||||
could not restore state from checkpoint: configured policy "static" differs from state checkpoint policy "none", please drain this node and delete the CPU manager checkpoint file "/var/lib/kubelet/cpu_manager_state" before restarting Kubelet
|
||||
```
|
||||
|
||||
### None policy
|
||||
|
||||
The `none` policy explicitly enables the existing default CPU
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints-pod-3.ya
|
||||
```
|
||||
|
||||
The output shows that the Pod does not get created, because it defines an unacceptable container.
|
||||
That container is not acceptable because it specifies a CPU limit that is lower than the
|
||||
That container is not acceptable because it specifies a CPU request that is lower than the
|
||||
enforced minimum:
|
||||
|
||||
```
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ Here are two of the restrictions that a resource quota imposes on a namespace:
|
||||
* For every Pod that runs in the namespace, the Pod and each of its containers must have a memory limit.
|
||||
(If you specify a memory limit for every container in a Pod, Kubernetes can infer the Pod-level memory
|
||||
limit by adding up the limits for its containers).
|
||||
* CPU limits apply a resource reservation on the node where the Pod in question is scheduled.
|
||||
* Memory limits apply a resource reservation on the node where the Pod in question is scheduled.
|
||||
The total amount of memory reserved for all Pods in the namespace must not exceed a specified limit.
|
||||
* The total amount of memory actually used by all Pods in the namespace must also not exceed a specified limit.
|
||||
|
||||
|
||||
@@ -130,6 +130,12 @@ The output is similar to:
|
||||
Now you can decode the `password` data:
|
||||
|
||||
```shell
|
||||
# This is an example for documentation purposes.
|
||||
# If you did things this way, the data 'MWYyZDFlMmU2N2Rm' could be stored in
|
||||
# your shell history.
|
||||
# Someone with access to you computer could find that remembered command
|
||||
# and base-64 decode the secret, perhaps without your knowledge.
|
||||
# It's usually better to combine the steps, as shown later in the page.
|
||||
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
|
||||
```
|
||||
|
||||
@@ -139,6 +145,15 @@ The output is similar to:
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
In order to avoid storing a secret encoded value in your shell history, you can
|
||||
run the following command:
|
||||
|
||||
```shell
|
||||
kubectl get secret db-user-pass -o jsonpath='{.data.password}' | base64 --decode
|
||||
```
|
||||
|
||||
The output shall be similar as above.
|
||||
|
||||
## Clean Up
|
||||
|
||||
Delete the Secret you created:
|
||||
|
||||
@@ -199,7 +199,7 @@ As Pod specs with GMSA fields populated (as described above) are applied in a cl
|
||||
|
||||
1. The container runtime configures each Windows container with the specified GMSA credential spec so that the container can assume the identity of the GMSA in Active Directory and access services in the domain using that identity.
|
||||
|
||||
## Authenticating to network shares usinig hostname of FQDN
|
||||
## Authenticating to network shares using hostname or FQDN
|
||||
|
||||
If you are experiencing issues connecting to SMB shares from Pods using hostname or FQDN, but are able to access the shares via their IPv4 address then make sure the following registry key is set on the Windows nodes.
|
||||
|
||||
@@ -225,7 +225,7 @@ kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe
|
||||
|
||||
`nltest.exe /parentdomain` results in the following error:
|
||||
|
||||
```PowerShell
|
||||
```output
|
||||
Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
|
||||
```
|
||||
|
||||
@@ -245,7 +245,7 @@ nltest.exe /query
|
||||
|
||||
Results in the following output:
|
||||
|
||||
```PowerShell
|
||||
```output
|
||||
I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
|
||||
```
|
||||
|
||||
@@ -257,7 +257,7 @@ nltest /sc_reset:domain.example
|
||||
|
||||
If the command is successful you will see and output similar to this:
|
||||
|
||||
```PowerShell
|
||||
```output
|
||||
Flags: 30 HAS_IP HAS_TIMESERV
|
||||
Trusted DC Name \\dc10.domain.example
|
||||
Trusted DC Connection Status Status = 0 0x0 NERR_Success
|
||||
|
||||
@@ -291,7 +291,7 @@ command line arguments to `kube-apiserver`:
|
||||
|
||||
* `--service-account-issuer`
|
||||
|
||||
It can be used as the Identifier of the service account token issuer. You can specify the `--service-account-issuer` argument multiple times, this can be useful to enable a non-disruptive change of the issuer. When this flag is specified multiple times, the first is used to generate tokens and all are used to determine which issuers are accepted. You must be running running Kubernetes v1.22 or later to be able to specify `--service-account-issuer` multiple times.
|
||||
It can be used as the Identifier of the service account token issuer. You can specify the `--service-account-issuer` argument multiple times, this can be useful to enable a non-disruptive change of the issuer. When this flag is specified multiple times, the first is used to generate tokens and all are used to determine which issuers are accepted. You must be running Kubernetes v1.22 or later to be able to specify `--service-account-issuer` multiple times.
|
||||
* `--service-account-key-file`
|
||||
|
||||
File containing PEM-encoded x509 RSA or ECDSA private or public keys, used to verify ServiceAccount tokens. The specified file can contain multiple keys, and the flag can be specified multiple times with different files. If specified multiple times, tokens signed by any of the specified keys are considered valid by the Kubernetes API server.
|
||||
|
||||
@@ -19,30 +19,323 @@ admission controller. This can be done effectively using a combination of dry-ru
|
||||
|
||||
- Ensure the `PodSecurity` [feature gate](/docs/reference/command-line-tools-reference/feature-gates/#feature-gates-for-alpha-or-beta-features) is enabled.
|
||||
|
||||
This page assumes you are already familiar with the basic [Pod Security Admission](/docs/concepts/security/pod-security-admission/)
|
||||
concepts.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## Steps
|
||||
## Overall approach
|
||||
|
||||
- **Eliminate mutating PodSecurityPolicies, if your cluster has any set up.**
|
||||
- Clone all mutating PSPs into a non-mutating version.
|
||||
- Update all ClusterRoles authorizing use of those mutating PSPs to also authorize use of the
|
||||
non-mutating variant.
|
||||
- Watch for Pods using the mutating PSPs and work with code owners to migrate to valid,
|
||||
non-mutating resources.
|
||||
- Delete mutating PSPs.
|
||||
- **Select a compatible policy level for each namespace.** Analyze existing resources in the
|
||||
namespace to drive this decision.
|
||||
- Review the requirements of the different [Pod Security Standards](/docs/concepts/security/pod-security-standards).
|
||||
- Evaluate the difference in privileges that would come from disabling the PSP controller.
|
||||
- In the event that a PodSecurityPolicy falls between two levels, consider:
|
||||
- Selecting a _less_ permissive PodSecurity level prioritizes security, and may require adjusting
|
||||
workloads to fit within the stricter policy.
|
||||
- Selecting a _more_ permissive PodSecurity level prioritizes avoiding disrupting or
|
||||
changing workloads, but may allow workload authors in the namespace greater permissions
|
||||
than desired.
|
||||
- **Apply the selected profiles in `warn` and `audit` mode.** This will give you an idea of how
|
||||
your Pods will respond to the new policies, without breaking existing workloads. Iterate on your
|
||||
[Pods' configuration](/docs/concepts/security/pod-security-admission#configuring-pods) until
|
||||
they are in compliance with the selected profiles.
|
||||
- Apply the profiles in `enforce` mode.
|
||||
- Stop including `PodSecurityPolicy` in the `--enable-admission-plugins` flag.
|
||||
There are multiple strategies you can take for migrating from PodSecurityPolicy to Pod Security
|
||||
Admission. The following steps are one possible migration path, with a goal of minimizing both the
|
||||
risks of a production outage and of a security gap.
|
||||
|
||||
<!-- Keep section header numbering in sync with this list. -->
|
||||
0. Decide whether Pod Security Admission is the right fit for your use case.
|
||||
1. Review namespace permissions
|
||||
2. Simplify & standardize PodSecurityPolicies
|
||||
3. Update namespaces
|
||||
1. Identify an appropriate Pod Security level
|
||||
2. Verify the Pod Security level
|
||||
3. Enforce the Pod Security level
|
||||
4. Bypass PodSecurityPolicy
|
||||
4. Review namespace creation processes
|
||||
5. Disable PodSecurityPolicy
|
||||
|
||||
## 0. Decide whether Pod Security Admission is right for you {#is-psa-right-for-you}
|
||||
|
||||
Pod Security Admission was designed to meet the most common security needs out of the box, and to
|
||||
provide a standard set of security levels across clusters. However, it is less flexible than
|
||||
PodSecurityPolicy. Notably, the following features are supported by PodSecurityPolicy but not Pod
|
||||
Security Admission:
|
||||
|
||||
- **Setting default security constraints** - Pod Security Admission is a non-mutating admission
|
||||
controller, meaning it won't modify pods before validating them. If you were relying on this
|
||||
aspect of PSP, you will need to either modify your workloads to meet the Pod Security constraints,
|
||||
or use a [Mutating Admission Webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/)
|
||||
to make those changes. See [Simplify & Standardize PodSecurityPolicies](#simplify-psps) below for more detail.
|
||||
- **Fine-grained control over policy definition** - Pod Security Admission only supports
|
||||
[3 standard levels](/docs/concepts/security/pod-security-standards/).
|
||||
If you require more control over specific constraints, then you will need to use a
|
||||
[Validating Admission Webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/)
|
||||
to enforce those policies.
|
||||
- **Sub-namespace policy granularity** - PodSecurityPolicy lets you bind different policies to
|
||||
different Service Accounts or users, even within a single namespace. This approach has many
|
||||
pitfalls and is not recommended, but if you require this feature anyway you will
|
||||
need to use a 3rd party webhook instead. The exception to this is if you only need to completely exempt
|
||||
specific users or [RuntimeClasses](/docs/concepts/containers/runtime-class/), in which case Pod
|
||||
Security Admission does expose some
|
||||
[static configuration for exemptions](/docs/concepts/security/pod-security-admission/#exemptions).
|
||||
|
||||
Even if Pod Security Admission does not meet all of your needs it was designed to be _complementary_
|
||||
to other policy enforcement mechanisms, and can provide a useful fallback running alongside other
|
||||
admission webhooks.
|
||||
|
||||
|
||||
## 1. Review namespace permissions {#review-namespace-permissions}
|
||||
|
||||
Pod Security Admission is controlled by [labels on
|
||||
namespaces](/docs/concepts/security/pod-security-admission/#pod-security-admission-labels-for-namespaces).
|
||||
This means that anyone who can update (or patch or create) a namespace can also modify the Pod
|
||||
Security level for that namespace, which could be used to bypass a more restrictive policy. Before
|
||||
proceeding, ensure that only trusted, privileged users have these namespace permissions. It is not
|
||||
recommended to grant these powerful permissions to users that shouldn't have elevated permissions,
|
||||
but if you must you will need to use an
|
||||
[admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/)
|
||||
to place additional restrictions on setting Pod Security labels on Namespace objects.
|
||||
|
||||
## 2. Simplify & standardize PodSecurityPolicies {#simplify-psps}
|
||||
|
||||
In this section, you will reduce mutating PodSecurityPolicies and remove options that are outside
|
||||
the scope of the Pod Security Standards. You should make the changes recommended here to an offline
|
||||
copy of the original PodSecurityPolicy being modified. The cloned PSP should have a different
|
||||
name that is alphabetically before the original (for example, prepend a `0` to it). Do not create the
|
||||
new policies in Kubernetes yet - that will be covered in the [Rollout the updated
|
||||
policies](#psp-update-rollout) section below.
|
||||
|
||||
### 2.a. Eliminate purely mutating fields {#eliminate-mutating-fields}
|
||||
|
||||
If a PodSecurityPolicy is mutating pods, then you could end up with pods that don't meet the Pod
|
||||
Security level requirements when you finally turn PodSecurityPolicy off. In order to avoid this, you
|
||||
should eliminate all PSP mutation prior to switching over. Unfortunately PSP does not cleanly
|
||||
separate mutating & validating fields, so this is not a straightforward migration.
|
||||
|
||||
You can start by eliminating the fields that are purely mutating, and don't have any bearing on the
|
||||
validating policy. These fields (also listed in the
|
||||
[Mapping PodSecurityPolicies to Pod Security Standards](/docs/reference/access-authn-authz/psp-to-pod-security-standards/)
|
||||
reference) are:
|
||||
|
||||
- `.spec.defaultAllowPrivilegeEscalation`
|
||||
- `.spec.runtimeClass.defaultRuntimeClassName`
|
||||
- `.metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName']`
|
||||
- `.metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName']`
|
||||
- `.spec.defaultAddCapabilities` - Although technically a mutating & validating field, these should
|
||||
be merged into `.spec.allowedCapabilities` which performs the same validation without mutation.
|
||||
|
||||
{{< caution >}}
|
||||
Removing these could result in workloads missing required configuration, and cause problems. See
|
||||
[Rollout the updated policies](#psp-update-rollout) below for advice on how to roll these changes
|
||||
out safely.
|
||||
{{< /caution >}}
|
||||
|
||||
### 2.b. Eliminate options not covered by the Pod Security Standards {#eliminate-non-standard-options}
|
||||
|
||||
There are several fields in PodSecurityPolicy that are not covered by the Pod Security Standards. If
|
||||
you must enforce these options, you will need to supplement Pod Security Admission with an
|
||||
[admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/),
|
||||
which is outside the scope of this guide.
|
||||
|
||||
First, you can remove the purely validating fields that the Pod Security Standards do not cover.
|
||||
These fields (also listed in the
|
||||
[Mapping PodSecurityPolicies to Pod Security Standards](/docs/reference/access-authn-authz/psp-to-pod-security-standards/)
|
||||
reference with "no opinion") are:
|
||||
|
||||
- `.spec.allowedHostPaths`
|
||||
- `.spec.allowedFlexVolumes`
|
||||
- `.spec.allowedCSIDrivers`
|
||||
- `.spec.forbiddenSysctls`
|
||||
- `.spec.runtimeClass`
|
||||
|
||||
You can also remove the following fields, that are related to POSIX / UNIX group controls.
|
||||
|
||||
{{< caution >}}
|
||||
If any of these use the `MustRunAs` strategy they may be mutating! Removing these could result in
|
||||
workloads not setting the required groups, and cause problems. See
|
||||
[Rollout the updated policies](#psp-update-rollout) below for advice on how to roll these changes
|
||||
out safely.
|
||||
{{< /caution >}}
|
||||
|
||||
- `.spec.runAsGroup`
|
||||
- `.spec.supplementalGroups`
|
||||
- `.spec.fsGroup`
|
||||
|
||||
The remaining mutating fields are required to properly support the Pod Security Standards, and will
|
||||
need to be handled on a case-by-case basis later:
|
||||
|
||||
- `.spec.requiredDropCapabilities` - Required to drop `ALL` for the Restricted profile.
|
||||
- `.spec.seLinux` - (Only mutating with the `MustRunAs` rule) required to enforce the SELinux
|
||||
requirements of the Baseline & Restricted profiles.
|
||||
- `.spec.runAsUser` - (Non-mutating with the `RunAsAny` rule) required to enforce `RunAsNonRoot` for
|
||||
the Restricted profile.
|
||||
- `.spec.allowPrivilegeEscalation` - (Only mutating if set to `false`) required for the Restricted
|
||||
profile.
|
||||
|
||||
### 2.c. Rollout the updated PSPs {#psp-update-rollout}
|
||||
|
||||
Next, you can rollout the updated policies to your cluster. You should proceed with caution, as
|
||||
removing the mutating options may result in workloads missing required configuration.
|
||||
|
||||
For each updated PodSecurityPolicy:
|
||||
|
||||
1. Identify pods running under the original PSP. This can be done using the `kubernetes.io/psp`
|
||||
annotation. For example, using kubectl:
|
||||
```sh
|
||||
PSP_NAME="original" # Set the name of the PSP you're checking for
|
||||
kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}"
|
||||
```
|
||||
2. Compare these running pods against the original pod spec to determine whether PodSecurityPolicy
|
||||
has modified the pod. For pods created by a [workload resource](/docs/concepts/workloads/controllers/)
|
||||
you can compare the pod with the PodTemplate in the controller resource. If any changes are
|
||||
identified, the original Pod or PodTemplate should be updated with the desired configuration.
|
||||
The fields to review are:
|
||||
- `.metadata.annotations['container.apparmor.security.beta.kubernetes.io/*']` (replace * with each container name)
|
||||
- `.spec.runtimeClassName`
|
||||
- `.spec.securityContext.fsGroup`
|
||||
- `.spec.securityContext.seccompProfile`
|
||||
- `.spec.securityContext.seLinuxOptions`
|
||||
- `.spec.securityContext.supplementalGroups`
|
||||
- On containers, under `.spec.containers[*]` and `.spec.initContainers[*]`:
|
||||
- `.securityContext.allowPrivilegeEscalation`
|
||||
- `.securityContext.capabilities.add`
|
||||
- `.securityContext.capabilities.drop`
|
||||
- `.securityContext.readOnlyRootFilesystem`
|
||||
- `.securityContext.runAsGroup`
|
||||
- `.securityContext.runAsNonRoot`
|
||||
- `.securityContext.runAsUser`
|
||||
- `.securityContext.seccompProfile`
|
||||
- `.securityContext.seLinuxOptions`
|
||||
3. Create the new PodSecurityPolicies. If any Roles or ClusterRoles are granting `use` on all PSPs
|
||||
this could cause the new PSPs to be used instead of their mutating counter-parts.
|
||||
4. Update your authorization to grant access to the new PSPs. In RBAC this means updating any Roles
|
||||
or ClusterRoles that grant the `use` permision on the original PSP to also grant it to the
|
||||
updated PSP.
|
||||
5. Verify: after some soak time, rerun the command from step 1 to see if any pods are still using
|
||||
the original PSPs. Note that pods need to be recreated after the new policies have been rolled
|
||||
out before they can be fully verified.
|
||||
6. (optional) Once you have verified that the original PSPs are no longer in use, you can delete
|
||||
them.
|
||||
|
||||
## 3. Update Namespaces {#update-namespaces}
|
||||
|
||||
The following steps will need to be performed on every namespace in the cluster. Commands referenced
|
||||
in these steps use the `$NAMESPACE` variable to refer to the namespace being updated.
|
||||
|
||||
### 3.a. Identify an appropriate Pod Security level {#identify-appropriate-level}
|
||||
|
||||
Start reviewing the [Pod Security Standards](/docs/concepts/security/pod-security-standards/) and
|
||||
familiarizing yourself with the 3 different levels.
|
||||
|
||||
There are several ways to choose a Pod Security level for your namespace:
|
||||
|
||||
1. **By security requirements for the namespace** - If you are familiar with the expected access
|
||||
level for the namespace, you can choose an appropriate level based on those requirements, similar
|
||||
to how one might approach this on a new cluster.
|
||||
2. **By existing PodSecurityPolicies** - Using the
|
||||
[Mapping PodSecurityPolicies to Pod Security Standards](/docs/reference/access-authn-authz/psp-to-pod-security-standards/)
|
||||
reference you can map each
|
||||
PSP to a Pod Security Standard level. If your PSPs aren't based on the Pod Security Standards, you
|
||||
may need to decide between choosing a level that is at least as permissive as the PSP, and a
|
||||
level that is at least as restrictive. You can see which PSPs are in use for pods in a given
|
||||
namespace with this command:
|
||||
```sh
|
||||
kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u
|
||||
```
|
||||
3. **By existing pods** - Using the strategies under [Verify the Pod Security level](#verify-pss-level),
|
||||
you can test out both the Baseline and Restricted levels to see
|
||||
whether they are sufficiently permissive for existing workloads, and chose the least-privileged
|
||||
valid level.
|
||||
|
||||
{{< caution >}}
|
||||
Options 2 & 3 above are based on _existing_ pods, and may miss workloads that aren't currently
|
||||
running, such as CronJobs, scale-to-zero workloads, or other workloads that haven't rolled out.
|
||||
{{< /caution >}}
|
||||
|
||||
### 3.b. Verify the Pod Security level {#verify-pss-level}
|
||||
|
||||
Once you have selected a Pod Security level for the namespace (or if you're trying several), it's a
|
||||
good idea to test it out first (you can skip this step if using the Privileged level). Pod Security
|
||||
includes several tools to help test and safely roll out profiles.
|
||||
|
||||
First, you can dry-run the policy, which will evaluate pods currently running in the namespace
|
||||
against the applied policy, without making the new policy take effect:
|
||||
```sh
|
||||
# $LEVEL is the level to dry-run, either "baseline" or "restricted".
|
||||
kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
|
||||
```
|
||||
This command will return a warning for any _existing_ pods that are not valid under the proposed
|
||||
level.
|
||||
|
||||
The second option is better for catching workloads that are not currently running: audit mode. When
|
||||
running under audit-mode (as opposed to enforcing), pods that violate the policy level are recorded
|
||||
in the audit logs, which can be reviewed later after some soak time, but are not forbidden. Warning
|
||||
mode works similarly, but returns the warning to the user immediately. You can set the audit level
|
||||
on a namespace with this command:
|
||||
```sh
|
||||
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL
|
||||
```
|
||||
|
||||
If either of these approaches yield unexpected violations, you will need to either update the
|
||||
violating workloads to meet the policy requirements, or relax the namespace Pod Security level.
|
||||
|
||||
### 3.c. Enforce the Pod Security level {#enforce-pod-security-level}
|
||||
|
||||
When you are satisfied that the chosen level can safely be enforced on the namespace, you can update
|
||||
the namespace to enforce the desired level:
|
||||
|
||||
```sh
|
||||
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
|
||||
```
|
||||
|
||||
### 3.d. Bypass PodSecurityPolicy {#bypass-psp}
|
||||
|
||||
Finally, you can effectively bypass PodSecurityPolicy at the namespace level by binding the fully
|
||||
{{< example file="policy/privileged-psp.yaml" >}}privileged PSP{{< /example >}} to all service
|
||||
accounts in the namespace.
|
||||
|
||||
```sh
|
||||
# The following cluster-scoped commands are only needed once.
|
||||
kubectl apply -f privileged-psp.yaml
|
||||
kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged
|
||||
|
||||
# Per-namespace disable
|
||||
kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE
|
||||
```
|
||||
|
||||
Since the privileged PSP is non-mutating, and the PSP admission controller always
|
||||
prefers non-mutating PSPs, this will ensure that pods in this namespace are no longer being modified
|
||||
or restricted by PodSecurityPolicy.
|
||||
|
||||
The advantage to disabling PodSecurityPolicy on a per-namespace basis like this is if a problem
|
||||
arises you can easily roll the change back by deleting the RoleBinding. Just make sure the
|
||||
pre-existing PodSecurityPolicies are still in place!
|
||||
|
||||
```sh
|
||||
# Undo PodSecurityPolicy disablement.
|
||||
kubectl delete -n $NAMESPACE rolebinding disable-psp
|
||||
```
|
||||
|
||||
## 4. Review namespace creation processes {#review-namespace-creation-process}
|
||||
|
||||
Now that existing namespaces have been updated to enforce Pod Security Admission, you should ensure
|
||||
that your processes and/or policies for creating new namespaces are updated to ensure that an
|
||||
appropriate Pod Security profile is applied to new namespaces.
|
||||
|
||||
You can also statically configure the Pod Security admission controller to set a default enforce,
|
||||
audit, and/or warn level for unlabeled namespaces. See
|
||||
[Configure the Admission Controller](docs/tasks/configure-pod-container/enforce-standards-admission-controller/#configure-the-admission-controller)
|
||||
for more information.
|
||||
|
||||
## 5. Disable PodSecurityPolicy {#disable-psp}
|
||||
|
||||
Finally, you're ready to disable PodSecurityPolicy. To do so, you will need to modify the admission
|
||||
configuration of the API server:
|
||||
[How do I turn off an admission controller?](/docs/reference/access-authn-authz/admission-controllers/#how-do-i-turn-off-an-admission-controller).
|
||||
|
||||
To verify that the PodSecurityPolicy admission controller is no longer enabled, you can manually run
|
||||
a test by impersonating a user without access to any PodSecurityPolicies (see the
|
||||
[PodSecurityPolicy example](/docs/concepts/policy/pod-security-policy/#example)), or by verifying in
|
||||
the API server logs. At startup, the API server outputs log lines listing the loaded admission
|
||||
controller plugins:
|
||||
|
||||
```
|
||||
I0218 00:59:44.903329 13 plugins.go:158] Loaded 16 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,ServiceAccount,NodeRestriction,TaintNodesByCondition,Priority,DefaultTolerationSeconds,ExtendedResourceToleration,PersistentVolumeLabel,DefaultStorageClass,StorageObjectInUseProtection,RuntimeClass,DefaultIngressClass,MutatingAdmissionWebhook.
|
||||
I0218 00:59:44.903350 13 plugins.go:161] Loaded 14 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,DenyServiceExternalIPs,ValidatingAdmissionWebhook,ResourceQuota.
|
||||
```
|
||||
|
||||
You should see `PodSecurity` (in the validating admission controllers), and neither list should
|
||||
contain `PodSecurityPolicy`.
|
||||
|
||||
Once you are certain the PSP admission controller is disabled (and after sufficient soak time to be
|
||||
confident you won't need to roll back), you are free to delete your PodSecurityPolicies and any
|
||||
associated Roles, ClusterRoles, RoleBindings and ClusterRoleBindings (just make sure they don't
|
||||
grant any other unrelated permissions).
|
||||
|
||||
+266
-148
@@ -40,70 +40,77 @@ kubectl get pods
|
||||
```
|
||||
|
||||
```none
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1006230814-6winp 1/1 Running 0 11s
|
||||
nginx-deployment-1006230814-fmgu3 1/1 Running 0 11s
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-67d4bdd6f5-cx2nz 1/1 Running 0 13s
|
||||
nginx-deployment-67d4bdd6f5-w6kd7 1/1 Running 0 13s
|
||||
```
|
||||
|
||||
We can retrieve a lot more information about each of these pods using `kubectl describe pod`. For example:
|
||||
|
||||
```shell
|
||||
kubectl describe pod nginx-deployment-1006230814-6winp
|
||||
kubectl describe pod nginx-deployment-67d4bdd6f5-w6kd7
|
||||
```
|
||||
|
||||
```none
|
||||
Name: nginx-deployment-1006230814-6winp
|
||||
Namespace: default
|
||||
Node: kubernetes-node-wul5/10.240.0.9
|
||||
Start Time: Thu, 24 Mar 2016 01:39:49 +0000
|
||||
Labels: app=nginx,pod-template-hash=1006230814
|
||||
Annotations: kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
|
||||
Status: Running
|
||||
IP: 10.244.0.6
|
||||
Controllers: ReplicaSet/nginx-deployment-1006230814
|
||||
Name: nginx-deployment-67d4bdd6f5-w6kd7
|
||||
Namespace: default
|
||||
Priority: 0
|
||||
Node: kube-worker-1/192.168.0.113
|
||||
Start Time: Thu, 17 Feb 2022 16:51:01 -0500
|
||||
Labels: app=nginx
|
||||
pod-template-hash=67d4bdd6f5
|
||||
Annotations: <none>
|
||||
Status: Running
|
||||
IP: 10.88.0.3
|
||||
IPs:
|
||||
IP: 10.88.0.3
|
||||
IP: 2001:db8::1
|
||||
Controlled By: ReplicaSet/nginx-deployment-67d4bdd6f5
|
||||
Containers:
|
||||
nginx:
|
||||
Container ID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
|
||||
Image: nginx
|
||||
Image ID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
|
||||
Port: 80/TCP
|
||||
QoS Tier:
|
||||
cpu: Guaranteed
|
||||
memory: Guaranteed
|
||||
Container ID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
|
||||
Image: nginx
|
||||
Image ID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
|
||||
Port: 80/TCP
|
||||
Host Port: 0/TCP
|
||||
State: Running
|
||||
Started: Thu, 17 Feb 2022 16:51:05 -0500
|
||||
Ready: True
|
||||
Restart Count: 0
|
||||
Limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
Requests:
|
||||
memory: 128Mi
|
||||
cpu: 500m
|
||||
State: Running
|
||||
Started: Thu, 24 Mar 2016 01:39:51 +0000
|
||||
Ready: True
|
||||
Restart Count: 0
|
||||
Environment: <none>
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
Environment: <none>
|
||||
Mounts:
|
||||
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
|
||||
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bgsgp (ro)
|
||||
Conditions:
|
||||
Type Status
|
||||
Initialized True
|
||||
Ready True
|
||||
PodScheduled True
|
||||
Type Status
|
||||
Initialized True
|
||||
Ready True
|
||||
ContainersReady True
|
||||
PodScheduled True
|
||||
Volumes:
|
||||
default-token-4bcbi:
|
||||
Type: Secret (a volume populated by a Secret)
|
||||
SecretName: default-token-4bcbi
|
||||
Optional: false
|
||||
QoS Class: Guaranteed
|
||||
Node-Selectors: <none>
|
||||
Tolerations: <none>
|
||||
kube-api-access-bgsgp:
|
||||
Type: Projected (a volume that contains injected data from multiple sources)
|
||||
TokenExpirationSeconds: 3607
|
||||
ConfigMapName: kube-root-ca.crt
|
||||
ConfigMapOptional: <nil>
|
||||
DownwardAPI: true
|
||||
QoS Class: Guaranteed
|
||||
Node-Selectors: <none>
|
||||
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
|
||||
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
54s 54s 1 {default-scheduler } Normal Scheduled Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
|
||||
54s 54s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulling pulling image "nginx"
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulled Successfully pulled image "nginx"
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Created Created container with docker id 90315cc9f513
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Started Started container with docker id 90315cc9f513
|
||||
Type Reason Age From Message
|
||||
---- ------ ---- ---- -------
|
||||
Normal Scheduled 34s default-scheduler Successfully assigned default/nginx-deployment-67d4bdd6f5-w6kd7 to kube-worker-1
|
||||
Normal Pulling 31s kubelet Pulling image "nginx"
|
||||
Normal Pulled 30s kubelet Successfully pulled image "nginx" in 1.146417389s
|
||||
Normal Created 30s kubelet Created container nginx
|
||||
Normal Started 30s kubelet Started container nginx
|
||||
```
|
||||
|
||||
Here you can see configuration information about the container(s) and Pod (labels, resource requirements, etc.), as well as status information about the container(s) and Pod (state, readiness, restart count, events, etc.).
|
||||
@@ -203,18 +210,22 @@ kubectl get pod nginx-deployment-1006230814-6winp -o yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
annotations:
|
||||
kubernetes.io/created-by: |
|
||||
{"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1006230814","uid":"4c84c175-f161-11e5-9a78-42010af00005","apiVersion":"extensions","resourceVersion":"133434"}}
|
||||
creationTimestamp: 2016-03-24T01:39:50Z
|
||||
generateName: nginx-deployment-1006230814-
|
||||
creationTimestamp: "2022-02-17T21:51:01Z"
|
||||
generateName: nginx-deployment-67d4bdd6f5-
|
||||
labels:
|
||||
app: nginx
|
||||
pod-template-hash: "1006230814"
|
||||
name: nginx-deployment-1006230814-6winp
|
||||
pod-template-hash: 67d4bdd6f5
|
||||
name: nginx-deployment-67d4bdd6f5-w6kd7
|
||||
namespace: default
|
||||
resourceVersion: "133447"
|
||||
uid: 4c879808-f161-11e5-9a78-42010af00005
|
||||
ownerReferences:
|
||||
- apiVersion: apps/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: ReplicaSet
|
||||
name: nginx-deployment-67d4bdd6f5
|
||||
uid: 7d41dfd4-84c0-4be4-88ab-cedbe626ad82
|
||||
resourceVersion: "1364"
|
||||
uid: a6501da1-0447-4262-98eb-c03d4002222e
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
@@ -231,42 +242,88 @@ spec:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-4bcbi
|
||||
name: kube-api-access-bgsgp
|
||||
readOnly: true
|
||||
dnsPolicy: ClusterFirst
|
||||
nodeName: kubernetes-node-wul5
|
||||
enableServiceLinks: true
|
||||
nodeName: kube-worker-1
|
||||
preemptionPolicy: PreemptLowerPriority
|
||||
priority: 0
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
serviceAccount: default
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 30
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/unreachable
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
volumes:
|
||||
- name: default-token-4bcbi
|
||||
secret:
|
||||
secretName: default-token-4bcbi
|
||||
- name: kube-api-access-bgsgp
|
||||
projected:
|
||||
defaultMode: 420
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
expirationSeconds: 3607
|
||||
path: token
|
||||
- configMap:
|
||||
items:
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
name: kube-root-ca.crt
|
||||
- downwardAPI:
|
||||
items:
|
||||
- fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: metadata.namespace
|
||||
path: namespace
|
||||
status:
|
||||
conditions:
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: 2016-03-24T01:39:51Z
|
||||
lastTransitionTime: "2022-02-17T21:51:01Z"
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:06Z"
|
||||
status: "True"
|
||||
type: Ready
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:06Z"
|
||||
status: "True"
|
||||
type: ContainersReady
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:01Z"
|
||||
status: "True"
|
||||
type: PodScheduled
|
||||
containerStatuses:
|
||||
- containerID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
|
||||
image: nginx
|
||||
imageID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
|
||||
- containerID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
|
||||
image: docker.io/library/nginx:latest
|
||||
imageID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
|
||||
lastState: {}
|
||||
name: nginx
|
||||
ready: true
|
||||
restartCount: 0
|
||||
started: true
|
||||
state:
|
||||
running:
|
||||
startedAt: 2016-03-24T01:39:51Z
|
||||
hostIP: 10.240.0.9
|
||||
startedAt: "2022-02-17T21:51:05Z"
|
||||
hostIP: 192.168.0.113
|
||||
phase: Running
|
||||
podIP: 10.244.0.6
|
||||
startTime: 2016-03-24T01:39:49Z
|
||||
podIP: 10.88.0.3
|
||||
podIPs:
|
||||
- ip: 10.88.0.3
|
||||
- ip: 2001:db8::1
|
||||
qosClass: Guaranteed
|
||||
startTime: "2022-02-17T21:51:01Z"
|
||||
```
|
||||
|
||||
## Example: debugging a down/unreachable node
|
||||
@@ -279,116 +336,177 @@ kubectl get nodes
|
||||
|
||||
```none
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
kubernetes-node-861h NotReady <none> 1h v1.13.0
|
||||
kubernetes-node-bols Ready <none> 1h v1.13.0
|
||||
kubernetes-node-st6x Ready <none> 1h v1.13.0
|
||||
kubernetes-node-unaj Ready <none> 1h v1.13.0
|
||||
kube-worker-1 NotReady <none> 1h v1.23.3
|
||||
kubernetes-node-bols Ready <none> 1h v1.23.3
|
||||
kubernetes-node-st6x Ready <none> 1h v1.23.3
|
||||
kubernetes-node-unaj Ready <none> 1h v1.23.3
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl describe node kubernetes-node-861h
|
||||
kubectl describe node kube-worker-1
|
||||
```
|
||||
|
||||
```none
|
||||
Name: kubernetes-node-861h
|
||||
Role
|
||||
Labels: kubernetes.io/arch=amd64
|
||||
kubernetes.io/os=linux
|
||||
kubernetes.io/hostname=kubernetes-node-861h
|
||||
Annotations: node.alpha.kubernetes.io/ttl=0
|
||||
volumes.kubernetes.io/controller-managed-attach-detach=true
|
||||
Taints: <none>
|
||||
CreationTimestamp: Mon, 04 Sep 2017 17:13:23 +0800
|
||||
Phase:
|
||||
Name: kube-worker-1
|
||||
Roles: <none>
|
||||
Labels: beta.kubernetes.io/arch=amd64
|
||||
beta.kubernetes.io/os=linux
|
||||
kubernetes.io/arch=amd64
|
||||
kubernetes.io/hostname=kube-worker-1
|
||||
kubernetes.io/os=linux
|
||||
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
|
||||
node.alpha.kubernetes.io/ttl: 0
|
||||
volumes.kubernetes.io/controller-managed-attach-detach: true
|
||||
CreationTimestamp: Thu, 17 Feb 2022 16:46:30 -0500
|
||||
Taints: node.kubernetes.io/unreachable:NoExecute
|
||||
node.kubernetes.io/unreachable:NoSchedule
|
||||
Unschedulable: false
|
||||
Lease:
|
||||
HolderIdentity: kube-worker-1
|
||||
AcquireTime: <unset>
|
||||
RenewTime: Thu, 17 Feb 2022 17:13:09 -0500
|
||||
Conditions:
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
---- ------ ----------------- ------------------ ------ -------
|
||||
OutOfDisk Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
MemoryPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
DiskPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Ready Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Addresses: 10.240.115.55,104.197.0.26
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
---- ------ ----------------- ------------------ ------ -------
|
||||
NetworkUnavailable False Thu, 17 Feb 2022 17:09:13 -0500 Thu, 17 Feb 2022 17:09:13 -0500 WeaveIsUp Weave pod has set this
|
||||
MemoryPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
DiskPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
PIDPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Ready Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Addresses:
|
||||
InternalIP: 192.168.0.113
|
||||
Hostname: kube-worker-1
|
||||
Capacity:
|
||||
cpu: 2
|
||||
hugePages: 0
|
||||
memory: 4046788Ki
|
||||
pods: 110
|
||||
cpu: 2
|
||||
ephemeral-storage: 15372232Ki
|
||||
hugepages-2Mi: 0
|
||||
memory: 2025188Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
cpu: 1500m
|
||||
hugePages: 0
|
||||
memory: 1479263Ki
|
||||
pods: 110
|
||||
cpu: 2
|
||||
ephemeral-storage: 14167048988
|
||||
hugepages-2Mi: 0
|
||||
memory: 1922788Ki
|
||||
pods: 110
|
||||
System Info:
|
||||
Machine ID: 8e025a21a4254e11b028584d9d8b12c4
|
||||
System UUID: 349075D1-D169-4F25-9F2A-E886850C47E3
|
||||
Boot ID: 5cd18b37-c5bd-4658-94e0-e436d3f110e0
|
||||
Kernel Version: 4.4.0-31-generic
|
||||
OS Image: Debian GNU/Linux 8 (jessie)
|
||||
Operating System: linux
|
||||
Architecture: amd64
|
||||
Container Runtime Version: docker://1.12.5
|
||||
Kubelet Version: v1.6.9+a3d1dfa6f4335
|
||||
Kube-Proxy Version: v1.6.9+a3d1dfa6f4335
|
||||
ExternalID: 15233045891481496305
|
||||
Non-terminated Pods: (9 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
--------- ---- ------------ ---------- --------------- -------------
|
||||
......
|
||||
Machine ID: 9384e2927f544209b5d7b67474bbf92b
|
||||
System UUID: aa829ca9-73d7-064d-9019-df07404ad448
|
||||
Boot ID: 5a295a03-aaca-4340-af20-1327fa5dab5c
|
||||
Kernel Version: 5.13.0-28-generic
|
||||
OS Image: Ubuntu 21.10
|
||||
Operating System: linux
|
||||
Architecture: amd64
|
||||
Container Runtime Version: containerd://1.5.9
|
||||
Kubelet Version: v1.23.3
|
||||
Kube-Proxy Version: v1.23.3
|
||||
Non-terminated Pods: (4 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
|
||||
--------- ---- ------------ ---------- --------------- ------------- ---
|
||||
default nginx-deployment-67d4bdd6f5-cx2nz 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
|
||||
default nginx-deployment-67d4bdd6f5-w6kd7 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
|
||||
kube-system kube-proxy-dnxbz 0 (0%) 0 (0%) 0 (0%) 0 (0%) 28m
|
||||
kube-system weave-net-gjxxp 100m (5%) 0 (0%) 200Mi (10%) 0 (0%) 28m
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
------------ ---------- --------------- -------------
|
||||
900m (60%) 2200m (146%) 1009286400 (66%) 5681286400 (375%)
|
||||
Events: <none>
|
||||
Resource Requests Limits
|
||||
-------- -------- ------
|
||||
cpu 1100m (55%) 1 (50%)
|
||||
memory 456Mi (24%) 256Mi (13%)
|
||||
ephemeral-storage 0 (0%) 0 (0%)
|
||||
hugepages-2Mi 0 (0%) 0 (0%)
|
||||
Events:
|
||||
...
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl get node kubernetes-node-861h -o yaml
|
||||
kubectl get node kube-worker-1 -o yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Node
|
||||
metadata:
|
||||
creationTimestamp: 2015-07-10T21:32:29Z
|
||||
annotations:
|
||||
kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
|
||||
node.alpha.kubernetes.io/ttl: "0"
|
||||
volumes.kubernetes.io/controller-managed-attach-detach: "true"
|
||||
creationTimestamp: "2022-02-17T21:46:30Z"
|
||||
labels:
|
||||
kubernetes.io/hostname: kubernetes-node-861h
|
||||
name: kubernetes-node-861h
|
||||
resourceVersion: "757"
|
||||
uid: 2a69374e-274b-11e5-a234-42010af0d969
|
||||
spec:
|
||||
externalID: "15233045891481496305"
|
||||
podCIDR: 10.244.0.0/24
|
||||
providerID: gce://striped-torus-760/us-central1-b/kubernetes-node-861h
|
||||
beta.kubernetes.io/arch: amd64
|
||||
beta.kubernetes.io/os: linux
|
||||
kubernetes.io/arch: amd64
|
||||
kubernetes.io/hostname: kube-worker-1
|
||||
kubernetes.io/os: linux
|
||||
name: kube-worker-1
|
||||
resourceVersion: "4026"
|
||||
uid: 98efe7cb-2978-4a0b-842a-1a7bf12c05f8
|
||||
spec: {}
|
||||
status:
|
||||
addresses:
|
||||
- address: 10.240.115.55
|
||||
- address: 192.168.0.113
|
||||
type: InternalIP
|
||||
- address: 104.197.0.26
|
||||
type: ExternalIP
|
||||
- address: kube-worker-1
|
||||
type: Hostname
|
||||
allocatable:
|
||||
cpu: "2"
|
||||
ephemeral-storage: "14167048988"
|
||||
hugepages-2Mi: "0"
|
||||
memory: 1922788Ki
|
||||
pods: "110"
|
||||
capacity:
|
||||
cpu: "1"
|
||||
memory: 3800808Ki
|
||||
pods: "100"
|
||||
cpu: "2"
|
||||
ephemeral-storage: 15372232Ki
|
||||
hugepages-2Mi: "0"
|
||||
memory: 2025188Ki
|
||||
pods: "110"
|
||||
conditions:
|
||||
- lastHeartbeatTime: 2015-07-10T21:34:32Z
|
||||
lastTransitionTime: 2015-07-10T21:35:15Z
|
||||
reason: Kubelet stopped posting node status.
|
||||
status: Unknown
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:32Z"
|
||||
lastTransitionTime: "2022-02-17T22:20:32Z"
|
||||
message: Weave pod has set this
|
||||
reason: WeaveIsUp
|
||||
status: "False"
|
||||
type: NetworkUnavailable
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has sufficient memory available
|
||||
reason: KubeletHasSufficientMemory
|
||||
status: "False"
|
||||
type: MemoryPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has no disk pressure
|
||||
reason: KubeletHasNoDiskPressure
|
||||
status: "False"
|
||||
type: DiskPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has sufficient PID available
|
||||
reason: KubeletHasSufficientPID
|
||||
status: "False"
|
||||
type: PIDPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:15:15Z"
|
||||
message: kubelet is posting ready status. AppArmor enabled
|
||||
reason: KubeletReady
|
||||
status: "True"
|
||||
type: Ready
|
||||
daemonEndpoints:
|
||||
kubeletEndpoint:
|
||||
Port: 10250
|
||||
nodeInfo:
|
||||
bootID: 4e316776-b40d-4f78-a4ea-ab0d73390897
|
||||
containerRuntimeVersion: docker://Unknown
|
||||
kernelVersion: 3.16.0-0.bpo.4-amd64
|
||||
kubeProxyVersion: v0.21.1-185-gffc5a86098dc01
|
||||
kubeletVersion: v0.21.1-185-gffc5a86098dc01
|
||||
machineID: ""
|
||||
osImage: Debian GNU/Linux 7 (wheezy)
|
||||
systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E
|
||||
architecture: amd64
|
||||
bootID: 22333234-7a6b-44d4-9ce1-67e31dc7e369
|
||||
containerRuntimeVersion: containerd://1.5.9
|
||||
kernelVersion: 5.13.0-28-generic
|
||||
kubeProxyVersion: v1.23.3
|
||||
kubeletVersion: v1.23.3
|
||||
machineID: 9384e2927f544209b5d7b67474bbf92b
|
||||
operatingSystem: linux
|
||||
osImage: Ubuntu 21.10
|
||||
systemUUID: aa829ca9-73d7-064d-9019-df07404ad448
|
||||
```
|
||||
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,12 @@ only the termination message:
|
||||
|
||||
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
|
||||
|
||||
If you are running a multi-container pod, you can use a Go template to include the container's name. By doing so, you can discover which of the containers is failing:
|
||||
|
||||
```shell
|
||||
kubectl get pod multi-container-pod -o go-template='{{range .status.containerStatuses}}{{printf "%s:\n%s\n\n" .name .lastState.terminated.message}}{{end}}'
|
||||
```
|
||||
|
||||
## Customizing the termination message
|
||||
|
||||
Kubernetes retrieves termination messages from the termination message file
|
||||
|
||||
@@ -101,7 +101,7 @@ If filing a bug, please include detailed information about how to reproduce the
|
||||
problem, such as:
|
||||
|
||||
* Kubernetes version: `kubectl version`
|
||||
* Cloud provider, OS distro, network configuration, and Docker version
|
||||
* Cloud provider, OS distro, network configuration, and container runtime version
|
||||
* Steps to reproduce the problem
|
||||
|
||||
|
||||
|
||||
@@ -152,4 +152,5 @@ Some example values of `matchImages` patterns are:
|
||||
|
||||
* Read the details about `CredentialProviderConfig` in the
|
||||
[kubelet configuration API (v1alpha1) reference](/docs/reference/config-api/kubelet-config.v1alpha1/).
|
||||
* Read the [kubelet credential provider API reference (v1alpha1)](/docs/reference/config-api/kubelet-credentialprovider.v1alpha1/).
|
||||
|
||||
|
||||
@@ -95,6 +95,11 @@ For example, to download version {{< param "fullversion" >}} on Linux, type:
|
||||
```bash
|
||||
kubectl version --client
|
||||
```
|
||||
Or use this for detailed view of version:
|
||||
|
||||
```cmd
|
||||
kubectl version --client --output=yaml
|
||||
```
|
||||
|
||||
### Install using native package management
|
||||
|
||||
|
||||
@@ -111,6 +111,11 @@ The following methods exist for installing kubectl on macOS:
|
||||
```bash
|
||||
kubectl version --client
|
||||
```
|
||||
Or use this for detailed view of version:
|
||||
|
||||
```cmd
|
||||
kubectl version --client --output=yaml
|
||||
```
|
||||
|
||||
### Install with Homebrew on macOS
|
||||
|
||||
|
||||
@@ -66,6 +66,11 @@ The following methods exist for installing kubectl on Windows:
|
||||
```cmd
|
||||
kubectl version --client
|
||||
```
|
||||
Or use this for detailed view of version:
|
||||
|
||||
```cmd
|
||||
kubectl version --client --output=yaml
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
[Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/#kubernetes) adds its own version of `kubectl` to `PATH`.
|
||||
|
||||
Reference in New Issue
Block a user