cks
# 沙箱运行容器 gVisor

**Context**
该 cluster使用 `containerd`作为CRI运行时。`containerd`的默认运行时处理程序是runc。`containerd`已准备好支持额外的运行时处理程序`runsc`(gVisor)。
**Task**
使用名为`runsc`的现有运行时处理程序,创建一个名为`untrusted` 的RuntimeClass。更新 namespace `server`中的所有Pod以在gVisor上运行。
您可以在 `/cks/gVisor/rc.yaml`中找到一个模版清单。
**答题:**
考试时执行,切换集群。模拟环境中不需要执行。
`# kubectl config use-context KSMV00301`
1 创建RuntimeClass
```
vi /cks/gVisor/rc.yaml
添加如下内容
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
name: untrusted # 用来引用 RuntimeClass 的名字,RuntimeClass 是一个集群层面的资源
handler: runsc # 对应的 CRI 配置的名称
```
创建
`kubectl apply -f /cks/gVisor/rc.yaml`
检查
`kubectl get RuntimeClass`

2 将命名空间为server下的Pod引用RuntimeClass。
考试时Pod是创建好的,直接使用kubectl edit直接修改即可。
模拟环境里,有1个deployment和3个pod。其中1个pod是deployment的,只需要修改这个deployment和另外2个pod即可。
`kubectl get all -n server`

编辑deployment (这里环境有点问题,没有安装runsc,所以改完后保存会报错,忽略吧,先模拟一下命令即可。)
`kubectl edit deployments nginx-host -n server`
修改如下内容
```
spec: #找到这个spec,注意在deployment里是有两个单独行的spec的,要找第二个,也就是下面有containers这个字段的。
runtimeClassName: untrusted #添加这一行,注意空格对齐,保存会报错,忽略即可。
containers:
- image: vicuu/nginx:host
imagePullPolicy: IfNotPresent
name: nginx-host
```
编辑pod
`kubectl edit pod nginx-gvisor -n server`
```
spec: #在pod里,只有一个定单独行的spec,选择这个spec下面添加。
runtimeClassName: untrusted #添加这一行,注意空格对齐,保存会报错,忽略即可。
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx-gvisor
```
编辑pod
`kubectl edit pod busybox -n server`
```
spec:
runtimeClassName: untrusted #添加这一行,注意空格对齐,保存会报错,忽略即可。
containers:
- args:
- /bin/sh
- -c
- |
i=0; while true; do
echo "$(date) INFO $i" >> /var/log/11-factor-app.log;
i=$((i+1));
sleep 1;
done
image: busybox
imagePullPolicy: IfNotPresent
name: busybox
```
# 创建 Secret(真题第8题)

**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`
参考资料:
三个网址都要看
`https://kubernetes.io/zh/docs/tasks/configmap-secret/managing-secret-using-kubectl/#decoding-secret`
`https://kubernetes.io/zh/docs/tasks/configmap-secret/managing-secret-using-kubectl/#create-a-secret`
`https://kubernetes.io/zh/docs/concepts/configuration/secret/#using-secrets`
** 答题:**
考试时执行,切换集群。模拟环境中不需要执行。
`# kubectl config use-context KSCH00701`
**1 将db1-test的username和password,通过base64解码保存到题目指定文件:**
**方法1:**
`kubectl get secrets db1-test -n istio-system -o jsonpath={.data}`
会反馈结果为:{"password":"aGVsbG8=","username":"ZGIx"}
```
echo 'ZGIx'|base64 -d > /cks/sec/user.txt
echo 'aGVsbG8='|base64 -d > /cks/sec/pass.txt
```
**方法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`
检查
```
cat /cks/sec/user.txt
cat /cks/sec/pass.txt
```

2 创建名为 db2-test 的 secret 使用题目要求的用户名和密码作为键值。注意要加命名空间。
注意,如果密码中有特殊字符(例如:$,\,*,= 和 !),需要加单引号来转义--from-literal=password='G!Y\*d$zDsb'这样。
`kubectl create secret generic db2-test -n istio-system --from-literal=username=production-instance --from-literal=password=KvLftKgs4aVH`
检查
kubectl get secret -n istio-system

3 根据题目要求,参考官网,创建Pod使用该secret
vim k8s-secret.yaml
添加如下内容
```
apiVersion: v1
kind: Pod
metadata:
name: secret-pod #pod名字
namespace: istio-system #命名空间
spec:
containers:
- name: dev-container #容器名字
image: nginx #镜像名字
volumeMounts: #挂载路径
- name: secret-volume #卷名
mountPath: /etc/secret
volumes:
- name: secret-volume #卷名
secret:
secretName: db2-test #名为 db2-test 的 secret
```
创建
kubectl apply -f k8s-secret.yaml

检查
kubectl get pod -n istio-system

# Dockerfile检测

**Task**
分析和编辑给定的Dockerfile `/cks/docker/Dockerfile`(基于`ubuntu:16.04` 镜像),并修复在文件中拥有的突出的安全/最佳实践问题的两个指令。
分析和编辑给定的清单文件 `/cks/docker/deployment.yaml` ,并修复在文件中拥有突出的安全/最佳实践问题的两个字段。
注意:请勿添加或删除配置设置;只需修改现有的配置设置让以上两个配置设置都不再有安全/最佳实践问题。
注意:如果您需要非特权用户来执行任何项目,请使用用户ID `65535` 的用户 `nobody` 。
参考资料:
`https://kubernetes.io/zh/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container`
**答题:**
考试时执行,切换集群。模拟环境中不需要执行。
`# kubectl config use-context KSSC00301`
注意,本次的Dockerfile和deployment.yaml仅修改即可,无需部署。
1 修改Dockerfile
```
`vi /cks/docker/Dockerfile`
1、仅将CMD上面的USER root修改为USER nobody,不要改其他的USER root。
USER nobody
2、修改基础镜像为题目要求的 ubuntu:16.04
FROM ubuntu:16.04
```


2 修改deployment.yaml
```
vi /cks/docker/deployment.yaml
1、修改如下两行,将'privileged': True 修改为'privileged': False,检查确保‘runAsUser’: 65535为65535。
securityContext:
{"Capabilities": {'add':{NET_BIND_SERVICE}, 'drop: []'}, 'privileged': False, ‘readonlyRootFilesystem’: False, ‘runAsUser’: 65535}
2、考试时deployment.yaml的labels标签跟上面的不一致,所以需要将原先的run: couchdb修改为app: couchdb
app: couchdb
```


# 容器安全,删除特权Pod(真题第10题)
**Context**
最佳实践是将容器设计为无状态和不可变的。
**Task**
检查在 namespace production中运行的Pod,并删除任何非无状态或非不可变的 Pod。
使用以下对无状态和不可变的严格解释:
- 能够在容器内存储数据的 Pod 的容器必须被视为`非无状态`的。
注意:你不必担心数据是否实际上已经存储在容器中。
- 被配置为任何形式的特权 Pod 必须被视为可能是非无状态和非不可变的.
参考资料:
`https://kubernetes.io/docs/tasks/configure-pod-container/security-context/`
**答题:**
考试时执行,切换集群。模拟环境中不需要执行。
`# kubectl config use-context KSRS00501`
```
查看此命名空间下的所有 pod,删除有特权 Privileged 或者挂载 volume 的 pod
kubectl get pod -n production
kubectl get pods XXXX -n production -o yaml | grep -i "privileged: true" #注意冒号后面有一个空格,XXXX换成production命名空间下的pod名。
```

将上面查出来的有特权的pod删除
`kubectl delete pod XXXX -n production`

上面只是将特权的pod查出来了,根据题目要求,还应该查挂载volume的pod,命令为
```
kubectl get pods XXXX -n production -o jsonpath={.spec.volumes} | jq
kubectl get pods XXXX -n production -o jsonpath={.spec.volumes} | python -m json.tool
```
模拟环境里的3个pod,都没有挂载volume,所以无需删除了。考试中也是这样的,都没有挂载volume。

什么样的是挂载了volume的pod呢?
比如kube-system命名空间下的etcd-master01是挂载了volume的。
具体是否挂载,可以依据是否有hostPath或路径

# 网络策略 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找到一个模板清单文件。
参考资料:
`https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/#networkpolicy-resource`
**答题:**
考试时执行,切换集群。模拟环境中不需要执行。
`# kubectl config use-context KSSH00301`
1 检查namespace标签
模拟环境已提前打好标签了,所以你只需要检查标签即可。但为了防止考试时,没有给你打标签,所以还是需要你将下面打标签的命令记住。
查看 qa 命名空间标签(name: qa)
`kubectl get ns --show-labels`

查看 pod 标签(environment: testing)
`kubectl get pod -n dev-team --show-labels`

如果 Pod 或者 Namespace 没有标签,则需要打上标签。
注意:我这里将pod products-service的标签打成了environment: testing,下面会有解释,不要和题目里要求的“位于任何namespace,带有标签environment: testing的Pod”这句话里的标签混淆了。
```
kubectl label ns qa name=qa
kubectl label pod products-service environment=testing -n dev-team
```
2 创建NetworkPolicy
`vi /cks/net/po.yaml`
根据官网,修改为如下内容:
```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pod-restriction #修改
namespace: dev-team #修改
spec:
podSelector:
matchLabels:
environment: testing #根据题目要求的标签修改,这个写的是Pod products-service的标签,也就是使用kubectl get pod -n dev-team --show-labels查出来的pod的标签,这个标签不要和题目里要求的“位于任何namespace,带有标签environment: testing的Pod”这句话里的标签混淆了,两个没有关系,所以可不一样。比如你考试时查出来的POD products-service的标签是name: products,那这里的environment: testing就要换成name: products。
policyTypes:
- Ingress #注意,这里只写 - Ingress,不要将 - Egress也复制进来!
ingress:
- from: #第一个from
- namespaceSelector:
matchLabels:
name: qa #命名空间有name: qa标签的
- from: #第二个from
- namespaceSelector: {} #修改为这样,所有命名空间
podSelector: #注意,这个podSelector前面的“-” 要删除,换成空格,空格对齐要对。
matchLabels:
environment: testing #有environment: testing标签的Pod,这个地方是根据题目要求“Pods with label environment: testing , in any namespace”,这句话里的pod标签写的。不要和上面spec里的混淆。
```
创建
`kubectl apply -f /cks/net/po.yaml`
检查
`kubectl get networkpolicy -n dev-team`