13、容器安全上下文

Context
Container Security Context 应在特定 namespace 中修改 Deployment。

Task
按照如下要求修改 sec-ns 命名空间里的 Deployment secdep
一、用 ID 为 30000 的用户启动容器(设置用户 ID 为: 30000)
二、不允许进程获得超出其父进程的特权(禁止 allowPrivilegeEscalation)
三、以只读方式加载容器的根文件系统(对根文件的只读权限)

官方文档搜索”容器上下文" 找到 “为Pod或容器配置安全上下文”这个文档,可以看到有相关介绍。根据题目要求,有三个参数需要设置:

  • 用户ID,按照文档应该是 runAsUser 参数设置
  • allowPrivilegeEscalation 参数,按要求应该设置为 false
  • 根目录只读,是 readOnlyRootFilesystem 参数,按要求应该设置为 true

runAsUser 这个参数可以在pod设置,也可以在container设置,后面两个参数都是container级别的,只能在container里面设置。所以每个container里都要设置一次。

# kubectl get deploy -n sec-ns secdep -o yaml > secdep_deploy.yaml  #先备份一下
# kubeclt edit deploy -n sec-ns secdep 

要注意,pod级别默认是应该有 securityContext参数了(我自己环境测试的时候是自动补全了,如果考试时没找到就自己加)。

视频里没注意到这点,直接在 template.spec 下面新增多一个,最后修改完发现还是空的。

...
        volumeMounts:
        - mountPath: /usr/local/nginx/conf/conf.d
          name: nginx-config
        securityContext:                     ## 这里与container的 volumeMounts对齐。每个container都要新增这三行。
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
...
      schedulerName: default-scheduler
      securityContext:                      ## 这个pod级别的,默认就有了,只不过默认值是 {}
        runAsUser: 30000                    ## 新增一行,添加这个参数。

14、启用 API server 认证

Context
由 kubeadm 创建的 cluster 的 Kubernetes API 服务器,出于测试目的,
临时配置允许未经身份验证和未经授权的访问,授予匿名用户 cluster-admin 的访问权限.

Task
重新配置 cluster 的 Kubernetes APl 服务器,以确保只允许经过身份验证和授权的 REST 请求。
使用授权模式 Node,RBAC 和准入控制器 NodeRestriction。
删除用户 system:anonymous 的 ClusterRoleBinding 来进行清理。
注意:所有 kubectl 配置环境/文件也被配置使用未经身份验证和未经授权的访问。
你不必更改它,但请注意,一旦完成 cluster 的安全加固, kubectl 的配置将无法工作。
您可以使用位于 cluster 的 master 节点上,cluster 原本的 kubectl 配置文件
/etc/kubernetes/admin.conf ,以确保经过身份验证的授权的请求仍然被允许。

14.1 配置Api Server 授权认证

关于授权模式,其实在前面的题目中已经涉及过,在api server参数中设置

    - --authorization-mode=Node,RBAC

准入控制器 NodeRestriction,也可以在 apiserver的官方文档中搜索NodeRestriction 可以找到有两个参数的值列表是包含这个的。

--disable-admission-plugins strings
--enable-admission-plugins strings

按题目要求,我们是要使用准入控制器,所以应该使用 –enable-admission-plugins 这个参数。所以我们修改 apiserver的yaml文件。注意,这两个参数应该是已经存在的,所以直接搜索后修改其值(不要直接新增)

#vi /etc/kubernetes/manifests/kube-apiserver.yaml
...
    - --authorization-mode=Node,RBAC
    - --enable-admission-plugins=NodeRestriction

然后重新重启kubelet生效

#systemctl daemon-reload 
#systemctl restart kubelet.service 

重启完成后,无法再直接使用kubectl命令,需要指定kubeconf文件才能继续使用

#kubectl --kubeconfig /etc/kubernetes/admin.conf get nodes

14.2 删除匿名用户的角色绑定

按照题目要求,是要删除 system:anonymous 这个用户的 ClusterRoleBinding。所以我们要先找到这个 ClusterRoleBinding 的名称,再删除。

# kubectl get ClusterRoleBinding -o jsonpath='{range .items[*]}{.metadata.name},{.subjects[0].name}{"\n"}{end}'|grep coredns  #我的环境没有那个用户,所以用coredns来演示
system:coredns,coredns             ##结果,逗号前面的是 ClusterRoleBinding 名称,逗号后面的是用户名

但是看视频,ClusterRoleBinding 的名字就是 system:anonymous ,直接删除就行。可能是题目的中文翻译有问题,因为这种格式确实不太像是用户名称。

所以正式考试时先直接找 system:anonymous 这个 ClusterRoleBinding 是否存在,存在的话可以 describe 看下是否符合,确定就可以删除

#kubectl delete ClusterRoleBinding system:anonymous

15、TLS安全配置

Task
通过 TLS 加强 kube-apiserver 安全配置,要求
1、kube-apiserver 除了 VersionTLS13 及以上的版本可以使用,其他版本都不允许使用。
2、密码套件(Cipher suite)为 TLS_AES_128_GCM_SHA256
通过 TLS 加强 ETCD 安全配置,要求
1、密码套件(Cipher suite)为 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

这道题跟正式考试时差别比较大,仅供参考了。

15.1 kube-apiserver配置

打开官方文档关于kube-apiserver的介绍,根据关键字 VersionTLS13 搜索,找到下面这个参数

--tls-min-version string
支持的最低 TLS 版本。可能的值:VersionTLS10,VersionTLS11,VersionTLS12,VersionTLS13

再根据TLS_AES_128_GCM_SHA256 找到:

--tls-cipher-suites strings
服务器的密码套件的列表,以逗号分隔。如果省略,将使用默认的 Go 密码套件。
首选值: TLS_AES_128_GCM_SHA256、TLS_AES_256_GCM_SHA384....

所以我们修改kube-apiserver的yaml文件,修改或增加这两个参数的值。

#cp /etc/kubernetes/manifests/kube-apiserver.yaml  /tmp
#vi /etc/kubernetes/manifests/kube-apiserver.yaml 
...
    - --tls-min-version=VersionTLS13
    - --tls-cipher-suites=TLS_AES_128_GCM_SHA256

重启kubelet生效,也可以等etcd也修改好后再一起重启。

#systemctl daemon-reload 
#systemctl restart kubelet.service 

15.2 etcd配置

etcd的参数在k8s官网找不到,而考试时是不允许打开其它网站的。可以按照视频办法,通过etcd -h命令查看。若没有etcd命令,则需要先安装

#apt install etcd-server
#etcd -h
        --cipher-suites ''   ## 能找到这个参数最符合题目要求(Cipher suite)

然后修改 etcd的yaml文件

# cp /etc/kubernetes/manifests/etcd.yaml /tmp/
#vi /etc/kubernetes/manifests/etcd.yaml 
...
    - --cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

重启kubelet生效.

#systemctl daemon-reload 
#systemctl restart kubelet.service 

15.3 另外的查看参数办法

除了上面介绍的办法,我们也可以通过进入kube-apiserver 和 etcd 的pod里面执行帮助命令来查找相关参数

# kubectl exec -it -n kube-system kube-apiserver-t-kubeadm-001 -- kube-apiserver -h|grep tls
      --tls-cipher-suites strings              Comma-separated list of cipher suites for the server. If omitted, the default Go cipher suites will be used. 
      --tls-min-version string                 Minimum TLS version supported. Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13
# kubectl exec -it -n kube-system etcd-t-kubeadm-001 -- etcd -h|grep cipher
  --cipher-suites ''
    Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).

16、 ImagePolicyWebhook 容器镜像扫描

Context
cluster上设置了容器镜像扫描器,但尚未完全集成到 cluster 的配置中。
完成后,容器镜像扫描器应扫描并拒绝易受攻击的镜像的使用。

Task
注意:你必须在 cluster 的 master 节点上完成整个考题,所有服务和文件都已被准备好并放置在该节点上。
给定一个目录 /etc/kubernetes/epconfig 中不完整的配置,
以及具有 HTTPS 端点 https://image-bouncer-webhook.default.svc:1323/image_policy 的功能性容器镜像扫描器:
1. 启用必要的插件来创建镜像策略
2. 校验控制配置并将其更改为隐式拒绝(implicit deny)
3. 编辑配置以正确指向提供的 HTTPS 端点
最后,通过尝试部署易受攻击的资源 /cks/img/web1.yaml 来测试配置是否有效。

/etc/kubernetes/epconfig 目录下有以下文件:

admission_configuraton.json
kubeconfig.yml
front-proxy-client.key
front-proxy=client.crt
server.crt
server-key.pem

admission_configuraton.json 内容如下

{
  "imagePolicy":{
     "kubeConfigFile":"/etc/kubernetes/epconfig/kubeconfig.yml",
     "allowTTL": 50,
     "denyTTL": 50,
     "retryBackoff":500,
     "defaultAllow": true
  }
}

kubeconfig.yml 内容如下:

apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/epconfig/server.crt
  name: houncer_webhook
contextst:
- context:
    cluster: bouncer_webhook
    user: api-server
  name: bouncer_validator
current-context: bouncer_validator
preferences: {}
users :
- name: api-server
  user:
    client-certificate: /etc/kubernetes/pki/front-proxy-client.crt
    client-key: /etc/kubernetes/pki/front-proxy-client.key

16.1 修改 ImagePolicyWebhook 准入配置

首先,我们官网搜索准入控制器或者ImagePolicyWebhook。找到准入控制器的介绍文档,然后搜索 ImagePolicyWebhook 找到这个准入控制器的介绍部分。

ImagePolicyWebhook 准入控制器允许使用后端 Webhook 做出准入决策。
此准入控制器默认被禁用。

因为这个准入控制器是默认被禁用的,所以需要先显式声明启用。我们在apiserver文档里搜索ImagePolicyWebhook这个可以找到启用这个准入控制器的参数

--enable-admission-plugins strings

接着看准入控制器的介绍,看到

在通过命令行标志 --admission-control-config-file 为 API 服务器提供的文件中, 引用 ImagePolicyWebhook 配置文件:

我们在apiserver中也找到了该参数

--admission-control-config-file string
	包含准入控制配置的文件。

这两个参数我们在第二步里再修改(apiserver里面的参数)。

我们看题目要求的第二点:校验控制配置并将其更改为隐式拒绝(implicit deny)。这个是在admission_configuraton.json文件里配置

{
  "imagePolicy":{
     "kubeConfigFile":"/etc/kubernetes/epconfig/kubeconfig.yml",
     "allowTTL": 50,
     "denyTTL": 50,
     "retryBackoff":500,
     "defaultAllow": false
  }
}

只需要把 defaultAllow 的值从 true 修改为 false。另外,注意检查 kubeConfigFile 这个参数指定的文件是否正确。

再看第三点要求:编辑配置以正确指向提供的 HTTPS 端点。 这个是在kubeconfig.yml文件里定义,参考文档里的介绍,我们修改如下

...
- cluster:
    certificate-authority: /etc/kubernetes/epconfig/server.crt
    server: https://image-bouncer-webhook.default.svc:1323/image_policy   ## 增加这行
...

这样就修改完了(我有点疑问就是其他认证文件好像都没用上,总感觉不至于给多这么多文件的)。

16.2 配置apiserver支持ImagePolicyWebhook

按照上面的分析,需要增加两个参数,而且由于涉及到使用配置文件,所以要增加卷的挂载(和前面的审计日志后端类似)

#cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp
#vi /etc/kubernetes/manifests/kube-apiserver.yaml 
...
    - --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook  ## 注意,原来已经有这个参数了,不要删除原来的值,在后面添加。
    - --admission-control-config-file=/etc/kubernetes/epconfig/admission_configuraton.json  ## 先检查是否存在,存在则修改值,不存在则新增。
...
    volumeMounts:
    - mountPath: /etc/kubernetes/epconfig/  ## 注意检查是否已经存在,不要重复添加,会报错。
      name: epconfig
      readOnly: true
...
  volumes:
  - hostPath:
      path: /etc/kubernetes/epconfig/   ## 注意检查是否已经存在,不要重复添加,会报错。
      type: DirectoryOrCreate
    name: epconfig

16.3 生效和验证

重启kubelet让配置生效

#systemctl daemon-reload 
#systemctl restart kubelet.service 
#kubectl apply -f /cks/img/web1.yaml 

如果应用 /cks/img/web1.yaml 提示镜像被阻止就说明成功了。