写点什么

在 Kubeadm 中使用 pod 安全策略

  • 2019-11-20
  • 本文字数:6803 字

    阅读完需:约 22 分钟

在Kubeadm中使用pod安全策略

Pod 安全策略是一种机制,用于限制容器在 k8s 上运行时可执行的操作,例如防止其作为特权容器的运行,和主机网络运行等。


本文内容较多,所以在此做了一个完整的简介说明:


  • 在 master 节点运行 kubeadm init 并启用 PodSecurityPolicy admission controller;

  • 使用 RBAC 配置添加一些 pod 安全策略 - 足够启动 CNI 和 DNS 等;

  • 没有它,CNI daemonsets 将无法启动

  • 应用您的 CNI 插件,该插件可以使用以前创建的一个 pod 安全策略

  • 通过 kubeadm join 完成向集群添加节点的配置

  • 在向集群添加更多工作负载时,请检查是否需要额外的 pod 安全策略和 RBAC 配置

我们将要做什么

以下是在 kubeadm 上安装运行 pod 安全策略所采取的步骤:


  1. 为 master 节点的初始化配置 pod 安全策略 admission controller

  2. 为网络层组件配置一些 pod 安全策略

  3. 配置 CNI 插件 - 这里将使用 flannel

  4. 然后将使用下面的代码演示一些其他的 pod 安全策略方案

  5. 安装一个具有一些特定要求的 nginx-ingress controller - 这只是为了说明添加额外的策略

  6. 安装没有特定 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 VERSIONpmcgrath-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\_0k8s\_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 accessapiVersion: 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 workloadcurl -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政策


添加小助手微信,加入【容器魔方】技术社群。



2019-11-20 19:11719

评论

发布
暂无评论
发现更多内容

这是我在金九银十收到的第五个 Offer:字节跳动 Java 研发岗

Java 程序员 架构 面试 后端

区块链技术在商业领域的新运用-智能合同

CECBC

自我提升:高效能人士的 7 个习惯学习笔记(三)

程序员架构进阶

读书笔记 自我管理 自我提升 10月月更

架构实战营-模块九

NewBranSTONE

架构实战营

v05.05 鸿蒙内核源码分析(任务管理) | 任务池是如何管理的 | 百篇博客分析 HarmonyOS 源码

鸿蒙研究站

HarmonyOS OpenHarmony 鸿蒙系统 任务队列

模块九作业

河马先生

架构实战营

''内卷"把我逼成什么样了!气得我把 Github 上所有面试题都整理了一遍!

程序员 架构 面试 后端 java

区块链+数字经济,我们看到了什么

CECBC

【Flutter 专题】33 图解自定义 View 之 Canvas (一)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 10月月更

《C++ Primer Plus第六版》读书笔记

IT蜗壳-Tango

10月月更

双非本科怎么了,照样拿到阿里offer!分享阿里技术四面+交叉面+HR面难忘经历

Java 程序员 架构 面试 大前端

v04.03 鸿蒙内核源码分析(任务调度) | 任务是内核调度的单元 | 百篇博客分析 HarmonyOS 源码

鸿蒙研究站

HarmonyOS 任务栈 OpenHarmony 鸿蒙系统

【LeetCode】合并两个有序链表Java题解

Albert

算法 LeetCode 10月月更

微信频繁读取 iOS15 用户的相册?

池建强

微信 隐私

接棒运动赛事!工厂里也有热血竞技?

脑极体

DjangoTask2

南湖职业技术学院机械狗

四面阿里巴巴如愿拿到offer定级P7,为此我筹备了半年

程序员 架构 面试 大前端 java

Sql学习

南湖职业技术学院机械狗

Cortex 是什么?

耳东@Erdong

Prometheus Cortex 水平扩展 10月月更

拯救遗留系统:重构函数的 7 个小技巧

Phoenix

重构 java

在线HTML转JS/JSON工具

入门小站

工具

模块九作业

Mr.He

架构实战营

阿里云云计算助理工程师认证(ACA)50个资源合集和备考题库 易筋 ARTS 打卡 Week 72

John(易筋)

ARTS 打卡计划

风雨兼程,零代码训练营第四期顺利结业

明道云

产品设计:娱乐化思维

石云升

产品设计 产品分析 10月月更

微博评论架构设计

小智

架构训练营

【设计模式】第二篇 - 组合迭代器

Brave

组合模式 迭代器模式 10月月更

再说JavaScript 的 null 和 undefined

devpoint

null JavaScrip 10月月更

linux之yum源设置代理

入门小站

Linux

校友录小程序开发笔记三十一:校庆模块设计与实现

CC同学

产品经理技能手册

俞凡

产品经理 产品管理 认知

在Kubeadm中使用pod安全策略_容器_华为云原生团队_InfoQ精选文章