前言

去年黑五买了cka和cks的认证考试套餐(实在是便宜,多个cks也就多500块),cka已经高分考过了,想着卷快到期了要把cks也考了,不要浪费。然后像cka一样,先去官网考试里的模拟考测试一番,把试题内容和答案下载下来复习了几遍,自认学习得不错,第二次模拟考机会也是高分通过。谁料到,真正考试时被考懵了,好多知识点都没涉及到,亏那个模拟考还说真实考试会容易点。

痛定思痛,一番找资料,结果发现B站已经有大佬把CKS的试题讲解得很清楚了,看了一遍题目和我考试的内容居然相差无几,如获至宝。为了加深印象,也为了给自己的学习一个总结,也为了即将到来的考试能顺利通过,所以准备在二刷的同时整理出来做个归纳。

由于是在本地环境中测试的,所以部分命令可能跟考试会有些偏差,请大家注意甄别。

大家也可以直接去B站看大佬的视频,搜伯乐大典 这个up主就可以找到,或者搜 CKS考试真题讲解

1、 kube-bench修复不安全项

Context
针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时,发现了多个必须立即解决的问题
Task
通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效
修复针对 API 服务器发现的所有以下违规行为:
1.2.7 Enlure that the --authorization-mode argument is not set to AlwaysAllow   FAIL
1.2.8 Ensure that the --authorization-mode argument includes Node               FAIL
1.2.9 Ensure that the --authorization-mode argument includes RBAC               FAIL

修复针对 kubelet 发现的所有以下违规行为:
Fix all of the following violations that were found against the kubelet:
4.2.1 Ensure that the anonymous-auth argument is set to false                   FAIL
4.2.2 Ensure that the --authorization-mode argument is not set to AlwaysAllow   FAIL

注意:尽可能使用 Webhook 身份验证/授权。
修复针对etcd发现的所有以下违规行为:
Fix all of the following violations that were found against etcd:
2.2 Ensure that the -client-cert-auth argument is set to true                  FAIL

本题考察对kube-bench工具的使用,上面给出的那些项都是通过kube-bench检测出来的。

1.1 kube-apiserver 部分

先来看第一部分,针对kube-apiserver的检查,前三个都是 authorization-mode 这个参数的设置问题。这个参数的含义是:

在安全端口上进行鉴权的插件的顺序列表。 逗号分隔的列表:AlwaysAllow、AlwaysDeny、ABAC、Webhook、RBAC、Node。默认值:"AlwaysAllow"

根据题目要求,这个参数不得设置为AlwaysAllow,并且应该包含 Node 和 RBAC 两种模式。这个是kube-apiserver的启动参数,所以我们去修改。

##ssh 到master节点
#cp /etc/kubernetes/manifests/kube-apiserver.yaml ~/bak1/kube-apiserver.yaml   ##先备份
#vi /etc/kubernetes/manifests/kube-apiserver.yaml 
    - --authorization-mode=Node,RBAC    ## 修改这里的值

上面我们把 authorization-mode 的值修改成了 Node,RBAC,符合题目要求。

如果不知道如何修复,可以使用kube-bench工具查看修复建议的。kube-apiserver是属于master的服务,所以targets要指定为master。

# ./kube-bench  run --targets=master --config-dir=/app/cfg |grep authorization-mode -A 2
[FAIL] 1.2.7 Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)
[FAIL] 1.2.8 Ensure that the --authorization-mode argument includes Node (Automated)
[FAIL] 1.2.9 Ensure that the --authorization-mode argument includes RBAC (Automated)
[WARN] 1.2.10 Ensure that the admission control plugin EventRateLimit is set (Manual)
[FAIL] 1.2.11 Ensure that the admission control plugin AlwaysAdmit is not set (Automated)
--
on the control plane node and set the --authorization-mode parameter to values other than AlwaysAllow.
One such example could be as below.
--authorization-mode=RBAC

1.2.8 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set the --authorization-mode parameter to a value that includes Node.
--authorization-mode=Node,RBAC

1.2.9 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set the --authorization-mode parameter to a value that includes RBAC,
for example `--authorization-mode=Node,RBAC`.

上面的kube-bench给出了这些项的修复建议,和我们上面修复的命令是一样的。

1.2 kubelet 部分

再看第二部分,关于kubelet的不安全项的修复。涉及两个参数。

使用Kube-bench查看修复建议,因为kubelet是属于node服务,所以targets要指定为node。

#./kube-bench  run --targets=node --config-dir=/app/cfg
...
4.2.1 If using a Kubelet config file, edit the file to set `authentication: anonymous: enabled` to
`false`.
If using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
`--anonymous-auth=false`
Based on your system, restart the kubelet service. For example,
systemctl daemon-reload
systemctl restart kubelet.service

4.2.2 If using a Kubelet config file, edit the file to set `authorization.mode` to Webhook. If
using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_AUTHZ_ARGS variable.
--authorization-mode=Webhook
Based on your system, restart the kubelet service. For example,
systemctl daemon-reload
systemctl restart kubelet.service

上面的修复建议不太准确了,就我使用的1.22版本,已经不是在这个配置里面配置了。而是放到一个config文件里,这个config文件可以从上面建议的这个配置里找到:

# cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
......

就是/var/lib/kubelet/config.yaml 这个文件。内容比较长,下面只列出需要修改的部分内容,修改前最好备份一下。

# cp /var/lib/kubelet/config.yaml ~/bak1/
#vi /var/lib/kubelet/config.yaml
...
authentication:
  anonymous:
    enabled: false   ## 这里如果是true,则要修改为falas,表示禁止匿名用户登录。
  webhook:
    cacheTTL: 0s
    enabled: true   ## 这里正常是true的,一般不用改,但如果是false,则需要修改成true,表示启用webhook认证
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
  mode: Webhook    ## 认证模式,如果是AlwaysAllow需要修改成 Webhook ,注意大小写。
  webhook:
    cacheAuthorizedTTL: 0s
    cacheUnauthorizedTTL: 0s
...

1.3 etcd 部分

最后一部分是关于etcd的,-client-cert-auth 这个参数,也用kube-bench来看看修复建议,注意targets需要改成etcd

# ./kube-bench run --targets=etcd --config-dir=/app/cfg
...
2.2 Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master
node and set the below parameter.
--client-cert-auth="true"

可以看到需要修改/etc/kubernetes/manifests/etcd.yaml里的参数。

#vi  /etc/kubernetes/manifests/etcd.yaml
...
    - --client-cert-auth=true  ## 把这个参数修改成true

1.4 使修改生效

上面只是说明了如何修复配置文件,但是修改后我们还需要让其生效才行。上面三种情况的生效方式都是一样的,如下

# systemctl daemon-reload 
# systemctl restart kubelet

考试时可以都修改完后再重启,重启完kubelet服务后,我们要检查下集群的node状态和pod等状态是否正常。

另外,可以使用kube-bench再次检查下那些问题项是否都已经变成了PASS

2、 Pod指定 ServiceSAccount

Context
您组织的安全策略包括:
- ServiceAccount 不得自动挂载 API 凭据
- ServiceAccount 名称必须以“-sa”结尾
清单文件 /cks/sa/pod1.yaml 中指定的 Pod 由于 ServiceAccount 指定错误而无法调度
请完成以下项目:
Task
1. 在现有 namespace qa 中创建一个名为 backend-sa 的新 ServiceAccount,确保此 ServiceAccount 不自动挂载API 凭据。
2. 使用 /cks/sa/pod1.yaml 中的清单文件来创建一个 Pod。
3. 最后,清理 namespace qa 中任何未使用的 ServiceAccount。

/cks/sa/pod1.yaml 内容如下:

apiversion: V1
kind: Pod
metadata:
  name: backend
  namespace: qa
spec:
  serviceAccountName: test01
  containers:
  - image: nginx:1.9
    imagePullPolicy: IfNotPresent
    name: backend

2.1 创建符合要求的sa账号

这里考点是ServiceAccount 不自动挂载API 凭据。我们可以通过官方文档搜索serviceaccount找到ServiceAccount的介绍文档,里面有下面这个参数的介绍。

automountServiceAccountToken (boolean)

AutomountServiceAccountToken 指示作为此服务帐户运行的 Pod 是否应自动挂载 API 令牌, 可以在 Pod 级别覆盖。

这个参数就是控制sa账号是否为pod自动挂载API令牌。题目要求的是不自动挂载,所以应该设置为 false

# kubectl -n qa create sa backend-sa
# kubectl -n qa edit sa backend-sa 
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: false  ## 增加这一个参数,并且值设置为false
metadata:
...

这个参数如果你不记得怎么写,可以这样查到

# kubectl explain serviceaccount |grep auto
   automountServiceAccountToken <boolean>

2.2 使用给定的yaml文件创建pod

需要先修改yaml文件,主要有两点需要注意:

  1. 确保命名空间是qa
  2. serviceAccountName 的值修改为 backend-sa
# vi /cks/sa/pod1.yaml
metadata:
  name: backend
  namespace: qa  ## 确认命名空间正确
spec:
  serviceAccountName: backend-sa  ## 修改为backend-sa这个账号
# kubectl apply -f /cks/sa/pod1.yaml  ## 修改完记得创建

2.3 清理未使用的sa账号

我们需要先找到已使用的sa账号,然后就可以把qa空间下未使用的sa删除

#kubectl get pod -n qa -o yaml|grep -i serviceaccountname
#kubectl get sa -n qa
#kubectl -n qa delete sa test01

3、网络策略(一)

Context
一个默认拒绝 (default-deny)的 NetworkPolicy 可避免在未定义任何其他 NetworkPoliy 的 namespace 中意外公开 Pod。

Task
为所有类型为 ingress+Egress 的流量在 namespace testing 中创建一个名为 denypolicy 的新默认拒绝 NetworkPolicy.
此新的 NetworkPolicy 必须拒绝 namespace testing 中的所有的 Ingress + Egress 流量
将新创建的默认拒绝NetworkPolicy 应用与在namespace testing 中运行的所有 Pod。

你可以在 /cks/net/p1.yaml 找到一个模板清单文件.

这里主要考对网络策略的理解。

3.1 创建符合要求的 NetworkPolicy

分析题目要求,可以找到这个网络策略的核心是拒绝 namespace testing 中的所有的 Ingress + Egress 流量。题目给出的模板文件很少内容,基本没啥用,所以我们最好去官网查看文档。

在官方文档搜索NetworkPolicy 第一个结果就是(按自己实际情况哈)。然后右侧的标题栏可以找到默认拒绝所有入站和出站流量,点击就可以得到下面的模板

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

跟题目要求的还差一个条件,就是需要指定 namespace 为 testing 的才拒绝。当然,名字也要修改成题目要求的,最终的yaml文件如下

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: denypolicy
  namesapce: testing
spec:
  podSelector: {}
  policyTypes:
  - Ingress   ## 注意,我考试时碰到的是只要求拒绝Egress流量,所以这行是要删除。每次考试可能要求的不一样,要注意应对。
  - Egress

yaml文件没问题后我们就创建,并检查

#kubectl apply -f denypolicy.yaml
#kubectl describe NetworkPolicy -n testing

3.2 应用 NetworkPolicy 到 pod

这里的 NetworkPolicy 是针对整个 testing 空间的,所以testing空间下的pod默认就会应用这个策略。不需要再额外的配置了,也不需要重启pod。 但是如果题目要求是针对一些特定的label的pod,那就需要给pod加上相应的标签才能应用上策略了。

4、RBAC

Context
绑定到 Pod的 ServiceAocount 的 Role 授予过度宽松的权限,完成以下项目以减少权限集。
Task
一个名为 web-pod 的现有 Pod 已在 namespace db 中运行。
编辑绑定到 Pod 的 ServiceAccount service-account-web 的现有 Role,仅允许只对 services 类型的资源执行get操作。
在namespace db 中创建一个名为 role-2 ,并仅允许只对 namespaces 类型的资源执行 delete 操作的新 Role。
创建一个名为 role-2-binding 的新 RoleBinding.将新创建的 Role 绑定到 Pod 的 ServiceAccount。
注意:请勿删除现有的 RoleBinding。

这题考察我们对RBAC的理解。

4.1 编辑现有role使其符合规定

题目里已经给出sa名称了,并且其是绑定到 namespace db中的,所以我们可以查看db中的rolebinding来找到该sa对应的rolebinding。

#k describe rolebindings -n db
...
Role:
  Kind:  Role
  Name:  role-1
Subjects:
  Kind            Name                 Namespace
  ----            ----                 ---------
  ServiceAccount  service-account-web  db

找到对应的role为 role-1 ,然后就可以编辑其权限以符合要求了。

# kubectl edit role role-1 -n db
...
rules:
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get

确认resources只有services,verbs只有get。

正式考试时rules是空的,我们可以使用官网给出的案例来进行修改

rules:
- apiGroups: [""] # "" 标明 core API 组
  resources: ["services"]
  verbs: ["get"]

4.2、创建符合要求的role和rolebinding

可以直接使用命令行创建,当然也可以使用yaml文件创建。这里我们直接使用命令创建。

# kubectl create role role-2 --verb=delete --resource=namespaces -n db
role.rbac.authorization.k8s.io/role-2 created
# kubectl create rolebinding role-2-binding --serviceaccount=db:service-account-web --role=role-2 -n db
rolebinding.rbac.authorization.k8s.io/role-2-binding created

做完有时间可以检查下是否正确

# kubectl describe rolebindings.rbac.authorization.k8s.io role-2-binding -n db
Name:         role-2-binding
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  role-2
Subjects:
  Kind            Name                 Namespace
  ----            ----                 ---------
  ServiceAccount  service-account-web  db