作者:scwang18,主要負責技術架構,在容器云方向頗有研究,
前言
CKA 和 CKS 是 Linux 基金會聯合 CNCF 社區組織的云原生技術領域權威的技術水平認證考試,考試采用實操方式進行,CKS 全稱是 Certified Kubernetes Security Specialist,它在一個模擬真實的環境中測驗考生對 Kubernetes 和云安全的知識,在參加 CKS 考試之前,必須已經通過 CKA(Kubernetes 管理員認證),在獲得 CKA 證書之后才可以預約 CKS 考試,CKS 的考試難度相對于 CKA 提高了很多,2 個小時的考試時間很緊張,因為考試是在外網上進行,這兩個考試又是實操考試,網路條件不好,很影響效率,如果不抓緊的話,很可能做不完所有實操題,提醒備考的同學善用考試軟體提供的 notepad 功能,先把 yaml 檔案或命令寫到 notepad 里,再粘貼到 Terminal 里,
我因為上次 CKA 考試還是比較順利,所以這次的 CKS 考試有點疏忽了,搞忘帶身份證和護照,CKA/CKS 考試需要身份證+護照 / 信用卡,因此跟監考老師溝通了很久時間,最后修改了考試人姓名為中文,是用駕駛證完成的考試,意外之喜是 CKS 給我的證書是中文名的,
我這次考試的 Kubernetes 版本是 1.22,特意記錄了一下考試會考到的知識點,分享給需要的同學,
補充:Kubernetes 1.25 開始,正式廢止了 PSP,這個部分可以參考本文的記錄,
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 兩個屬性,
# 如果不設定 ingress 或者 ingress 為空值,將禁止該型別流量,
# from 和 ports 屬性如果沒有設定或者為空{},表示匹配所有,這一點同 podSelector 一樣,
# inress 規則是陣列,多條規則之間是 or 關系,
# 以下示例中,第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 兩個屬性,
# 如果不設定 egress 或者 egress 為空值,將禁止該型別流量,
# to 和 ports 屬性如果沒有設定或者為空{},表示匹配所有,這一點同 podSelector 一樣,
# egress 規則是陣列,多條規則之間是 or 關系,
# {} 代表全部放行
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
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 這一行要確保注釋掉,考試環境提供的可能沒有注釋,加載組態檔按時會報錯,
$ 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 檔案,在注釋里設定為 Pod 加載 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
修復 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
解決 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
設定默認網路策略
這道題是送分題,設定默認拒絕所有出站和入站的 Pod 流量,基本上可以參考官網的案例直接改一下名字就可以了,
默認網路策略
RBAC
這道題也基本是送分題,參考官網檔案,根據題目要求,設定 role 的 資源訪問權限,系結到 serviceaccount 就可以了,
RBAC
日志審計
這道題稍復雜,需要按照要求啟動日志審計,包括兩個步驟:
(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 組態檔,啟用日志審計策略,日志策略組態檔位置、日志檔案存盤位置、回圈周期,
啟動日志配置
# /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
創建 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
創建 Secret,
$ kubectl create secret generic db2-test -n istio-system --from-literal=username=production-instance --from-literal=password=KvLftKgs4aVH
使用 Secret,
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
檢測 Dockerfile 的不安全指令
這道題也是送分題,主要是把 Dockerfile 里使用 root 用戶的指令洗掉,把添加特定能力的 securityContext 安全背景關系注釋掉,
# 洗掉兩處
USER root
# 注釋 securityContext
# securityContext:
# {"Capabilities": {'add':{NET_BIND_SERVICE}, 'drop: []'}, 'privileged': TRUE}
運行沙箱容器
支持安全沙箱容器運行時 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
洗掉不符合最佳實踐的 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
掃描鏡像安全漏洞并洗掉使用有安全漏洞鏡像的 Pod
這道題考察對于鏡像掃描工具 trivy 的使用
# 獲取鏡像名
$ kubect get pod XXXX -n kamino -o yaml | grep image
# 掃描鏡像
$ trivy image -s HIGH,CRITICAL imagename
# kubectl delete po xxx
使用 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
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
啟用 API server 認證
這道題同前面 kube-bench 的考核內容有點重合,題目中是用 kubeadm 創建的 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
ImagePolicyWebhook
這道題考察 ImagePolicyWebhook 準入控制器的使用,分 4 個步驟,
- 修改控制器組態檔,將未找到有效后端時的默認拒絕改為默認不拒絕,
參考鏈接
# /etc/kubernetes/epconfig/admission_configuration.json
{
"imagePolicy": {
"kubeConfigFile": "/etc/kubernetes/epconfig/kubeconfig.yaml",
"allowTTL": 50,
"denyTTL": 50,
"retryBackoff": 500,
"defaultAllow": false
}
}
- 修改 控制器訪問 webhook server 的 kubeconfig,
# /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,
# /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
本文由博客一文多發平臺 OpenWrite 發布!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/508810.html
標籤:其他
上一篇:帶您了解昇騰模型壓縮工具
下一篇:實體決議Java反射
