探索容器镜像安全管理之道

邓宇星,Rancher 中国软件架构师,7 年云原生领域经验,参与 Rancher 1.x 到 Rancher 2.x 版本迭代变化,目前负责 Rancher for openEuler(RFO)项目开发。

最近 Rancher v2.7.4 发布了,作为一个安全更新版本,也让大家对软件供应链安全多了一份思考。本文将围绕其中比较流行的容器镜像安全管理进行探讨和实践。

运行环境介绍

软件/操作系统版本
Rancherv2.7.4
Host OS: openEuler22.03-LTS-SP1
K8s: RFOv1.26.5+rfor1
cosignv2.0.2
Harborv2.8.2
Client OS: MacOS13.4
Kubewardenv1.6.0

本次实践将使用最新版 Rancher v2.7.4 作为 K8s 集群管理工具。在此之上可安装 Kubewarden UI 作为可视策略管理工具。整体运行架构以及流程如下:

arch

使用 RFO 分发版作为本次下游 K8s 集群,RFO 为 Rancher for openEuler 的简称,是一个基于 openEuler 基础镜像的 RKE2 分发版。同时我们使用 openEuler 作为本次 K8s 的 Host OS,与 RFO 适配性更佳。

RFO 介绍与 Quick Start 请点击:https://gitee.com/openeuler/community/tree/master/sig/sig-rfo

本次使用 Harbor + cosign + Kubewarden 的组合,对容器镜像进行存储/签名/验证操作,cosign 与 harbor v2.5.0+版本有较好的兼容性,能直接在 harbor UI 上看到 cosign 证书配置。经测试 Harbor v2.1.1 版本也可使用 cosign 进行签名,只是 Harbor UI 上显示不太直观。

环境准备

  • Harbor 安装请参考官网文档,请尽量使用 https 方式让 Harbor 对外提供服务,并使用可信的证书减少配置步骤。在本次实践当中,我们使用一个免费可信证书来规避此问题。
  • cosign 安装参考官方文档,本次使用的是 go install github.com/sigstore/cosign/v2/cmd/cosign@latest 的方式安装。
  • RFO 参考上文的 quick 地址,本次准备环境使用 1 master + 1 worker 的集群,机器规格都是 4c8g,确保有足够的资源运行所需组件。
  • Rancher 使用 Docker run 方式启动,并将 RFO 集群使用 import 方式纳管到 Rancher 中。

Kubewarden 安装

Kubewarden 是一个开源项目,它是针对 Kubernetes 平台的策略引擎。它的目标是通过策略即代码的方式,为 Kubernetes 集群提供强大的安全性和策略控制功能。Kubewarden 可以帮助管理员和开发人员定义和实施各种策略,以确保应用程序和基础设施的安全性和合规性。

首先,我们需要在 Rancher 开启 extension 以及安装 Kubewarden 插件,从左侧菜单进入 Configuration -> Extensions

extension

开启 Extensions 后,在 Available 选项卡中,找到 Kubewarden 进行安装:

kubewarden

PS:安装时,如果是国内的环境,容易出现安装插件失败的情况,可以使用以下操作进行修复
进入 local 集群的 workload 页面,编辑 cattle-ui-plugin-system 命名空间下 ui-plugin-operator 工作负载配置
Pod 选项卡中,修改 Networking 配置,添加 Host Aliases,配置:185.199.110.133 raw.githubusercontent.com并保存,这样能减少国内 Github 相关域名被 DNS 污染的问题。

安装成功后,刷新页面,并进入下游 RFO 集群管理页面,左侧菜单出现 Kubewarden 管理页面。

rfo-kubewarden

并根据 Kubewarden 安装指引安装 Kubewarden,这个过程需要安装 cert-manager,将 Kubewarden 的 charts repo 添加到 Rancher 中,并在集群中安装 Kubewarden APP。安装成功后,集群中 Kubewarden 页面如下:

kubewarden-installed

根据提示安装 default-policy-server,这个默认 policy-server 将会使用 validatingwebhookconfigurations 以及 mutatingwebhookconfigurations 进行策略应用。

default-policy-server

镜像构建推送并验证

整个镜像推送验证的环节包括:

  • 使用 cosign 创建镜像签名密钥
  • Kubewarden 界面中,创建镜像签名验证策略
  • 构建镜像并推送到镜像仓库中
  • 对镜像使用 cosign 签名并推送
  • 在集群中部署镜像

cosign 创建签名密钥

参考文档,这次我们使用 k8s secret 作为 cosign 的 kms provider,使用以下命令创建密钥:

# 创建 cosign namespace
kubectl create ns cosign
# 使用cosign 创建 key,并存储在 k8s secret中,通过 COSIGN_PASSWORD 指定证书密码,此处为了简化操作,使用了空密码,请在应用时使用密码加强管理
COSIGN_PASSWORD= cosign generate-key-pair k8s://cosign/imagekey
# 通过kubectl 查看secret是否创建成功
kubectl get secret -n cosign imagekey
# NAME       TYPE     DATA   AGE
# imagekey   Opaque   3      2m46s

正常情况下,公钥会同时保存在运行目录下的 cosign.pub 文件中。

在 Kubewarden 中创建策略

进入集群下的 Kubewarden 菜单下 ClusterAdmissionPolicy 页面,点击 Create 进入创建页面,查找 Verify Image Signatures

create-policy

PS: 在第一次进入时,可能无法看到 artifacthub 中 kubewarden 策略,可以根据页面提示,添加 artifacthub.io 到访问白名单即可查询到配置。

选择 Verify Image Signatures 策略之后,在 General 中填写 Name image-validate,然后切换到 Settings 配置页面中,修改 Signature TypePublicKey

signature-type

Public Key 下点击 Add 之后,出现 image 输入框,此处需要输入镜像匹配名称,本次填写为 yuxing-test.cnrancher.com/test/*,其中 yuxing-test.cnrancher.com 是本次测试使用的 Harbor 域名,test 为镜像所在项目。

Public Keys 下添加我们的证书公钥,内容可以在cosign 创建签名密钥 中找到。输入完成后,点击 Finish 创建完成。

创建完成后,回到 ClusterAdmissionPolicies 列表页面,我们可以看到刚创建的 policy 状态:

policy-list

等待 Policy 状态为 Active 后生效,过程中 default-policy-server 会重启进行重新配置。若规则配置有问题,可以通过 kubectl get po -n cattle-kubewarden-system 找到 policy-server 并查看日志确认问题。

构建镜像并推送到镜像仓库中

本次简化构建镜像过程,使用 alpine:3.18.0 作为测试目标。

# pull alpine image
docker pull alpine:3.18.0
# retag it to our registry
docker tag $DIGEST yuxing-test.cnrancher.com/test/alpine:3.18.0
# push to registry
docker push yuxing-test.cnrancher.com/test/alpine:3.18.0

使用 cosign 对镜像进行签名:

# get the digest of alpine image, it should be only to diegst for this image and the one we need should be index to 1
IMAGE_DIGEST=`docker inspect --format='{{index .RepoDigests 1}}' yuxing-test.cnrancher.com/test/alpine:3.18.0`
# sign image with key stored in k8s, --tlog-upload=false is aim to not upload transparency log to sigstore server.
cosign sign --key k8s://cosign/imagekey --tlog-upload=false ${IMAGE_DIGEST}
# Pushing signature to: yuxing-test.cnrancher.com/test/alpine

签名完成后,可以登录到 Harbor,查看该镜像的签名情况:

harbor-alpine

同时我们推送 alpine:3.17.0 镜像到镜像仓库中但不进行 cosign 签名。

docker pull alpine:3.17.0
docker tag alpine:3.17.0 yuxing-test.cnrancher.com/test/alpine:3.17.0
docker push yuxing-test.cnrancher.com/test/alpine:3.17.0

在集群中部署镜像

我们在 Rancher UI 上,进入集群管理页面,使用 yuxing-test.cnrancher.com/test/alpine:3.18.0 镜像创建 deployment:

create-ok

点击创建后,成功部署,并注意到镜像名称被修改为只用 digest 的格式。

然后我们使用没有签名的 alpine:3.17.0 镜像创建 deployment,在创建后,会提示由于无签名而无法创建 pod:

create-fail

如果我们对 Verify Image Signatures 规则进行调整/升级,并应用到 Deployment/StatefulSet/DaemonSet 等类型上,则会在创建该类型资源时提示错误。

至此,我们完成了整个镜像的构建、签名和部署。

总结与思考

镜像签名的场景,可以应用在容器供应链安全的保障上,增强镜像来源的可信程度,在以下场景能发挥巨大的作用:

  • 使用镜像签名对生产环境进行保护,只部署已签名的镜像,减少镜像从其他环境误操作导致进入生产环境的问题。
  • 对引入的开源镜像进行可信扫描并签名,进行镜像准入核查。
  • 使用签名结合 SBOM(Software Bill of Materials)文档,增强对镜像中的软件进行溯源和审计的能力。

在引入签名的同时,也会带来额外的管理成本:

  • 使用 self-generated 证书固然很方便,但不利于分发和管理,对于大型的开发团队来说并不是一个好的选择。
  • 引入 CA(certificate authority) 管理机构,或使用公开可信的 CA 机构签发的证书进行签名。
    • 使用公网中可信 CA 的证书进行签名,需要 CI 环境有互联网访问的能力,并不利于私有环境的场景。cosign 本身也提供基于 sigstore 的 CA 机构Fulcio 签发证书对镜像进行签名的操作。
    • 虽然公有云中有提供私有 CA 证书管理服务,但大部分场景下企业需要有自己的证书管理工具与流程,这些流程本身就不利于证书的利用。
  • 对签名密钥的生命周期管理一直都是证书管理领域的大问题,这个问题在容器镜像签名中被放大。对何时需要对证书进行轮换,以及证书轮换时的影响与调整方案,都需要更深入的研究。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/8075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Spring MVC】Spring MVC的功能使用和相关注解介绍

Spring MVC主要有三个功能: 连接获取参数输出数据 对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了Spring MVC。 1.连接 连接的功能:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能…

基于YOLOv5的WiderFace人脸检测检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于YOLOv5的WiderFace人脸检测系统可用于日常生活中检测与定位人脸目标,利用深度学习算法可实现图片、视频、摄像头等方式的人脸目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据集&…

css终极方案PostCSS

一见如故 原理 所有的css框架都在一样的事,那就是由一个css生成一个新的css,那么postcss就来做了一个抽离: 1、将原有的css解析成抽象语法树 2、中间经过若干个插件 3、重新文本化,形成新的css postcss.config.js module.expor…

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例)

几种传参方式简单对比 传值 1.1 参数形式&#xff1a;void fun(vector<int> v); 1.2 函数调用&#xff1a;fun(v); 1.3 函数内使用&#xff1a;cout << v[1]; 1.4 是否可以改变函数外对象的值&#xff1a;否 1.5 是否会调用拷贝构造函数&#xff1a;是传指针 2.1 …

快速了解新一轮Moonbeam Grants申请提案

随着Moonbeam Grant第二期计划的发布&#xff0c;超过12个项目同时提交了生态Grant申请的提案。任何大于25万枚GLMR Grant的申请都将会要求项目在Moonbeam社区治理论坛上发布Grant提案&#xff0c;内容包含项目概览、申请金额、Grant使用方案以及背后的原因等等。 Grant的发放…

【软件架构】企业架构4A定义

文章目录 前言战略、BA、DA、AA、TA五者的关系1、业务架构&#xff08;BA&#xff09;2、数据架构&#xff08;DA&#xff09;3、应用架构&#xff08;AA&#xff09;4、技术架构&#xff08;TA&#xff09;总结 前言 业务架构是跨系统的业务架构蓝图&#xff0c;应用架构、数…

Redis

介绍 redis是内存数据结构存储&#xff0c;可用作数据库、缓存、消息代理和流引擎。 提供的数据结构有&#xff1a;String、hash、lists、sets、sorted sets、bitmaps、hyperloglogs、streams 字符串、哈希、列表、集、带有范围查询的排序集、位图、超日志日志、地理空间索引…

【每日运维】RockyLinux8非容器化安装Mysql、Redis、RabitMQ单机环境

系统版本&#xff1a;RockyLinux 8.6 安装方式&#xff1a;非容器化单机部署 安装版本&#xff1a;mysql 8.0.32 redis 6.2.11 rabbitmq 3.11.11 elasticsearch 6.7.1 前置条件&#xff1a;时间同步、关闭selinux、主机名、主机解析host 环境说明&#xff1a;PC电脑VMware Work…

互联网医院系统|互联网医院软件开发|互联网医院搭建方案

随着互联网技术的发展&#xff0c;互联网医院系统逐渐成为医疗服务的新模式&#xff0c;为患者和医生提供了更加方便和高效的医疗体验。下面将介绍互联网医院系统的功能优势。   在线挂号和预约&#xff1a;互联网医院系统可以提供在线挂号和预约功能&#xff0c;患者可以通过…

C++_01_初步认识C++语言

本人博客园亦可见 一、认识 “C语言” 一、首先聊聊什么是语言&#xff1f; 语言是一套具有“语法”、“词法”规律的系统&#xff0c;是思维的工具。   计算程序设计语言是计算机可以识别的语言&#xff0c;用于描述解决问题的方法&#xff0c;供计算机阅读和执行。 语言由…

vue中实现列表自由拖拽排序

元素的 dragable 属性设置 为 true &#xff08;文本 图片 链接 的draggable 属性默认为 true&#xff09;则元素可拖放 <template><transition-group class"list"><uldragstart"dragstart(index)"dragenter"dragenter($event, index)…

【设计模式——学习笔记】23种设计模式——原型模式Prototype(原理讲解+应用场景介绍+案例介绍+Java代码实现)

原型模式 介绍 原型模式指用通过拷贝原型实例创建新的实例&#xff0c;新实例和原型实例的属性完全一致原型模式是一种创建型设计模式工作原理是通过调用原型实例的 clone()方法来完成克隆&#xff0c;原型实例需要实现Cloneable接口&#xff0c;并重写clone()方法需要为每个…

naive-ui的dialog.warning 关闭和阻止关闭

序&#xff1a; 1、如果你卡到 了&#xff0c;博主没写博客&#xff0c;可以在博主的公众号&#xff1a;“程序员野区” 留言。博主看到有时间再帮你去试 2、博主主要讲的怎么 主动关闭dialog和阻止dialog 自动关闭。 注意&#xff01;&#xff01;&#xff01;&#xff01;来&…

Spring Data Redis操作Redis

在Spring Boot项目中&#xff0c;可以使用Spring Data Redis来简化Redis操作&#xff0c;maven的依赖坐标&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></…

5分钟搞懂池化的本质

大家好啊&#xff0c;我是董董灿&#xff01; 在很多与计算机视觉相关的神经网络中&#xff0c;我们往往都会看到池化这一算法&#xff0c;它一般跟在卷积层后面。 神经网络中用到最多的池化方式无外乎是最大池化和平均池化。两者运算接近&#xff0c;区别在于是在kernel范围…

在使用《快递批量查询高手》时从TXT文本导入的快递单号出现乱码如何解决。

在日常 工作中&#xff0c;有没有单号用TXT 文档保存吗&#xff1f;那么没有出现这种情况呢&#xff0c;打开TXT文档进去看都是正常没有问题&#xff0c;一但导入软件中就出现乱码的&#xff1f;遇到这个种情况需要什么解决呢&#xff1f;小编今天就教 您一招解决好方法&#x…

电脑微信空间占用简便清理

1、打开电脑版微信、点击左下角的三根横线 2、点击左侧的“设置” 3、弹出层左侧点击“通用设置”->“存储空间管理” 4、点击清理缓存&#xff0c;或者管理 5、点击“管理”后&#xff0c;根据选择的筛选条件&#xff0c;勾线需要清理的&#xff0c;最后点击清理

WormGPT – 网络犯罪分子用来犯罪的人工智能工具

WormGPT – 网络犯罪分子用来发起商业电子邮件泄露攻击的生成式人工智能工具 前言 什么是蠕虫GPT&#xff08;WormGPT&#xff09; WormGPT是基于EleutherAI于2021年创建的大型语言模型GPT-J的AI模型。它具有无限的字符支持、聊天记忆保留和代码格式化功能。 如果未部署适当…

C#|无法打开cs文件设计窗口

报错信息&#xff1a;To prevent possible data loss before loading the designer, the following errors must be resolved: 解决方案&#xff1a;实不相瞒我把项目解决方案名称改短了就可以了。。有其他原因或者解决方案望不吝赐教。。

electron dialog.showMessageBox使用案例

electron 版本&#xff1a;25.3.1 index.html <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>Hello World!</title><meta http-equiv"Content-Security-Policy" content"script-src self unsa…