M系列MacBook连接l2tp时失败的问题修复

  1. 启用基于预共享秘钥的l2tp连接功能

    1
    2
    3
    4
    5
    #!/bin/sh
    [ -d /etc/ppp ] || mkdir /etc/ppp
    echo '''plugin L2TP.ppp
    l2tpnoipsec''' > /etc/ppp/options
    chmod 777 /etc/ppp/options
  2. 解决连接lt2p后能ping但是所有端口都无法访问的问题,关闭网络checksum功能。ip-up是会在lt2p连接建立时自动运行的脚本

    1
    2
    3
    4
    echo '''#!/bin/sh
    /usr/sbin/sysctl net.link.generic.system.hwcksum_tx=0
    /usr/sbin/sysctl net.link.generic.system.hwcksum_rx=0''' > /etc/ppp/ip-up
    chmod 755 /etc/ppp/ip-up
  3. 在断开l2tp连接后会将相关配置还原为系统默认。ip-down是会在l2tp连接断开时自动运行的脚本

    1
    2
    3
    4
    echo '''#!/bin/sh
    /usr/sbin/sysctl net.link.generic.system.hwcksum_tx=1
    /usr/sbin/sysctl net.link.generic.system.hwcksum_rx=1''' > /etc/ppp/ip-down
    chmod 755 /etc/ppp/ip-down

Rust学习笔记

学习资料

📚书单

GZtZbEGZtZbE

官方资料

其他

安装

1
2
curl  https://sh.rustup.rs -sSf | sh
rustc

Hello World

Tab:用4个空格替换;

分号:可要可不要,但 Rust 风格是需要;

代码文件命名:用下划线分割不同单词;

1
2
3
fn main() {
println!("hello world!")
}

编译与运行

1
2
rustc main.rs
./main

cargo

使用cargo比rustc的优势

  • 依赖管理
  • 编译大型项目

常用命令

  • cargo new
  • cargo build
  • cargo run
  • cargo check

Calico证书学习笔记

准备工作

安装测试集群

1
2
3
4
curl https://raw.githubusercontent.com/tigera/ccol1/main/control-init.yaml | multipass launch -n control -m 2048M 20.04 --cloud-init -
curl https://raw.githubusercontent.com/tigera/ccol1/main/node1-init.yaml | multipass launch -n node1 20.04 --cloud-init -
curl https://raw.githubusercontent.com/tigera/ccol1/main/node2-init.yaml | multipass launch -n node2 20.04 --cloud-init -
curl https://raw.githubusercontent.com/tigera/ccol1/main/host1-init.yaml | multipass launch -n host1 20.04 --cloud-init -

calico 的四种安装方式

  • Manifest
  • Operator
  • Managed Kubernetes Service(EKS、GKE、AKS)
  • Kubernetes Distro(MicroK8s)

以Operator的方式来安装calico

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
multipass shell host1
kubectl create -f https://docs.projectcalico.org/archive/v3.21/manifests/tigera-operator.yaml
cat <<EOF | kubectl apply -f -
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
containerIPForwarding: Enabled
ipPools:
- cidr: 198.19.16.0/21
natOutgoing: Enabled
encapsulation: None
EOF

安装测试所需的模拟业务

1
2
multipass shell host1
kubectl apply -f https://raw.githubusercontent.com/tigera/ccol1/main/yaobank.yaml

网络策略

原生网络策略

  • 要想 NetworkPolicy 生效,必须使用实现了此的 CNI 插件,如 calico。
  • ingress 进 pod 流量 默认全部打开,当被应用规则后,pod 所在 node 上、ingress 规则列表中允许的流量可以进入 pod;
  • egress 出 pod 流量,默认全部可以出,当被应用规则后,只有规则中允许的流量可以出 pod;
  • 白名单机制,即在 rules 中配置了,才能通行(包括进和出),规则可以叠加,但能做到只要配置了就能通行;

默认配置

  • 命名空间中没有 policy 时,全部开放;

  • 拒绝/允许所有流量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: default-deny-all
    spec:
    podSelector: {}
    policyTypes:
    - Ingress
    - Egress
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: allow-all-ingress
    spec:
    podSelector: {}
    ingress:
    - {}
    policyTypes:
    - Ingress
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: default-deny-egress
    spec:
    podSelector: {}
    policyTypes:
    - Egress
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: allow-all-egress
    spec:
    podSelector: {}
    egress:
    - {}
    policyTypes:
    - Egress

选择流量的3种方式

  • podSelector
  • namespaceSelector
  • ipBlock

DNS 记录

  • Service
    • shs-8080.tcp.shs-svc.default.svc.cluster.local
    • shs-svc.default.svc.cluster.local
  • Pod
    • 10-244-0-8.default.pod.cluster.local

Calico Network Policy

比原生网络策略的优势

  1. 原生策略为白名单机制,即只有 allow 这一个动作,calico 还有 deny,log 等操作。
  2. 原生策略资源是ns级别的,calico 即支持ns级别、也支持cluster级别。

CKS证书学习资料汇编

真题①基于1.22版本

前言

CKA 和 CKS 是 LINUX 基金会联合 CNCF社区组织的云原生技术领域权威认证,考试采用实操方式进行。CKS全称是Kubernetes安全专家认证,它在一个模拟真实的环境中测试考生对Kubernetes和云安全的知识。在参加CKS考试之前,必须已经通过CKA(Kubernetes管理员认证),在获得CKA认证之后才可以预约CKS考试。CKS 的考试难度相对于 CKA 提高了很多,2个小时的考试时间很紧张,因为考试是在外网上进行,这两个考试又是实操考试,网络条件不好,很影响效率,如果不抓紧的话,很可能做不完所有实操题。提醒备考的同学善用考试软件提供的 notepad 功能,先把 yaml 文件或命令写到notepad里,再粘贴到 terminal里。

我因为上次 CKA 考试还是比较顺利,94 高分通过,所以这次的 CKS 考试有点疏忽了,搞忘带身份证和护照,CKA/CKS 考试需要身份证+护照/信用卡,因此跟监考老师沟通了很久时间,最后修改了考试人姓名为中文,是用驾驶证完成的考试。意外之喜是 CKS 给我的证书是中文名的。

我这次考试的 kubernetes 版本是 1.22,特意记录了一下考试会考到的知识点,分享给需要的同学。

1. NetworkPolicy

通常使用标签选择器来选择pod,控制流量。所以要对 kubectl label的使用方法熟悉起来。

1
2
kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N 
[--resource-version=version] [options]

网络策略的实用方法见注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
# podSelector: {} 表示选择所有 pod 应用 NetworkPolicy
podSelector: # 表示选择包含标签 role=db 的 pod 应用下面的 NetworkPolicy
matchLabels:
role: db
policyTypes: # 表示 NetworkPolicy 包含 ingress 和 egress 流量规则
- Ingress
- Egress
ingress: # ingress 规则白名单列表,每条规则允许同时匹配 from 和 ports 流,可以有条个规则。
# 第1条白名单,允许以下pod访问(限 tcp 6379 端口),包含
# 1. from + ports 的组合规则,允许来自172.17网段(172.17.1除外);
# 2. 标签 project=myproject 的命名空间的所有 pod;
# 3. default 命名空间下标签 role=frontend 的 pod;
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
# 第二条白名单,只包含 from 规则,允许
# 1. 来自所有命名空间包含 environment=testing 标签的 pod 访问(不限端口)
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
environment: testing
egress: # egress 规则白名单列表,同 ingress 规则一样,每条规则包含 to+ports,可以有多条规则。
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978

2. Apparmor

查看当前节点加载的 apparmor profile ,如果没有加载,要手工加载

1
2
apparmor_status | grep nginx
apparmor_parser /etc/apparmor.d/nginx_apparmor

cks 考试的 apparmor profile 文件内容:

1
2
3
4
5
6
7
8
#include <tunables/global>
#nginx-profile-3
profile nginx-profile-3 flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}

注意: nginx-profile-3 这一行要确保注释掉,考试环境提供的可能没有注释,加载配置文件按时会报错

1
2
root@node01:~# apparmor_parser /etc/apparmor.d/nginx_apparmor
AppArmor parser error for /etc/apparmor.d/nginx_apparmor in /etc/apparmor.d/ninx_apparmor at line 2: Found unexpected character: '-'

修改 pod yaml 文件,在注释里设置为 podx 加载 apparmor profile

1
2
annotations:
container.apparmor.security.beta.kubernetes.io/podx: localhost/nginx-profile-3

yaml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: podx
annotations:
container.apparmor.security.beta.kubernetes.io/podx: localhost/nginx-profile-3
spec:
containers:
- image: busybox
imagePullPolicy: IfNotPresent
name: podx
command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
resources: {}
nodeName: node01
dnsPolicy: ClusterFirst
restartPolicy: Always

3. 修复kube-bench发现的安全问题

kube-bench 是一个 CIS 评估工具,扫描 kubernetes 集群存在的安全问题,基本上按照 扫描结果的修复建议进行修复就可以了,系统会给出很具体的修复措施。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 修复 kube-apiserver 安全问题
vi /etc/kubernetes/manifests/kube-apiserver
#修改:
--authorization-mode=Node,RBAC
#添加
--insecure-port=0
#删除
# --insecure-bind-address=0.0.0.0

#修复 kubelet 安全问题
vi /var/lib/kubelet/config.yaml
# 将authentication.anonymous.enabled 设置为 false
authentication:
anonymous:
enabled: false
# authorization.mode 设置为 Webhook
authorization:
mode: Webhook

# 修复 etcd 安全问题
vi /etc/kubernetes/manifests/etcd.yaml
# 修改为true:
- --client-cert-auth=true

# 以上修复完成后 重新加载配置文件并重启kubelet

systemctl daemon-reload
systemctl restart kubelet

4. 解决 pod 的 serviceaccount 设置错误问题

这个题要注意 serviceaccount 有个选项 automountServiceAccountToken, 这个选项决定是否自动挂载 secret 到 pod。
有这个选项,我们可以控制 pod 创建并绑定 serviceaccount 时,不自动挂载对应的 secret,这样 pod 就没有权限访问 apiserver,提高了业务 pod 的安全性。

可以在 serviceaccount 和 pod 的 spec 里设置,pod的设置优先于 serviceaccount 里的设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend-sa
namespace: qa
automountServiceAccountToken: false
apiVersion: v1
kind: Pod
metadata:
name: backend
namespace: qa
spec:
serviceAccountName: backend-sa
containers:
- image: nginx:1.9
imagePullPolicy: IfNotPresent
name: backend

删除未使用的 serviceaccount

5. 设置默认网络策略

这道题是送分题,设置默认拒绝所有出站和入站的 pod 流量,基本上可以参考官网的案例直接改一下名字就可以了
默认网络策略

6. RBAC

这道题也基本是送分题,参考官网文档,根据题目要求,设置 role 的 资源访问权限,绑定到 serviceaccount 就可以了。
RBAC

7. 日志审计

这道题稍复杂,需要按照要求启动日志审计,包括两个步骤:
(1) 编写日志审计策略文件
日志审计策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- "RequestReceived"
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["namespaces"]

- level: Request
resources:
- group: ""
resources: ["persistentvolumes"]
namespaces: ["front-apps"]

- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]

- level: Metadata
omitStages:
- "RequestReceived"

(2) 修改 kube-apiserver.yaml配置文件,启用日志审计策略,日志策略配置文件位置、日志文件存储位置、循环周期。
启动日志配置

vi /etc/kubernetes/manifests/kube-apiserver.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 设置日志审计策略文件在 pod 里的 mount 位置
- --audit-policy-file=/etc/kubernetes/logpolicy/sample-policy.yaml

# 设置日志文件存储位置
- --audit-log-path=/var/log/kubernetes/audit-logs.txt

# 设置日志文件循环
- --audit-log-maxage=10
- --audit-log-maxbackup=2

# mount 日志策略和日志文件的
volumeMounts:
- mountPath: /etc/kubernetes/logpolicy/sample-policy.yaml
name: audit
readOnly: true
- mountPath: /var/log/kubernetes/audit-logs.txt
name: audit-log
readOnly: false
volumes:
- name: audit
hostPath:
path: /etc/kubernetes/logpolicy/sample-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/kubernetes/audit-logs.txt
type: FileOrCreate

重启 kubelet

1
2
systemctl daemon-reload
systemctl restart kubelet

8. 创建 secret

这道题考解码 secret 的 base64 编码信息,创建新的 secret 并 mount 到 pod 的特定位置。
解码 secret

1
2
kubectl get secrets -n istio-system db1-test -o jsonpath={.data.username} | base64 -d >  /cks/sec/user.txt
kubectl get secrets -n istio-system db1-test -o jsonpath={.data.password} | base64 -d > /cks/sec/pass.txt

创建secret

1
kubectl create secret generic db2-test -n istio-system --from-literal=username=production-instance --from-literal=password=KvLftKgs4aVH

使用secret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
namespace: istio-system
spec:
containers:
- name: dev-container
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
volumes:
- name:
secret:
secretName: db2-test

9. 检测 dockerfile 的不安全指令

这道题也是送分题,主要是把 dockerfile里两个 使用了 root 用户的指令删除,把添加特定能力的 securityContext 安全上下文注释掉。

1
2
3
4
5
6
# 删除两处
USER root

# 注释 securityContext
# securityContext:
# {"Capabilities": {'add':{NET_BIND_SERVICE}, 'drop: []'}, 'privileged': TRUE}

10. 运行沙箱容器

给出了 支持安全沙箱容器运行时 handler runsc, 我们需要创建一个 RuntimeClass 并在 pod spec里指定是用该 RuntimeClass
参考资料

  • 创建 RuntimeClass
1
2
3
4
5
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
name: untrusted
handler: runsc
  • 修改 server 命名空间 所有 pod,设置 runtimeClassName
1
2
3
4
5
6
7
8
注意:运行中的 pod 只能修改有限的几个属性,不支持修改 RuntimeClass,需要将所有 pod 的 yaml 解析出来,修改 yaml 后,再重新创建 pod
还需要修改deployment
spec:。
runtimeClassName: untrusted
containers:
- image: vicuu/nginx:host
imagePullPolicy: IfNotPresent
name: nginx-host

11. 删除 不符合最佳实践的 pod

参考链接

  • 删除启用了特权的 pod
    主要是检查 pod 是否含 privileged: true
    kubectl get po xxx -n production -o yaml| grep -i “privileged: true”
  • 删除有状态 pod
    kubectl get pods XXXX -n production -o jsonpath={.spec.volumes} | jq

12. 扫描镜像安全漏洞并删除使用有安全漏洞镜像的pod

这道题考察对于镜像扫描工具 trivy 的使用

1
2
3
4
5
# 获取镜像名
kubect get pod XXXX -n kamino -o yaml | grep image
# 扫描镜像
trivy image -s HIGH,CRITICAL imagename
# kubectl delete po xxx

13. 使用 sysdig 检查容器里里的异常进程

本体考察是否掌握 sysdig 的基本用法,记住两个帮助命令:

  • sysdig -h 查看 sysdig 帮助
  • sysdig -l 查看 sysdig 支持的元数据

另外 sysdig 支持指定 containerid 分析特定容器

1
2
3
# 查看容器id
docker ps |grep tomcat
sysdig -M 30 -p "*%evt.time,%user.uid,%proc.name" container.id=xxxx>opt/DFA/incidents/summary

14. PodSecurityPolicy

这道题考察是否掌握 psp 的用法,包括5步骤
(1) 创建 psp
参考链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-policy
spec:
privileged: false
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'

(2) 创建 clusterrole,使用 psp

1
kubectl create clusterrole restrict-access-role --verb=use --resource=psp --resource-name=restrict-policy

(3) 创建 serviceaccount

1
kubectl create sa psp-denial-sa -n staging

(4) 绑定 clusterrole 到 serviceaccount

1
kubectl create clusterrolebinding dany-access-bind --clusterrole=restrict-access-role --serviceaccount=staging:psp-denial-sa

(5) 启用 PodSecurityPolicy

1
2
3
vi /etc/kubernetes/manifests/kube-apiserver.yaml 
#确保有以下内容:
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy

15. 启用 API server认证

这道题同前面 kube-bench 的考核内容有点重合,题目中是用 kubeamd创建的 kubernetes服务器权限设置有问题,允许未经授权的访问。
参考链接
需要进行以下修改:

  • 使用 Node,RBAC 授权模式和 NodeRestriction 准入控制器
1
2
3
4
5
6
vi /etc/kubernetes/manifests/kube-apiserver.yaml
# 确保以下内容
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=NodeRestriction
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-bootstrap-token-auth=true
  • 删除 system:anonymous 的 ClusterRolebinding角色绑定,取消匿名用户的集群管理员权限
1
kubectl delete clusterrolebinding system:anonymous

16. ImagePolicyWebhook

这道题考察 ImagePolicyWebhook 准入控制器的使用,分4个步骤

  • 修改控制器配置文件,将未找到有效后端时的默认拒绝改为默认不拒绝
    参考链接

vi /etc/kubernetes/epconfig/admission_configuration.json

1
2
3
4
5
6
7
8
9
10
{

"imagePolicy": {
"kubeConfigFile": "/etc/kubernetes/epconfig/kubeconfig.yaml",
"allowTTL": 50,
"denyTTL": 50,
"retryBackoff": 500,
"defaultAllow": false
}
}
  • 修改 控制器访问 webhook server 的 kubeconfig
1
2
3
4
5
6
7
8
9
10
11
12
vi /etc/kubernetes/epconfig/kubeconfig.yaml

修改如下内容

apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /etc/kubernetes/epconfig/webhook.pem
server: https://acme.local:8082/image_policy # web hook server 的地址
name: bouncer_webhook
# 以下省略
  • 启用ImagePolicyWebhook
    vi /etc/kubernetes/manifests/kube-apiserver.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
# 启用 ImagePolicyWebhook
- --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook
# 指定准入控制器配置文件
- --admission-control-config-file=/etc/kubernetes/epconfig/admission_configuration.json
# mount
volumeMounts:
- mountPath: /etc/kubernetes/epconfig
name: epconfig
# 映射 volumes
volumes:
- name: epconfig
hostPath:
path: /etc/kubernetes/epconfig
  • 测试是否生效
1
2
3
systemctl daemon-reload
systemctl restart kubelet
kubectl apply -f /cks/img/web1.yaml

From: 2022年2月我的CKS备考记录 - scwang18 - 博客园 (cnblogs.com)


真题②基于1.26版本

考试内容

CKS 考试链接
Important Instructions: CKS

  • 考试包括 15-20 项performance-based tasks。
    • 2023.1 实测是16道题
  • 考生有 2 小时的时间完成 CKS 考试。
    • 因为从06/2022开始环境升级(贬义),考试环境更难用了,变的很卡,所以时间变得比较紧张。容易做不完题,建议先把有把握的,花费时间不多的题先做掉
  • CKS考试67分以上即可通过,考试不通过有一次补考机会。

Certifications- expire 36 months from the date that the Program certification requirements are met by a candidate.

Certified Kubernetes Security Specialist (CKS)

The following tools and resources are allowed during the exam as long as they are used by candidates to work independently on exam tasks (i.e. not used for 3rd party assistance or research) and are accessed from within the Linux server terminal on which the Exam is delivered.
During the exam, candidates may:

You’re only allowed to have one other browser tab open with:

CKS Environment

  • Each task on this exam must be completed on a designated cluster/configuration context.
  • Sixteen clusters comprise the exam environment, one for each task. Each cluster is made up of one master node and one worker node.
  • An infobox at the start of each task provides you with the cluster name/context and the hostname of the master and worker node.
  • You can switch the cluster/configuration context using a command such as the following:
  • kubectl config use-context <cluster/context name>
  • Nodes making up each cluster can be reached via ssh, using a command such as the following:
  • ssh <nodename>
  • You have elevated privileges on any node by default, so there is no need to assume elevated privileges.
  • You must return to the base node (hostname cli) after completing each task.
  • Nested −ssh is not supported.
  • You can use kubectl and the appropriate context to work on any cluster from the base node. When connected to a cluster member via ssh, you will only be able to work on that particular cluster via kubectl.
  • For your convenience, all environments, in other words, the base system and the cluster nodes, have the following additional command-line tools pre-installed and pre-configured:
    • kubectl with kalias and Bash autocompletion
    • yq and jq for YAML/JSON processing
    • tmux for terminal multiplexing
    • curl and wget for testing web services
    • man and man pages for further documentation
  • Further instructions for connecting to cluster nodes will be provided in the appropriate tasks
  • The CKS environment is currently running etcd v3.5
  • The CKS environment is currently running Kubernetes v1.26
  • The CKS exam environment will be aligned with the most recent K8s minor version within approximately 4 to 8 weeks of the K8s release date.

More items for CKS than CKA and CKAD

  • Pod Security Policies(PSP) - removed from Kubernetes in v1.25
  • AppArmor
  • Apiserver
    • Apiserver Crash
    • Apiserver NodeRestriction
  • ImagePolicyWebhook
  • kube-bench
  • Trivy

CKS 知识点&练习题总结

如何备考

k8s练习环境(同CKA)

CKS练习题

有几个练习库,建议将每个题目都自己亲自操作一遍,一定要操作。

CKS课程

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 不熟
## 输出pod status
kubectl -n default describe pod pod1 | grep -i status:
kubectl -n default get pod pod1 -o jsonpath="{.status.phase}"
## Check the pod for error
kubectl describe pod podname | grep -i error
... Error: ImagePullBackOff
## a fast way to get an overview of the ReplicaSets of a Deployment and their images could be done with:
kubectl -n neptune get rs -o wide | grep deployname
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
deployname 3 3 3 9m6s httpd httpd:alpine app=wonderful

## 创建job
kubectl -n neptune create job neb-new-job --image=busybox:1.31.0 $do > /opt/course/3/job.yaml -- sh -c "sleep 2 && echo done"
## If a Secret bolongs to a serviceaccount, it'll have the annotation kubernetes.io/service-account.name
kubectl get secrets -oyaml | grep annotations -A 1 # shows secrets with first annotation
## log
kubectl logs podname > /opt/test.log
## decode base64
base64 -d filename
## check service connection using a temporary Pod
## k run tmp --restart=Never --rm --image=nginx:alpine -i -- curl http://svcname.namespace:svcport
kubectl run tmp --restart=Never --rm --image=nginx:alpine -i -- curl http://svcname.namespace:80
## check that both PV and PVC have the status Bound:
k -n earth get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/earth-project-earthflower-pv 2Gi RWO Retain Bound earth/earth-project-earthflower-pvc 8m4s

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/earth-project-earthflower-pvc Bound earth-project-earthflower-pv 2Gi RWO 7m38s

## We can confirm the pod of deployment with PVC mounting correctly:
k describe pod project-earthflower-586758cc49-hb87f -n earth | grep -A2 Mount:
Mounts:
/tmp/project-data from task-pv-storage (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jj2t2 (ro)

## Verify everything using kubectl auth can-i
kubectl auth can-i create deployments --as system:serviceaccount:app-team1:cicd-token -n app-team1 # YES
# 常用
## 创建pod
kubectl run pod1 --image=httpd:2.4.41-alpine $do > 2.yaml
kubectl get pod sat-003 -o yaml > 7-sat-003.yaml # export
kubectl delete pod pod1 --force --grace-period=0
## 创建service
kubectl expose deployment d1 --name=服务名 --port=服务端口 --target-port=pod运行端口 --type=类型
kubectl expose pod pod名 --name=服务名 --port=服务端口 --target-port=pod运行端口 --type=类型
# CKS
## 创建secret
kubectl create secret generic db-credentials --from-literal db-password=passwd
## modify a pod yaml to deployment yaml
### put the Pod's metadata: and spec: into the Deployment's template: section:

## To verify that the token hasn't been mounted run the following commands:
kubectl -n one exec -it pod-name -- mount | grep serviceaccount
kubectl -n one exec -it pod-name -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

### 创建 clusterrole,使用 psp
kubectl create clusterrole restrict-access-role --verb=use --resource=psp --resource-name=restrict-policy

## after modify /etc/kubernetes/manifests/kube-apiserver.yaml
systemctl restart kubelet

### 查询 sa 对应的 role 名称(假设是 role-1)
kubectl get rolebinding -n db -oyaml | grep 'service-account-web' -B 10

### grep
grep apple -A 10 # apple之后10行

grep apple -B 10 # apple之前10行

### secret used by pod
kubectl exec pod1 -- env
kubectl exec pod1 -- cat /etc/diver/hosts

CKS 2023 真题 1.26

考题1 - AppArmor 访问控制

Context

AppArmor is enabled on the cluster’s worker node. An AppArmor profile is prepared, but not enforced yet.
You may use your browser to open one additional tab to access the AppArmor documentation.

AppArmor 已在 cluster 的工作节点上被启用。一个 AppArmor 配置文件已存在,但尚未被实施。

Task

On the cluster’s worker node, enforce the prepared AppArmor profile located at /etc/apparmor.d/nginx_apparmor .
Edit the prepared manifest file located at /home/candidate/KSSH00401/nginx-deploy.yaml to apply the AppArmor profile.
Finally, apply the manifest file and create the pod specified in it.

在 cluster 的工作节点上,实施位于 /etc/apparmor.d/nginx_apparmor 的现有 AppArmor 配置文件。
编辑位于 /home/candidate/KSSH00401/nginx-deploy.yaml 的现有清单文件以应用 AppArmor 配置文件。
最后,应用清单文件并创建其中指定的 Pod 。

Solution

搜索 apparmor(使用 AppArmor 限制容器对资源的访问),接着再搜索字符串 “parser”
https://kubernetes.io/zh/docs/tutorials/security/apparmor/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
### 远程登录到指定工作节点
ssh cka-node01

### 从profile文件查看策略名称
cat /etc/apparmor.d/nginx_apparmor

profile nginx-profile flags=(attach_disconnected) {
...

### 加载 apparmor 配置文件
apparmor_parser /etc/apparmor.d/nginx_apparmor

### 查看策略名称,结果是 nginx-profile
apparmor_status | grep nginx-profile

### 回到控制节点,并更新 Pod 的注解
exit

vim /home/candidate/KSSH00401/nginx-deploy.yaml
annotations:
### hello 是 Pod 里容器名称,nginx-profile 则是 apparmor_status 解析出来的结果
container.apparmor.security.beta.kubernetes.io/hello: localhost/nginx-profile

### 如果 apply 后报错,则先删除保存并删除旧 Pod,改完后再创建新的
kubectl apply -f /home/candidate/KSSH00401/nginx-deploy.yaml

考题2 - Kube-Bench 基准测试

Context

A CIS Benchmark tool was run against the kubeadm-created cluster and found multiple issues that must be addressed immediately.

针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时, 发现了多个必须立即解决的问题。

Task

Fix all issues via configuration and restart theaffected components to ensure the new settings take effect.
通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效。

Fix all of the following violations that were found against the API server:
修复针对 API 服务器发现的所有以下违规行为:
Ensure that the 1.2.7 –authorization-mode FAIL argument is not set to AlwaysAllow
Ensure that the 1.2.8 –authorization-mode FAIL argument includes Node
Ensure that the 1.2.9 –authorization-mode FAIL argument includes RBAC
Ensure that the 1.2.18 –insecure-bind-address FAIL argument is not set
Ensure that the 1.2.19 –insecure-port FAIL argument is set to 0

Fix all of the following violations that were found against the kubelet:
修复针对 kubelet 发现的所有以下违规行为:
Ensure that the 4.2.1 –anonymous-auth FAIL argument is set to false
Ensure that the 4.2.2 –authorization-mode FAIL argument is not set to AlwaysAllow
Use Webhook authn/authz where possible. 注意:尽可能使用 Webhook authn/authz。

Fix all of the following violations that were found against etcd:
修复针对 etcd 发现的所有以下违规行为:
Ensure that the 4.2.1 –client-cert-auth FAIL argument is set to true

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ ssh [email protected]

# kube-bench run --target=master --check=1.2.7
kube-bench run --target=master | grep FAIL

### 修复针对 APIserver 发现的以下所有问题:
### 确保 1.2.7 --authorization-mode 参数不能设置为 AlwaysAllow
### 确保 1.2.8 --authorization-mode 参数包含 Node
### 确保 1.2.9 --authorization-mode 参数包含 RBAC
### 确保 1.2.18 --insecure-bind-address 参数不能设置
### 确保 1.2.19 --insecure-port 参数设置为 0
### 注意:修改 master 节点!
vim /etc/kubernetes/manifests/kube-apiserver.yaml
#- --authorization-mode=AlwaysAllow 删除AlwaysAllow,加Node,RBAC
- --authorization-mode=Node,RBAC
#- --insecure-bind-address=0.0.0.0
- --insecure-port=0

### 修复针对 kubelet 发现的以下所有问题:
### 确保 4.2.1 anonymous-auth 参数设置为 false
### 确保 4.2.2 --authorization-mode 参数不能设置为 AlwaysAllow,尽可能使用 Webhook authn/authz
### 注意:master 和 node 节点都要修改!
vim /var/lib/kubelet/config.yaml
authentication:
anonymous:
enabled: false
authorization:
mode: Webhook

### 修复针对 etcd 发现的以下所有问题:
### 确保 4.2.--client-cert-auth 参数设置为 true
### 注意:修改 master 节点!
vim /etc/kubernetes/manifests/etcd.yaml
- --client-cert-auth=true

### 加载并重启 kubelet 服务
### 注意:master 和 node 节点都要重启!
systemctl daemon-reload
systemctl restart kubelet

考题3 - Trivy 镜像扫描

Task

使用 Trivy 开源容器扫描器检测 namespace kamino 中 Pod 使用的具有严重漏洞的镜像。
查找具有 High 或 Critical 严重性漏洞的镜像,并删除使用这些镜像的 Pod。
注意:Trivy 仅安装在 cluster 的 master 节点上,在工作节点上不可使用。你必须切换到 cluster 的 master 节点才能使用 Trivy 。

Use the Trivy open-source container scanner to detect images with severe vulnerabilities used by Pods in the namespace kamino.
Look for images with High or Critical severity vulnerabilities, and delete the Pods that use those images.

Trivy is pre-installed on the cluster’s master node only; it is not available on the base system or the worker nodes. You’ll have to connect to the cluster’s master node to use Trivy.

Solution

搜索 kubectl images(列出集群中所有运行容器的镜像)
https://kubernetes.io/zh-cn/docs/tasks/access-application-cluster/list-all-running-container-images/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
### 需登录到控制节点操作
ssh cka-master01

### 查询命名空间 kamino 中 pod 使用的镜像
kubectl get pod -n kamino -o yaml | grep image:
# 或者
kubectl get pods -n kamino -o jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' | sort

### 假设镜像是 registry.aliyuncs.com/google_containers/coredns:1.7.0
### 使用 trivy 工具查询具有 HIGH 或 CRITICAL 漏洞的镜像
trivy --help
trivy image --severity HIGH,CRITICAL 'registry.aliyuncs.com/google_containers/coredns:1.7.0'

### 删除检测到的漏洞镜像对应的 pod(如果有控制器,得删除控制器)
kubectl delete pod -n kamino pod名称

考题4 - Sysdig & Falco

you may use you brower to open one additonal tab to access sysdig’s documentation or Falco’s documentaion

Task

Use runtime detection tools to detect anomalous processes spawning and executing frequently in the sigle container belonging to Pod redis. Two tools are avaliable to use:
使用运行时检测工具来检测 Pod tomcat 单个容器中频发生成和执行的异常进程。有两种工具可供使用:

  • sysdig
  • falco

The tools are pre-installed on the cluster’s worker node only, they are not avaliable on the base system or the master node.
Using the tool of you choice (including any non pre-install tool) analyse the container’s behavior for at least 30 seconds, using filers that detect newly spawing and executing processes, store an incident file at /opt/KSR00101/incidents/summary, containing the detected incidents one per line in the follwing format:
注:这些工具只预装在 cluster 的工作节点,不在 master 节点。
使用工具至少分析 30 秒,使用过滤器检查生成和执行的进程,将事件写到 /opt/KSR00101/incidents/summary 文件中,其中包含检测的事件, 每个单独一行
格式如下:

1
[timestamp],[uid],[processName]

保持工具的原始时间戳格式不变。
注:确保事件文件存储在集群的工作节点上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 方法一 sysdig
### 需登录到工作节点操作
ssh cka-node01

### 查看 sysdig 帮助
sysdig -h

### 查看 sysdig 支持的元数据
sysdig -l

### 查看指定容器ID
crictl ps | grep redis

### -M 分析容器30秒,-p 指定事件保存格式,--cri 指定容器运行时,并且保存到指定文件路径中
sysdig -M 30 -p "*%evt.time,%user.uid,%proc.name" --cri /run/containerd/containerd.sock container.id=xxxxx > /opt/KSR00101/incidents/summary
# 方法二 falco
### 需登录到工作节点操作
ssh cka-node01

###
cd /etc/falco
ls

###
vim /etc/falco/falco_rules.yaml
# Container is supposed to be immutable. Package management should be done in building the image.
- rule: Launch Package Management Process in Container
desc: Package management process ran inside container
condition: >
spawned_process
and container
and user.name != "_apt"
and package_mgmt_procs
and not package_mgmt_ancestor_procs
and not user_known_package_manager_in_container
output: >
Package management process launched in container %evt.time,%user.uid,%proc.name

### 查看指定容器ID
cat /var/log/sysdig | grep falco | grep "Package management" -i

#
vim /opt/KSR00101/incidents/summary

考题5 - ServiceAccount

Context
A Pod fails to run because of an incorrectly specified ServiceAcccount.

Task

create a new ServiceAccount named backend-sa in the existing namespace qa, which must not have access to any secrets.

  • Inspect the Pods in the namespace

    1
    qa

    .

    • Edit the Pod to use the newly created serviceAccount backend-sa.
    • Ensure that the modified specification is applied and the Pod is running.
  • Finally, clean-up and delete the now unused serviceAccount in the namespace qa.
    在现有 namespace qa 中创建一个名为 backend-sa 的新 ServiceAccount, 确保此 ServiceAccount 不自动挂载secrets。
    使用 /cks/9/pod9.yaml 中的清单文件来创建一个 Pod。
    最后,清理 namespace qa 中任何未使用的 ServiceAccount。

Solution

搜索 serviceaccount(为Pod配置服务账号),接着再搜索字符串 “automount”
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-service-account/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
### 创建 ServiceAccount
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend-sa
namespace: qa
automountServiceAccountToken: false
EOF

###
k get pods -n qa
web1-xxx1
web2-xwx2
web3-xwx3
k get deployment -n qa
web1
web2
web3
# 发现这些pod都属于deployment

### 编辑 Pod 使用新创建的 serviceaccount
k edit deployment/web1 -n qa
k edit deployment/web2 -n qa
k edit deployment/web3 -n qa

...
template:
spec:
serviceAccountName: backend-sa # add
...

### 应用清单文件
kubectl apply -f /cks/9/pod9.yaml

### 把除了 backend-sa, 并且没有被使用的 serviceaccount 都删除
kubectl get serviceaccount -n qa
backend-sa
default
contentsa

kubectl get rolebinding -n qa -o wide
kubectl get clustorrolebinding -n qa -o wide

kubectl delete -n qa serviceaccount contentsa

考题6 - 2022真题v1.20 Pod 安全策略-PodSecurityPolicy

2023的最新考试已经没有这道题了,替代的是Pod Security Standard

Context6

A PodsecurityPolicy shall prevent the creation on of privileged Pods in a specific namespace.
PodSecurityPolicy 应防止在特定 namespace 中特权 Pod 的创建。

Task6

Create a new PodSecurityPolicy named restrict-policy, which prevents the creation of privileged Pods.

Create a new ClusterRole named restrict-access-role, which uses the newly created PodSecurityPolicy restrict-policy.
Create a new serviceAccount named psp-denial-sa in the existing namespace staging.

Finally, create a new clusterRoleBinding named dany-access-bind, which binds the newly created ClusterRole restrict-access-role to the newly created serviceAccount psp-denial-sa.

创建一个名为 restrict-policy 的新的 PodSecurityPolicy,以防止特权 Pod 的创建。
创建一个名为 restrict-access-role 并使用新创建的 PodSecurityPolicy restrict-policy 的 ClusterRole。
在现有的 namespace staging 中创建一个名为 psp-denial-sa 的新 ServiceAccount 。
最后,创建一个名为 dany-access-bind 的 ClusterRoleBinding,将新创建的 ClusterRole restrict-access-role 绑定到新创建的 ServiceAccount psp-denial-sa
你可以在一下位置找到模版清单文件: /cks/psp/psp.yaml

Solution6

搜索 runasany(Pod Security Policy)
https://kubernetes.io/id/docs/concepts/policy/pod-security-policy/
搜索 clusterrole(使用RBAC鉴权)
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
### (1)创建 psp
vim /cks/psp/psp.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-policy
spec:
privileged: false
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'

kubectl apply -f /cks/psp/psp.yaml

### (2)创建 clusterrole,使用 psp
kubectl create clusterrole restrict-access-role --verb=use --resource=psp --resource-name=restrict-policy

### (3)创建 serviceaccount
kubectl create serviceaccount psp-denial-sa -n staging

### (4)创建 clusterrolebinding
kubectl create clusterrolebinding dany-access-bind --clusterrole=restrict-access-role --serviceaccount=staging:psp-denial-sa

### (5)启用 PodSecurityPolicy(在控制节点上修改 apiserver 配置)
vim /etc/kubernetes/manifests/kube-apiserver.yaml
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy

systemctl restart kubelet

考题6 - 2023真题V1.26 Pod Security Standard

Task weight: 8%
Use context: kubectl config use-context workload-prod

There is Deployment container-host-hacker in Namespace team-red which mounts /run/containerd as a hostPath volume on the Node where it’s running. This means that the Pod can access various data about other containers running on the same Node.

To prevent this configure Namespace team-red to enforce the baseline Pod Security Standard. Once completed, delete the Pod of the Deployment mentioned above.

Check the ReplicaSet events and write the event/log lines containing the reason why the Pod isn’t recreated into /opt/course/4/logs.

Answer

Making Namespaces use Pod Security Standards works via labels. We can simply edit it:

1
k edit ns team-red

Now we configure the requested label:

1
2
3
4
5
6
7
8
9
# kubectl edit namespace team-red
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: team-red
pod-security.kubernetes.io/enforce: baseline # add
name: team-red
...

This should already be enough for the default Pod Security Admission Controller to pick up on that change. Let’s test it and delete the Pod to see if it’ll be recreated or fails, it should fail!

1
2
3
4
5
6
7
8
9
➜ k -n team-red get pod
NAME READY STATUS RESTARTS AGE
container-host-hacker-dbf989777-wm8fc 1/1 Running 0 115s

➜ k -n team-red delete pod container-host-hacker-dbf989777-wm8fc
pod "container-host-hacker-dbf989777-wm8fc" deleted

➜ k -n team-red get pod
No resources found in team-red namespace.

Usually the ReplicaSet of a Deployment would recreate the Pod if deleted, here we see this doesn’t happen. Let’s check why:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜ k -n team-red get rs
NAME DESIRED CURRENT READY AGE
container-host-hacker-dbf989777 1 0 0 5m25s

➜ k -n team-red describe rs container-host-hacker-dbf989777
Name: container-host-hacker-dbf989777
Namespace: team-red
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
...
Warning FailedCreate 2m41s replicaset-controller Error creating: pods "container-host-hacker-dbf989777-bjwgv" is forbidden: violates PodSecurity "baseline:latest": hostPath volumes (volume "containerdata")
Warning FailedCreate 2m2s (x9 over 2m40s) replicaset-controller (combined from similar events): Error creating: pods "container-host-hacker-dbf989777-kjfpn" is forbidden: violates PodSecurity "baseline:latest": hostPath volumes (volume "containerdata")

There we go! Finally we write the reason into the requested file so that Mr Scoring will be happy too!

1
2
# /opt/course/4/logs
Warning FailedCreate 2m2s (x9 over 2m40s) replicaset-controller (combined from similar events): Error creating: pods "container-host-hacker-dbf989777-kjfpn" is forbidden: violates PodSecurity "baseline:latest": hostPath volumes (volume "containerdata")

Pod Security Standards can give a great base level of security! But when one finds themselves wanting to deeper adjust the levels like baseline or restricted… this isn’t possible and 3rd party solutions like OPA could be looked at.

考题7 - NetworkPolicy - default-deny

Context

A default-deny NetworkPolicy avoids to accidentally expose a Pod in a namespace that doesn’t have any other NetworkPolicy defined.
一个默认拒绝(default-deny)的 NetworkPolicy 可避免在未定义任何其他 NetworkPolicy 的 namespace 中意外公开 Pod。

Task

Create a new default-deny NetworkPolicy named denynetwork in the namespace development for all traffic of type Ingress.
The new NetworkPolicy must deny all ingress traffic in the namespace development.

Apply the newly created default-deny NetworkPolicy to all Pods running in namespace development.
You can find a skeleton manifest file at /cks/15/p1.yaml

为所有类型为 Ingress+Egress 的流量在 namespace testing 中创建一个名为 denynetwork 的新默认拒绝 NetworkPolicy。 此新的 NetworkPolicy 必须拒绝 namespace testng 中的所有的 Ingress + Egress 流量。
将新创建的默认拒绝 NetworkPolicy 应用与在 namespace testing 中运行的所有 Pod。
你可以在 /cks/15/p1.yaml 找到一个模板清单文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 修改模板清单文件
vim /cks/15/p1.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: denynetwork
namespace: testing
spec:
podSelector: {}
policyTypes:
- Ingress

### 应用清单文件
kubectl apply -f /cks/15/p1.yaml

考题8 - NetworkPolicy

Task

create a NetworkPolicy named pod-restriction to restrict access to Pod products-service running in namespace dev-team.
Only allow the following Pods to connect to Pod products-service:

  • Pods in the namespace qa
  • Pods with label environment: testing, in any namespace

Make sure to apply the NetworkPolicy.
You can find a skelet on manifest file at /cks/6/p1.yaml

创建一个名为 pod-restriction 的 NetworkPolicy 来限制对在 namespace dev-team 中运行的 Pod products-service 的访问。只允许以下 Pod 连接到 Pod products-service

  • namespace qa 中的 Pod
  • 位于任何 namespace,带有标签 environment: testing 的 Pod

注意:确保应用 NetworkPolicy。
你可以在/cks/net/po.yaml 找到一个模板清单文件。

Solution

搜索 networkpolicy(网络策略)
https://kubernetes.io/zh-cn/docs/concepts/services-networking/network-policies/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
### (1)查看命名空间 qa 具有的标签
kubectl get namespace qa --show-labels

### (2)查看 pod 具有的标签
kubectl get pod products-service -n dev-team --show-labels

### 修改模板清单文件
vim /cks/net/po.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pod-restriction # name
namespace: dev-team # namespace
spec:
podSelector:
matchLabels:
run: products-service # (2)
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: qa # (1)
- podSelector: # 注意带 - ,表示或的关系
matchLabels:
environment: testing
namespaceSelector: {} ## 任何命名空间, 不带 - ,且的关系
### 应用清单文件
kubectl apply -f /cks/net/po.yaml

考题9 - RBAC

Context

绑定到 Pod 的 ServiceAccount 的 Role 授予过度宽松的权限。完成以下项目以减少权限集。
A Role bound to a Pod’s serviceAccount grants overly permissive permissions.
Complete the following tasks to reduce the set of permissions.

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。

Given an existing Pod named web-pod running in the namespace db. Edit the existing Role bound to the Pod’s serviceAccount sa-dev-1 to only allow performing list operations, only on resources of type Endpoints.

  • create a new Role named role-2 in the namespace db, which only allows performing update operations, only on resources of type persistentvolumeclaims
  • create a new RoleBinding named role-2-binding binding the newly created Role to the Pod’s serviceAccount.

Don’t delete the existing RoleBinding

solution

搜索 clusterrole(使用RBAC鉴权)
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
### 查询 sa 对应的 role 名称(假设是 role-1)
kubectl get rolebinding -n db -oyaml | grep 'service-account-web' -B 10

### 修改 role 清单文件(仅允许对 services 类型的资源执行 get 操作)
kubectl edit role -n db role-1

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-1
namespace: db
resourceVersion: "9528"
rules:
- apiGroups:
- ""
resources:
- services
verbs:
- get

### 创建新角色 role-2(仅允许只对 namespaces 类型的资源执行 delete 操作)
kubectl create role role-2 -n db --verb=delete --resource=namespaces

### 创建 rolebinding,并绑定到 sa 上
kubectl create rolebinding role-2-binding --role=role-2 --serviceaccount=db:service-account-web

考题10 - kube-apiserver 审计日志记录和采集

Task

Enable audit logs in the cluster.
To do so, enable the log backend, and ensure that:

  • logs are stored at /var/log/kubernetes/audit-logs.txt
  • log files are retained for 10 days
  • at maximum, a number of 2 auditlog files are retained
    A basic policy is provided at /etc/kubernetes/logpolicy/sample-policy.yaml. it only specifies what not to log. The base policy is located on the cluster’s master node.

Edit and extend the basic policy to log:

  • namespaces changes at RequestResponse level
  • the request body of pods changes in the namespace front-apps
  • configMap and secret changes in all namespaces at the Metadata level
  • Also, add a catch-all ruie to log all other requests at the Metadata level.

Don’t forget to apply the modifiedpolicy.
/etc/kubernetes/logpolicy/sample-policy.yaml

在 cluster 中启用审计日志。为此,请启用日志后端,并确保:

  • 日志存储在 /var/log/kubernetes/audit-logs.txt
  • 日志文件能保留 10
  • 最多保留 2 个旧审计日志文件
    /etc/kubernetes/logpolicy/sample-policy.yaml 提供了基本策略。它仅指定不记录的内容。
    注意:基本策略位于 cluster 的 master 节点上。

编辑和扩展基本策略以记录:

  • RequestResponse 级别的 cronjobs 更改
  • namespace front-apps 中 deployment 更改的请求体
  • Metadata 级别的所有 namespace 中的 ConfigMap 和 Secret 的更改
  • 此外,添加一个全方位的规则以在 Metadata 级别记录所有其他请求。
    注意:不要忘记应用修改后的策略

Solution

搜索 audit(审计)
https://kubernetes.io/zh-cn/docs/tasks/debug/debug-cluster/audit/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
### 如果没有 /var/log/kubernetes/,则创建目录
mkdir /var/log/kubernetes/

### 修改 audit 模板文件
vim /etc/kubernetes/logpolicy/sample-policy.yaml

apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- "RequestReceived"
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["cronjobs"]
- level: Request
resources:
- group: ""
resources: ["deployments"]
namespaces: ["front-apps"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: Metadata
omitStages:
- "RequestReceived"

### 修改 apiserver 配置文件,启用审计日志
vim /etc/kubernetes/manifests/kube-apiserver.yaml
--audit-policy-file=/etc/kubernetes/logpolicy/sample-policy.yaml
--audit-log-path=/var/log/kubernetes/audit-logs.txt
--audit-log-maxage=10
--audit-log-maxbackup=2

### 在 apiserver 的 Pod 上挂载策略文件和日志文件所在的目录(考试时可能已经挂载好)
vim /etc/kubernetes/manifests/kube-apiserver.yaml
volumeMounts:
- mountPath: /var/log/kubernetes
name: kubernetes-logs
- mountPath: /etc/kubernetes/logpolicy
name: kubernetes-policy
volumes:
- name: kubernetes-logs
hostPath:
path: /var/log/kubernetes
- name: kubernetes-policy
hostPath:
path: /etc/kubernetes/logpolicy

### 重载生效配置
systemctl daemon-reload
systemctl restart kubelet

考题11 - Secret

Task

Retrieve the content of the existing secret named db1-test in the istio-system namespace.
store the username field in a file named /home/candidate/user.txt, and the password field in a file named /home/candidate/pass.txt.

You must create both files; they don’t exist yet.
Do not use/modify the created files in the following steps, create new temporary files if needed.

Create a new secret named db2-test in the istio-system namespace, with the following

1
2
username : production-instance
password : KvLftKgs4aVH

Finally, create a new Pod that has access to the secret db2-test via a volume:

  • Pod name secret-pod
  • Namespace istio-system
  • container name dev-container
  • image nginx
  • volume name secret-volume
  • mount path /etc/secret

在 namespace istio-system 中获取名为 db1-test 的现有 secret 的内容.
将 username 字段存储在名为 /cks/sec/user.txt 的文件中,并将 password 字段存储在名为 /cks/sec/pass.txt 的文件中。

注意:你必须创建以上两个文件,他们还不存在。
注意:不要在以下步骤中使用/修改先前创建的文件,如果需要,可以创建新的临时文件。

istio-system namespace 中创建一个名为 db2-test 的新 secret,内容如下:

1
2
username : production-instance
password : KvLftKgs4aVH

最后,创建一个新的 Pod,它可以通过卷访问 secret db2-test

  • Pod 名称 secret-pod
  • Namespace istio-system
  • 容器名 dev-container
  • 镜像 nginx
  • 卷名 secret-volume
  • 挂载路径 /etc/secret

Solution

搜索 secret(使用 kubectl 管理 Secret)
https://kubernetes.io/zh-cn/docs/tasks/configmap-secret/managing-secret-using-kubectl/
搜索 secret(Secret)
https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
### 检索已存在的 secret,将获取到的用户名和密码字段存储到指定文件
kubectl get secrets db2-test -o jsonpath='{.data.username}' | base64 -d > /home/candidate/user.txt
kubectl get secrets db2-test -o jsonpath='{.data.password}' | base64 -d > /home/candidate/pass.txt

### 创建 secret
kubectl -n istio-system create secret generic db2-test --from-literal=username=production-instance --from-literal=password=KvLftKgs4aVH
# kubectl create secret generic db2-test -n istio-system --from-literal username=production-instance --from-literal password=KvLftKgs4aVH
# error: exactly one NAME is required, got 2

### 在 Pod 中以文件形式使用 Secret
vim k8s-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
namespace: istio-system
spec:
containers:
- name: dev-container
image: nginx
volumeMounts:
- name: secret-volume
mountPath: "/etc/secret"
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db2-test
optional: false

### 应用清单文件
kubectl apply -f k8s-secret.yaml

### 验证 pod
kubectl get pods -n istio-system dev-pod

考题12 - dockerfile 和 deployment 安全优化

Task

  • Analyze and edit the given Dockerfile (based on the ubuntu:16.04 image) /cks/docker/Dockerfile fixing two instructions present in the file being prominent security/best-practice issues.
  • Analyze and edit the given manifest file /cks/docker/deployment.yaml fixing two fields present in the file being prominent security/best-practice issues.

Don’t add or remove configuration settings; only modify the existing configuration settings, so that two configuration settings each are no longer security/best-practice concerns.

Should you need an unprivileged user for any of the tasks, use user nobody with user id 65535.

  • 分析和编辑给定的 Dockerfile /cks/docker/Dockerfile(基于 ubuntu:16.04 镜像),并修复在文件中拥有的突出的安全/最佳实践问题的两个指令。
  • 分析和编辑给定的清单文件 /cks/docker/deployment.yaml,并修复在文件中拥有突出的安全/最佳实践问题的两个字段。

注意:请勿添加或删除配置设置;只需修改现有的配置设置让以上两个配置设置都不再有安全/最佳实践问题。
注意:如果您需要非特权用户来执行任何项目,请使用用户 ID 65535 的用户 nobody 。
答题: 注意,本次的 Dockerfile 和 deployment.yaml 仅修改即可,无需部署。

Solution 12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
### 修复 dockerfile 文件中存在的两个安全/最佳实践指令
### (1)把ubuntu:latest改为ubuntu:16.04 (2)将 root 注释掉;增加 nobody
vim /cks/docker/Dockerfile
# FROM ubuntu:latest 1 修改
FROM ubuntu:16.04
#USER root
USER nobody # 2

### 修复 deployment 文件中存在的两个安全/最佳实践问题字段
### (1)将 privileged 变为 False;(2)将 readOnlyRootFilesystem 变为 True 3 check runAsUser 65535
vim /cks/docker/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dev
name: dev
spec:
replicas: 1
selector:
matchLabels:
app: dev
template:
metadata:
labels:
app: dev
spec:
containers:
- image: mysql
name: mysql
securityContext: {'capabilities':{'add':['NET_ADMIN'],'drop':['all']},'privileged': False,'readOnlyRootFilesystem': True, 'runAsUser': 65535}

考题13 - admission-controllers - ImagePolicyWebhook

Context

A container image scanner is set up on the cluster, but it’s not yet fully integrated into the cluster’s configuration. When complete, the container image scanner shall scan for and reject the use of vulnerable images.

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

Task

You have to complete the entire task on the cluster’s master node, where all services and files have been prepared and placed.
Given an incomplete configuration in directory /etc/kubernetes/epconfig and a functional container image scanner with HTTPS endpoint https://acme.local:8082/image_policy:

  1. Enable the necessary plugins to create an image policy
  2. validate the control configuration and change it to an implicit deny
  3. Edit the configuration to point to the provided HTTPS endpoint correctly.
  4. Finally , test if the configuration is working by trying to deploy the vulnerable resource /cks/1/web1.yaml

You can find the container image scanner’s log file at /var/loglimagepolicyiacme.log

注意:你必须在 cluster 的 master 节点上完成整个考题,所有服务和文件都已被准备好并放置在该节点上。 给定一个目录 /etc/kubernetes/epconfig 中不完整的配置以及具有 HTTPS 端点 https://acme.local:8082/image_policy 的功能性容器镜像扫描器:

  1. 启用必要的插件来创建镜像策略
  2. 校验控制配置并将其更改为隐式拒绝(implicit deny)
  3. 编辑配置以正确指向提供的 HTTPS 端点
  4. 最后,通过尝试部署易受攻击的资源 /cks/img/web1.yaml 来测试配置是否有效。

你可以在 /var/log/imagepolicy/roadrunner.log 找到容器镜像扫描仪的日志文件。

Solution

搜索 imagepolicywebhook(使用准入控制器),接着再搜索字符串”imagepolicywebhook”
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 0 master node
ssh masterNode

cd /etc/kubernetes/epconfig
ls
admission_configuration.json kubeconfig.yaml

### 查看config-file路径
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep --admission-control-config-file
- --admission-control-config-file=/etc/kubernetes/epconfig/admission_configuration.json

### 1 验证控制平面的配置并将其更改为拒绝
vim /etc/kubernetes/epconfig/admission_configuration.json
{
"apiVersion": "apiserver.config.k8s.io/v1",
"kind": "AdmissionConfiguration",
"plugins": [
{
"name": "ImagePolicyWebhook",
"configuration": {
"imagePolicy": {
"kubeConfigFile": "/etc/kubernetes/epconfig/kubeconfig.yaml", // 1.1 kubeconfig
"allowTTL": 100,
"denyTTL": 50,
"retryBackoff": 500,
"defaultAllow": false // 1.2 modify from true to false
}
}
}
]
}
### 2 编辑配置以正确指向提供的 HTTPS 端点
vim kubeconfig.yaml
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /etc/kubernetes/epconfig/webhook.pem
server: https://acme.local:8082/image_policy # 2 配置此步
name: bouncer_webhook

### 3 启用必要的插件以创建镜像策略
vim /etc/kubernetes/manifests/kube-apiserver.yaml

- --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook # 3.1 Add ImagePolicyWebhook
- --admission-control-config-file=/etc/kubernetes/epconfig/admission_configuration.json # 3.2 Check config-file path
......
volumeMounts: # 3.3 Check Mount, can search audit log in kubernetes.io
- mountPath: /etc/kubernetes/epconfig
name: config
readyOnly: false
volumes:
- hostPath:
path: /etc/kubernetes/epconfig
type: DirectoryOrCreate
name: config

### 4 加载生效配置
systemctl daemon-reload
systemctl restart kubelet

### 5 通过部署易受攻击的资源来测试配置是否有效
kubectl apply -f /cks/img/web1.yaml

考题14 - 删除非无状态或非不可变的 pod

Context: it is best-practice to design containers to be stateless and immutable

Task

Inspect Pods runnings in namespace production and delete any Pod that is either not stateless or not immutable.

Use the following strict interpretation of stateless and immutable:

  • Pod being able to store data inside containers must be treated as not stateless. You don’t have to worry whether data is actually stored inside containers or not already.
  • Pod being configured to be privileged in any way must be treated as potentially not stateless and not immutable.

检查在 namespace production 中运行的 Pod,并删除任何非无状态或非不可变的 Pod。
使用以下对无状态和不可变的严格解释:

  • 能够在容器内存储数据的 Pod 的容器必须被视为非无状态的。
  • 被配置为任何形式的特权 Pod 必须被视为可能是非无状态和非不可变的。
    注意:你不必担心数据是否实际上已经存储在容器中。
1
2
3
4
5
6
7
8
9
10
11
12
### 在命名空间 dev 中检查 running 状态的 pod
kubectl get pods -n production | grep running -i

### 查看具有特权的 pod
kubectl get pods -n production -oyaml | grep -i "privileged: true"

### 查看具有 volume 的 pod
# jq 用于处理JSON输入,将给定过滤器应用于其JSON文本输入并在标准输出上将过滤器的结果生成为JSON。
kubectl get pods -n production -o jsonpath={.spec.volumes} | jq

### 将查询到的具有特权和 volume 的 pod 都删除
kubectl delete pods -n production pod名称

考题15 - gVisor/runtimeclass

Context

This cluster uses containerd as CRI runtime.
Containerd’s default runtime handler is runc . Containerd has been prepared to support an additional runtime handler , runsc (gVisor).

该 cluster 使用 containerd 作为 CRI 运行时。
containerd 的默认运行时处理程序是 runc。 containerd 已准备好支持额外的运行时处理程序 runsc (gVisor)。

Task

Create a RuntimeClass named untrusted using the prepared runtime handler named runsc.
Update all Pods in the namespace server to run on gvisor, unless they are already running on anon-default runtime handler.
You can find a skeleton manifest file at /cks/13/rc.yaml

使用名为 runsc 的现有运行时处理程序,创建一个名为 untrusted 的 RuntimeClass。
更新 namespace server 中的所有 Pod 以在 gVisor 上运行。
您可以在 /cks/gVisor/rc.yaml 中找到一个模版清单

Solution

搜索 runtimeclass(容器运行时类)
https://kubernetes.io/zh-cn/docs/concepts/containers/runtime-class/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
### 修改模板清单文件
vim /cks/gVisor/rc.yaml
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: untrusted
handler: runsc

### 应用清单文件
kubectl apply -f /cks/gVisor/rc.yaml

### 修改 server 命名空间下的所有 pod(还需要修改deployment)
kubectl get pods -n server
kubectl get deployments -n server

kubectl get pods -n server -oyaml > myrc.yaml
vim myrc.yaml
spec:
......
runtimeClassName: untrusted

### 更新清单文件
kubectl delete -f myrc.yaml
kubectl apply -f myrc.yaml

考题16 - 启用 API Server 认证

Context

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

Task

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
k get nodes

### 注意:修改 master 节点!
ssh masterNode

### (1)使用授权模式 Node,RBAC 和准入控制器 NodeRestriction
vim /etc/kubernetes/manifests/kube-apiserver.yaml
- --authorization-mode=Node,RBAC # modify Node,RBAC
- --enable-admission-plugins=NodeRestriction # modify NodeRestriction
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-bootstrap-token-auth=true

### (2)删除 system:anonymous 的 ClusterRolebinding 角色绑定(取消匿名用户的集群管理员权限)
k get clusterrolebinding -A | grep system:anonymous
kubectl delete clusterrolebinding system:anonymous

参考文章

From: http://liyuankun.top/Kubernates-Certified%20Kubernetes%20Security%20Specialist-CKS.html


真题③基于1.22版本

1、Pod 指定 ServiceAccount

Task

  1. 在现有 namespace qa 中创建一个名为 backend-sa 的新 ServiceAccount, 确保此
    ServiceAccount 不自动挂载 API 凭据。
  2. 使用 /cks/sa/pod1.yaml 中的清单文件来创建一个 Pod。
  3. 最后,清理 namespace qa 中任何未使用的 ServiceAccount。

2、RBAC - RoleBinding
Context 绑定到 Pod 的 ServiceAccount 的 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。

3、启用 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 ,以确保经过身份验证的授权的请求仍然被允许。

4、Sysdig & falco
Task:

使用运行时检测工具来检测 Pod tomcat 单个容器中频发生成和执行的异常进程。 有两种工具可供使用:

⚫ sysdig
⚫ falco

注: 这些工具只预装在 cluster 的工作节点,不在 master 节点。 使用工具至少分析 30 秒,使用过滤器检查生成和执行的进程,将事件写到 /opt/KSR00101/incidents/summary 文件中,其中包含检测的事件, 格式如下: [timestamp],[uid],[processName] 保持工具的原始时间戳格式不变。

注:确保事件文件存储在集群的工作节点上。

5、 容器安全,删除特权 Pod
Task

检查在 namespace production 中运行的 Pod,并删除任何非无状态或非不可变的 Pod。
使用以下对无状态和不可变的严格解释:

⚫ 能够在容器内存储数据的 Pod 的容器必须被视为非无状态的。
注意:你不必担心数据是否实际上已经存储在容器中。

⚫ 被配置为任何形式的特权 Pod 必须被视为可能是非无状态和非不可变的。

6、沙箱运行容器 gVisor
Context 该 cluster 使用 containerd 作为 CRI 运行时。containerd 的默认运行时处理程序是runc。 containerd 已准备好支持额外的运行时处理程序 runsc (gVisor)。 Task 使用名为 runsc的现有运行时处理程序,创建一个名为 untrusted 的 RuntimeClass。 更新 namespace server 中的所有Pod 以在 gVisor 上运行。

您可以在 /cks/gVisor/rc.yaml 中找到一个模版清单

7、Pod 安全策略-PSP
Context PodSecurityPolicy 应防在特定 namespace 中特权 Pod 的创建。 Task 创建一个名为restrict-policy 的新的PodSecurityPolicy,以防止特权 Pod 的创建。 创建一个名为restrict-access-role 并使用新创建的 PodSecurityPolicy restrict-policy 的ClusterRole。 在现有的 namespace staging 中创建一个名为 psp-denial-sa 的新ServiceAccount 。最后,创建一个名为 dany-access-bind 的 ClusterRoleBinding ,将新创建的 ClusterRole restrict-access-role 绑定到新创建的 ServiceAccount psp-denial-sa。

你可以在一下位置找到模版清单文件: /cks/psp/psp.yaml

8、创建 Secret
Task

在 namespace istio-system 中获取名为 db1-test 的现有 secret 的内容 将 username字段存储在名为 /cks/sec/user.txt 的文件中,并将 password 字段存储在名为 /cks/sec/pass.txt 的文件 中。注意:你必须创建以上两个文件,他们还不存在。 注意:不要在以下步骤中使用/修改先前创建的文件,如果需要,可以创建新的临时文件。

在 istio-system namespace 中创建一个名为 db2-test 的新 secret,内容如下:

username : production-instance

password : KvLftKgs4aVH

最后,创建一个新的 Pod,它可以通过卷访问 secret db2-test :

Pod 名称 secret-pod

Namespace istio-system

容器名 dev-container

镜像 nginx

卷名 secret-volume

挂载路径 /etc/secret

9、AppArmor
Context

APPArmor 已在 cluster 的工作节点上被启用。一个 APPArmor 配置文件已存在,但尚未被实施

Task
在 cluster 的工作节点上,实施位于 /etc/apparmor.d/nginx_apparmor 的现有 APPArmor配置文件。 编辑位于 /home/candidate/KSSH00401/nginx-deploy.yaml 的现有清单文件以应用 AppArmor 配置文件。 最后,应用清单文件并创建其中指定的 Pod 。

10、kube-bench 修复不安全项
Context 针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时, 发现了多个必须立即解决的问题。

Task
通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效。

修复针对 API 服务器发现的所有以下违规行为:

1.2.7 Ensure that the –authorization-mode argument is not set to AlwaysAllow

1.2.8 Ensure that the –authorization-mode argument includes Node

1.2.9 Ensure that the –authorization-mode argument includes RBAC

1.2.18 Ensure that the –insecure-bind-address argument is not set

1.2.19 Ensure that the –insecure-port argument is set to 0

FAIL FAIL FAIL FAIL 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 4.2.2

Ensure that the –authorization-mode argument is not set to AlwaysAllow

FAIL 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

11、网络策略 NetworkPolicy
Task

创建一个名为 pod-restriction 的 NetworkPolicy 来限制对在 namespace dev-team 中运行的 Pod products-service 的访问。 只允许以下 Pod 连接到 Pod products-service

⚫ namespace qa 中的 Pod

⚫ 位于任何 namespace,带有标签 environment: testing 的 Pod

注意:确保应用 NetworkPolicy。 你可以在/cks/net/po.yaml 找到一个模板清单文件。

12、Dockerfile 检测
Task

分析和编辑给定的 Dockerfile /cks/docker/Dockerfile(基于 ubuntu:16.04 镜像),
并修复在文件中拥有的突出的安全/最佳实践问题的两个指令。 分析和编辑给定的清单文件 /cks/docker/deployment.yaml
, 并修复在文件中拥有突出的安全/最佳实践问题的两个字段。
注意:请勿添加或删除配置设置;只需修改现有的配置设置让以上两个配置设置都不再有安全/最佳实践问题。
注意:如果您需要非特权用户来执行任何项目,请使用用户 ID 65535 的用户 nobody 。 答题: 注意,本次的 Dockerfile
和 deployment.yaml 仅修改即可,无需部署。

13、ImagePolicyWebhook 容器镜像扫描
Context

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

Task

注意:你必须在 cluster 的 master 节点上完成整个考题,所有服务和文件都已被准备好并放置在该节点上。

给定一个目录 /etc/kubernetes/epconfig 中不完整的配置以及具有 HTTPS 端点 https://acme.local:8082/image_policy 的功能性容器镜像扫描器:

  1. 启用必要的插件来创建镜像策略

  2. 校验控制配置并将其更改为隐式拒绝(implicit deny)

  3. 编辑配置以正确指向提供的 HTTPS 端点

  4. 最后,通过尝试部署易受攻击的资源 /cks/img/web1.yaml 来测试配置是否有效。

你可以在 /var/log/imagepolicy/roadrunner.log 找到容器镜像扫描仪的日志文件。

14、Trivy 扫描镜像安全漏洞
Task

使用 Trivy 开源容器扫描器检测 namespace kamino 中 Pod 使用的具有严重漏洞的镜像。 查找具有 High 或 Critical 严重性漏洞的镜像,并删除使用这些镜像的 Pod。

注意:Trivy 仅安装在 cluster 的 master 节点上, 在工作节点上不可使用。 你必须切换到 cluster 的 master 节点才能使用 Trivy

15、默认网络策略
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 找到一个模板清单文件。

16、日志审计 log audit
Task

在 cluster 中启用审计日志。为此,请启用日志后端,并确保:
⚫ 日志存储在 /var/log/kubernetes/audit-logs.txt
⚫ 日志文件能保留 10 天
⚫ 最多保留 2 个旧审计日志文件
/etc/kubernetes/logpolicy/sample-policy.yaml 提供了基本策略。它仅指定不记录的内容。
注意:基本策略位于 cluster 的 master 节点上。 编辑和扩展基本策略以记录:
⚫ RequestResponse 级别的
cronjobs 更改
⚫ namespace front-apps 中 deployment 更改的请求体
⚫ Metadata级别的所有 namespace 中的 ConfigMap 和 Secret 的更改 此外,添加一个全方位的规则以在 Metadata
级别记录所有其他请求。 注意:不要忘记应用修改后的策略


真题④基于1.22版本

云原生|kubernetes|2022年底cks真题解析(1-10)_cks试题_晚风_END的博客-CSDN博客
云原生|kubernetes|2022年底cks真题解析(11-16)_晚风_END的博客-CSDN博客

2024年CKS考试准备

Start : 2024.1.15

DDL1:2024.2.3 15:00 (Rescheduled)

DDL2:2024.2.8 20:00 (Failed)

DDL3: 2024.2.23 23:30 (Success)

学习环境搭建

Install Calico CNI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Other prerequisites
# swap,br_netfilter....

# Configure containerd
$ containerd config default | sed 's|SystemdCgroup = false|SystemdCgroup = true|g' | sudo tee /etc/containerd/config.toml > /dev/null
$ sudo systemctl restart containerd && systemctl status containerd

# Hosts
$ echo "127.0.0.1 kube.multipass.local" | sudo tee -a /etc/hosts > /dev/null

# Initialize Kubernetes cluster
$ kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint kube.multipass.local

# untaint master node
$ kubectl get node --no-headers | grep control-plane | awk '{cmd="kubectl taint node "$1" node-role.kubernetes.io/control-plane-";system(cmd)}'

# Install Calico CNI which supports Network Policy
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
$ curl https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml | sed 's|192.168|10.244|g' | kubectl apply -f -

There may be lots of impediments to setting up this kubernetes cluster successfully due to network conditions or some misconfigurations, but those above can be solved step by step. Finally, node(s) is(are) ready as follows:

1
2
3
$ kubectl get node
NAME STATUS ROLES AGE VERSION
kube-master Ready control-plane 21m v1.28.3

做题工具

alias

1
2
3
alias k=kubectl                         # will already be pre-configured
export do="--dry-run=client -o yaml" # k create deploy nginx --image=nginx $do
export now="--force --grace-period 0" # k delete pod x $now

vim

1
2
3
set tabstop=2
set expandtab
set shiftwidth=2

jsonpath

https://kubernetes.io/docs/reference/kubectl/jsonpath/

Function Description Example Result
text the plain text kind is {.kind} kind is List
@ the current object {@} the same as input
. or [] child operator {.kind}, {['kind']} or {['name\.type']} List
.. recursive descent {..name} 127.0.0.1 127.0.0.2 myself e2e
* wildcard. Get all objects {.items[*].metadata.name} [127.0.0.1 127.0.0.2]
[start:end:step] subscript operator {.users[0].name} myself
[,] union operator {.items[*]['metadata.name', 'status.capacity']} 127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8]
?() filter {.users[?(@.name=="e2e")].user.password} secret
range, end iterate list {range .items[*]}[{.metadata.name}, {.status.capacity}] {end} [127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]]
'' quote interpreted string {range .items[*]}{.metadata.name}{'\t'}{end} 127.0.0.1 127.0.0.2
\ escape termination character {.items[0].metadata.labels.kubernetes\.io/hostname} 127.0.0.1

Examples using kubectl and JSONPath expressions:

1
2
3
4
5
6
7
kubectl get pods -o json
kubectl get pods -o=jsonpath='{@}'
kubectl get pods -o=jsonpath='{.items[0]}'
kubectl get pods -o=jsonpath='{.items[0].metadata.name}'
kubectl get pods -o=jsonpath="{.items[*]['metadata.name', 'status.capacity']}"
kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.startTime}{"\n"}{end}'
kubectl get pods -o=jsonpath='{.items[0].metadata.labels.kubernetes\.io/hostname}'

yq

examples

1
2
3
4
5
6
7
8
9
10
11
# Read a value
yq '.a.b[0].c' file.yaml

# Pipe from STDIN
yq '.a.b[0].c' < file.yaml

# Update a yaml file, in place
yq -i '.a.b[0].c = "cool"' file.yaml

# Find and update an item in an array
yq '(.[] | select(.name == "foo") | .address) = "12 cat st"'
  • jq
  • tr
  • truncate
  • crictl
  • cut

awk

常规使用

组装命令并执行

1
kubectl get svc | awk '{cmd="kubectl get svc "$1" -oyaml";system(cmd)}'
  • sed
  • sha512sum
  • podman(to build image)

日志查看

https://kubernetes.io/docs/concepts/cluster-administration/logging/#system-component-logs

  • 对 kubelet 组件:journalctl -xefu kubelet

  • 对以容器形式启动的 kubernetes 组件:在/var/log/pods下(当把kube-apiserver的yaml弄坏起不来之后,应该可以在这个目录下查看启动失败的原因)

group缩写问题

group为空时表示core group,此时的 gv 缩写只有 v,即

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ kubectl api-resources --api-group=''
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service

常见的控制器资源基本属于apps group

1
2
3
4
5
6
NAME                  SHORTNAMES   APIVERSION   NAMESPACED   KIND
controllerrevisions apps/v1 true ControllerRevision
daemonsets ds apps/v1 true DaemonSet
deployments deploy apps/v1 true Deployment
replicasets rs apps/v1 true ReplicaSet
statefulsets sts apps/v1 true StatefulSet

常见的几种需要填充group的地方

  • rbac

    role.rules.apiGroups 只需要填写group

  • audit policy

    rules.resources.group 只需要填写group

做题方法论

客观局限

  1. 网络卡顿,导致做题时及其不流畅;
  2. 题量大,总共有16道题,需要在120分钟内完成,完成一道题的平局时间应该120/16=7分钟;

主观局限

  1. 对安全相关的操作不熟练;
  2. 无做题策略,选择按顺序,从头做到尾;
  3. 开始做题前,未对该题进行自我评估,不确定能否短时间内搞定,做了一半,发现搞不定,非常浪费时间;

改进措施

  1. 改用香港/澳门移动网络漫游来做题(如果这次还是考不过,有网络卡顿的原因,下次得肉身跑到香港去了23333);
  2. 及格分数需要67,粗略估计取得证书,需要做完67/(100/16)=11道题,可以允许5道题不做,但每题的平均用时为10分钟多一点。
  3. 做题步骤
    1. 1分钟浏览全题,理解题意,并评估是否有把握能完成;
    2. 没把握的用flag标记,跳过,下一题;
  4. 优先去做的题目类型
    1. audit policy
    2. apparmor
    3. pod security standard
    4. runtime class
    5. image policy webhook
    6. trivy & kube-bench
    7. rbac & opa
    8. secret
    9. security context

主题

RBAC

Reference: https://kubernetes.io/docs/reference/access-authn-authz/rbac/

创建sa、role、rolebinding

1
2
3
kubectl create sa shs-sa
kubectl create role shs-role --resource=pods,secrets --verb=*
kubectl create rolebinding shs-rolebinding --role=shs-role --serviceaccount=default:shs-sa

使用该ServiceAccount

1
kubectl patch -p '{"spec":{"template":{"spec":{"serviceAccountName":"shs-saax","serviceAccount":"shs-saax"}}}}' deployment shs-dep

Tips:

  1. 如果sa异常(如:不存在),则deployment的pod不会建出来,因为rs控制器已经检测到了异常,所以未建pod。
  2. deploy.spec.template.spec.serviceAccountdeploy.spec.template.spec.serviceAccountName 都需要修改。

NetworkPolicy

Pod Isolation

  • Egress, outbound connection from pod, non-isolated by default. If NetworkPolicy selects this pod and was Egress type, then only out connections mentioned in it allowed. If lots of NetworkPolicy select the same pod, then all connections mentoined in those list are allowed. Additive.
  • Ingress, inbound connection to pod, non-isolated by default. Effects are as the same as Egress. Only connections mentioned by NetworkPolicy can connect to this Pod successfully.
    Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
# Indicates which pods this NetworkPolicy will apply to, selecting by pod's label
# podSelector: {} indicates this NetworkPolicy apply to all pods in default ns.
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
# Defines which pod can connect to this pod.
ingress:
# both `from` and `port` rules are satitisfied, then allowed
- from:
# 1. IP CIDR, connections from pod whose IP in this CIDR are allowd to connect
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
# 2. Namespace, connection from pod whose namespace has following labels are allowed to connect
- namespaceSelector:
matchLabels:
project: myproject
# 3. Pod, connections from pod which has following labels are allowed to connect
- podSelector:
matchLabels:
role: frontend
# Based on `from`, if the target port of those connection was 6379 and protocl was TCP, allowed.
ports:
- protocol: TCP
port: 6379
# Defines which pod can be connected by this pod
# both `to` and `port` rules are satitisfied, then allowed
egress:
- to:
# 1. Connections from this pod can connect to this CIDR
- ipBlock:
cidr: 10.0.0.0/24
# Based on `to`, if the target port and protocol of this connection was 5978 and TCP, allowed.
ports:
- protocol: TCP
port: 5978

parameters of to and from was the same, as follows(irrelevant informations are omitted):

1
2
3
4
5
6
$ kubectl explain networkpolicy.spec.ingress
from <[]NetworkPolicyPeer>
ports <[]NetworkPolicyPort>
$ kubectl explain networkpolicy.spec.egress
to <[]NetworkPolicyPeer>
ports <[]NetworkPolicyPort>

details of NetworkPolicyPeer are as follows:

1
2
3
4
$ kubectl explain networkpolicy.spec.egress.to
ipBlock <IPBlock>
namespaceSelector <LabelSelector>
podSelector <LabelSelector>

As for details of IPBlock and LabelSelector, just kubectl explain before coding yamls.

Tips

  • NetworkPolicy was namespaced, and only works in the namespace to which it belongs.
  • NetworkPolicy can define only allowed rules.
  • NetworkPolicy selects pod by labels only.

Default network policy

Deny all in & out bound traffics for a pod

1
2
3
4
5
6
7
8
9
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

The OPA(Open Policy Agent) Gatekeeper

Ref: https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes

gatekeeper admission controller 拦截所有资源的创建、更新、删除请求,并针对相关资源,做所配置的校验。

定义校验模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
listKind: K8sRequiredLabelsList
plural: k8srequiredlabels
singular: k8srequiredlabels
validation:
# Schema for the `parameters` field
openAPIV3Schema:
properties:
labels:
type: array
items: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels

deny[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("you must provide labels: %v", [missing])
}

创建具体约束

每个命名空间都需要一个标签hr

1
2
3
4
5
6
7
8
9
10
11
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-hr
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["hr"]

审计

Gatekeeper stores audit results as violations listed in the status field of the relevant Constraint.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-hr
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["hr"]
status:
#...
violations:
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"hr"}'
name: default
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"hr"}'
name: gatekeeper-system
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"hr"}'
name: kube-public
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"hr"}'
name: kube-system

Apparmor

https://kubernetes.io/docs/tutorials/security/apparmor/

Confine programs or containers to limited set of resources, such as Linux capabilities, network access, file permissions, etc.

Works in 2 Modes

  • enforcing, blocks access
  • complain, only reports invalid access

Prerequisites

  • works on kubernetes v1.4 +
  • AppArmor kernel moduls enabled
  • Container Runtime supports AppArmor
  • Profile is loaded by kernel

Usage

Add annotations to pod which needed to be secured with key, name of container in Pod should be referred in key:

1
2
container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>
container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>

The profile_ref can be one of:

  • runtime/default to apply the runtime’s default profile
  • localhost/<profile_name> to apply the profile loaded on the host with the name <profile_name>
  • unconfined to indicate that no profiles will be loaded

Works

  • View Pod Events
  • kubectl exec <pod_name> -- cat /proc/1/attr/current

Helpful commands

  • Show AppArmor Status
1
$ apparmor_status
  • Load Profile to kernel
1
2
3
4
5
6
7
8
9
10
11
12
13
$ apparmor_parser /etc/apparmor.d/nginx_apparmor
$ sudo apparmor_parser -q <<EOF
#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>

file,

# Deny all file writes.
deny /** w,
}
EOF

Audit Policy

Reference: https://kubernetes.io/docs/reference/config-api/apiserver-audit.v1/#audit-k8s-io-v1-Policy

Getting Started

Stage

  • RequestReceived - Before handled by handler chain
  • ResponseStarted - After response header sent, but before response body sent
  • ResponseComplete - After response body sent
  • Panic - After panic occurred.

Audit Level

  • None - don’t log events that match this rule
  • Metadata - log request metadata only(user, timestamp,resource,vert) but not request or response body.
  • Request - log event metadata plus request body
  • RequestResponse - log event metadata plus request, response bodies.

Example

1
2
3
4
5
6
7
8
9
10
11
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- ResponseStarted
- ResponseComplete
- Panic
rules:
- level: Metadata
resources:
- group: ""
resources: ["pods"]

Configure it to kube-apiserver, see audit log.

Tips

If the Policy doesn’t work as expected, check kube-apiserver logs as below, make sure the Policy was loaded successfully. Since it seems to load a default AuditPolicy when failled to load the AuditPolicy passed in parameters of kube-apiserver. Logs are as below:

1
W0122 16:00:29.139016       1 reader.go:81] Audit policy contains errors, falling back to lenient decoding: strict decoding error: unknown field "rules[0].resources[0].resource"

Pod Security Standard

Reference

Policies

The Pod Security Standards define three different policies to broadly cover the security spectrum. These policies are cumulative and range from highly-permissive to highly-restrictive. This guide outlines the requirements of each policy.

3种策略,每种策略只是定义了检查、校验哪些字段、即校验范围。此3种策略,从上至下,校验范围依次增大。具体校验内容,可参考文档。

Profile Description
Privileged Unrestricted policy, providing the widest possible level of permissions. This policy allows for known privilege escalations.
Baseline Minimally restrictive policy which prevents known privilege escalations. Allows the default (minimally specified) Pod configuration.
Restricted Heavily restricted policy, following current Pod hardening best practices.

Levels

有3种针对不符合上述3种Policy的处理方式,即强制要求(否则拒绝创建)记录到审计日志中用户可见警告

Mode Description
enforce Policy violations will cause the pod to be rejected.
audit Policy violations will trigger the addition of an audit annotation to the event recorded in the audit log, but are otherwise allowed.
warn Policy violations will trigger a user-facing warning, but are otherwise allowed.

Usage

在命名空间上打标签

1
2
3
4
5
6
7
8
9
10
11
12
# The per-mode level label indicates which policy level to apply for the mode.
#
# MODE must be one of `enforce`, `audit`, or `warn`.
# LEVEL must be one of `privileged`, `baseline`, or `restricted`.
pod-security.kubernetes.io/<MODE>: <LEVEL>

# Optional: per-mode version label that can be used to pin the policy to the
# version that shipped with a given Kubernetes minor version (for example v1.29).
#
# MODE must be one of `enforce`, `audit`, or `warn`.
# VERSION must be a valid Kubernetes minor version, or `latest`.
pod-security.kubernetes.io/<MODE>-version: <VERSION>

SecurityContext

Reference: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

总共有两个安全配置的地方,位置分别为

  • pod.spec.securityContext 属于 PodSecurityContext 这个结构体,表示pod中所有的容器都使用这个配置;
  • pod.spec["initContainers","containers"].securityContext 属于 SecurityContext 这个结构体,只限于当前容器使用此配置,且优先级高于上面的配置。

上述两种不同位置的安全配置中,有的字段是重复的,SecurityContext 的优先级更高。两者之间值的差异(都存在的字段已加粗):

PodSecurityContext SecurityContext
fsGroup allowPrivilegeEscalation
fsGroupChangePolicy capabilities
runAsGroup privileged
runAsNonRoot procMount
runAsUser readOnlyRootFilesystem
seLinuxOptions runAsGroup
seccompProfile runAsNonRoot
supplementalGroups runAsUser
sysctls seLinuxOptions
windowsOptions seccompProfile
windowsOptions

来源:https://www.mrdadong.com/archives/cks-securitycontext

按照如下要求修改 sec-ns 命名空间里的 Deployment secdep

一、用 ID 为 30000 的用户启动容器(设置用户 ID 为: 30000 runAsUser

二、不允许进程获得超出其父进程的特权(禁止 allowPrivilegeEscalation

三、以只读方式加载容器的根文件系统(对根文件的只读权限readOnlyRootFilesystem

注意点:

  1. readOnlyRootFilesystemallowPrivilegeEscalation 只存在于SecurityContext中,因此需要为各个容器都配置上,需注意容器数量,避免漏配;
  2. runAsUser 存在于PodSecurityContextSecurityContext中,可只配 PodSecurityContext

RuntimeClass

Reference: https://kubernetes.io/docs/concepts/containers/runtime-class/

  • Create RuntimeClass
  • Specify created RuntimeClass in pod.spec.runtimeClassName

Secret

Reference: https://kubernetes.io/docs/concepts/configuration/secret

  • Secret Type
  • Mount to a pod

练手速【来源】

  1. 在 namespace istio-system 中获取名为 db1-test 的现有 secret 的内容。将 username 字段存储在名为 /cks/sec/user.txt 的文件中,并将 password 字段存储在名为 /cks/sec/pass.txt 的文件中。

    注意:你必须创建以上两个文件,他们还不存在。

    注意:不要在以下步骤中使用/修改先前创建的文件,如果需要,可以创建新的临时文件。

  2. istio-system namespace 中创建一个名为 db2-test 的新 secret,内容如下:

  • username : production-instance

  • password : KvLftKgs4aVH

  1. 最后,创建一个新的 Pod,它可以通过卷访问 secret db2-test
  • Pod 名称 secret-pod

  • Namespace istio-system

  • 容器名 dev-container

  • 镜像 nginx

  • 卷名 secret-volume

  • 挂载路径 /etc/secret

ServiceAccount

Reference: https://kubernetes.io/docs/concepts/security/service-accounts/

  • Prevent kubernetes from injecting credentials for a pod
1
2
$ kubectl explain sa.automountServiceAccountToken
$ kubectl explain pod.spec.automountServiceAccountToken

Set one of fields above to false to prevent auto injection for a pod.

  • Restrict access to Secrets
    Set annotation kubernetes.io/enforce-mountable-secrets to true for a ServiceAccount, then only secrets in the field of sa.secrets of this ServiceAccount was allowed to use in a pod, such as a secret volume, envFrom, imagePullSecrets.

  • How to use ServiceAccount to connect to apiserver? reference

    1
    2
    3
    curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -X GET https://kubernetes.default.svc/api/v1/namespaces/default/secrets
    # or
    curl -k -XGET --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/default/secrets

    整个kubeAPIServer提供了三类API Resource接口:

    • core group:主要在 /api/v1 下;
    • named groups:其 path 为 /apis/$GROUP/$VERSION
    • 系统状态的一些 API:如/metrics/version 等;

    而API的URL大致以 /apis/{group}/{version}/namespaces/{namespace}/{resources}/{name} 组成,结构如下图所示:

    https://img2020.cnblogs.com/other/2041406/202101/2041406-20210120094608734-1433747602.png

    Tips:

    在apiserver的URL中,资源需要用复数形式,如:

    1
    2
    curl -k -H "Authorization: Bearer $(cat /run/secrets/kubernetes.io/serviceaccount/token)" \
    https://kubernetes.default.svc/api/v1/namespaces/default/pods/shs-dep-b56c568d6-n8h6d

etcd

How to use etcdctl to get raw data from etcd?

1
2
3
4
ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
get /registry/secrets/default -w=json | jq .

Upgrade kubernetes version

Follow these steps:

for master

  1. k drain controller-plane
  2. apt-mark unhold kubeadm
  3. apt-mark hold kubelet kubectl
  4. apt update && apt upgrade -y
  5. kubeadm upgrade plan
  6. kubeadm upgrade apply v1.2x.x
  7. kubeadm upgrade plan(for check purpose)
  8. apt-mark hold kubeadm
  9. apt-mark unhold kubelet kubectl
  10. apt install kubectl=1.2x.x kubelet=1.2x.x
  11. apt-mark hold kubelet kubectl
  12. systemctl restart kubelet
  13. systemctl status kubelet
  14. k uncordon controller-plane

for node

  1. k drain node
  2. apt update
  3. apt-mark unhold kubeadm
  4. apt-mark hold kubectl kubelet
  5. apt install kubeadm=1.2x.x
  6. kubeadm upgrade plan
  7. kubeadm upgrade node
  8. apt-mark hold kubeadm
  9. apt-mark unhold kubectl kubelet
  10. apt install kubectl=1.2x.x kubelet=1.2x.x
  11. systemctl restart kubelet
  12. systemctl status kubelet
  13. k uncordon kubelet

check upgrade result

  1. k get node

ImagePolicyWebhook

https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook

安全工具使用

kube-bench

A tool to detect potential security issues and give the specific means to solve the issue.

Reference:

1
2
3
# Simple way in a kubernetes cluster created by kubeadm
$ kubectl apply \
-f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml

Contents
Consists of the following topics:

  • master
  • etcd
  • controlplane
  • node
  • policies

Each topic starts with a list of items which was checked with checked status, then a list of remediations to FAIL or WARN items given. You can fix those issues under the given instructions. At last, check summary of this topic.

Here is a output example for topic master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[WARN] 1.1.9 Ensure that the Container Network Interface file permissions are set to 600 or more restrictive (Manual)
[WARN] 1.1.10 Ensure that the Container Network Interface file ownership is set to root:root (Manual)

== Remediations master ==
1.1.9 Run the below command (based on the file location on your system) on the control plane node.
For example, chmod 600 <path/to/cni/files>
1.1.10 Run the below command (based on the file location on your system) on the control plane node.
For example,
chown root:root <path/to/cni/files>

== Summary master ==
38 checks PASS
9 checks FAIL
13 checks WARN
0 checks INFO

Full contexts can be touch by this link

trivy

Reference: https://github.com/aquasecurity/trivy

Scan a docker image

1
trivy image --severity LOW,MEDIUM ghcr.io/feiyudev/shs:latest

扫描某命名空间下所有pod所使用的镜像包含 HIGH, CRITICAL 类型漏洞,并删除该pod

1
k get pod -A -ojsonpath="{range .items[*]}{.spec['initContainers','containers'][*].image} {.metadata.name} {'#'} {end}" | sed 's|#|\n|g' | sed 's|^ ||g' | sed 's| $||g' | awk '{cmd="echo "$2"; trivy -q image "$1" --severity HIGH,CRITICAL | grep Total";system(cmd)}'

该命令的注意点:

  • jsonpath range
  • awk system(cmd)
  • sed replace

sysdig

Reference: https://github.com/draios/sysdig

Installation(Based on Ubuntu 22.04)

  • Download deb from sysdig-release
  • sudo dpkg -i sysdig-0.34.1-x86_64.deb
  • sudo apt -f install

Output format

1
2
%evt.num %evt.outputtime %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.info
173884 15:06:10.075401786 7 sudo (1453517.1453517) > read fd=9(<f>/dev/ptmx) size=65536

Notes:

  1. evt.dir aka event direction, < represents out, > represents in.
  2. evt.type aka event type, perceiving it as a name of system call.

Chisels

predefined function sets based on sysdig events, to implements complex situation. Locates in /usr/share/sysdig/chisels on Linux machine.

What are those chisels?

  1. To see chisels.
1
2
3
sysdig -cl
# or
sysdig --list-chisels
  1. To use a chisel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# See HTTP log
sysdig -c httplog
2024-01-25 23:06:16.423272777 < method=GET url=:8080/health response_code=200 latency=0ms size=2B
2024-01-25 23:06:16.423299653 > method=GET url=:8080/health response_code=200 latency=0ms size=2B
# See CPU usage ranking
sysdig -c topprocs_cpu
CPU% Process PID
--------------------------------------------------------------------------------
8.01% kube-apiserver 39124
3.00% kubelet 25007
3.00% etcd 1613
2.00% sysdig 102489
2.00% kube-controller 38957
2.00% calico-node 4705
1.00% containerd 874
1.00% vmtoolsd 790
1.00% kube-scheduler 39017
0.00% svlogd 2505
  1. Advanced usage about a chisel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ sysdig -i spy_file

Category: I/O
-------------
spy_file Echo any read/write made by any process to all files. Optionall
y, you can provide the name of one file to only intercept reads
/writes to that file.

This chisel intercepts all reads and writes to all files. Instead of all files,
you can limit interception to one file.
Args:
[string] read_or_write - Specify 'R' to capture only read event
s; 'W' to capture only write events; 'RW' to capture read and w
rite events. By default both read and write events are captured
.
[string] spy_on_file_name - The name of the file which the chis
el should spy on for all read and write activity.

$ sysdig -c spy_file "RW /root/spy_file_test.txt"
23:53:25.592303985 date(112109) W 32B /root/spy_file_test.txt
Thu Jan 25 11:53:25 PM HKT 2024

23:53:43.333152845 cat(112206) R 32B /root/spy_file_test.txt
Thu Jan 25 11:53:25 PM HKT 2024

23:53:43.333166670 cat(112206) R 0B /root/spy_file_test.txt NULL
23:53:51.856062624 date(112270) W 32B /root/spy_file_test.txt
Thu Jan 25 11:53:51 PM HKT 2024

23:53:56.965894638 cat(112307) R 64B /root/spy_file_test.txt
Thu Jan 25 11:53:25 PM HKT 2024
Thu Jan 25 11:53:51 PM HKT 2024

23:53:56.965902094 cat(112307) R 0B /root/spy_file_test.txt NULL

Usage

  1. Save events to a file
1
sysdig -w test.scap
  1. Read events from a file while analyzing (by chisels)
1
sysdig -r test.scap -c httptop
  1. Specify the format to be used when printing the events
    -p , –print=
    Specify the format to be used when printing the events.
    With -pc or -pcontainer will use a container-friendly format.
    With -pk or -pkubernetes will use a kubernetes-friendly format.
    With -pm or -pmesos will use a mesos-friendly format.
    See the examples section below for more info.
1
sysdig -r test.scap -c httptop -pc
  1. Specify the number of events Sysdig should capture by passing it the -n flag. Once Sysdig captures the specified number of events, it’ll automatically exit:
1
sysdig -n 5000 -w test.scap
  1. Use the -C flag to configure Sysdig so that it breaks the capture into smaller files of a specified size.
    The following example continuously saves events to files < 10MB:
1
sysdig -C 10 -w test.scap
  1. Specify the maximum number of files Sysdig should keep with the -W flag. For example, you can combine the -C and -W flags like so:
1
sysdig -C 10 -W 4 -w test.scap
  1. You can analyze the processes running in the WordPress container with:
1
sysdig -pc -c topprocs_cpu container.name=wordpress-sysdig_wordpress_1
  1. -M Stop collecting after reached.

Help

关于filter可用的字段,可以通过sysdig -l来查看所有支持的字段。例如查看容器相关的过滤字段,有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ubuntu@primary:~$ sysdig -l | grep "^container."
container.id The truncated container ID (first 12 characters), e.g. 3ad7b26ded6d is extracted from the
container.full_id The full container ID, e.g.
container.name The container name. In instances of userspace container engine lookup delays, this field
container.image The container image name (e.g. falcosecurity/falco:latest for docker). In instances of
container.image.id The container image id (e.g. 6f7e2741b66b). In instances of userspace container engine
container.type The container type, e.g. docker, cri-o, containerd etc.
container.privileged 'true' for containers running as privileged, 'false' otherwise. In instances of userspace
container.mounts A space-separated list of mount information. Each item in the list has the format
container.mount (ARG_REQUIRED) Information about a single mount, specified by number (e.g.
container.mount.source (ARG_REQUIRED) The mount source, specified by number (e.g. container.mount.source[0]) or
container.mount.dest (ARG_REQUIRED) The mount destination, specified by number (e.g. container.mount.dest[0])
container.mount.mode (ARG_REQUIRED) The mount mode, specified by number (e.g. container.mount.mode[0]) or
container.mount.rdwr (ARG_REQUIRED) The mount rdwr value, specified by number (e.g. container.mount.rdwr[0])
container.mount.propagation (ARG_REQUIRED) The mount propagation value, specified by number (e.g.
container.image.repository The container image repository (e.g. falcosecurity/falco). In instances of userspace
container.image.tag The container image tag (e.g. stable, latest). In instances of userspace container engine
container.image.digest The container image registry digest (e.g.
container.healthcheck The container's health check. Will be the null value ("N/A") if no healthcheck
container.liveness_probe The container's liveness probe. Will be the null value ("N/A") if no liveness probe
container.readiness_probe The container's readiness probe. Will be the null value ("N/A") if no readiness probe
container.start_ts Container start as epoch timestamp in nanoseconds based on proc.pidns_init_start_ts and
container.duration Number of nanoseconds since container.start_ts.
container.ip The container's / pod's primary ip address as retrieved from the container engine. Only
container.cni.json The container's / pod's CNI result field from the respective pod status info. It contains

可以看出,container.id只能取前12个字符,另外也可以用容器id的全名,即container.full_id。另外k8s可支持的字段有:

1
2
3
4
5
6
7
8
9
10
11
ubuntu@primary:~$ sysdig -l | grep "^k8s."
k8s.ns.name The Kubernetes namespace name. This field is extracted from the container runtime socket
k8s.pod.name The Kubernetes pod name. This field is extracted from the container runtime socket
k8s.pod.id [LEGACY] The Kubernetes pod UID, e.g. 3e41dc6b-08a8-44db-bc2a-3724b18ab19a. This legacy
k8s.pod.uid The Kubernetes pod UID, e.g. 3e41dc6b-08a8-44db-bc2a-3724b18ab19a. Note that the pod UID
k8s.pod.sandbox_id The truncated Kubernetes pod sandbox ID (first 12 characters), e.g 63060edc2d3a. The
k8s.pod.full_sandbox_id The full Kubernetes pod / sandbox ID, e.g
k8s.pod.label (ARG_REQUIRED) The Kubernetes pod label. The label can be accessed either with the
k8s.pod.labels The Kubernetes pod comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'. This
k8s.pod.ip The Kubernetes pod ip, same as container.ip field as each container in a pod shares the
k8s.pod.cni.json The Kubernetes pod CNI result field from the respective pod status info, same as

Traps

此处有坑

使用container.id过滤时,注意id的长度需要为12,不然数据出不来。通过crictl ps看到的container id13位的,使用sysdig时,需要注意长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ubuntu@primary:~$ crictl ps | grep -v ^C | awk '{print $1,$2,$6,$7}'
0fd88042f1ddf 848c5b919e8d3 Running calico-apiserver
ad81cac0dbf9e 848c5b919e8d3 Running calico-apiserver
f6d6b81c75f69 4e87edec0297d Running calico-kube-controllers
87c4fbddeb123 d36ef67f7b24c Running csi-node-driver-registrar
46095b3ea4bf6 91c1c91da7602 Running calico-csi
51e65353815dc cbb01a7bd410d Running coredns
7fc6f4ad4aafa cbb01a7bd410d Running coredns
de42d610f5530 1843802b91be8 Running calico-node
21ae9adf53e47 b33768e0da1f8 Running calico-typha
a2f7701ceae6c 7bc79e0d3be4f Running tigera-operator
d91edc95d2edf 9344fce2372f8 Running kube-proxy
5f7d85179ade0 6fc5e6b7218c7 Running kube-scheduler
d40dd28cc171c 138fb5a3a2e34 Running kube-controller-manager
c71d33c5aea6e 8a9000f98a528 Running kube-apiserver
0cdeff9542f15 a0eed15eed449 Running etcd

falco

Reference: https://falco.org/docs

strace

监控进程系统调用信号量,基础的使用方式

  1. 监听某个已存在的进程 strace -p <pid>
  2. 直接启动一个二进制 strace <binary-name>
  3. 对输出结果进行过滤 strace -e trace=file

考试说明书

Handbook of CKS exam

Requirments of your computer, microphone, camera, speaker, etc.

Don’t use headphone, earbuds.

Exam Details

Online tests, 15-20 performance-based tasks, 2 hours to complete the tasks.

Don’t cheat, audio,camera,screen capture of the test will be reviewed.

利用OpenWrt为虚拟机做流量代理

安装Openwrt虚拟机

下载镜像:Index of /releases/22.03.5/targets/x86/64/ (openwrt.org)

转换镜像:

1
qemu-img convert -f raw -O vdi openwrt-22.03.5-x86-64-generic-ext4-combined-efi.img openwrt-22.03.5-x86-64-generic-ext4-combined-efi.img.vdi

配置虚拟机网卡:

  1. 在VirtualBox中新建HostNetwork(Host-Only网络),网段为192.168.56.0/24

  2. 在openwrt虚拟机的网络选项中设置:

    1)启用网卡1,连接方式选仅主机网络,名称选上步创建的HostNetwork

    2)启用网卡2,连接方式选桥接网卡,名称选本机上能访问外网的网卡

  3. 进入openwrt虚拟机,为lan口设置静态IP地址为HostNetwork中的一个IP,这里用 192.168.56.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
option device 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'

config globals 'globals'
option ula_prefix 'fdd4:bccc:9ebb::/48'

config device
option name 'br-lan'
option type 'bridge'
list ports 'eth0'

config interface 'lan'
option device 'br-lan'
option proto 'static'
option ipaddr '192.168.56.2'
option netmask '255.255.255.0'
option ip6assign '60'

config interface 'wan'
option device 'eth1'
option proto 'dhcp'

config interface 'wan6'
option device 'eth1'
option proto 'dhcpv6'

OPENWRT开启SFTP,实现文件下载上传

同时也能使用scp命令进行拷贝

1
2
3
4
opkg update
opkg install vsftpd openssh-sftp-server
/etc/init.d/vsftpd enable
/etc/init.d/vsftpd start

OpenClash安装与配置

1
2
3
#iptables
opkg update
opkg install coreutils-nohup bash iptables dnsmasq-full curl ca-certificates ipset ip-full iptables-mod-tproxy iptables-mod-extra libcap libcap-bin ruby ruby-yaml kmod-tun kmod-inet-diag unzip luci-compat luci luci-base

如果需要强制安装,可以先opkg remove,再opkg install

Releases · vernesong/OpenClash (github.com)页面,将openclash安装包下载到openwrt虚拟机中,通过 opkg install 安装。

配置手册:Home · vernesong/OpenClash Wiki (github.com)

其他虚拟机的旁路由配置

此处用的是ubuntu server,可以在安装界面时设置,也可以等安装完成后,手动修改配置。手动修改的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
enp0s3:
addresses:
- 192.168.56.3/24
nameservers:
addresses:
- 114.114.114.114
search: []
routes:
- to: default
via: 192.168.56.2
version: 2

配置修改后,可以看到默认路由已变成 192.168.56.2

1
2
3
4
$ ip route
default via 192.168.56.2 dev enp0s3 proto static
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.56.0/24 dev enp0s3 proto kernel scope link src 192.168.56.3

Reference

Git 操作及原理

Git Diff 的工作原理

Myers差分算法

创建基于某个 commit id 的分支

1
git checkout -b dev c99d6500

查看指定分支的提交

1
2
git log master
git config --global alias.nicelog "log --graph --abbrev-commit --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'"

如下所示:

git 如何存储

git 如何 merge

git 如何 rebase

是否能 cherry-pick 所有的 commit