前言
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的使用方法熟悉起來。
kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] [options]
網絡策略的實用方法見注釋
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條白名單,包含 from + ports 的組合規則,允許來自172.17網段(172.17.1除外)、或標 簽 project=myproject 的命名空間的所 有 pod 、或 default 命名空間下標簽 role=frontend 的 pod 訪問(限 tcp 6379 端口)
- 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 規則,允許來自所有命名空間包含 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 ,如果沒有加載,要手工加載
apparmor_status|grep nginx
apparmor_parser /etc/apparmor.d/nginx_apparmor
cks 考試的 apparmor profile 文件內容:
#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 這一行要確保注釋掉,考試環境提供的可能沒有注釋,加載配置文件按時會報錯
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
annotations:
container.apparmor.security.beta.kubernetes.io/podx: localhost/nginx-profile-3
yaml 文件內容如下:
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 集群存在的安全問題,基本上按照 掃描結果的修復建議進行修復就可以了,系統會給出很具體的修復措施。
# 修復 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 里的設置。
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) 編寫日志審計策略文件
日志審計策略
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
# 設置日志審計策略文件在 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
systemctl daemon-reload
systemctl restart kubelet
8. 創建 secret
這道題考解碼 secret 的 base64 編碼信息,創建新的 secret 並 mount 到 pod 的特定位置。
解碼 secret
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
kubectl create secret generic db2-test -n istio-system --from-literal=username=production-instance --from-literal=password=KvLftKgs4aVH
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 安全上下文注釋掉。
# 刪除兩處
USER root
# 注釋 securityContext
# securityContext:
# {"Capabilities": {'add':{NET_BIND_SERVICE}, 'drop: []'}, 'privileged': TRUE}
10. 運行沙箱容器
給出了 支持安全沙箱容器運行時 handler runsc
, 我們需要創建一個 RuntimeClass 並在 pod spec里指定是用該 RuntimeClass
參考資料
- 創建 RuntimeClass
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
name: untrusted
handler: runsc
- 修改 server 命名空間 所有 pod,設置 runtimeClassName
注意:運行中的 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 的使用
# 獲取鏡像名
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 分析特定容器
# 查看容器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
參考鏈接
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
kubectl create clusterrole restrict-access-role --verb=use --resource=psp --resource-name=restrict-policy
(3) 創建 serviceaccount
kubectl create sa psp-denial-sa -n staging
(4) 綁定 clusterrole 到 serviceaccount
kubectl create clusterrolebinding dany-access-bind --clusterrole=restrict-access-role --serviceaccount=staging:psp-denial-sa
(5) 啟用 PodSecurityPolicy
vi /etc/kubernetes/manifests/kube-apiserver.yaml
#確保有以下內容:
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
15. 啟用 API server認證
這道題同前面 kube-bench 的考核內容有點重合,題目中是用 kubeamd創建的 kubernetes服務器權限設置有問題,允許未經授權的訪問。
參考鏈接
需要進行以下修改:
- 使用 Node,RBAC 授權模式和 NodeRestriction 准入控制器
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角色綁定,取消匿名用戶的集群管理員權限
kubectl delete clusterrolebinding system:anonymous
16. ImagePolicyWebhook
這道題考察 ImagePolicyWebhook 准入控制器的使用,分4個步驟
- 修改控制器配置文件,將未找到有效后端時的默認拒絕改為默認不拒絕
參考鏈接
vi /etc/kubernetes/epconfig/admission_configuration.json
{
"imagePolicy": {
"kubeConfigFile": "/etc/kubernetes/epconfig/kubeconfig.yaml",
"allowTTL": 50,
"denyTTL": 50,
"retryBackoff": 500,
"defaultAllow": false
}
}
- 修改 控制器訪問 webhook server 的 kubeconfig
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
# 啟用 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
- 測試是否生效
systemctl daemon-reload
systemctl restart kubelet
kubectl apply -f /cks/img/web1.yaml