Kubernetes安全之KubeEye">Kubernetes安全之KubeEye
794
2025-04-02
Pod 安全策略是一種機制,用于限制容器在 k8s 上運行時可執行的操作,例如防止其作為特權容器的運行,和主機網絡運行等。
本文內容較多,所以在此做了一個完整的簡介說明:
在 master 節點運行 kubeadm init 并啟用 PodSecurityPolicy admission controller;
使用 RBAC 配置添加一些 pod 安全策略 - 足夠啟動 CNI 和 DNS 等;
沒有它,CNI daemonsets 將無法啟動
應用您的 CNI 插件,該插件可以使用以前創建的一個 pod 安全策略
通過 kubeadm join 完成向集群添加節點的配置
在向集群添加更多工作負載時,請檢查是否需要額外的 pod 安全策略和 RBAC 配置
我們將要做什么
以下是在 kubeadm 上安裝運行 pod 安全策略所采取的步驟:
為 master 節點的初始化配置 pod 安全策略 admission controller
為網絡層組件配置一些 pod 安全策略
配置 CNI 插件 - 這里將使用 flannel
然后將使用下面的代碼演示一些其他的 pod 安全策略方案
安裝一個具有一些特定要求的 nginx-ingress controller - 這只是為了說明添加額外的策略
安裝沒有特定 pod 安全策略要求的常規服務 - 基于 httpbin.org
環境
將只在單個節點說明,而不是具有高可用集群的多節點集群
Ubuntu:根據 kubeadm 的要求切換,為 UTC 配置時區
Docker:假設當前用戶在 docker 組中
kubernetes 1.11.3 - 使用 RBAC
master 節點配置
按照說明安裝 kubeadm
安裝 jq,用它來進行一些 json 輸出處理
sudo?apt-get?update?? sudo?apt-get?install?-y?jq
驗證 kubeadm 的版本
sudo?kubeadm?version
接著我們將為下面創建的內容創建一個目錄,在以下所有說明中我們假設您在此目錄中
mkdir?~/psp-inv?? cd?~/psp-inv
kubeadm 配置文件
將創建這個文件,并將其用于 master 上的 kubeadm init,使用此內容創建一個 kubeadm-config.yaml 文件 - 請注意我們必須為 flannel 指定 pod 子網為 10.244.0.0/16
請注意,此文件對于此演示是最小的,如果您使用更高版本的 kubeadm,則可能需要更改 apiVersion
apiVersion:?kubeadm.k8s.io/v1alpha2?? kind:?MasterConfiguration?? apiServerExtraArgs:?? ?enable-admission-plugins:?PodSecurityPolicy?? controllerManagerExtraArgs:?? address:?0.0.0.0?? kubernetesVersion:?v1.11.3?? networking:?? podSubnet:?10.244.0.0/16?? schedulerExtraArgs:?? address:?0.0.0.0
Master init
根據上面命令輸出的說明獲取您自己的 kubeconfig 文件副本,如果要將工作節點添加到集群,請注意加入以下信息,并檢查 master 節點的狀態
NAME?STATUS?ROLES?AGE?VERSION pmcgrath-k8s-master?NotReady?master?1m?v1.11.3
這說明節點還沒有準備好,因為它正在等待 CNI,檢查一下 pods
No?resources?found.
所以,如果我們沒有啟用 pod security policy admission control,通常看不到任何正在運行的 pod,檢查 docker
docker?container?ls?--format?'{{?.Names?}}' k8s\_kube-scheduler\_kube-scheduler-pmcgrath-k8s-master\_kube-system\_a00c35e56ebd0bdfcd77d53674a5d2a1\_0 k8s\_kube-controller-manager\_kube-controller-manager-pmcgrath-k8s-master\_kube-system\_fd832ada507cef85e01885d1e1980c37\_0?? k8s\_etcd\_etcd-pmcgrath-k8s-master\_kube-system\_16a8af6b4a79e9b0f81092f85eab37cf\_0?? k8s\_kube-apiserver\_kube-apiserver-pmcgrath-k8s-master\_kube-system\_db201a8ecaf8e99623b425502a6ba627\_0?? k8s\_POD\_kube-controller-manager-pmcgrath-k8s-master\_kube-system\_fd832ada507cef85e01885d1e1980c37\_0?? k8s\_POD\_kube-scheduler-pmcgrath-k8s-master\_kube-system\_a00c35e56ebd0bdfcd77d53674a5d2a1\_0?? k8s\_POD\_kube-apiserver-pmcgrath-k8s-master\_kube-system\_db201a8ecaf8e99623b425502a6ba627\_0?? k8s\_POD\_etcd-pmcgrath-k8s-master\_kube-system\_16a8af6b4a79e9b0f81092f85eab37cf\_0
所有容器都在運行,但這不是通過 kubectl 獲取的信息, 還需檢查事件
會看到類似這樣的錯誤:pods “kube-proxy-“ is forbidden: no providers available to validate pod request
配置 pod 安全策略
當前已經配置了:
任何工作負載都可以使用默認的 pod 安全策略,它沒有什么特權,但應該適用于大多數工作負載
將創建一個 RBAC ClusterRole
將為所有經過身份驗證的用戶創建 RBAC ClusterRoleBinding
我授予 kube-system 命名空間中的節點和所有服務帳戶訪問權限的特權 pod 安全策略
考慮這個權限應該被限制在這個命名空間內
應該只在此命名空間中運行 k8s 組件
將創建一個 RBAC ClusterRole
將在 kube-system 命名空間中創建 RBAC RoleBinding
使用此內容創建 default-psp-with-rbac.yaml 文件
apiVersion:?policy/v1beta1?? kind:?PodSecurityPolicy?? metadata:?? ?annotations:?? ?apparmor.security.beta.kubernetes.io/allowedProfileNames:?'runtime/default'?? ?apparmor.security.beta.kubernetes.io/defaultProfileName:?'runtime/default'?? ?seccomp.security.alpha.kubernetes.io/allowedProfileNames:?'docker/default'?? ?seccomp.security.alpha.kubernetes.io/defaultProfileName:?'docker/default'?? ?name:?default?? spec:?allowedCapabilities:?\[\]?#?default?set?of?capabilities?are?implicitly?allowed?? ?allowPrivilegeEscalation:?false?? ?fsGroup:?? ?rule:?'MustRunAs'?? ?ranges:?? ?#?Forbid?adding?the?root?group.?? \-?min:?1?? ?max:?65535?? ?hostIPC:?false?? ?hostNetwork:?false?? ?hostPID:?false?? ?privileged:?false?? ?readOnlyRootFilesystem:?false?? ?runAsUser:?? ?rule:?'MustRunAsNonRoot'?? ?seLinux:?? ?rule:?'RunAsNonRoot'?? ?supplementalGroups:?? ?rule:?'RunAsNonRoot'?? ?ranges:?? ?#?Forbid?adding?the?root?group.?? \-?min:?1?? ?max:?65535?? ?volumes:?? \-?'configMap'?? \-?'downwardAPI'?? \-?'emptyDir'?? \-?'persistentVolumeClaim'?? \-?'projected'?? \-?'secret'?? ?hostNetwork:?false?? ?runAsUser:?? ?rule:?'RunAsAny'?? ?seLinux:?? ?rule:?'RunAsAny'?? ?supplementalGroups:?? ?rule:?'RunAsAny'?? ?fsGroup:?? ?rule:?'RunAsAny' \--- \#?Cluster?role?which?grants?access?to?the?default?pod?security?policy? apiVersion:?rbac.authorization.k8s.io/v1?? kind:?ClusterRole?? metadata:?? ?name:?default-psp?? rules:?? \-?apiGroups:?? ?-?policy?? ?resourceNames:?? ?-?default?? ?resources:?? ?-?podsecuritypolicies?? ?verbs:?? ?-?use\--- \#?Cluster?role?binding?for?default?pod?security?policy?granting?all?authenticated?users?access apiVersion:?rbac.authorization.k8s.io/v1?? kind:?ClusterRoleBinding?? metadata:?? ?name:?default-psp?? roleRef:?? ?apiGroup:?rbac.authorization.k8s.io?? ?kind:?ClusterRole?? ?name:?default-psp?? subjects:?? \-?apiGroup:?rbac.authorization.k8s.io?? ?kind:?Group?? ?name:?system:authenticated
使用此內容創建 privileged-psp-with-rbac.yaml 文件
#?Should?grant?access?to?very?few?pods,?i.e.?kube-system?system?pods?and?possibly?CNI?pods?? apiVersion:?policy/v1beta1?? kind:?PodSecurityPolicy?? metadata:?? ?annotations:?? ?#?See?https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp?? ?seccomp.security.alpha.kubernetes.io/allowedProfileNames:?'\*'?? ?name:?privileged?? spec:?? ?allowedCapabilities:?? \-?'\*'?? ?allowPrivilegeEscalation:?true?? ?fsGroup:?? ?rule:?'RunAsAny'?? ?hostIPC:?true?? ?hostNetwork:?true?? ?hostPID:?true?? ?hostPorts:?? \-?min:?0?? ?max:?65535?? ?privileged:?true?? ?readOnlyRootFilesystem:?false?? ?runAsUser:?? ?rule:?'RunAsAny'?? ?seLinux:?? ?rule:?'RunAsAny'?? ?supplementalGroups:?? ?rule:?'RunAsAny'?? ?volumes:?? \-?'\*' \--- \#?Cluster?role?which?grants?access?to?the?privileged?pod?security?policy? apiVersion:?rbac.authorization.k8s.io/v1?? kind:?ClusterRole?? metadata:?? ?name:?privileged-psp?? rules:?? \-?apiGroups:?? ?-?policy?? ?resourceNames:?? ?-?privileged?? ?resources:?? ?-?podsecuritypolicies?? ?verbs:?? ?-?use\--- \#?Role?binding?for?kube-system?-?allow?nodes?and?kube-system?service?accounts?-?should?take?care?of?CNI?i.e.?flannel?running?in?the?kube-system?namespace? \#?Assumes?access?to?the?kube-system?is?restricted?? apiVersion:?rbac.authorization.k8s.io/v1?? kind:?RoleBinding?? metadata:?? ?name:?kube-system-psp?? ?namespace:?kube-system?? roleRef:?? ?apiGroup:?rbac.authorization.k8s.io?? ?kind:?ClusterRole?? ?name:?privileged-psp?? subjects:?? \#?For?the?kubeadm?kube-system?nodes?? \-?apiGroup:?rbac.authorization.k8s.io?? ?kind:?Group?? ?name:?system:nodes?? \#?For?all?service?accounts?in?the?kube-system?namespace?? \-?apiGroup:?rbac.authorization.k8s.io?? ?kind:?Group?? ?name:?system:serviceaccounts:kube-system
使用 RBAC 配置應用上述 pod 安全策略
kubectl?apply?-f?default-psp-with-rbac.yaml?? kubectl?apply?-f?privileged-psp-with-rbac.yaml
校驗
一段時間后,網絡層 pods 將處于運行狀態,coredns pods 將掛起 - 等待 CNI
kubectl?get?pods?--all-namespaces?--output?wide?--watch
在配置 CNI 之前, 網絡層 pods 將再次啟動失敗,因為節點仍未準備就緒
安裝 flannel**
只有當前存在有特權 pod 安全策略才能完成此操作,并且 kube-system 中的 flannel 服務帳戶將能夠使用,如果使用不同的 CNI 插件,則應使用其安裝說明,可能需要修改用于 kubeadm init 的 kubeadm-config.yaml 文件中的 podSubnet。
延伸鏈接
kubectl?apply?-f?https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
再次校驗
kubectl?get?pods?--all-namespaces?--output?wide?--watch
所有 pods 最終將進入運行狀態,包括 coredns pod(s)
kubectl?get?nodes
節點現已準備就緒。
允許 master 上的工作負載
如果想要啟動工作節點,可以正常使用 kubeadm join 命令,利用 kubeadm init 輸出,在這里跳過。
這些工作節點上沒有特別需要加入集群 pod 安全策略,允許 master 節點上的工作負載,因為我們只是嘗試在單個節點集群上進行驗證。
kubectl?taint?nodes?--all?node-role.kubernetes.io/master-
nginx ingress
使用下方鏈接的清單
創建一個新的命名空間和單個實例 ingress controller,足以說明額外的 pod 安全策略。
由于命名空間尚不存在,因此我們可以創建,以便引用服務帳戶
kubectl create namespace ingress-nginx
創建一個 pod 安全策略
本 pod 安全策略基于 deployment 清單,使用此內容創建文件 nginx-ingress-psp-with-rbac.yaml
apiVersion:?policy/v1beta1?? kind:?PodSecurityPolicy?? metadata:?? ?annotations:?? ?#?Assumes?apparmor?available?? ?apparmor.security.beta.kubernetes.io/allowedProfileNames:?'runtime/default'?? ?apparmor.security.beta.kubernetes.io/defaultProfileName:?'runtime/default'?? ?seccomp.security.alpha.kubernetes.io/allowedProfileNames:?'docker/default'?? ?seccomp.security.alpha.kubernetes.io/defaultProfileName:?'docker/default'?? ?name:?ingress-nginx?? spec:?? ?#?See?nginx-ingress-controller?deployment?at?https://github.com/kubernetes/ingress-nginx/blob/master/deploy/mandatory.yaml?? ?#?See?also?https://github.com/kubernetes-incubator/kubespray/blob/master/roles/kubernetes-apps/ingress\_controller/ingress\_nginx/templates/psp-ingress-nginx.yml.j2?? ?allowedCapabilities:?? \-?NET\_BIND\_SERVICE?? ?allowPrivilegeEscalation:?true?? ?fsGroup:?? ?rule:?'MustRunAs'?? ?ranges:?? \-?min:?1?? ?max:?65535?? ?hostIPC:?false?? ?hostNetwork:?false?? ?hostPID:?false?? ?hostPorts:?? \-?min:?80?? ?max:?65535?? ?privileged:?false?? ?readOnlyRootFilesystem:?false?? ?runAsUser:?? ?rule:?'MustRunAsNonRoot'?? ?ranges:?? \-?min:?33?? ?max:?65535?? ?seLinux:?? ?rule:?'RunAsAny'?? ?supplementalGroups:?? ?rule:?'MustRunAs'?? ?ranges:?? ?#?Forbid?adding?the?root?group.?? \-?min:?1?? ?max:?65535?? ?volumes:?? \-?'configMap'?? \-?'downwardAPI'?? \-?'emptyDir'?? \-?'projected'?? \-?'secret' \--- apiVersion:?rbac.authorization.k8s.io/v1 ?? kind:?Role?? metadata:?? ?name:?ingress-nginx-psp?? ?namespace:?ingress-nginx?? rules:?? \-?apiGroups:?? ?-?policy?? ?resourceNames:?? ?-?ingress-nginx?? ?resources:?? ?-?podsecuritypolicies?? ?verbs:?? ?-?use\--- apiVersion:?rbac.authorization.k8s.io/v1 ?? kind:?RoleBinding?? metadata:?? ?name:?ingress-nginx-psp?? ?namespace:?ingress-nginx?? roleRef:?? ?apiGroup:?rbac.authorization.k8s.io?? ?kind:?Role?? ?name:?ingress-nginx-psp?? subjects:?? \#?Lets?cover?default?and?nginx-ingress-serviceaccount?service?accounts?? \#?Could?have?altered?default-http-backend?deployment?to?use?the?same?service?acccount?to?avoid?granting?the?default?service?account?access?? \-?kind:?ServiceAccount?? ?name:?default?? \-?kind:?ServiceAccount?? ?name:?nginx-ingress-serviceaccount
即創建
kubectl?apply?-f?nginx-ingress-psp-with-rbac.yaml
創建 nginx-ingress 工作負載
刪除 controller-publish-service arg,因為在這里不需要
curl?-s?https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml?|?sed?'/--publish-service/d'?|?kubectl?apply?-f?-
檢查 pods
kubectl?get?pods?--namespace?ingress-nginx?--watch
現在可以看到 pod 安全策略附加了注釋
kubectl?get?pods?--namespace?ingress-nginx?--selector?app.kubernetes.io/name=ingress-nginx?-o?json?|?jq?-r?'.items\[0\].metadata.annotations."kubernetes.io/psp"'
Httpbin.org 工作負載
部署一個工作負載,默認的 pod 安全策略就足夠了,使用此內容創建一個 httpbin.yaml 文件
apiVersion:?apps/v1?? kind:?Deployment?? metadata:?? ?labels:?? ?app.kubernetes.io/name:?httpbin?? ?name:?httpbin?? spec:?? ?replicas:?1?? ?selector:?? ?matchLabels:?? ?app.kubernetes.io/name:?httpbin?? ?template:?? ?metadata:?? ?labels:?? ?app.kubernetes.io/name:?httpbin?? ?spec:?? ?containers:?? \-?args:?\["-b",?"0.0.0.0:8080",?"httpbin:app"\]?? ?command:?\["gunicorn"\]?? ?image:?docker.io/kennethreitz/httpbin:latest?? ?imagePullPolicy:?Always?? ?name:?httpbin?? ?ports:?? \-?containerPort:?8080?? ?name:?http?? ?restartPolicy:?Always \--- apiVersion:?extensions/v1beta1 ?? kind:?Ingress?? metadata:?? ?annotations:?? ?kubernetes.io/ingress.class:?"nginx"?? ?labels:?? ?app.kubernetes.io/name:?httpbin?? ?name:?httpbin?? spec:?? ?rules:?? ?-?host:?my.httpbin.com?? ?http:?? ?paths:?? ?-?path:?? ?backend:?? ?serviceName:?httpbin?? ?servicePort:?8080\--- apiVersion:?v1 ?? kind:?Service?? metadata:?? ?labels:?? ?app.kubernetes.io/name:?httpbin?? ?name:?httpbin?? spec:?? ?ports:?? ?-?name:?http?? ?port:?8080?? ?selector:?? ?app.kubernetes.io/name:?httpbin
創建命名空間并在工作負載里運行
kubectl?create?namespace?demo?? kubectl?apply?--namespace?demo?-f?httpbin.yaml
檢查 pod 是否存在以及是否使用了默認策略
kubectl?get?pods?--namespace?demo??kubectl?get?pods?--namespace?demo?--selector?app.kubernetes.io/name=httpbin?-o?json?|?jq?-r?'.items\[0\].metadata.annotations."kubernetes.io/psp"'
測試工作負載
通過調用 ingress controller pod 實例
\#?Get?nginx?ingress?controller?pod?IP?? nginx\_ip=$(kubectl?get?pods?--namespace?ingress-nginx?--selector?app.kubernetes.io/name=ingress-nginx?--output?json?|?jq?-r?.items\[0\].status.podIP) \#?Test?ingress?and?out?httpbin?workload curl?-H?'Host:?my.httpbin.com'?http://$nginx\_ip/get
如果打亂它,可以重置并重啟
\#?Note:?Will?loose?PKI?also?which?is?fine?here?as?kubeadm?master?init?will?re-create?? sudo?kubeadm?reset \#?Should?flush?iptable?rules?after?a?kubeadm?reset,?see?https://blog.heptio.com/properly-resetting-your-kubeadm-bootstrapped-cluster-nodes-heptioprotip-473bd0b824aa? sudo?iptables?-F?&&?sudo?iptables?-t?nat?-F?&&?sudo?iptables?-t?mangle?-F?&&?sudo?iptables?-X
參考文檔
安全建議
GCE 政策
參考:?https://www.infoq.cn/article/QEKvAlu4UoxqVxo1Uh5F
容器 安全 Kubernetes
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。