mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-hardeni
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# Exposing Services in Kubernetes
|
||||
# 在 Kubernetes 中暴露 Services
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
在 Kubernetes 中有 **different ways to expose services**,这样 **internal** 端点和 **external** 端点都可以访问它们。这个 Kubernetes 配置非常关键,因为管理员可能会让 **attackers** 访问他们本不该访问的服务。
|
||||
在 Kubernetes 中有 **不同的方式来暴露 services**,这样 **internal** endpoints 和 **external** endpoints 都可以访问它们。这个 Kubernetes 配置非常关键,因为管理员可能会让 **attackers 访问他们本不该访问的 services**。
|
||||
|
||||
### Automatic Enumeration
|
||||
|
||||
在开始枚举 K8s 提供的对外暴露 services 的方式之前,要知道如果你可以列出 namespaces、services 和 ingresses,你就可以用以下方式找到所有对外暴露的内容:
|
||||
在开始枚举 K8s 提供的将 services 暴露给 public 的各种方式之前,要知道如果你可以列出 namespaces、services 和 ingresses,你就可以通过以下方式找到所有暴露到 public 的内容:
|
||||
```bash
|
||||
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
|
||||
echo "Namespace: $ns"
|
||||
@@ -20,13 +20,13 @@ done | grep -v "ClusterIP"
|
||||
```
|
||||
### ClusterIP
|
||||
|
||||
**ClusterIP** service 是 Kubernetes 的 **默认** **service**。它会在你的 cluster 内部提供一个 **service inside**,供 cluster 内的其他 app 访问。**没有外部访问**。
|
||||
**ClusterIP** service 是 Kubernetes 的 **default** **service**。它会在你的 cluster 内提供一个 **service inside**,供 cluster 内的其他 app 访问。**没有 external access**。
|
||||
|
||||
但是,这可以通过 Kubernetes Proxy 访问:
|
||||
However, this can be accessed using the Kubernetes Proxy:
|
||||
```bash
|
||||
kubectl proxy --port=8080
|
||||
```
|
||||
现在,你可以通过 Kubernetes API 导航,以使用这个方案访问 services:
|
||||
现在,你可以通过 Kubernetes API 按照这个方案访问 services:
|
||||
|
||||
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
|
||||
|
||||
@@ -50,7 +50,7 @@ port: 80
|
||||
targetPort: 80
|
||||
protocol: TCP
|
||||
```
|
||||
_此方法要求你以**已认证用户**身份运行 `kubectl`。_
|
||||
_这种方法需要你以 **authenticated user** 身份运行 `kubectl`。_
|
||||
|
||||
列出所有 ClusterIPs:
|
||||
```bash
|
||||
@@ -58,7 +58,7 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
|
||||
```
|
||||
### NodePort
|
||||
|
||||
当使用 **NodePort** 时,会在所有 Nodes(代表 Virtual Machines)上开放一个指定的端口。随后,指向这个特定端口的 **Traffic** 会被系统性地**路由到 service**。通常不推荐使用这种方法,因为它有一些缺点。
|
||||
当使用 **NodePort** 时,会在所有 Nodes(代表 Virtual Machines)上开放一个指定端口。指向这个特定端口的 **Traffic** 随后会被系统地**路由到 service**。通常,由于其缺点,不推荐使用这种方法。
|
||||
|
||||
列出所有 NodePorts:
|
||||
```bash
|
||||
@@ -81,13 +81,24 @@ targetPort: 80
|
||||
nodePort: 30036
|
||||
protocol: TCP
|
||||
```
|
||||
如果你在 yaml 中**不指定** **nodePort**(它是将被打开的端口),则会使用 **30000–32767 范围内的端口**。
|
||||
如果你**不指定** yaml 中的 **nodePort**(它就是将被开放的端口),将使用 **30000–32767 范围内的端口**。
|
||||
|
||||
在审查 NodePort 或 LoadBalancer Services 时,也要检查 traffic-policy 字段,因为它们会改变从给定来源可用的节点和后端:
|
||||
```bash
|
||||
kubectl get services --all-namespaces \
|
||||
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
|
||||
```
|
||||
- `externalTrafficPolicy: Local` 保留原始客户端源 IP 用于 NodePort/LoadBalancer 流量,并避免转发到其他节点上的 endpoints。没有本地 ready endpoint 的节点即使 Service 在别处有 endpoints,也可能会丢弃流量。
|
||||
- `externalTrafficPolicy: Cluster` 是默认值,可以通过任意节点转发,但后端日志里可能看到的是节点 IP,而不是真实的外部客户端 IP。
|
||||
- `internalTrafficPolicy: Local` 将集群内的 Service 流量限制到源节点本地的 endpoints。这是 locality routing,不是授权边界。
|
||||
- `sessionAffinity: ClientIP` 可以让同一个客户端的重复测试命中同一个 backend,在手动检查时隐藏其他 ready endpoints。
|
||||
- `trafficDistribution` 和 EndpointSlice topology hints 在较新的集群上可以优先选择同 zone 或同 node 的 endpoints;应将它们视为路由偏好,而不是严格的安全策略。
|
||||
|
||||
### LoadBalancer
|
||||
|
||||
使用云 provider 的 load balancer 将 Service 暴露到外部。在 GKE 上,这会启动一个 [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/),它会给你一个单一 IP 地址,并将所有 traffic 转发到你的 service。在 AWS 中,它会启动一个 Load Balancer。
|
||||
使用 **cloud provider 的 load balancer** 将 Service 暴露到外部。在 GKE 上,这会启动一个 [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/),为你提供一个单独的 IP 地址,并将所有流量转发到你的 service。在 AWS 中,它会启动一个 Load Balancer。
|
||||
|
||||
你必须为每个暴露的 service 支付一个 LoadBalancer 费用,这可能会很贵。
|
||||
每个暴露的 service 都需要为一个 LoadBalancer 付费,这可能很昂贵。
|
||||
|
||||
列出所有 LoadBalancers:
|
||||
```bash
|
||||
@@ -100,11 +111,11 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
|
||||
>
|
||||
> For finding them, check for load balancers with values in the `EXTERNAL-IP` field.
|
||||
|
||||
当流入集群的流量以 **external IP** 作为 **destination IP**,并且目标端口是 Service port 时,会被 **routed to one of the Service endpoints**。`externalIPs` 不由 Kubernetes 管理,而是由集群管理员负责。
|
||||
Traffic that ingresses into the cluster with the **external IP** (as **destination IP**), on the Service port, will be **routed to one of the Service endpoints**. `externalIPs` are not managed by Kubernetes and are the responsibility of the cluster administrator.
|
||||
|
||||
`externalIPs` 是一个敏感的 route-control 字段,因为如果周围网络把该 IP 路由到集群,那么能够设置它的用户可能会为一个 Service owner 不应控制的 IP address 争取流量。Kubernetes 已宣布在 v1.36 中弃用并计划移除 Service `externalIPs`,因此应尽可能优先使用由 controller 管理的暴露机制,例如 LoadBalancer integrations 或 Gateway API,并在它仍然存在时谨慎地 restrict/admit 该字段。
|
||||
`externalIPs` is a sensitive route-control field because a user who can set it might claim traffic for an IP address the Service owner should not control if the surrounding network routes that IP to the cluster. Kubernetes announced the deprecation and planned removal of Service `externalIPs` in v1.36, so prefer controller-owned exposure mechanisms such as LoadBalancer integrations or Gateway API where possible, and restrict/admit this field carefully while it still exists.
|
||||
|
||||
在 Service spec 中,`externalIPs` 可以与任意 `ServiceTypes` 一起指定。在下面的示例中,`"my-service"` 可以被客户端通过 `"80.11.12.10:80"` (`externalIP:port`) 访问
|
||||
In the Service spec, `externalIPs` can be specified along with any of the `ServiceTypes`. In the example below, "`my-service`" can be accessed by clients on "`80.11.12.10:80`" (`externalIP:port`)
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -123,9 +134,9 @@ externalIPs:
|
||||
```
|
||||
### ExternalName
|
||||
|
||||
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) type 为 ExternalName 的 Services **map 一个 Service 到一个 DNS name**,而不是像 `my-service` 或 `cassandra` 这样的典型 selector。你可以使用 `spec.externalName` 参数来指定这些 Services。
|
||||
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services of type ExternalName **map a Service to a DNS name**, not to a typical selector such as `my-service` or `cassandra`. You specify these Services with the `spec.externalName` parameter.
|
||||
|
||||
例如,这个 Service 定义将 `prod` namespace 中的 `my-service` Service map 到 `my.database.example.com`:
|
||||
This Service definition, for example, maps the `my-service` Service in the `prod` namespace to `my.database.example.com`:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -136,15 +147,15 @@ spec:
|
||||
type: ExternalName
|
||||
externalName: my.database.example.com
|
||||
```
|
||||
在查找主机 `my-service.prod.svc.cluster.local` 时,cluster DNS Service 会返回一个值为 `my.database.example.com` 的 `CNAME` 记录。访问 `my-service` 的方式与其他 Services 相同,但关键区别在于**重定向发生在 DNS 层**,而不是通过代理或转发。
|
||||
当查询主机 `my-service.prod.svc.cluster.local` 时,cluster DNS Service 会返回一个值为 `my.database.example.com` 的 `CNAME` 记录。访问 `my-service` 的方式与其他 Service 相同,但关键区别在于**重定向发生在 DNS 层**,而不是通过 proxying 或 forwarding。
|
||||
|
||||
列出所有 ExternalNames:
|
||||
列出所有 ExternalNames:
|
||||
```bash
|
||||
kubectl get services --all-namespaces | grep ExternalName
|
||||
```
|
||||
### EndpointSlices
|
||||
|
||||
EndpointSlices 显示 Service 当前路由到的具体 backend 地址和 ports。当 Service 没有 selector、labels 不能说明 traffic path,或者只有部分 backends 已就绪时,它们尤其有用。
|
||||
EndpointSlices 显示 Service 当前路由到的具体 backend 地址和端口。当 Service 没有 selector、labels 无法说明 traffic path,或者只有部分 backend 已 ready 时,它们尤其有用。
|
||||
|
||||
列出与 Services 关联的 EndpointSlices:
|
||||
```bash
|
||||
@@ -153,17 +164,17 @@ kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-
|
||||
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
|
||||
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
|
||||
```
|
||||
审查暴露情况时,将 Service selector 与 EndpointSlice 的 `targetRef`、endpoint addresses、readiness conditions 和 ports 进行比较。一个 selectorless Service 可以与手动管理的 EndpointSlices 配对,并将流量路由到非-Pod 或意外的目标。
|
||||
在审查暴露面时,将 Service selector 与 EndpointSlice 的 `targetRef`、endpoint addresses、readiness conditions 和 ports 进行对比。一个没有 selector 的 Service 可以与手动管理的 EndpointSlices 配对,并将流量路由到非 Pod 或意外的目标。
|
||||
|
||||
### Ingress
|
||||
|
||||
不同于上面所有示例,**Ingress 不是一种 service**。相反,它位于**多个 services 前面,并作为集群的“smart router”**或入口点。
|
||||
不同于上面的所有示例,**Ingress 不是一种 service**。相反,它位于多个 services **前面,并充当“smart router”** 或进入你 cluster 的入口点。
|
||||
|
||||
你可以用 Ingress 做很多不同的事情,而且**有许多类型的 Ingress controllers,且它们具有不同的 capabilities**。
|
||||
你可以用 Ingress 做很多不同的事情,而且有**许多类型的 Ingress controllers,它们具有不同的能力**。
|
||||
|
||||
默认的 GKE ingress controller 会为你启动一个 [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)。这将允许你同时进行基于 path 和基于 subdomain 的路由到 backend services。例如,你可以把 foo.yourdomain.com 上的所有流量发送到 foo service,并把 yourdomain.com/bar/ path 下的所有流量发送到 bar service。
|
||||
默认的 GKE ingress controller 会为你启动一个 [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)。这将允许你同时进行基于 path 和基于 subdomain 的路由到 backend services。例如,你可以将 foo.yourdomain.com 上的所有请求发送到 foo service,并将 yourdomain.com/bar/ path 下的所有请求发送到 bar service。
|
||||
|
||||
GKE 上带有 [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) 的 Ingress object 的 YAML 可能如下所示:
|
||||
GKE 上一个带有 [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) 的 Ingress object 的 YAML 可能看起来像这样:
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
@@ -197,17 +208,17 @@ name: bar
|
||||
port:
|
||||
number: 8080
|
||||
```
|
||||
列出所有 ingresses:
|
||||
列出所有 ingress:
|
||||
```bash
|
||||
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
|
||||
```
|
||||
尽管在这种情况下,更好的是逐个获取每一个的信息,以便更好地阅读:
|
||||
尽管在这种情况下,最好逐个获取每个信息,以便更好地阅读:
|
||||
```bash
|
||||
kubectl get ingresses --all-namespaces -o=yaml
|
||||
```
|
||||
### Gateway API
|
||||
|
||||
Gateway API 是用于暴露 Services 的更新版 Kubernetes API。它将基础设施所有的 Gateway objects 与应用所有的 Route objects(例如 HTTPRoute)分离开来。这对于 delegation 很有用,但也意味着 exposure 可以跨 namespaces 分散。
|
||||
Gateway API 是用于暴露 Services 的较新的 Kubernetes API。它将基础设施拥有的 Gateway 对象与应用拥有的 Route 对象(如 HTTPRoute)分离开来。这对于 delegation 很有用,但也意味着 exposure 可以跨 namespace 拆分。
|
||||
|
||||
列出 Gateway API exposure objects:
|
||||
```bash
|
||||
@@ -217,13 +228,16 @@ kubectl get httproutes --all-namespaces
|
||||
kubectl get gateway -n <namespace> <gateway-name> -o yaml
|
||||
kubectl get httproute -n <namespace> <route-name> -o yaml
|
||||
```
|
||||
检查 Gateway listeners、allowed route namespaces、Route `parentRefs`、hostnames、filters、backend references,以及状态条件,例如该 route 是否已被 accepted。一个被共享 Gateway accepted 的 Route 即使没有 legacy Ingress 对象,也可以暴露一个 backend。
|
||||
检查 Gateway listeners、allowed route namespaces、Route `parentRefs`、hostnames、filters、backend references,以及状态条件,例如 route 是否被 accepted。即使不存在 legacy Ingress 对象,被 shared Gateway accepted 的 Route 也可以暴露后端服务。
|
||||
|
||||
### References
|
||||
|
||||
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
|
||||
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
|
||||
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
|
||||
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
|
||||
|
||||
|
||||
@@ -2,63 +2,65 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
**本页的原作者是** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **(阅读他的原帖** [**here**](https://sickrov.github.io)**)**
|
||||
**The original author of this page is** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **(read his original post** [**here**](https://sickrov.github.io)**)**
|
||||
|
||||
## Architecture & Basics
|
||||
|
||||
### What does Kubernetes do?
|
||||
|
||||
- 允许在 container engine 中运行 container/s。
|
||||
- schedule 允许 containers mission efficient。
|
||||
- 保持 containers 存活。
|
||||
- 允许 container communications。
|
||||
- 允许 deployment techniques。
|
||||
- 处理信息 volumes。
|
||||
- Allows running container/s in a container engine.
|
||||
- Schedule allows containers mission efficient.
|
||||
- Keep containers alive.
|
||||
- Allows container communications.
|
||||
- Allows deployment techniques.
|
||||
- Handle volumes of information.
|
||||
|
||||
### Architecture
|
||||
|
||||

|
||||
|
||||
- **Node**: 带有 pod 或 pods 的 operating system。
|
||||
- **Pod**: container 或多个 containers 的外层包装。一个 pod 应该只包含一个 application(所以通常,一个 pod 只运行 1 个 container)。pod 是 kubernetes 抽象 container technology 并运行它的方式。
|
||||
- **Service**: 每个 pod 都有来自节点内部范围的 1 个内部 **IP address**。不过,也可以通过 service 暴露它。**service 也有一个 IP address**,其目标是维持 pods 之间的通信,因此如果其中一个死掉,**新的替换实例**(具有不同的内部 IP)**仍然可以通过 service 的相同 IP 被访问**。它可以配置为 internal 或 external。service 还会在 **2 个 pods 连接到同一个 service** 时充当 **load balancer**。\
|
||||
当 **service** 被 **created** 时,你可以通过运行 `kubectl get endpoints` 查看每个 service 的 endpoints
|
||||
- **Kubelet**: 主节点代理。负责在 node 和 kubectl 之间建立通信的组件,并且只能运行 pods(通过 API server)。kubelet 不管理不是由 Kubernetes 创建的 containers。
|
||||
- **Kube-proxy**: 负责 apiserver 和 node 之间通信(services)的服务。基础是 node 的 IPtables。更有经验的用户可以安装来自其他厂商的其他 kube-proxies。
|
||||
- **Sidecar container**: Sidecar containers 是应该与 pod 中主 container 一起运行的 containers。这个 sidecar pattern 在不修改现有 containers 的情况下扩展并增强其功能。如今,我们知道会使用 container technology 来封装 application 运行所需的全部依赖,使其可以在任何地方运行。一个 container 只做一件事,并把这件事做好。
|
||||
- **Node**: operating system with pod or pods.
|
||||
- **Pod**: Wrapper around a container or multiple containers with. A pod should only contain one application (so usually, a pod run just 1 container). The pod is the way kubernetes abstracts the container technology running.
|
||||
- **Service**: Each pod has 1 internal **IP address** from the internal range of the node. However, it can be also exposed via a service. The **service has also an IP address** and its goal is to maintain the communication between pods so if one dies the **new replacement** (with a different internal IP) **will be accessible** exposed in the **same IP of the service**. It can be configured as internal or external. The service also actuates as a **load balancer when 2 pods are connected** to the same service.\
|
||||
When a **service** is **created** you can find the endpoints of each service running `kubectl get endpoints`
|
||||
- **Kubelet**: Primary node agent. The component that establishes communication between node and kubectl, and only can run pods (through API server). The kubelet doesn’t manage containers that were not created by Kubernetes.
|
||||
- **Kube-proxy**: is the service in charge of the communications (services) between the apiserver and the node. The base is an IPtables for nodes. Most experienced users could install other kube-proxies from other vendors.
|
||||
- **Sidecar container**: Sidecar containers are the containers that should run along with the main container in the pod. This sidecar pattern extends and enhances the functionality of current containers without changing them. Nowadays, We know that we use container technology to wrap all the dependencies for the application to run anywhere. A container does only one thing and does that thing very well.
|
||||
- **Master process:**
|
||||
- **Api Server:** 是 users 和 pods 用来与 master process 通信的方式。只应允许经过认证的请求。
|
||||
- **Scheduler**: Scheduling 指的是确保 Pods 被匹配到 Nodes,从而让 Kubelet 可以运行它们。它足够智能,能够决定哪个 node 拥有更多可用资源,并将新的 pod 分配给它。注意,scheduler 不会启动新的 pods,它只是与运行在 node 内部的 Kubelet process 通信,由后者启动新的 pod。
|
||||
- **Kube Controller manager**: 它检查 replica sets 或 deployments 等资源,以确认例如正确数量的 pods 或 nodes 是否正在运行。如果某个 pod 缺失,它会与 scheduler 通信以启动一个新的。它控制 replication、tokens 以及 account services 到 API。
|
||||
- **etcd**: 数据存储,持久、consistent、distributed。它是 Kubernetes 的 database 和 key-value storage,用来保存集群的完整状态(每次变更都会记录在这里)。Scheduler 或 Controller manager 等组件依赖这个 date 来知道发生了哪些变化(节点的可用 resourced、正在运行的 pods 数量……)。
|
||||
- **Cloud controller manager**: 针对 flow controls 和 applications 的特定 controller,例如:如果你在 AWS 或 OpenStack 上有 clusters。
|
||||
- **Api Server:** Is the way the users and the pods use to communicate with the master process. Only authenticated request should be allowed.
|
||||
- **Scheduler**: Scheduling refers to making sure that Pods are matched to Nodes so that Kubelet can run them. It has enough intelligence to decide which node has more available resources the assign the new pod to it. Note that the scheduler doesn't start new pods, it just communicate with the Kubelet process running inside the node, which will launch the new pod.
|
||||
- **Kube Controller manager**: It checks resources like replica sets or deployments to check if, for example, the correct number of pods or nodes are running. In case a pod is missing, it will communicate with the scheduler to start a new one. It controls replication, tokens, and account services to the API.
|
||||
- **etcd**: Data storage, persistent, consistent, and distributed. Is Kubernetes’s database and the key-value storage where it keeps the complete state of the clusters (each change is logged here). Components like the Scheduler or the Controller manager depends on this date to know which changes have occurred (available resourced of the nodes, number of pods running...)
|
||||
- **Cloud controller manager**: Is the specific controller for flow controls and applications, i.e: if you have clusters in AWS or OpenStack.
|
||||
|
||||
注意,可能会有多个 nodes(运行多个 pods),也可能会有多个 master processes,它们对 Api server 的访问是 load balanced 的,而它们的 etcd 是 synchronized 的。
|
||||
Note that as the might be several nodes (running several pods), there might also be several master processes which their access to the Api server load balanced and their etcd synchronized.
|
||||
|
||||
**Volumes:**
|
||||
|
||||
当一个 pod 创建了不应在 pod 消失后丢失的数据时,这些数据应存储在物理 volume 中。**Kubernetes allow to attach a volume to a pod to persist the data**。volume 可以位于本地机器或 **remote storage** 中。如果你在不同的 physical nodes 上运行 pods,应该使用 remote storage,这样所有 pods 都可以访问它。
|
||||
When a pod creates data that shouldn't be lost when the pod disappear it should be stored in a physical volume. **Kubernetes allow to attach a volume to a pod to persist the data**. The volume can be in the local machine or in a **remote storage**. If you are running pods in different physical nodes you should use a remote storage so all the pods can access it.
|
||||
|
||||
Kubernetes also supports **image volumes** in recent versions. An `image` volume mounts an OCI image or artifact as a **read-only** filesystem source inside the Pod, using fields such as `volumes[].image.reference` and `volumes[].image.pullPolicy`. The kubelet pulls the artifact with the same credential sources used for container images, including node credentials, Pod `imagePullSecrets`, and ServiceAccount `imagePullSecrets`. During a security review, treat image volumes as runtime inputs and supply-chain dependencies: check whether the reference is pinned by digest, which registry credentials can fetch it, where it is mounted, and whether `subPath` limits the visible directory.
|
||||
|
||||
**Other configurations:**
|
||||
|
||||
- **ConfigMap**: 你可以配置用于访问 services 的 **URLs**。pod 会从这里获取数据,以知道如何与其余的 services (pods) 通信。注意,这不是保存 credentials 的推荐位置!
|
||||
- **Secret**: 这是 **store secret data** 的地方,比如 passwords、API keys... 以 B64 编码。pod 将能够访问这些数据,以使用所需的 credentials。
|
||||
- **Deployments**: 这里指定由 kubernetes 运行的 components。用户通常不会直接处理 pods,pods 被抽象为 **ReplicaSets**(相同 pods 的复制数量),它们通过 deployments 运行。注意,deployments 适用于 **stateless** applications。deployment 的最小配置是 name 和要运行的 image。
|
||||
- **StatefulSet**: 这个组件专门用于 **databases** 这类需要 **access the same storage** 的 applications。
|
||||
- **Ingress**: 这是用于 **expose the application publicly with an URL** 的配置。注意,这也可以通过 external services 完成,但这才是暴露 application 的正确方式。
|
||||
- 如果你实现了 Ingress,就需要创建 **Ingress Controllers**。Ingress Controller 是一个 **pod**,它将作为接收 requests 的 endpoint,进行检查并将其 load balance 到 services。ingress controller 会 **send the request based on the ingress rules configured**。注意,ingress rules 可以指向不同的 paths,甚至不同的 subdomains,对应到不同的内部 kubernetes services。
|
||||
- 更好的 security practice 是使用 cloud load balancer 或 proxy server 作为 entrypoint,这样就不会暴露 Kubernetes cluster 的任何部分。
|
||||
- 当收到不匹配任何 ingress rule 的 request 时,ingress controller 会将其转发到 "**Default backend**"。你可以 `describe` ingress controller 来获取这个参数的 address。
|
||||
- **ConfigMap**: You can configure **URLs** to access services. The pod will obtain data from here to know how to communicate with the rest of the services (pods). Note that this is not the recommended place to save credentials!
|
||||
- **Secret**: This is the place to **store secret data** like passwords, API keys... encoded in B64. The pod will be able to access this data to use the required credentials.
|
||||
- **Deployments**: This is where the components to be run by kubernetes are indicated. A user usually won't work directly with pods, pods are abstracted in **ReplicaSets** (number of same pods replicated), which are run via deployments. Note that deployments are for **stateless** applications. The minimum configuration for a deployment is the name and the image to run.
|
||||
- **StatefulSet**: This component is meant specifically for applications like **databases** which needs to **access the same storage**.
|
||||
- **Ingress**: This is the configuration that is use to **expose the application publicly with an URL**. Note that this can also be done using external services, but this is the correct way to expose the application.
|
||||
- If you implement an Ingress you will need to create **Ingress Controllers**. The Ingress Controller is a **pod** that will be the endpoint that will receive the requests and check and will load balance them to the services. the ingress controller will **send the request based on the ingress rules configured**. Note that the ingress rules can point to different paths or even subdomains to different internal kubernetes services.
|
||||
- A better security practice would be to use a cloud load balancer or a proxy server as entrypoint to don't have any part of the Kubernetes cluster exposed.
|
||||
- When request that doesn't match any ingress rule is received, the ingress controller will direct it to the "**Default backend**". You can `describe` the ingress controller to get the address of this parameter.
|
||||
- `minikube addons enable ingress`
|
||||
|
||||
### PKI infrastructure - Certificate Authority CA:
|
||||
|
||||

|
||||
|
||||
- CA 是 cluster 内所有 certificates 的 trusted root。
|
||||
- 允许 components 彼此验证。
|
||||
- 所有 cluster certificates 都由 CA 签名。
|
||||
- ETCd 有自己的 certificate。
|
||||
- CA is the trusted root for all certificates inside the cluster.
|
||||
- Allows components to validate to each other.
|
||||
- All cluster certificates are signed by the CA.
|
||||
- ETCd has its own certificate.
|
||||
- types:
|
||||
- apiserver cert.
|
||||
- kubelet cert.
|
||||
@@ -68,7 +70,7 @@
|
||||
|
||||
### Minikube
|
||||
|
||||
**Minikube** 可用于在 kubernetes 上进行一些 **quick tests**,而无需部署完整的 kubernetes environment。它会在 **one machine** 上运行 **master 和 node processes**。Minikube 会使用 virtualbox 来运行 node。安装方法见 [**here how to install it**](https://minikube.sigs.k8s.io/docs/start/)。
|
||||
**Minikube** can be used to perform some **quick tests** on kubernetes without needing to deploy a whole kubernetes environment. It will run the **master and node processes in one machine**. Minikube will use virtualbox to run the node. See [**here how to install it**](https://minikube.sigs.k8s.io/docs/start/).
|
||||
```
|
||||
$ minikube start
|
||||
😄 minikube v1.19.0 on Ubuntu 20.04
|
||||
@@ -103,9 +105,9 @@ $ minikube delete
|
||||
🔥 Deleting "minikube" in virtualbox ...
|
||||
💀 Removed all traces of the "minikube" cluster
|
||||
```
|
||||
### Kubectl 基础
|
||||
### Kubectl Basics
|
||||
|
||||
**`Kubectl`** 是 kubernetes clusters 的命令行工具。它与 master process 的 Api server 通信,以在 kubernetes 中执行操作或请求 data。
|
||||
**`Kubectl`** 是 kubernetes 集群的命令行工具。它与 master process 的 Api server 通信,以在 kubernetes 中执行操作或请求数据。
|
||||
```bash
|
||||
kubectl version #Get client and server version
|
||||
kubectl get pod
|
||||
@@ -138,7 +140,7 @@ kubectl apply -f deployment.yml
|
||||
```
|
||||
### Minikube Dashboard
|
||||
|
||||
dashboard 允许你更容易地查看 minikube 正在运行什么,你可以在这里找到访问它的 URL:
|
||||
dashboard 让你更容易查看 minikube 正在运行的内容,你可以在以下位置找到访问它的 URL:
|
||||
```
|
||||
minikube dashboard --url
|
||||
|
||||
@@ -153,12 +155,12 @@ http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kube
|
||||
```
|
||||
### YAML configuration files examples
|
||||
|
||||
Each configuration file has 3 parts: **metadata**, **specification** (what need to be launch), **status** (desired state).\
|
||||
在 deployment configuration file 的 specification 内,你可以找到 template,它定义了一个新的 configuration structure,用于指定要运行的 image:
|
||||
每个 configuration file 有 3 部分:**metadata**、**specification**(要启动什么)、**status**(desired state)。\
|
||||
在 deployment configuration file 的 specification 中,你可以找到用新的 configuration structure 定义的 template,其中定义了要运行的 image:
|
||||
|
||||
**Example of Deployment + Service declared in the same configuration file (from** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
|
||||
**在同一个 configuration file 中声明的 Deployment + Service 示例(来自** [**这里**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
|
||||
|
||||
由于一个 service 通常与一个 deployment 相关联,因此可以在同一个 configuration file 中同时声明两者(此 config 中声明的 service 只能在内部访问):
|
||||
由于 service 通常与一个 deployment 相关联,因此可以在同一个 configuration file 中同时声明两者(此 config 中声明的 service 只能在内部访问):
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -205,9 +207,9 @@ ports:
|
||||
port: 27017
|
||||
targetPort: 27017
|
||||
```
|
||||
**外部 service 配置示例**
|
||||
**外部服务配置示例**
|
||||
|
||||
该 service 将可从外部访问(检查 `nodePort` 和 `type: LoadBlancer` 属性):
|
||||
此服务将可从外部访问(检查 `nodePort` 和 `type: LoadBlancer` 属性):
|
||||
```yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
@@ -225,11 +227,11 @@ targetPort: 8081
|
||||
nodePort: 30000
|
||||
```
|
||||
> [!NOTE]
|
||||
> 这对测试很有用,但在生产环境中你应该只保留 internal services,并通过 Ingress 来暴露应用。
|
||||
> 这对测试很有用,但在生产环境中你应该只保留 internal services,并使用 Ingress 来暴露 application。
|
||||
|
||||
**Ingress config file 示例**
|
||||
**Example of Ingress config file**
|
||||
|
||||
这将把应用暴露在 `http://dashboard.com`。
|
||||
这会把 application 暴露在 `http://dashboard.com`。
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
@@ -245,9 +247,9 @@ paths:
|
||||
serviceName: kubernetes-dashboard
|
||||
servicePort: 80
|
||||
```
|
||||
**secrets config file 示例**
|
||||
**秘密 config file 示例**
|
||||
|
||||
注意 password 是如何用 B64 编码的(这并不 secure!)
|
||||
注意 password 是如何以 B64 编码的(这并不 secure!)
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -260,7 +262,7 @@ mongo-root-password: cGFzc3dvcmQ=
|
||||
```
|
||||
**ConfigMap 示例**
|
||||
|
||||
**ConfigMap** 是提供给 pods 的配置,让它们知道如何定位并访问其他 services。在这种情况下,每个 pod 都会知道名称 `mongodb-service` 是一个它们可以通信的 pod 的地址(这个 pod 将运行 mongodb):
|
||||
**ConfigMap** 是提供给 pods 的配置,这样它们就知道如何定位并访问其他 services。在这种情况下,每个 pod 都会知道名称 `mongodb-service` 是一个它们可以通信的 pod 的地址(这个 pod 将运行一个 mongodb):
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -269,7 +271,7 @@ name: mongodb-configmap
|
||||
data:
|
||||
database_url: mongodb-service
|
||||
```
|
||||
然后,在一个 **deployment config** 中,这个地址可以通过以下方式指定,这样它就会被加载到 pod 的 env 中:
|
||||
然后,在一个 **deployment config** 中,可以通过以下方式指定这个地址,使其加载到 pod 的 env 中:
|
||||
```yaml
|
||||
[...]
|
||||
spec:
|
||||
@@ -290,16 +292,16 @@ name: mongodb-configmap
|
||||
key: database_url
|
||||
[...]
|
||||
```
|
||||
**volume config 的示例**
|
||||
**Example of volume config**
|
||||
|
||||
你可以在 [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes) 中找到不同的 storage configuration yaml files 示例。\
|
||||
**请注意 volumes 不在 namespaces 内部**
|
||||
你可以在 [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes) 找到不同的 storage configuration yaml 文件示例。\
|
||||
**注意 volumes 不在 namespaces 里面**
|
||||
|
||||
### Namespaces
|
||||
|
||||
Kubernetes 支持由同一个 physical cluster 支撑的 **多个 virtual clusters**。这些 virtual clusters 被称为 **namespaces**。它们用于有许多用户分布在多个团队或项目的环境中。对于只有少量到几十个用户的 cluster,你通常完全不需要创建或考虑 namespaces。只有当你想更好地控制和组织 kubernetes 中部署的 application 的各个部分时,才应该开始使用 namespaces。
|
||||
Kubernetes 支持由同一个物理集群支持的 **multiple virtual clusters**。这些 virtual clusters 被称为 **namespaces**。它们用于有许多用户、分布在多个 teams 或 projects 的环境。对于只有几个到几十个用户的 cluster,你通常不需要创建或考虑 namespaces。你只有在想更好地控制和组织部署在 kubernetes 中的应用各部分时,才应该开始使用 namespaces。
|
||||
|
||||
Namespaces 为 names 提供了作用域。资源的名称在一个 namespace 内必须唯一,但不需要在不同 namespaces 之间唯一。Namespaces 不能相互嵌套,而且每个 Kubernetes **resource** 只能位于一个 namespace 中。
|
||||
Namespaces 为 names 提供作用域。资源的名称在一个 namespace 内必须唯一,但不需要在不同 namespaces 之间唯一。Namespaces 不能相互嵌套,并且 **each** Kubernetes **resource** 只能 **in** **one** **namespace**。
|
||||
|
||||
如果你使用 minikube,默认有 4 个 namespaces:
|
||||
```
|
||||
@@ -310,37 +312,37 @@ kube-node-lease Active 1d
|
||||
kube-public Active 1d
|
||||
kube-system Active 1d
|
||||
```
|
||||
- **kube-system**: 它不是给用户使用的,你不应该触碰它。它用于 master 和 kubectl processes。
|
||||
- **kube-public**: 公开可访问的数据。包含一个包含集群信息的 configmap
|
||||
- **kube-node-lease**: 确定一个 node 的可用性
|
||||
- **default**: 用户会用来创建资源的 namespace
|
||||
- **kube-system**: 它不是给用户使用的,你不应该碰它。它用于 master 和 kubectl 进程。
|
||||
- **kube-public**: 公开可访问的数据。包含一个 configmap,其中包含 cluster 信息
|
||||
- **kube-node-lease**: 用于确定一个 node 的可用性
|
||||
- **default**: 用户将用来创建资源的 namespace
|
||||
```bash
|
||||
#Create namespace
|
||||
kubectl create namespace my-namespace
|
||||
```
|
||||
> [!NOTE]
|
||||
> 请注意,大多数 Kubernetes 资源(例如 pods、services、replication controllers 等)都在某些 namespace 中。然而,其他资源,如 namespace resources 和低级资源,例如 nodes 和 persistenVolumes,不在 namespace 中。要查看哪些 Kubernetes resources 在 namespace 中,哪些不在 namespace 中:
|
||||
> 请注意,大多数 Kubernetes resources(例如 pods、services、replication controllers 等)都位于某些 namespaces 中。但是,其他 resources,比如 namespace resources 和低级 resources,如 nodes 和 persistenVolumes,不在 namespace 中。要查看哪些 Kubernetes resources 在 namespace 中,哪些不在:
|
||||
>
|
||||
> ```bash
|
||||
> kubectl api-resources --namespaced=true #In a namespace
|
||||
> kubectl api-resources --namespaced=false #Not in a namespace
|
||||
> ```
|
||||
|
||||
你可以为该 context 中后续的所有 kubectl commands 保存 namespace。
|
||||
你可以在该 context 中为后续所有 kubectl commands 保存 namespace。
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=<insert-namespace-name-here>
|
||||
```
|
||||
### Helm
|
||||
|
||||
Helm 是 Kubernetes 的 **package manager**。它允许将 YAML 文件打包并分发到 public 和 private repositories。这些 packages 被称为 **Helm Charts**。
|
||||
Helm 是 Kubernetes 的 **package manager**。它允许将 YAML 文件打包并分发到 public 和 private repositories 中。这些 package 被称为 **Helm Charts**。
|
||||
```
|
||||
helm search <keyword>
|
||||
```
|
||||
Helm 也是一个 template engine,它允许使用变量生成 config files:
|
||||
Helm 也是一个 template engine,允许使用 variables 生成 config files:
|
||||
|
||||
## Kubernetes secrets
|
||||
|
||||
A **Secret** 是一个 **contains sensitive data** 的对象,例如 password、token 或 key。这类信息否则可能会被放在 Pod specification 或 image 中。Users 可以创建 Secrets,system 也会创建 Secrets。一个 Secret object 的名称必须是有效的 **DNS subdomain name**。请参阅 [the official documentation](https://kubernetes.io/docs/concepts/configuration/secret/)。
|
||||
A **Secret** 是一个 **包含敏感数据** 的对象,例如 password、token 或 key。这类信息否则可能会放在 Pod specification 或 image 中。Users 可以创建 Secrets,system 也会创建 Secrets。Secret object 的 name 必须是有效的 **DNS subdomain name**。请查看这里 [the official documentation](https://kubernetes.io/docs/concepts/configuration/secret/)。
|
||||
|
||||
Secrets 可能包括:
|
||||
|
||||
@@ -364,13 +366,13 @@ Kubernetes 中有不同类型的 secrets
|
||||
| bootstrap.kubernetes.io/token | bootstrap token data |
|
||||
|
||||
> [!NOTE]
|
||||
> **The Opaque type is the default one, the typical key-value pair defined by users.**
|
||||
> **Opaque type 是默认类型,也就是用户定义的典型 key-value pair。**
|
||||
|
||||
**How secrets works:**
|
||||
|
||||

|
||||
|
||||
以下配置文件定义了一个名为 `mysecret` 的 **secret**,包含 2 个 key-value pairs:`username: YWRtaW4=` 和 `password: MWYyZDFlMmU2N2Rm`。它还定义了一个名为 `secretpod` 的 **pod**,该 pod 会将 `mysecret` 中定义的 `username` 和 `password` 暴露为 **environment variables** `SECRET_USERNAME` __ 和 __ `SECRET_PASSWOR`。它还会将 `mysecret` 中的 `username` secret **mount** 到路径 `/etc/foo/my-group/my-username`,权限为 `0640`。
|
||||
下面的 configuration file 定义了一个名为 `mysecret` 的 **secret**,包含 2 个 key-value pair:`username: YWRtaW4=` 和 `password: MWYyZDFlMmU2N2Rm`。它还定义了一个名为 `secretpod` 的 **pod**,该 pod 会将 `mysecret` 中定义的 `username` 和 `password` 暴露为 **environment variables** `SECRET_USERNAME` __ 和 __ `SECRET_PASSWOR`。它还会把 `mysecret` 中的 `username` secret **mount** 到路径 `/etc/foo/my-group/my-username`,权限为 `0640`。
|
||||
```yaml:secretpod.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -422,25 +424,25 @@ env | grep SECRET && cat /etc/foo/my-group/my-username && echo
|
||||
```
|
||||
### etcd 中的 Secrets <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
|
||||
|
||||
**etcd** 是一个一致且高可用的 **key-value store**,作为 Kubernetes 的底层存储,用于保存所有集群数据。让我们访问存储在 etcd 中的 secrets:
|
||||
**etcd** 是一个一致且高可用的 **key-value store**,作为 Kubernetes 的 backing store 用于存储所有集群数据。让我们访问存储在 etcd 中的 secrets:
|
||||
```bash
|
||||
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
|
||||
```
|
||||
你会看到 certs、keys 和 url’s 位于 FS 中。一旦你获取到它,就可以连接到 etcd。
|
||||
你会看到 certs、keys 和 url’s 位于 FS 中。一旦你获取到它们,你就能够连接到 etcd。
|
||||
```bash
|
||||
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health
|
||||
|
||||
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health
|
||||
```
|
||||
一旦你成功建立通信,你就能够获取这些 secrets:
|
||||
一旦你建立通信,就可以获取这些 secrets:
|
||||
```bash
|
||||
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>
|
||||
|
||||
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] get /registry/secrets/default/secret_02
|
||||
```
|
||||
**给 ETCD 添加 encryption**
|
||||
**为 ETCD 添加 encryption**
|
||||
|
||||
默认情况下,所有 secrets 都以**明文**存储在 etcd 中,除非你应用一层 encryption。以下示例基于 [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
|
||||
默认情况下,所有 secrets 都以**明文**存储在 etcd 中,除非你应用 encryption 层。以下示例基于 [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
|
||||
```yaml:encryption.yaml
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
@@ -454,7 +456,7 @@ keys:
|
||||
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
|
||||
- identity: {}
|
||||
```
|
||||
之后,你需要在 `kube-apiserver` 上设置 `--encryption-provider-config` 标志,使其指向已创建配置文件的位置。你可以修改 `/etc/kubernetes/manifest/kube-apiserver.yaml` 并添加以下行:
|
||||
之后,你需要在 `kube-apiserver` 上设置 `--encryption-provider-config` 标志,使其指向已创建的 config file 的位置。你可以修改 `/etc/kubernetes/manifest/kube-apiserver.yaml` 并添加以下行:
|
||||
```yaml
|
||||
containers:
|
||||
- command:
|
||||
@@ -476,7 +478,7 @@ name: etcd
|
||||
```
|
||||
**验证数据是否已加密**
|
||||
|
||||
数据在写入 etcd 时会被加密。重启 `kube-apiserver` 后,任何新创建或更新的 secret 在存储时都应该被加密。要进行检查,你可以使用 `etcdctl` 命令行程序来检索你的 secret 内容。
|
||||
数据在写入 etcd 时会被加密。重启 `kube-apiserver` 后,任何新创建或更新的 secret 在存储时都应被加密。要检查这一点,可以使用 `etcdctl` 命令行程序读取你的 secret 内容。
|
||||
|
||||
1. 在 `default` namespace 中创建一个名为 `secret1` 的新 secret:
|
||||
|
||||
@@ -490,8 +492,8 @@ kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
|
||||
|
||||
其中 `[...]` 必须是用于连接 etcd server 的额外参数。
|
||||
|
||||
3. 验证存储的 secret 以 `k8s:enc:aescbc:v1:` 为前缀,这表示 `aescbc` provider 已经对生成的数据进行了加密。
|
||||
4. 验证通过 API 读取时该 secret 能被正确解密:
|
||||
3. 验证存储的 secret 是否以 `k8s:enc:aescbc:v1:` 为前缀,这表示 `aescbc` provider 已对生成的数据进行了加密。
|
||||
4. 验证通过 API 获取时 secret 能被正确解密:
|
||||
|
||||
```
|
||||
kubectl describe secret secret1 -n default
|
||||
@@ -499,18 +501,18 @@ kubectl describe secret secret1 -n default
|
||||
|
||||
应当匹配 `mykey: bXlkYXRh`,mydata 已被编码,查看 [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret) 以完全解码该 secret。
|
||||
|
||||
**由于 secrets 是在写入时加密的,对 secret 执行更新会加密该内容:**
|
||||
**由于 secrets 在写入时会被加密,因此对 secret 执行更新也会对该内容进行加密:**
|
||||
```
|
||||
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
|
||||
```
|
||||
**最终提示:**
|
||||
**Final tips:**
|
||||
|
||||
- 尽量不要把 secrets 保存在 FS 中,改从其他地方获取。
|
||||
- 查看 [https://www.vaultproject.io/](https://www.vaultproject.io) 以为你的 secrets 增加更多保护。
|
||||
- Try not to keep secrets in the FS, get them from other places.
|
||||
- Check out [https://www.vaultproject.io/](https://www.vaultproject.io) for add more protection to your secrets.
|
||||
- [https://kubernetes.io/docs/concepts/configuration/secret/#risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks)
|
||||
- [https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm)
|
||||
|
||||
## 参考
|
||||
## References
|
||||
|
||||
{{#ref}}
|
||||
https://sickrov.github.io/
|
||||
@@ -520,4 +522,12 @@ https://sickrov.github.io/
|
||||
https://www.youtube.com/watch?v=X48VuDVv0do
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/concepts/storage/volumes/#image
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
+42
-36
@@ -4,81 +4,87 @@
|
||||
|
||||
## PodSecurityContext <a href="#podsecuritycontext-v1-core" id="podsecuritycontext-v1-core"></a>
|
||||
|
||||
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
|
||||
[**来自文档:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
|
||||
|
||||
在指定 Pod 的 security context 时,可以使用多个属性。从防御性安全角度看,你应考虑:
|
||||
在指定 Pod 的 security context 时,可以使用多个属性。从防御性安全角度来看,你应该考虑:
|
||||
|
||||
- 将 **runASNonRoot** 设为 **True**
|
||||
- 配置 **runAsUser**
|
||||
- 如果可能,考虑通过指定 **seLinuxOptions** 和 **seccompProfile** 来**限制** **permissions**
|
||||
- 不要通过 **runAsGroup** 和 **supplementaryGroups** 授予**特权** **group** 访问权限
|
||||
- 如果可能,考虑通过 **seLinuxOptions** 和 **seccompProfile** 来**限制** **permissions**
|
||||
- 不要通过 **runAsGroup** 和 **supplementaryGroups** 授予 **privilege** **group** 访问权限
|
||||
|
||||
| Parameter | Description |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>一个特殊的补充组,适用于 pod 中的<strong>所有 containers</strong>。某些 volume 类型允许 Kubelet 将该 volume 的<strong>所有权改为由 pod 拥有</strong>:<br>1. 所有者 GID 将是 FSGroup<br>2. setgid 位被设置(在 volume 中创建的新文件将归属于 FSGroup)<br>3. 权限位会与 rw-rw---- 做 OR 运算。如果未设置,Kubelet 不会修改任何 volume 的所有权和权限</p> |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>一个特殊的补充组,适用于 pod 中的<strong>所有 containers</strong>。某些 volume 类型允许 Kubelet 将该 volume 的<strong>所有权更改</strong>为由 pod 拥有:<br>1. 拥有的 GID 将是 FSGroup<br>2. 设置 setgid 位(在 volume 中创建的新文件将归属于 FSGroup)<br>3. 权限位与 rw-rw---- 进行 OR 运算。如果未设置,Kubelet 不会修改任何 volume 的所有权和权限</p> |
|
||||
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | 这定义了在 volume 暴露到 Pod 内部之前,**更改其所有权和权限**的行为。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | 用于运行容器进程 entrypoint 的 **GID**。如果未设置,则使用 runtime 默认值。也可以在 SecurityContext 中设置。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | 表示容器必须以非 root 用户运行。如果为 true,Kubelet 会在运行时验证镜像,确保它不会以 UID 0 (root) 运行;如果会,则启动容器失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | 用于运行容器进程 entrypoint 的 **UID**。如果未指定,默认使用镜像元数据中指定的用户。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | **应用于所有 containers 的 SELinux context**。如果未指定,container runtime 会为每个 container 分配一个随机的 SELinux context。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | 这个 pod 中 containers 使用的 **seccomp options**。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | 除了 container 的 primary GID 之外,还会应用到每个 container 运行的第一个进程上的**groups 列表**。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctls 保存了一个**用于 pod 的命名空间 sysctls** 列表。使用不受支持的 sysctls 的 Pod(由 container runtime 决定)可能会启动失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | 应用于所有 containers 的 Windows 特定设置。如果未指定,则会使用 container 的 SecurityContext 中的选项。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | 这定义了在 Pod 内部暴露之前,**更改 volume 的所有权和权限**的行为。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | 用于运行 container process entrypoint 的 **GID**。如果未设置,则使用 runtime 默认值。也可在 SecurityContext 中设置。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | 表示 container 必须以非 root 用户运行。如果为 true,Kubelet 将在运行时验证 image,确保它不会以 UID 0 (root) 运行;如果会,则启动 container 失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | 用于运行 container process entrypoint 的 **UID**。如果未指定,则默认为 image metadata 中指定的用户。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | 要应用于所有 containers 的 **SELinux context**。如果未指定,container runtime 会为每个 container 分配一个随机的 SELinux context。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | 该 pod 中 containers 使用的 **seccomp options**。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | 除 container 的主 GID 外,还会应用到每个 container 中第一个进程的 **groups** 列表。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctls 保存了 pod 使用的 **namespaced sysctls** 列表。使用不受支持的 sysctls(由 container runtime 不支持)的 Pod 可能会启动失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | 应用于所有 containers 的 Windows 特定设置。如果未指定,则使用 container 的 SecurityContext 中的选项。 |
|
||||
|
||||
## SecurityContext
|
||||
|
||||
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
|
||||
[**来自文档:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
|
||||
|
||||
这个 context 设置在 **containers definitions** 内部。从防御性安全角度看,你应考虑:
|
||||
这个 context 设置在 **containers definitions** 内部。从防御性安全角度来看,你应该考虑:
|
||||
|
||||
- 将 **allowPrivilegeEscalation** 设为 **False**
|
||||
- 不要添加敏感 **capabilities**(并移除不需要的)
|
||||
- 将 **privileged** 设为 **False**
|
||||
- 不要添加敏感的 **capabilities**(并移除不需要的)
|
||||
- **privileged** 设为 **False**
|
||||
- 如果可能,将 **readOnlyFilesystem** 设为 **True**
|
||||
- 将 **runAsNonRoot** 设为 **True**,并设置 **runAsUser**
|
||||
- 如果可能,考虑通过指定 **seLinuxOptions** 和 **seccompProfile** 来**限制** **permissions**
|
||||
- 不要通过 **runAsGroup** 授予**特权** **group** 访问权限
|
||||
- 将 **runAsNonRoot** 设为 **True** 并设置一个 **runAsUser**
|
||||
- 如果可能,考虑通过 **seLinuxOptions** 和 **seccompProfile** 来**限制** **permissions**
|
||||
- 不要通过 **runAsGroup** 授予 **privilege** **group** 访问权限。
|
||||
|
||||
注意,在 **SecurityContext** 和 **PodSecurityContext** 中都设置的属性,**SecurityContext** 中指定的值优先。
|
||||
注意,**SecurityContext 和 PodSecurityContext** 中都设置的属性,将以 **SecurityContext** 中指定的值为 **优先**。
|
||||
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation** 控制进程是否可以获得比其父进程**更多的 privileges**。这个 bool 直接控制是否会为容器进程设置 no_new_privs 标志。当容器以 **Privileged** 运行或拥有 **CAP_SYS_ADMIN** 时,AllowPrivilegeEscalation 总是为 true |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation** 控制一个 process 是否可以比其父 process 获得**更多 privileges**。这个 bool 会直接控制是否会为 container process 设置 no_new_privs 标志。当 container 以 **Privileged** 运行或具有 **CAP_SYS_ADMIN** 时,AllowPrivilegeEscalation 始终为 true |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | 运行 containers 时要添加/移除的 **capabilities**。默认使用默认的 capabilities 集合。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | 以 privileged 模式运行容器。privileged 容器中的进程本质上**等同于宿主机上的 root**。默认值为 false。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount 表示容器要使用的 **proc mount 类型**。默认值是 DefaultProcMount,它使用 container runtime 对只读路径和 masked 路径的默认设置。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | 以 privileged 模式运行 container。privileged containers 中的 processes 本质上**相当于 host 上的 root**。默认为 false。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount 表示 container 要使用的 **proc mount 类型**。默认值是 DefaultProcMount,它使用 container runtime 对只读路径和 masked paths 的默认设置。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | 该 **container 是否具有只读 root filesystem**。默认值为 false。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | 用于运行容器进程 entrypoint 的 **GID**。如果未设置,则使用 runtime 默认值。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | 表示容器必须**以非 root 用户运行**。如果为 true,Kubelet 会在运行时验证镜像,确保它不会以 UID 0 (root) 运行;如果会,则启动容器失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | 用于运行容器进程 entrypoint 的 **UID**。如果未指定,默认使用镜像元数据中指定的用户。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | **应用于容器的 SELinux context**。如果未指定,container runtime 会为每个 container 分配一个随机的 SELinux context。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | container process entrypoint 的 **GID**。如果未设置,则使用 runtime 默认值。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | 表示 container 必须**以非 root 用户运行**。如果为 true,Kubelet 将在运行时验证 image,确保它不会以 UID 0 (root) 运行;如果会,则启动 container 失败。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process entrypoint 的 **UID**。如果未指定,则默认为 image metadata 中指定的用户。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | 要应用于 container 的 **SELinux context**。如果未指定,container runtime 会为每个 container 分配一个随机的 SELinux context。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | 该 container 使用的 **seccomp options**。 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | 应用于所有 containers 的 **Windows specific settings**。 |
|
||||
|
||||
## Practical workload review checklist
|
||||
|
||||
在审查 Pod 或 workload template 时,检查 `spec.securityContext` 以及 `containers`、`initContainers` 和 `ephemeralContainers` 下每个 container 级别的 `securityContext`。container 级别字段可以覆盖 pod 级别默认值,因此一个看起来安全的 pod 默认配置,并不能保证每个 container 都安全。
|
||||
在审查 Pod 或 workload 模板时,请检查 `spec.securityContext` 以及 `containers`、`initContainers` 和 `ephemeralContainers` 下每个 container 级别的 `securityContext`。container 级别字段可以覆盖 pod 级别默认值,因此一个看起来安全的 pod 默认配置,并不能保证每个 container 都安全。
|
||||
|
||||
应优先关注的高风险组合:
|
||||
优先关注以下高风险组合:
|
||||
|
||||
- `privileged: true`,尤其是同时存在 `hostPID`、`hostIPC`、`hostNetwork`、`hostPath`、host ports 或 runtime socket mounts 时。
|
||||
- 添加了 `SYS_ADMIN`、`NET_ADMIN`、`SYS_PTRACE`、`SYS_MODULE`、`DAC_READ_SEARCH` 或 `DAC_OVERRIDE` 等 capabilities。
|
||||
- `allowPrivilegeEscalation: true`,或在可能执行攻击者控制代码的 containers 中未设置。
|
||||
- 对于可以执行 attacker-controlled code 的 containers,`allowPrivilegeEscalation: true` 或未设置。
|
||||
- `seccompProfile: Unconfined`、`procMount: Unmasked`,或敏感 workload 缺少 runtime profiles。
|
||||
- 可写 root filesystem,或在处理不受信任输入的 workload 中存在范围过大的可写 volume mounts。
|
||||
- 在多租户 namespaces 中缺少 CPU、memory 或 ephemeral-storage 的 requests 和 limits。
|
||||
- 在处理不受信任输入的 workload 中,root filesystem 可写,或存在范围很广的可写 volume mounts。
|
||||
- 在多租户 namespaces 中缺少 CPU、memory 或 ephemeral-storage requests 和 limits。
|
||||
- 缺少或不现实的 pod 级 `spec.resources` budgets,以及对 Pod `resize` 子资源具有 `patch` 或 `update` 权限的 principals,因为受支持的 clusters 可以在不重建 Pod 的情况下更改正在运行的 CPU 和 memory desired state。
|
||||
|
||||
对于大多数 application workload,一个好的基线是以非 root UID 运行,设置 `runAsNonRoot: true`,设置 `allowPrivilegeEscalation: false`,移除所有 capabilities 并只添加最少必需项,使用 `seccompProfile: RuntimeDefault`,优先使用只读 root filesystem,并避免 host namespaces、hostPath mounts 和 privileged 模式。
|
||||
资源控制不属于 `securityContext`,但应在同一轮 workload 审查中检查,因为它们定义了可用性边界。现代 Kubernetes 可以在 Pod 级通过 `spec.resources` 定义 CPU、memory 和 hugepage budgets,并且还可以定义 container 级 `resources`。带有 sidecars 的 Pod 可能会受整体 Pod envelope 限制,即使某个 container 没有单独的 limits,而本地 ephemeral storage 仍然需要单独的 `ephemeral-storage` limits、`emptyDir.sizeLimit`、LimitRanges 和 ResourceQuotas。此外,在执行 in-place resize 请求后,要将 Pod spec 中的 desired resources 与 `status.containerStatuses[].resources` 进行比较;失败或 pending 的 resize 可能会让 `spec` 中保留请求值,而 kubelet 仍保持之前的 runtime allocation,并报告 `PodResizePending` condition。
|
||||
|
||||
在 cluster 层面,尽可能使用 [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) 的 namespace labels 来强制执行 Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)。对于能够支持的 namespaces 使用 `restricted`,普通 application namespaces 至少使用 `baseline`,并将 privileged 例外保持得尽可能小、记录清楚,并仅隔离到受信任的 platform namespaces 或 node pools。
|
||||
对于大多数 application workload,较好的基线是使用非 root UID 运行,设置 `runAsNonRoot: true`,设置 `allowPrivilegeEscalation: false`,删除所有 capabilities 只保留最小必需项,使用 `seccompProfile: RuntimeDefault`,优先使用只读 root filesystem,并避免 host namespaces、hostPath mounts 和 privileged mode。
|
||||
|
||||
在 cluster 级别,尽可能使用 [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) namespace labels 来强制执行 Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)。对可以支持的 namespaces 使用 `restricted`,普通 application namespaces 至少使用 `baseline`,并将 privileged 例外保持在最小范围,做好文档记录,并隔离到受信任的 platform namespaces 或 node pools 中。
|
||||
|
||||
## References
|
||||
|
||||
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
|
||||
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
- [https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
|
||||
- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/)
|
||||
- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
|
||||
- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user