@@ -842,7 +842,7 @@ metadata:
842
842
name: test-ns
843
843
labels:
844
844
gk-ns: xxx
845
- EOF
845
+ EOF
846
846
847
847
# 创建 namespace , 因为这个 namespace 有 gk-ns: xxx 的 label 所以这个请求可以被允许
848
848
$ kubectl apply -f test-ns.yaml
@@ -852,7 +852,7 @@ $ cat <<EOF > gk-ns-constraintTemplate.yaml
852
852
apiVersion: templates.gatekeeper.sh/v1beta1
853
853
kind: ConstraintTemplate
854
854
metadata:
855
- name: k8srequiredregistry
855
+ name: k8srequiredregistry
856
856
spec:
857
857
crd:
858
858
spec:
@@ -933,6 +933,93 @@ kube-apiserver 是整个 k8s 的 api 接口,所有和 k8s 打交道的服务
933
933
- ImagePolicyWebhook -- 这个准入控制器是用来检查 pod 的 image 是否符合自定义的安全策略,即将验证 image 的合法性委托给一个外置的服务来完成,通常会和 ` Open Policy Agent GateKeeper ` 配合来使用。
934
934
- --enable-bootstrap-token-auth -- 当这个设置为 true 时会增加 kube-apiserver 认证的风险,攻击者可以利用这个 token 加入恶意的节点到集群中,所以这个参数的设置应该是 false。
935
935
936
+ #### 5.2.1 lab:启用 API server 认证
937
+
938
+ 操作如下:
939
+
940
+ - 使用 Node,RBAC 授权模式和 NodeRestriction 准入控制器
941
+
942
+ ``` yaml
943
+ vi /etc/kubernetes/manifests/kube-apiserver.yaml
944
+ # 确保以下内容
945
+ - --authorization-mode=Node,RBAC
946
+ - --enable-admission-plugins=NodeRestriction
947
+ - --client-ca-file=/etc/kubernetes/pki/ca.crt
948
+ - --enable-bootstrap-token-auth=true
949
+ ` ` `
950
+
951
+ - 删除 system:anonymous 的 ClusterRolebinding 角色绑定,取消匿名用户的集群管理员权限
952
+
953
+ ` ` ` bash
954
+ kubectl delete clusterrolebinding system:anonymous
955
+ ```
956
+
957
+ # ### 5.2.2 lab:ImagePolicyWebhook
958
+
959
+ 实验如下:
960
+
961
+ 1. 修改控制器配置文件,将未找到有效后端时的默认拒绝改为默认不拒绝
962
+
963
+ ` vi /etc/kubernetes/epconfig/admission_configuration.json`
964
+
965
+ ` ` ` json
966
+ {
967
+
968
+ "imagePolicy": {
969
+ "kubeConfigFile": "/etc/kubernetes/epconfig/kubeconfig.yaml",
970
+ "allowTTL": 50,
971
+ "denyTTL": 50,
972
+ "retryBackoff": 500,
973
+ "defaultAllow": false
974
+ }
975
+ }
976
+ ` ` `
977
+
978
+ 2. 修改控制器访问 webhook server 的 kubeconfig
979
+
980
+ ` vi /etc/kubernetes/epconfig/kubeconfig.yaml`
981
+
982
+ 修改如下内容
983
+
984
+ ` ` ` yaml
985
+ apiVersion: v1
986
+ kind: Config
987
+ clusters:
988
+ - cluster:
989
+ certificate-authority: /etc/kubernetes/epconfig/webhook.pem
990
+ server: https://acme.local:8082/image_policy # web hook server 的地址
991
+ name: bouncer_webhook
992
+ # 以下省略
993
+ ` ` `
994
+
995
+ 3. 启用 ImagePolicyWebhook
996
+
997
+ ` vi /etc/kubernetes/manifests/kube-apiserver.yaml`
998
+
999
+ ` ` ` yaml
1000
+ # 启用 ImagePolicyWebhook
1001
+ - --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook
1002
+ # 指定准入控制器配置文件
1003
+ - --admission-control-config-file=/etc/kubernetes/epconfig/admission_configuration.json
1004
+ # mount
1005
+ volumeMounts:
1006
+ - mountPath: /etc/kubernetes/epconfig
1007
+ name: epconfig
1008
+ # 映射 volumes
1009
+ volumes:
1010
+ - name: epconfig
1011
+ hostPath:
1012
+ path: /etc/kubernetes/epconfig
1013
+ ` ` `
1014
+
1015
+ 4. 测试是否生效
1016
+
1017
+ ` ` ` bash
1018
+ systemctl daemon-reload
1019
+ systemctl restart kubelet
1020
+ kubectl apply -f /cks/img/web1.yaml
1021
+ ` ` `
1022
+
936
1023
# ## 5.3 审计日志
937
1024
938
1025
在被攻击后追溯攻击者的行为也是重要的一部分的工作,如果 kube-apiserver 没有开启 audit 那么基本就很难追溯攻击者到底在 k8s 中做了什么,所以开启 audit 是非常重要的。审计日志有以下级别:
@@ -1003,39 +1090,201 @@ pod 安全策略是用过批量修改满足特定条件的 pod 的安全选项
1003
1090
1004
1091
但是值得注意的是这个功能[在 1.21 被标记为 deprecated,在 K8S 1.25 以后的版本中被彻底移除](https://kubernetes.io/docs/concepts/security/pod-security-policy/),所以我们应该尽快的使用 Admission Controllers 来替代 [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-admission/) 。目前这并不是考试的内容。
1005
1092
1093
+ 实验如下:
1094
+
1095
+ 1. 创建 psp
1096
+
1097
+ ` ` ` yaml
1098
+ apiVersion: policy/v1beta1
1099
+ kind: PodSecurityPolicy
1100
+ metadata:
1101
+ name: restrict-policy
1102
+ spec:
1103
+ privileged: false
1104
+ seLinux:
1105
+ rule: RunAsAny
1106
+ supplementalGroups:
1107
+ rule: RunAsAny
1108
+ runAsUser:
1109
+ rule: RunAsAny
1110
+ fsGroup:
1111
+ rule: RunAsAny
1112
+ volumes:
1113
+ - '*'
1114
+ ` ` `
1115
+
1116
+ 2. 创建 clusterrole,使用 psp
1117
+
1118
+ ` kubectl create clusterrole restrict-access-role --verb=use --resource=psp --resource-name=restrict-policy`
1119
+
1120
+ 3. 创建 serviceaccount
1121
+
1122
+ ` kubectl create sa psp-denial-sa -n staging`
1123
+
1124
+ 4. 绑定 clusterrole 到 serviceaccount
1125
+
1126
+ ` kubectl create clusterrolebinding dany-access-bind --clusterrole=restrict-access-role --serviceaccount=staging:psp-denial-sa`
1127
+
1128
+ 5. 启用 PSP
1129
+
1130
+ ` ` ` yaml
1131
+ vi /etc/kubernetes/manifests/kube-apiserver.yaml
1132
+ # 确保有以下内容:
1133
+ - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
1134
+ ` ` `
1135
+
1006
1136
# ## 5.6 服务账户令牌(Service Account Token)
1007
1137
1008
1138
这个是用来授权 pod 访问 kube-apiserver 的,所以这个 token 的安全性也是非常重要的,如果这个 token 泄露了,那么攻击者就可以通过这个 token 来做任何事情,所以我们应该定期的轮换这个 token,比如每个月轮换一次,这样即使这个 token 泄露了,比如由于不正确的配置导致攻击者将有 cluster-admin 权限的 service account 的 token 挂载到了 `恶意的 pod` 中, 那么他很容易通过 InClusterConfig() 方法轻易获取到访问 kube-apiserver 中所有的 api group 的所有的权限,他可以轻易删掉 node 对象和其他任何对象,对集群造成很大的破坏。
1009
1139
1010
1140
` ` ` bash
1011
- # 生成一个模板
1141
+ # 生成一个模板
1012
1142
kubectl create sa correct-sa -n task2 --dry-run=client -o yaml > task2-temp-sa.yaml
1013
- # 确保配置如下
1143
+ # 确保配置如下
1014
1144
vi task2-temp-sa.yaml
1015
1145
` ` `
1016
1146
1147
+ serviceaccount 有个选项 automountServiceAccountToken, 这个选项决定是否自动挂载 secret 到 pod。
1148
+
1149
+ 有这个选项,我们可以控制 pod 创建并绑定 serviceaccount 时,不自动挂载对应的 secret,这样 pod 就没有权限访问 apiserver,提高了业务 pod 的安全性。
1150
+
1151
+ 可以在 serviceaccount 和 pod 的 spec 里设置。serviceaccount 里的设置是全局的,pod 的设置会覆盖 serviceaccount 里的设置。
1152
+
1017
1153
` ` ` yaml
1018
1154
# task2-temp-sa.yaml
1019
1155
apiVersion: v1
1020
1156
kind: ServiceAccount
1021
1157
metadata:
1022
1158
name: correct-sa
1023
1159
namespace: task2
1024
- automountServiceAccountToken: false # 注意这里要是 false 默认是 true
1160
+ automountServiceAccountToken: false # 注意这里要是 false, 默认是 true
1025
1161
` ` `
1026
1162
1027
1163
` ` ` bash
1028
1164
# 创建 sa
1029
1165
kubectl create -f task2-temp-sa.yaml
1030
1166
1031
- # 修改改 pod
1032
- # 将 serviceAccountName: sa-not-exist 噶成 serviceAccountName: correct-sa
1033
- vi /tmp/task2/pod.yaml
1167
+ # 修改 pod
1168
+ # 将 serviceAccountName: sa-not-exist 改成 serviceAccountName: correct-sa
1169
+ vi /tmp/task2/pod.yaml
1170
+
1171
+ ` ` ` yaml
1172
+ apiVersion : v1
1173
+ kind : Pod
1174
+ metadata :
1175
+ name : backend
1176
+ namespace : qa
1177
+ spec :
1178
+ serviceAccountName : correct-sa
1179
+ containers :
1180
+ - image : nginx:1.9
1181
+ imagePullPolicy : IfNotPresent
1182
+ name : backend
1183
+ ` ` `
1184
+
1185
+ ### 5.7 lab
1186
+
1187
+ #### 5.7.1 lab1 审计日志
1188
+
1189
+ 编写日志审计策略文件
1190
+
1191
+ ` ` ` yaml
1192
+ apiVersion : audit.k8s.io/v1
1193
+ kind : Policy
1194
+ omitStages :
1195
+ - " RequestReceived"
1196
+ rules :
1197
+ - level : RequestResponse
1198
+ resources :
1199
+ - group : " "
1200
+ resources : ["namespaces"]
1201
+
1202
+ - level : Request
1203
+ resources :
1204
+ - group : " "
1205
+ resources : ["persistentvolumes"]
1206
+ namespaces : ["front-apps"]
1207
+
1208
+ - level : Metadata
1209
+ resources :
1210
+ - group : " "
1211
+ resources : ["secrets", "configmaps"]
1212
+
1213
+ - level : Metadata
1214
+ omitStages :
1215
+ - " RequestReceived"
1216
+ ` ` `
1217
+
1218
+ 修改 kube-apiserver.yaml 配置文件,启用日志审计策略,日志策略配置文件位置、日志文件存储位置、循环周期。
1219
+
1220
+ ` ` ` bash
1221
+ vi /etc/kubernetes/manifests/kube-apiserver.yaml
1222
+ ```
1223
+
1224
+ ``` yaml
1225
+ # 设置日志审计策略文件在 pod 里的 mount 位置
1226
+ - --audit-policy-file=/etc/kubernetes/logpolicy/sample-policy.yaml
1227
+
1228
+ # 设置日志文件存储位置
1229
+ - --audit-log-path=/var/log/kubernetes/audit-logs.txt
1230
+
1231
+ # 设置日志文件循环
1232
+ - --audit-log-maxage=10
1233
+ - --audit-log-maxbackup=2
1234
+
1235
+ # mount 日志策略和日志文件的
1236
+ volumeMounts :
1237
+ - mountPath : /etc/kubernetes/logpolicy/sample-policy.yaml
1238
+ name : audit
1239
+ readOnly : true
1240
+ - mountPath : /var/log/kubernetes/audit-logs.txt
1241
+ name : audit-log
1242
+ readOnly : false
1243
+ volumes :
1244
+ - name : audit
1245
+ hostPath :
1246
+ path : /etc/kubernetes/logpolicy/sample-policy.yaml
1247
+ type : File
1248
+ - name : audit-log
1249
+ hostPath :
1250
+ path : /var/log/kubernetes/audit-logs.txt
1251
+ type : FileOrCreate
1252
+ ` ` `
1253
+
1254
+ 重启 API Server 来检查 audit.log
1255
+
1256
+ ` ` ` bash
1257
+ cd /etc/kubernetes/manifests/
1258
+ mv kube-apiserver.yaml ..
1259
+ watch crictl ps # wait for apiserver gone
1260
+ truncate -s 0 /etc/kubernetes/audit/logs/audit.log
1261
+ mv ../kube-apiserver.yaml .
1262
+
1263
+ cat audit.log | tail | jq
1264
+
1265
+ # shows Secret entries
1266
+ cat audit.log | grep '"resource":"secrets"' | wc -l
1267
+
1268
+ # confirms Secret entries are only of level Metadata
1269
+ cat audit.log | grep '"resource":"secrets"' | grep -v '"level":"Metadata"' | wc -l
1270
+
1271
+ # shows RequestResponse level entries
1272
+ cat audit.log | grep -v '"level":"RequestResponse"' | wc -l
1273
+
1274
+ # shows RequestResponse level entries are only for system:nodes
1275
+ cat audit.log | grep '"level":"RequestResponse"' | grep -v "system:nodes" | wc -l
1276
+ ```
1034
1277
1035
1278
# 创建 pod
1036
1279
kubectl create -f /tmp/task2/pod.yaml
1280
+ ```
1281
+
1282
+ 自动挂载的 service token 的 pod 可以做很多事,比如 get secret
1037
1283
1038
- # all set
1284
+ ```bash
1285
+ k -n restricted get pod -o yaml | grep automountServiceAccountToken
1286
+
1287
+ curl https://kubernetes.default/api/v1/namespaces/restricted/secrets -H "Authorization: Bearer $(cat /run/secrets/kubernetes.io/serviceaccount/token)" -k
1039
1288
```
1040
1289
1041
1290
## 6. 网络
@@ -1410,6 +1659,20 @@ apparmor module is loaded.
1410
1659
1411
1660
# ### 7.3.1 lab1-trivy
1412
1661
1662
+ trivy 的操作,在考试和实际使用场景中都是三板斧:
1663
+
1664
+ ` ` ` bash
1665
+ # 获取镜像名
1666
+ kubect get pod XXXX -n kamino -o yaml | grep image
1667
+ # 扫描镜像
1668
+ trivy imagename | grep (HIGH|CRITICAL)
1669
+ trivy nginx:1.16.1-alpine | grep -E 'CVE-2020-10878|CVE-2020-1967'
1670
+ # 删除 pod
1671
+ kubectl delete po XXXX
1672
+ ` ` `
1673
+
1674
+ 完整的实验如下:
1675
+
1413
1676
分别使用镜像 `nginx:latest` 和 `alpine:latest` 启动 2 个 pod 在 namespace chapter-7 下, 然后用 trivy 对他们的镜像进行一个扫描
1414
1677
1415
1678
` ` ` bash
@@ -1505,15 +1768,17 @@ profile k8s-apparmor-chapter7-pod3-deny-write flags=(attach_disconnected) {
1505
1768
deny /** w,
1506
1769
}
1507
1770
EOF'
1771
+ ```
1508
1772
1773
+ ``` yaml
1509
1774
cat <<EOF > chapter7-pod3.yaml
1510
1775
apiVersion : v1
1511
1776
kind : Pod
1512
1777
metadata :
1513
1778
name : chapter7-pod3
1514
1779
namespace : chapter-7
1515
1780
annotations :
1516
- container.apparmor.security.beta.kubernetes.io/chapter7-container3: localhost/k8s-apparmor-chapter7-pod3-deny-write # 添加这一行
1781
+ container.apparmor.security.beta.kubernetes.io/chapter7-container3 : localhost/k8s-apparmor-chapter7-pod3-deny-write # 添加这一行,该注解表示加载对应的 apparmor profile。
1517
1782
spec :
1518
1783
containers :
1519
1784
- name : chapter7-container3
@@ -1562,5 +1827,22 @@ kill chain 攻击的生命周期的细化 -- 我们细化为 7 个详细的步
1562
1827
AI 反入侵工具:通过 AI 来检测入侵,就如果反到系统一样,会比我们人类反应更快,经过大量学习后这些 AI 反入侵工具可以自动的检测出入侵,比如:
1563
1828
1564
1829
- [ NeuVector] ( https://neuvector.com/ )
1565
- - [ StackRox] ( https://www.stackrox.com/ )
1830
+ - [ StackRox] ( https://www.stackrox.com/ )
1566
1831
- 其它
1832
+
1833
+ ## 9. Exam Tips
1834
+
1835
+ 用 k 代替 kubectl,减少敲键盘
1836
+
1837
+ ``` bash
1838
+ alias k=kubectl
1839
+ ```
1840
+
1841
+ 其它小窍门:
1842
+
1843
+ - 善用考试软件提供的 notepad 功能,先把 yaml 文件或命令写到 notepad 里,再粘贴到 terminal 里
1844
+ - 别忘了 ` kubectl apply -f `
1845
+ - 别忘了 set context & ssh,别忘了退出 ssh
1846
+ - 别忘了 log 文件一般放在外面
1847
+ - 修改文件之前先 cp
1848
+ - 修改 k8s 对象之前,先导出 yaml
0 commit comments