安全保障基于软件全生命周期-PSP应用

安全保障是基于软件全生命周期的,即贯穿了开发-分发-不熟-运行所有环节。在各个环节都可以进行一些安全活动保证系统安全。例如在代码开发环节从需求阶段即可加入安全的需求分析以及对应的保证策略,在代码提交前进行静态代码安全扫描、依赖扫描、IAC扫描等保证提交的代码安全。 

在分发环节,image需要push到代码仓库上进行存储,那么对于代码仓库可以进行安全隔离,提交的image进行安全扫描,对镜像进行签名以及签名验证等保障push到registry的image是安全的。

在运行环节,也可遵循一些安全保障优秀实践,例如

  • 只有经过批准的进程能在容器命名空间内运行
  • 禁止并报告未经授权的资源访问
  • 监控网络流量以检测恶意活动
  • 服务网格是另外一种常见的服务层抽象,它为已经编排的服务提供了整合和补充功能,而不会改变工作负载软件本身(如API流量的日志记录,传输加密,可观测性标记、认证和授权等)

分层对运行的应用实施安全保证,具体的措施如Network Policy,Pod Security,Container Security,Pod security Policy等等。

上面介绍了一些通用概念,接着将通过实际例子演示上面提到的一些具体安全保障措施如何保障运行时安全的。

第一:以Non-root身份运行容器

在DockerFile中通过User命令切换成非root用户,通过groupadd,useradd添加用户,通过USER username来制定后面的命令用非root用户来运行。

FROM python:3.9.5-slim
RUN pip install flask && \
    groupadd -r flask && useradd -r -g flask flask && \
    mkdir /src && \
    chown -R flask:flask /src
USER flask
COPY app.py /src/app.py
WORKDIR /src
ENV FLASK_APP=app.py
EXPOSE 5000
CMD ["flask", "run", "-h", "0.0.0.0"]

例如下面的实际例子,在Dockerfile中定义非root用户执行ENTRYPOINT命令

FROM ubuntu
ENV MY_SERVICE_PORT=80
ENV MY_SERVICE_PORT1=80
ENV MY_SERVICE_PORT2=80
ENV MY_SERVICE_PORT3=80
LABEL multi.label1="value1" multi.label2="value2" other="value3"
ADD bin/amd64/httpserver /httpserver
EXPOSE 8080
RUN useradd -m --uid 1000 web-admin && \
  echo "web-admin ALL=NOPASSWD: ALL" >> /etc/sudoers
RUN chown web-admin /httpserver
USER web-admin
ENTRYPOINT ["/httpserver"]

在部署文件中指定非root用户来运行容器。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: non-root-httpserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpserver
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
      labels:
        app: httpserver
    spec:
      securityContext:
        runAsUser: 1000
      containers:
        - name: httpserver
          imagePullPolicy: Always
          image: cncamp/httpserver:v1.0-nonroot
          ports:
            - containerPort: 80
      serviceAccount: fake-user

第二:集群间组件采用TLS加密进行安全通信,例如如果部署多个etcd的member,那么member之间访问可配置TLS加密,保证访问安全。

第三:添加NodeRestriction标签:准入控制器限制了kubelet可以修改Node和Pod对象,kubelet只可以修改自己的Node API对象,只能修改绑定到节点的Pod对象。可以对节点添加node-restriction.kubernetes.io前缀的标签,这样kubelet就不能删除节点了。

第四:Securtiy Policy:安全上下文描述了允许请求访问某个节点上的特定用户,获得特定权限访问主机网络等。Kubelets提供了三种配置的Security Context。
Container-level security context:仅应用到指定容器
Pod-leve security context:应用到Pod内所有的容器以及Volume
Pod Security Policies(PSP):应用到集群内部所有的Pod以及Volume

例如,查看被Istio注入的简单的toolbox的Pod的yaml文件,可以看到有securityContext的信息,drop all表示取消所有权限,1337进程号的User 来运行的容器。

再比如查看CoreDNS的pod的security context,有NET_BIND_SERVICE权限。 

在看Calico pod的security context,因为要修改主机网络配置,权限比较大,privileged=true。 

Pod Security Policies(PSP)是集群级的Pod安全策略,自动为集群内的Pod和Volume设置Security Context,Security Context设置的各字段和含义如下表所示

接下来通过实际例子演示如何通过PSP控制权限,PSP默认是不开启的,所以为了开启PSP,需要修改kube-apiserver.yaml中的配置信息,且因为开启后PSP就生效,所以提前通过Role/RoleBinding分配一个很大的权限,否则生效后很多操作都无法进行。启动前的PSP文件内容如下所示:这里的privileged=true,允许所有端口,所有Capalilities,任意用户运行。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
    - '*'
  volumes:
    - '*'
  hostNetwork: true
  hostPorts:
    - min: 0
      max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

 接着创建ClusterRole,这个Role的含义是:将名称为privileged的podsecuritypolicies use到这个role上,也就是role具备上面定义的PSP权限。然后通过RoleBinding将Role的权限赋值给kube-system namespace下面的所有serviceaccount和nodes对象。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: privileged-psp
rules:
  - apiGroups:
      - policy
    resourceNames:
      - privileged
    resources:
      - podsecuritypolicies
    verbs:
      - use
---
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:
  - apiGroup: rbac.authorization.k8s.io
    kind: Group
    name: system:nodes
    namespace: kube-system
  - apiGroup: rbac.authorization.k8s.io
    kind: Group
    name: system:serviceaccounts:kube-system

接着执行命令kubectl apply让上面的对象生效,修改/etc/kubernetes/manifests/kube-apiserver.yaml,开启PSP(--enable-admission-plugins=PodSecurityPolicy),配置文件修改后,APIServer会自动重启让配置生效。

因为配置了很大的权限,此时用kubectl执行各项操作仍然正常,接着来创建一个serviceaccount,对比serviceaccount绑定PSP前后的结果来理解PSP工作工程。

kubectl create namespace psp-example
kubectl create serviceaccount -n psp-example fake-user
kubectl create rolebinding -n psp-example fake-editor --clusterrole=edit --serviceaccount=psp-example:fake-user
### create alias to simulate users
```
alias kubectl-admin='kubectl -n psp-example'
alias kubectl-user='kubectl --as=system:serviceaccount:psp-example:fake-user -n psp-example'
```

定义个名叫example的PSP,通过kubectl apply命令让这个PSP生效。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: example
spec:
  privileged: false  # Don't allow privileged pods!
  # The rest fills in some required fields.
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
    - '*'

接着用创建的serviceaccount去尝试创建一个pod 

kubectl-user create -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pause
spec:
  containers:
    - name: pause
      image: k8s.gcr.io/pause
EOF

会显示创建失败,查看该serviceaccount是否绑定了上面的PSP,结果是No。

接着创建Role和Rolebinding将PSP与serviceaccount进行绑定。

### create a role which use the psp
kubectl-admin create role psp:unprivileged \
    --verb=use \
    --resource=podsecuritypolicy \
    --resource-name=example


### bind the role to user
```
kubectl-admin create rolebinding fake-user:psp:unprivileged \
    --role=psp:unprivileged \
    --serviceaccount=psp-example:fake-user
```

 接着再用上面的serviceaccount创建pod,可以看到创建pod成功。

通过上面的例子可以看到通过定义不同权限的PSP,再将PSP的权限分配给不同的serviceaccount,从而来保障集群内的安全。

除了上面介绍了PSP,实际给节点增加Taint也是一种安全防护措施。例如:为不同的租户的节点增加Taint,这样多租户情况下实现节点的相互隔离。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taoli-qiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值