一、kube-bench 修复不安全项
Context
针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时,发现了多个必须立即解决的问题。
Task
通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效。
修复针对 API 服务器发现的所有以下违规行为:
- 1.2.7 Ensure 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
- 1.2.18 Ensure that the --insecure-bind-address argument is not set FAIL (v1.28 考题中这项没给出,但最好也检查一下,模拟环境是里需要改的)
修复针对 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
修改apiserver配置
vim kube-apiserver.yaml
修改kubelet配置
vim /var/lib/kubelet/config.yaml
修改etcd配置
cp /etc/kubernetes/manifests/etcd.yaml /tmp
vim /etc/kubernetes/manifests/etcd.yaml
修改
- --client-cert-auth=true #修改为 true
#编辑完后重新加载配置文件,并重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
五、日志审计(12分)
创建yaml
apiVersion: audit.k8s.io/v1 # 这是必填项。
kind: Policy
# 不要在 RequestReceived 阶段为任何请求生成审计事件。
omitStages:
- "RequestReceived"
rules:
# 在日志中用 RequestResponse 级别记录 Pod 变化。
- level: RequestResponse
resources:
- group: ""
resources: ["persistentvolumes"]
- level: Request
resources:
- group: ""
resources: ["configmaps"]
namespaces: ["front-apps"]
# 在日志中按 Metadata 级别记录 "pods/log"、"pods/status" 请求
- level: Metadata
resources:
- group: ""
resources: ["configmaps", "secret"]
- level: Metadata
omitStages:
- "RequestReceived"
编辑apiserver的配置文件
- –audit-log-maxbackup=2 #定义要保留的审计日志文件的最大数量为 2 个
- –audit-log-maxage=10 # 日志文件的最大天数为 10 天
- –audit-policy-file=/etc/kubernetes/audit-policy.yaml #定义审计策略 yaml 文件位置,通过 hostpath 挂载
- –audit-log-path=/var/log/kubernetes/audit/audit.log
挂载数据卷
...
volumeMounts:
- mountPath: /etc/kubernetes/audit-policy.yaml
name: audit
readOnly: true
- mountPath: /var/log/kubernetes/audit/
name: audit-log
readOnly: false
...
volumes:
- name: audit
hostPath:
path: /etc/kubernetes/audit-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/kubernetes/audit/
type: DirectoryOrCreate
八、沙箱运行容器 gVisor
Context
该 cluster 使用 containerd 作为 CRI 运行时。containerd 的默认运行时处理程序是 runc。
containerd 已准备好支持额外的运行时处理程序 runsc (gVisor)。
Task
使用名为 runsc 的现有运行时处理程序,创建一个名为 untrusted 的 RuntimeClass。
更新 namespace server 中的所有 Pod 以在 gVisor 上运行。
创建runtimeclass
# RuntimeClass 定义于 node.k8s.io API 组
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# 用来引用 RuntimeClass 的名字
# RuntimeClass 是一个集群层面的资源
name: untrusted
# 对应的 CRI 配置的名称
handler: runsc
先全文搜索一下(输入上面 edit 后,用/ runtimeClassName 来搜索),有没有 runtimeClassName 字段,没有的话,就添加。如果有的话,且是在 spec:下一层,
则修改 runtimeClassName 字段。
修改如下内容
spec: #找到这个 spec,注意在 deployment 里是有两个单独行的 spec 的,要找第二个,也就是下面有 containers 这个字段的 spec。
runtimeClassName: untrusted #添加这一行,注意空格对齐,保存会报错,忽略即可。
containers:
- image: nginx:1.9
imagePullPolicy: IfNotPresent
name: run-test
九、 网络策略
Context
一个默认拒绝(default-deny)的 NetworkPolicy 可避免在未定义任何其他 NetworkPolicy 的 namespace 中意外公开 Pod。
Task
为所有类型为 Ingress+Egress 的流量在 namespace testing 中创建一个名为 denypolicy 的新默认拒绝 NetworkPolicy。
此新的 NetworkPolicy 必须拒绝 namespace testing 中的所有的 Ingress + Egress 流量。
将新创建的默认拒绝 NetworkPolicy 应用与在 namespace testing 中运行的所有 Pod。
你可以在 /cks/net/p1.yaml 找到一个模板清单文件。
创建yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: policy-demo
namespace: testing
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
十一、AppArmor
APPArmor 已在 cluster 的工作节点 node02 上被启用。一个 APPArmor 配置文件已存在,但尚未被实施。
Task
在 cluster 的工作节点 node02 上,实施位于 /etc/apparmor.d/nginx_apparmor 的现有 APPArmor 配置文件。
编辑位于 /cks/KSSH00401/nginx-deploy.yaml 的现有清单文件以应用 AppArmor 配置文件。
最后,应用清单文件并创建其中指定的 Pod 。
查看文件
controlplane $ cat /etc/apparmor.d/nginx_apparmor
#include <tunables/global>
profile nginx-profile3 flags=(attach_disconnected) {
#include <abstractions/base>
file,
deny /** w,
}
加载文件
注意:事先不知道pod会在哪个节点,所以需要再每个节点都加载profile
apparmor_parser /etc/apparmor.d/nginx_apparmor
controlplane $ apparmor_status | grep nginx
nginx-profile3
修改pod模板
使用刚才启用的apparmor profile
apiVersion: v1
kind: Pod
metadata:
name: hello-apparmor
annotations:
container.apparmor.security.beta.kubernetes.io/hello: localhost/nginx-profile3
spec:
containers:
- name: hello
image: busybox:1.28
command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
验证
controlplane $ kubectl exec hello-apparmor -- cat /proc/1/attr/current
nginx-profile3 (enforce)
controlplane $ kubectl exec hello-apparmor -- touch /tmp/test
touch: /tmp/test: Permission denied
command terminated with exit code 1
十三、 Container安全上下文
Context
Container Security Context 应在特定 namespace 中修改 Deployment。
Task
按照如下要求修改 sec-ns 命名空间里的 Deployment secdep
一、用 ID 为 30000 的用户启动容器(设置用户 ID 为: 30000)
二、不允许进程获得超出其父进程的特权(禁止 allowPrivilegeEscalation)
三、以只读方式加载容器的根文件系统(对根文件的只读权限)
以Nginx为例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-demo
namespace: default
spec:
replicas: 1
selector:
matchLabels:
region: k8s2
template:
metadata:
labels:
region: k8s2
spec:
securityContext:
runAsUser: 30000
containers:
- image: nginx:latest
imagePullPolicy: IfNotPresent
name: nginx-demo
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
serviceAccount: default
serviceAccountName: default