供应链安全
供应链安全

目录
[toc]
本节实战
| 实战名称 |
|---|
| 💘 实战:安装Trivy-2023.6.4(测试成功) |
| 💘 实战:安装kubesec-2023.6.4(测试成功) |
| 💘 实战:准入控制器: ImagePolicyWebhook-2023.6.6(测试成功) |
可信任软件供应链概述
**可信任软件供应链:**指在建设基础架构过程中,涉及的软件都是可信任的。
在K8s领域可信软件供应链主要是指镜像,因为一些软件交付物都是镜像,部署的最小载体。

构建镜像Dockerfile文件优化
- 减少镜像层:一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。
- **清理无用文件:**清理对应的残留数据,例如yum缓存。
- **清理无用的软件包:**基础镜像默认会带一些debug工具,可以删除掉,仅保留应用程序所需软件,防止黑客利用。
- 选择最小的基础镜像:例如alpine
- **使用非root用户运行:**USER指令指定普通用户

- 注意:
一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。


- 删除掉这个缓存目录就行

- alpine镜像大小:5MB

镜像漏洞扫描工具:Trivy
**Trivy:**是一种用于容器镜像、文件系统、Git仓库的漏洞扫描工具。发现目标软件存在的漏洞。
Trivy易于使用,只需安装二进制文件即可进行扫描,方便集成CI系统。
项目地址:https://github.com/aquasecurity/trivy
==💘 实战:安装Trivy-2023.6.4(测试成功)==

- 实验环境
1实验环境:
2centos7
- 实验软件
1链接:https://pan.baidu.com/s/17XstYWfyOWW3nyNgxhS4yQ?pwd=0820
2提取码:0820
32023.6.4-trivy-code

- 安装步骤
11、下载软件
2[root@k8s-master1 ~]#ll -h trivy_0.18.3_Linux-64bit.tar.gz #自己去官网下载,这里直接用提供的安装包
3-rw-r--r-- 1 root root 11M Jun 4 07:39 trivy_0.18.3_Linux-64bit.tar.gz
4
52、移动二进制文件到/usr/bin目录
6[root@k8s-master1 ~]#mkdir trivy
7[root@k8s-master1 ~]#mv trivy_0.18.3_Linux-64bit.tar.gz trivy
8[root@k8s-master1 ~]#cd trivy/
9[root@k8s-master1 trivy]#tar xf trivy_0.18.3_Linux-64bit.tar.gz
10[root@k8s-master1 trivy]#ls
11contrib LICENSE README.md trivy trivy_0.18.3_Linux-64bit.tar.gz
12[root@k8s-master1 trivy]#mv trivy /usr/bin/
13
143、测试
15[root@k8s-master1 ~]#trivy --help
16NAME:
17 trivy - A simple and comprehensive vulnerability scanner for containers
18
19USAGE:
20 trivy [global options] command [command options] target
21
22VERSION:
23 0.18.3
24
25COMMANDS:
26 image, i scan an image
27 filesystem, fs scan local filesystem
28 repository, repo scan remote repository
29 client, c client mode
30 server, s server mode
31 plugin, p manage plugins
32 help, h Shows a list of commands or help for one command
33
34GLOBAL OPTIONS:
35 --quiet, -q suppress progress bar and log output (default: false) [$TRIVY_QUIET]
36 --debug, -d debug mode (default: false) [$TRIVY_DEBUG]
37 --cache-dir value cache directory (default: "/root/.cache/trivy") [$TRIVY_CACHE_DIR]
38 --help, -h show help (default: false)
39 --version, -v print the version (default: false)
安装结束。😘
示例:
1# 容器镜像扫描
2trivy image nginx
3trivy image -i nginx.tar
4
5# 打印指定(高危、严重)漏洞信息
6trivy image -s HIGH nginx
7trivy image -s HIGH,CRITICAL nginx
8
9# JSON格式输出并保存到文件
10trivy image -f json -o output.json nginx


漏洞数据库:



检查YAML文件安全配置:kubesec
**kubesec:**是一个针对K8s资源清单文件进行安全配置评估的工具,根据安全配置最佳实践来验证并给出建议。
官网:https://kubesec.io
项目地址:https://github.com/controlplaneio/kubesec
==💘 实战:安装kubesec-2023.6.4(测试成功)==

- 实验环境
1实验环境:
2centos7
- 实验软件
1链接:https://pan.baidu.com/s/1SvQ1ijvplpe-hfUv6cCUgQ?pwd=0820
2提取码:0820
32023.6.4-kubesec-code

- 安装步骤
11、下载软件
2root@k8s-master1 ~]#ll -h kubesec_linux_amd64.tar.gz
3-rw-r--r-- 1 root root 3.9M Jun 4 07:39 kubesec_linux_amd64.tar.gz
4
52、解压
6[root@k8s-master1 ~]#tar xf kubesec_linux_amd64.tar.gz
7[root@k8s-master1 ~]#mv kubesec /usr/bin/
8
93、验证
10[root@k8s-master1 ~]#kubesec --help
11
12Validate Kubernetes resource security policies
13
14Usage:
15 kubesec [command]
16
17Available Commands:
18 help Help about any command
19 http Starts kubesec HTTP server on the specified port
20 scan Scans Kubernetes resource YAML or JSON
21 version Prints kubesec version
22
23Flags:
24 -h, --help help for kubesec
25
26Use "kubesec [command] --help" for more information about a command.
安装结束。😘
示例:
1kubesec scan deployment.yaml
2
3或者使用容器环境执行检查
4docker run -i kubesec/kubesec scan /dev/stdin < deployment.yaml
kubesec内置一个HTTP服务器,可以直接启用,远程调用。
- 二进制
1kubesec http 8080 &
- Docker容器
1docker run -d -p 8080:8080 kubesec/kubesec http 8080
2
3示例:
4curl -sSX POST --data-binary @deployment.yaml http://192.168.31.71:8080/scan
测试过程:
1[root@k8s-master1 ~]#kubectl create deployment web --image=nginx --dry-run=client -oyaml > deployment.yaml
2[root@k8s-master1 ~]#kubesec scan deployment.yaml

1[root@k8s-master1 ~]#docker run -d -p 8085:8080 kubesec/kubesec http 8080 #宿主机端口:容器端口
2[root@k8s-master1 ~]#curl -sSX POST --data-binary @deployment.yaml http://172.29.9.31:8085/scan #宿主机的8085端口

准入控制器: Admission Webhook
**Admission Webhook:**准入控制器Webhook是准入控制插件的一种,用于拦截所有向APISERVER发送的请求,并且可以修改请求或拒绝请求。
Admission webhook为开发者提供了非常灵活的插件模式,在kubernetes资源持久化之前,管理员通过程序可以对指定资源做校验、修改等操作。例如为资源自动打标签、pod设置默认SA,自动注入sidecar容器等。
相关Webhook准入控制器:
- MutatingAdmissionWebhook:修改资源,理论上可以监听并修改任何经过ApiServer处理的请求
- ValidatingAdmissionWebhook:验证资源
- ImagePolicyWebhook:镜像策略,主要验证镜像字段是否满足条件

准入控制器: ImagePolicyWebhook
==💘 实战:准入控制器: ImagePolicyWebhook-2023.6.6(测试成功)==

- 实验环境
1实验环境:
21、win10,vmwrokstation虚机;
32、k8s集群:3台centos7.6 1810虚机,1个master节点,2个node节点
4 k8s version:v1.20.0
5 docker://20.10.7
- 实验软件
1链接:https://pan.baidu.com/s/1RGJtAhqWXMNVxk7vauaCeA?pwd=0820
2提取码:0820
32023.6.6-ImagePolicyWebhook-code

- 课件步骤



1、准备配置文件
(在k8s-master1上操作)
- 创建
admission_configuration.yaml文件
1#创建/etc/kubernetes/image-policy目录及/etc/kubernetes/image-policy/admission_configuration.yaml文件
2[root@k8s-master1 ~]#mkdir /etc/kubernetes/image-policy/
3[root@k8s-master1 ~]#vim /etc/kubernetes/image-policy/admission_configuration.yaml
4apiVersion: apiserver.config.k8s.io/v1
5kind: AdmissionConfiguration
6plugins:
7- name: ImagePolicyWebhook
8 configuration:
9 imagePolicy:
10 kubeConfigFile: /etc/kubernetes/image-policy/connect_webhook.yaml # 连接镜像策略服务器配置文件
11 allowTTL: 50 # 控制批准请求的缓存时间,单位秒
12 denyTTL: 50 # 控制拒绝请求的缓存时间,单位秒
13 retryBackoff: 500 # 控制重试间隔,单位毫秒
14 defaultAllow: true # 确定webhook后端失效的行为
- 创建
connect_webhook.yaml文件
1[root@k8s-master1 ~]#vim /etc/kubernetes/image-policy/connect_webhook.yaml
2apiVersion: v1
3kind: Config
4clusters:
5- cluster:
6 certificate-authority: /etc/kubernetes/image-policy/webhook.pem # 数字证书,用于验证远程服务
7 server: https://172.29.9.32:8081/image_policy # 镜像策略服务器地址,必须是https
8 name: webhook
9contexts:
10- context:
11 cluster: webhook
12 user: apiserver
13 name: webhook
14current-context: webhook
15preferences: {}
16users:
17- name: apiserver
18 user:
19 client-certificate: /etc/kubernetes/image-policy/apiserver-client.pem # webhook准入控制器使用的证书
20 client-key: /etc/kubernetes/image-policy/apiserver-client-key.pem # 对应私钥证书
注:涉及的证书文件,下一步将生成,然后会拷贝到相应路径。
2、部署镜像服务器
(在k8s-node1上操作。)
自己用python开发一个简单的webhook端点服务器,作用是拒绝部署的镜像乜有指定标签(即latest)。
(1) 自签HTTPS证书
来到k8s-node1节点:
- 将压缩包
image-policy-webhook.zip拷贝到k8s-node1节点并解压:
1[root@k8s-node1 ~]#ll
2total 4
3-rw-r--r-- 1 root root 2910 Jun 5 07:09 image-policy-webhook.zip
4[root@k8s-node1 ~]#unzip image-policy-webhook.zip
5Archive: image-policy-webhook.zip
6 creating: image-policy-webhook/
7 inflating: image-policy-webhook/Dockerfile
8 inflating: image-policy-webhook/main.py
9 inflating: admission_configuration.yaml
10 inflating: connect_webhook.yaml
11 inflating: image-policy-certs.sh
12[root@k8s-node1 ~]#ls
13admission_configuration.yaml connect_webhook.yaml image-policy-certs.sh image-policy-webhook image-policy-webhook.zip
- 查看当前
image-policy-certs.sh自签脚本文件:
1[root@k8s-node1 ~]#cat image-policy-certs.sh
2[root@k8s-node1 ~]#cat image-policy-certs.sh
3cat > ca-config.json <<EOF
4{
5 "signing": {
6 "default": {
7 "expiry": "87600h"
8 },
9 "profiles": {
10 "kubernetes": {
11 "expiry": "87600h",
12 "usages": [
13 "signing",
14 "key encipherment",
15 "server auth",
16 "client auth"
17 ]
18 }
19 }
20 }
21}
22EOF
23
24cat > ca-csr.json <<EOF
25{
26 "CN": "kubernetes",
27 "key": {
28 "algo": "rsa",
29 "size": 2048
30 },
31 "names": [
32 {
33 "C": "CN",
34 "L": "Beijing",
35 "ST": "Beijing"
36 }
37 ]
38}
39EOF
40
41cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
42
43cat > webhook-csr.json <<EOF
44{
45 "CN": "webhook",
46 "hosts": [
47 "172.29.9.32"
48 ],
49 "key": {
50 "algo": "rsa",
51 "size": 2048
52 },
53 "names": [
54 {
55 "C": "CN",
56 "L": "BeiJing",
57 "ST": "BeiJing"
58 }
59 ]
60}
61EOF
62
63cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes webhook-csr.json | cfssljson -bare webhook
64
65cat > apiserver-client-csr.json <<EOF
66{
67 "CN": "apiserver",
68 "hosts": [],
69 "key": {
70 "algo": "rsa",
71 "size": 2048
72 },
73 "names": [
74 {
75 "C": "CN",
76 "L": "BeiJing",
77 "ST": "BeiJing"
78 }
79 ]
80}
81EOF
82
83cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes apiserver-client-csr.json | cfssljson -bare apiserver-client
- 执行脚本:
1[root@k8s-node1 ~]#sh image-policy-certs.sh
2[root@k8s-node1 ~]#ll
3total 5784
4-rw-r--r-- 1 root root 508 Oct 21 2021 admission_configuration.yaml
5-rw-r--r-- 1 root root 956 Jun 5 07:15 apiserver-client.csr
6-rw-r--r-- 1 root root 182 Jun 5 07:15 apiserver-client-csr.json
7-rw------- 1 root root 1679 Jun 5 07:15 apiserver-client-key.pem
8-rw-r--r-- 1 root root 1306 Jun 5 07:15 apiserver-client.pem
9-rw-r--r-- 1 root root 294 Jun 5 07:15 ca-config.json
10-rw-r--r-- 1 root root 960 Jun 5 07:15 ca.csr
11-rw-r--r-- 1 root root 212 Jun 5 07:15 ca-csr.json
12-rw------- 1 root root 1679 Jun 5 07:15 ca-key.pem
13-rw-r--r-- 1 root root 1273 Jun 5 07:15 ca.pem
14-rw-r--r-- 1 root root 5850685 Jun 5 07:15 cfssl.tar.gz
15-rw-r--r-- 1 root root 632 Oct 21 2021 connect_webhook.yaml
16-rw-r--r-- 1 root root 1365 Jun 5 07:13 image-policy-certs.sh
17drwxr-xr-x 2 root root 39 Jul 9 2021 image-policy-webhook
18-rw-r--r-- 1 root root 2910 Jun 5 07:09 image-policy-webhook.zip
19-rw-r--r-- 1 root root 1001 Jun 5 07:15 webhook.csr
20-rw-r--r-- 1 root root 202 Jun 5 07:15 webhook-csr.json
21-rw------- 1 root root 1679 Jun 5 07:15 webhook-key.pem
22-rw-r--r-- 1 root root 1330 Jun 5 07:15 webhook.pem
- 拷贝证书文件到
k8s-master1对应目录:
1[root@k8s-node1 ~]#scp webhook.pem apiserver-client-key.pem apiserver-client.pem root@172.29.9.31:/etc/kubernetes/image-policy/
2The authenticity of host '172.29.9.31 (172.29.9.31)' can't be established.
3ECDSA key fingerprint is SHA256:XfMhwZeoqC6kPHaF1uPzLdY9t2ZgNoNvyEd0kJd24eY.
4ECDSA key fingerprint is MD5:ec:5e:37:9d:fc:e7:af:e1:9e:3a:ac:21:81:92:b5:91.
5Are you sure you want to continue connecting (yes/no)? yes
6Warning: Permanently added '172.29.9.31' (ECDSA) to the list of known hosts.
7root@172.29.9.31's password:
8webhook.pem 100% 1330 1.3MB/s 00:00
9apiserver-client-key.pem 100% 1679 858.4KB/s 00:00
10apiserver-client.pem 100% 1306 330.6KB/s 00:00
11
12[root@k8s-master1 ~]#cd /etc/kubernetes/image-policy/
13[root@k8s-master1 image-policy]#ll
14total 20
15-rw-r--r-- 1 root root 509 Jun 5 07:01 admission_configuration.yaml
16-rw------- 1 root root 1679 Jun 5 07:27 apiserver-client-key.pem
17-rw-r--r-- 1 root root 1306 Jun 5 07:27 apiserver-client.pem
18-rw-r--r-- 1 root root 633 Jun 5 07:04 connect_webhook.yaml
19-rw-r--r-- 1 root root 1330 Jun 5 07:27 webhook.pem
(2) Docker容器启动镜像策略服务
- 构建镜像:
1[root@k8s-node1 ~]#pwd
2/root
3[root@k8s-node1 ~]#ls
4admission_configuration.yaml apiserver-client-key.pem ca.csr ca.pem image-policy-certs.sh webhook.csr webhook.pem
5apiserver-client.csr apiserver-client.pem ca-csr.json cfssl.tar.gz image-policy-webhook webhook-csr.json
6apiserver-client-csr.json ca-config.json ca-key.pem connect_webhook.yaml image-policy-webhook.zip webhook-key.pem
7[root@k8s-node1 ~]#cd image-policy-webhook
8[root@k8s-node1 image-policy-webhook]#ls
9Dockerfile main.py
10[root@k8s-node1 image-policy-webhook]#cat Dockerfile
11FROM python
12RUN useradd python
13RUN mkdir /data/www -p
14COPY . /data/www
15RUN chown -R python /data
16RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/
17WORKDIR /data/www
18USER python
19CMD python main.py
20[root@k8s-node1 image-policy-webhook]#docker build -t image-policy-webhook .
21[root@k8s-node1 image-policy-webhook]#docker images|grep image-policy-webhook
22image-policy-webhook latest 331d1c0b42d8 18 seconds ago 936MB
- 启动容器:
1docker run -d -u root --name=image-policy-webhook \
2-v $PWD/webhook.pem:/data/www/webhook.pem \
3-v $PWD/webhook-key.pem:/data/www/webhook-key.pem \
4-e PYTHONUNBUFFERED=1 -p 8081:8080 \
5image-policy-webhook
6
7#注意:这里的证书文件是放置在/root下的;
8#注意:课件里宿主机端口用的是8080,但自己宿主机8080端口被nodeCache占用了,因此这里使用8081.
9
10[root@k8s-node1 ~]#docker ps -l
11CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
127145eb5dfa6d image-policy-webhook "/bin/sh -c 'python …" 5 seconds ago Up 4 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp image-policy-webhook
13[root@k8s-node1 ~]#docker logs 7145eb5dfa6d
14 * Serving Flask app 'main'
15 * Debug mode: off
16WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
17 * Running on all addresses (0.0.0.0)
18 * Running on https://127.0.0.1:8080
19 * Running on https://172.17.0.2:8080
20Press CTRL+C to quit
21[root@k8s-node1 ~]#
3、启用准入控制插件
1[root@k8s-master1 ~]#vim /etc/kubernetes/manifests/kube-apiserver.yaml
2 - --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook
3 - --admission-control-config-file=/etc/kubernetes/image-policy/admission_configuration.yaml
4
5 ……
6 - mountPath: /etc/kubernetes/image-policy
7 name: image-policy
8 readOnly: true
9 ……
10 - hostPath:
11 path: /etc/kubernetes/image-policy
12 type: DirectoryOrCreate
13 name: image-policy


报错退出,此时可以看到静态pod kube-apiserver-k8s-master1发生重启了。
4、测试
- 在
k8s-node1上持续查看容器image-policy的日志
1[root@k8s-node1 ~]#docker logs -f image-policy-webhook

- 创建不带tag的deployment资源测试
1[root@k8s-master1 image-policy]#kubectl create deployment web-no-tag --image=nginx
2deployment.apps/web-no-tag created
3[root@k8s-master1 image-policy]#kubectl get deployment
4NAME READY UP-TO-DATE AVAILABLE AGE
5web-no-tag 0/1 0 0 10s
6[root@k8s-master1 image-policy]#kubectl describe replicaset web-no-tag-78bd59988f


- 创建tag的deployment资源测试
1[root@k8s-master1 image-policy]#kubectl create deployment web-with-tag --image=nginx:1.16
2deployment.apps/web-with-tag created
3[root@k8s-master1 image-policy]#kubectl get deployment
4NAME READY UP-TO-DATE AVAILABLE AGE
5web-no-tag 0/1 0 0 2m45s
6web-with-tag 1/1 1 1 6s

带有tag的镜像会被成功创建,不带tag的镜像会被ImagePolicyWebhook拒绝,符合预期。
测试结束。😘
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 微信二维码 x2675263825 (舍得), qq:2675263825。

🍀 微信公众号 《云原生架构师实战》

🍀 语雀
https://www.yuque.com/xyy-onlyone

🍀 csdn https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

🍀 知乎 https://www.zhihu.com/people/foryouone

最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!

