谈谈我对云原生与软件供应链安全的思考(代码片段)

阿里云云栖号 阿里云云栖号     2022-12-01     631

关键词:

2011 年,互联网技术先驱 Marc Andreessen 宣称,软件正在吞噬世界(Software is eating the world)。由软件驱动的行业创新正在颠覆着传统业务模式,推动着全球经济实现数字化连接。随着互联网的快速发展,数字化转型已经成为每一个企业的关键战略。但是现代软件开发涉及到多方协作,大量应用依赖开源代码或者三方组件。在上游开源软件的安全问题会传递到下游应用方并被放大,有可能给企业造成重大的安全风险和业务损失。

软件生产的过程与传统制造业在很多方面是相似的。软件制造商将自研业务代码和第三方组件组合成完整的软件,构建流程会将这些组件打包成为可部署的软件制品,然后被企业客户部署到生产环境中。这个过程被形象地称为“软件供应链”。而软件供应链安全的目标是保软件从开发到部署的整个生命周期的安全、可信赖。

在 Sonatypes's 2021 State of the Software Supply Chain 调查报告中,2021 年软件供应链攻击事件增长了 650%。

目前,软件供应链安全已经得到行业的高度重视。已经有很多国家出台了相关的政策法规来指导本国的供应链安全管理,以提高供应链安全韧性。2021 年 4 月,美国网络安全与基础设施安全局(CISA)和美国国家标准与技术院(NIST)联合发布《防御软件供应链攻击》报告,首次对软件供应链进行界定,并给出与软件供应链攻击相关的信息、关联风险以及缓解措施。

谷歌也提出了 Supply chain Levels for Software Artifacts - 软件制品的供应链等级,简称为 SLSA。SLSA 是 Google 内部实施的多年的安全流程的开源版本,提供了一个安全框架和一组最佳实践,来预防因为源代码篡改、三方组件漏洞、制品仓库入侵产生的安全威胁。

SBOM-提升软件构成透明度

软件供应链安全的基础就是透明性。只有理解了应用是如何从代码和依赖组件构建而成,我们才可以对应用的安全风险进行有效的治理。在美国 2021 年颁布的《关于改善国家网络安全的行政命令》行政令中,特别要求政府软件应包含机器可读的软件物料清单(Software Bill Of Materials, SBOM)。SBOM 是包含构建软件使用的各种组件的详细信息和供应链关系的正式记录。

美国国家电信和信息管理局(NITA)在 14028 号政令的要求下,在 2021 年 7 月 12 日发布了《SBOM 的最低要素》,该文档为各开发工具的组织和厂商提供了 SBOM 数据格式的参考。在新一代软件开发工具中,越来越多的软件提供了对 SBOM 的支持。

应用的 SBOM 信息

下面我们以一个 Golang 的 HTTP Server 示例应用为例,了解一下 SBOM 的的概念和使用方式。

$ git clone https://github.com/denverdino/secure-supply-chain-sample
$ cd secure-supply-chain-sample
$ go build .

熟悉 Go 语言的开发者一定对 go 模块概念非常熟悉。应用所依赖的模块,都通过 go.mod 文件声明。go mod tidy 命令可以用来更新 go.mod 文件,并”锁定“所依赖的模块和版本信息,这大大提升了构建的确定性、可重现性和可验证性。为了确保第三方无法篡改所依赖的模块版本, 在 go.sum 文件记录了每个模块依赖的加密哈希值。当利用go命令将模块代码下载到本地时,就会计算其哈希值,如果计算结果与 go.sum 记录的数据不符就意味着存在篡改的风险。更近一步,Google 运营着一个 Go 模块校验数据库服务,它记录了 go 模块版本的加密哈希值,进一步提升了 Go 基础设施的安全性。

更多内容可以阅读:https://go.dev/blog/supply-chain

对于已编译的应用二进制文件,我们可以通过 go version -m 命令查看应用的构建信息,包括其软件来源,依赖模块,构建参数等等。

$ go version -m secure-supply-chain-sample
secure-supply-chain-sample: go1.18.3
    path    github.com/denverdino/secure-supply-chain-sample
    mod    github.com/denverdino/secure-supply-chain-sample    (devel)
    dep    github.com/sirupsen/logrus    v1.8.1    h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
    dep    golang.org/x/sys    v0.0.0-20220702020025-31831981b65f    h1:xdsejrW/0Wf2diT5CPp3XmKUNbr7Xvw8kYilQ+6qjRY=
    build    -compiler=gc
    build    CGO_ENABLED=1
    build    CGO_CFLAGS=
    build    CGO_CPPFLAGS=
    build    CGO_CXXFLAGS=
    build    CGO_LDFLAGS=
    build    GOARCH=amd64
    build    GOOS=darwin
    build    GOAMD64=v1
    build    vcs=git
    build    vcs.revision=c630057157df402b658ab97139895337633b5bbc
    build    vcs.time=2022-07-04T01:33:01Z
    build    vcs.modified=false

容器镜像的 SBOM 支持

容器技术重塑了整个软件供应链。容器镜像将应用及其所有依赖项打包,从而使应用可以在不同的计算环境之间快速、可靠地运行。容器镜像已经成为了应用分发的标准,而 Kubernetes 成为了分布式资源调度和编排的事实标准。那么如何保障容器镜像在构建、分发和运行时的完整性、安全性呢?

我们继续以上面的 Golang 应用为例,介绍一下现容器化软件供应链安全的最新实践和工具链。

Ko 是 Google 开源的一个简单、快速的 Go 应用程序容器镜像构建器。今天我们只聚焦于 Ko 在软件供应链的一些设计,大家可以举一反三,应用在自己的语言和项目中。

无需编写 Dockerfile,利用 Ko build 我们可以将一个 Golang 项目构建成为一个 Docker 镜像。

$ go version -m secure-supply-chain-sample
secure-supply-chain-sample: go1.18.3
    path    github.com/denverdino/secure-supply-chain-sample
    mod    github.com/denverdino/secure-supply-chain-sample    (devel)
    dep    github.com/sirupsen/logrus    v1.8.1    h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
    dep    golang.org/x/sys    v0.0.0-20220702020025-31831981b65f    h1:xdsejrW/0Wf2diT5CPp3XmKUNbr7Xvw8kYilQ+6qjRY=
    build    -compiler=gc
    build    CGO_ENABLED=1
    build    CGO_CFLAGS=
    build    CGO_CPPFLAGS=
    build    CGO_CXXFLAGS=
    build    CGO_LDFLAGS=
    build    GOARCH=amd64
    build    GOOS=darwin
    build    GOAMD64=v1
    build    vcs=git
    build    vcs.revision=c630057157df402b658ab97139895337633b5bbc
    build    vcs.time=2022-07-04T01:33:01Z
    build    vcs.modified=false

为什么镜像的创建时间变成了 ”1970/1/1“ ? 这是因为 Ko 的一个设计目标就是支持 Reproducible Builds - 可重现的构建。Reproducible Builds 是一组开发实践,当源码与构建环境配置一模一样时,在不同机器上编译出来的目标二进制文件会在比特层面上做到完全相同。这样的好处是允许独立的第三方可以对从源代码到二进制文件编译过程中进行验证,确保没有引入漏洞或后门。常见的 docker build 命令构建出的容器镜像会在镜像的 manifest 文件中包含构建时间戳,而镜像的 HASH 计算会包含 manifest 文件。这样导致即使是使用相同的代码和 Dockerfile,也无法保障构建出的镜像 HASH 是相同的。

Ko 通过固定应用代码和镜像构建的时间戳,确保了在任何环境构建出的镜像 HASH 保持不变。所以我们可以通过比较镜像的 HASH 值来快速判断两个镜像中的内容是否一致。一个开放性的问题,Reproducible Build 是否是一个最佳实践?是否适合于您的业务场景?

此外,为了更好支持软件供应链安全。Ko 自动为应用容器镜像生成了相应的 SBOM 信息,并且作为一个应用制品推送到镜像仓库中。可以通过 URL 路径进行访问:KO_DOCKER_REPO/IMAGE_NAME:sha256-HASH.sbom

如何获得容器镜像的 SBOM 信息呢?我们有两个方法:
第一,如果在镜像仓库中没有保存容器镜像的 SBOM 信息,我们可以利用 docker sbom 命令分析生成应用镜像的 SBOM 信息。

$ docker sbom knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3
Syft v0.43.0
 ✔ Loaded image
 ✔ Parsed image
 ✔ Cataloged packages      [6 packages]
NAME                                              VERSION                             TYPE
base-files                                        11.1+deb11u3                        deb
github.com/denverdino/secure-supply-chain-sample                                      go-module
github.com/sirupsen/logrus                        v1.8.1                              go-module
golang.org/x/sys                                  v0.0.0-20220702020025-31831981b65f  go-module
netbase                                           6.3                                 deb
tzdata                                            2021a-1+deb11u4                     deb

第二,如果在镜像仓库中已经存储了容器镜像的 SBOM 信息,比如 Ko 所发布的 SBOM 信息。我们可以利用 Sigstore 项目中的 cosign 工具直接获得镜像的 SBOM 内容。

$ cosign download sbom knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3
Found SBOM of media type: text/spdx
SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: github.com/denverdino/secure-supply-chain-sample
DocumentNamespace: http://spdx.org/spdxpackages/github.com/denverdino/secure-supply-chain-sample
Creator: Tool: ko 0.11.2
Created: 1970-01-01T00:00:00Z

##### Package representing github.com/denverdino/secure-supply-chain-sample

PackageName: github.com/denverdino/secure-supply-chain-sample
SPDXID: SPDXRef-Package-github.com.denverdino.secure-supply-chain-sample
PackageSupplier: Organization: github.com/denverdino/secure-supply-chain-sample
PackageDownloadLocation: https://github.com/denverdino/secure-supply-chain-sample
FilesAnalyzed: false
PackageHomePage: https://github.com/denverdino/secure-supply-chain-sample
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseComments: NOASSERTION
PackageComment: NOASSERTION

Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-github.com.denverdino.secure-supply-chain-sample


Relationship: SPDXRef-Package-github.com.denverdino.secure-supply-chain-sample DEPENDS_ON SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1

##### Package representing github.com/sirupsen/logrus

PackageName: github.com/sirupsen/logrus
SPDXID: SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1
PackageVersion: v1.8.1
PackageSupplier: Organization: github.com/sirupsen/logrus
PackageDownloadLocation: https://proxy.golang.org/github.com/sirupsen/logrus/@v/v1.8.1.zip
FilesAnalyzed: false
PackageChecksum: SHA256: 7492ae1e0aa4d4d35096aa00e814e533559ff43387dcd063432bb487df806591
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseComments: NOASSERTION
PackageComment: NOASSERTION


Relationship: SPDXRef-Package-github.com.denverdino.secure-supply-chain-sample DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20220702020025-31831981b65f

##### Package representing golang.org/x/sys

PackageName: golang.org/x/sys
SPDXID: SPDXRef-Package-golang.org.x.sys-v0.0.0-20220702020025-31831981b65f
PackageVersion: v0.0.0-20220702020025-31831981b65f
PackageSupplier: Organization: golang.org/x/sys
PackageDownloadLocation: https://proxy.golang.org/golang.org/x/sys/@v/v0.0.0-20220702020025-31831981b65f.zip
FilesAnalyzed: false
PackageChecksum: SHA256: c5db1e8eb5bfd167f67624f908fa775e629435bafb5efc3c9188a543eeaa8d16
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseComments: NOASSERTION
PackageComment: NOASSERTION新一代镜像签名技术-Keyless

众所周知,我们可以用镜像签名的方式来保障镜像的可追溯性。一般而言,开发者利用私钥对镜像加签,在部署应用时,可以通过 OPA/Gatekeeper 拦截请求,对镜像进行验签。开发者可以定义安全策略来自动化安全流程。比如我们可以定义一个策略,不允许存在高风险漏洞的镜像部署到生产系统。在镜像构建阶段,我们可以对通过镜像扫描且不包含高风险漏洞的镜像进行签名,而在 K8s 生产集群中,通过安全策略来来校验镜像签名。

由于过去镜像加签/验签的工具易用性不好,并没有得到企业广泛的应用。阿里云镜像服务 ACR,ACK 在提供了集成、简化的镜像安全体验,极大降低了镜像安全的技术门槛。

我们今天给大家介绍一个新的技术思路。Sigstore 是由红帽、谷歌联合几所美国高校主导开发维护的供应链安全开源项目,旨在提供一个新的软件加签、验签和防护的标准。通过 Sigstore,我们可以自动对云原生下的各类开源制品进行数字签名并校验,帮助构建一个更安全、可追溯的供应监控链。

其中 Sigstore 的无密钥签名 Keyless Signatures 模式是这个项目最大的亮点之一。无密钥签名,支持自动化的密钥管理能力,使用者无需管理维护私钥,极大简化的镜像加签验签的体验。

我们首先通过 cosign sign 命令对镜像进行加签:

$ COSIGN_EXPERIMENTAL=true cosign sign knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3
Generating ephemeral keys...
Retrieving signed certificate...

        Note that there may be personally identifiable information associated with this signed artifact.
        This may include the email address associated with the account with which you authenticate.
        This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
        By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.

Are you sure you want to continue? (y/[N]): y
Your browser will now be opened to:
https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&code_challenge=Zj3B13VeqlwO1OEs_cc_gVly21ZWdotsB_ipAG1KUD0&code_challenge_method=S256&nonce=2BPd2p6uHg1e916zBz3MoEoH8FR&redirect_uri=http%3A%2F%2Flocalhost%3A55455%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=2BPd2uo32VlgXKC9NY0rDOJlfmA
Successfully verified SCT...
tlog entry created with index: 2824482
Pushing signature to: knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample

在 Keyless 模式中,终端会自动打开浏览器,由用户选择 OAuth 身份服务商进行认证,流程完成后。cosign 会对镜像进行签名,并将镜像签名保存在镜像仓库中,其 URL 路径为: IMAGE_REPO/IMAGE_NAME:sha256-HASH.sig

在这个过程中 cosign 利用 fulcio 的根证书,创建了一个临时秘钥和证书,对镜像进行加签。签名也会记录在 Rekor 的透明化日志中,为镜像签名提供远程证明。

我们可以利用 cosign verify 命令对镜像签名进行校验。

COSIGN_EXPERIMENTAL=true cosign verify knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3

Verification for knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3 --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - Any certificates were verified against the Fulcio roots.

["critical":"identity":"docker-reference":"knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample","image":"docker-manifest-digest":"sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3","type":"cosign container image signature","optional":"Bundle":"SignedEntryTimestamp":"MEQCIB1YeNP8suFn6xm7hn0qkAJBiID/gcOP//tsm7u2Z/FIAiBqiw0Zl1CvgVfcGhOWKUEkZKB2XdFm3FPaxq9E+Jsmyg==","Payload":"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MDRiZWI5M2Q0OGVhYzA4ZmE3OTQzNWNhNTVlZmQyNTE4ODhlN2NmZmMzODJlZTE0MmRjMzZkZDExMzhkYzFjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUNhNXhYd25pR1J6ckRlamtHRHFCSFNTdlMvdUVCeUJkVUV0cFBiRVRxZUVBSWdGY0hWOW9RWkYxYk4xYmtxMWY3UFdWOUpCY00vZlhyZXZTa0orT0tWSDJrPSIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVU52ZWtORFFXbHBaMEYzU1VKQlowbFZTSHByZFVSeVprODJWamxqVUhsSlkyZ3JOVXBFUlc4NVRtcHpkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BKZDA1NlFYbE5WRTB3VFdwSk1sZG9ZMDVOYWtsM1RucEJlVTFVVFRGTmFra3lWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWQ016UkNhRGRPZWtRMFRqaEVWVWxyWW5WWVkxWTVUMEZEV1d4MlpGcFNiMkkzVmt3S1RIaE9SMnhOSzNrMmIycGhUR05EZHpaNVlsaHNaak5RVFU0clduaERUVmROTUVreVkyWjFPRUpZZFhNelUzaFVka3RQUTBGVlkzZG5aMFpFVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWUFExUm5DakZMV1dKbFZFRlpWVmxvZUZwVU1HeDJja0YzU0RaWmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQwbG5XVVJXVWpCU1FWRklMMEpDWjNkR2IwVlZXa2RXZFdSdFZubGFSMngxWWpCQ2JtSlhSbkJpUXpWcVlqSXdkMHhCV1V0TGQxbENRa0ZIUkFwMmVrRkNRVkZSWldGSVVqQmpTRTAyVEhrNWJtRllVbTlrVjBsMVdUSTVkRXd5ZUhaYU1teDFUREk1YUdSWVVtOU5TVWRLUW1kdmNrSm5SVVZCWkZvMUNrRm5VVU5DU0hORlpWRkNNMEZJVlVGRFIwTlRPRU5vVXk4eWFFWXdaRVp5U2pSVFkxSlhZMWx5UWxrNWQzcHFVMkpsWVRoSloxa3lZak5KUVVGQlIwSUtkbmxZT0d0blFVRkNRVTFCVW1wQ1JVRnBRazVFYjBkNE16STNaMGRDZWxWeWRIaEZVVFZ6ZEZSRFF6Z3haRWMwY1dsU2VrMHZTMHR2Y3pGMU5IZEpad3BMVDIxTVNXdENXVzF6V21ZeFZIQTNNRXhaWkRCbGIwaFVVV3AyV1dFdldrbFdaVFEzWTBwMUwwaFpkME5uV1VsTGIxcEplbW93UlVGM1RVUmhVVUYzQ2xwblNYaEJTemREVFRkQ1NFMW1UWE5GY0hwa1lXbHlVRFIzUkZFeUwxUnZibEUxYTBack5FbEZWamRvY1dScFJWbDJVMEpEVVhoSU0xQjRjV2RGU1dJS2RVdEhiWEozU1hoQlR6VmlRamMyUVRSaE5qWXpUSGRFYVVkalYyUlpkVEZrY0Rabk1ubDRkREpyY0ZObFprcGlVMHBQT1dOWFJEVldOM1JUY1d0WmVRcGFSbkJSUmsxUlowdDNQVDBLTFMwdExTMUZUa1FnUTBWU1ZFbEdTVU5CVkVVdExTMHRMUW89In19fX0=","integratedTime":1656769347,"logIndex":2822273,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d","Issuer":"https://github.com/login/oauth","Subject":"denverdino@gmail.com","critical":"identity":"docker-reference":"knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample","image":"docker-manifest-digest":"sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3","type":"cosign container image signature","optional":"Bundle":"SignedEntryTimestamp":"MEYCIQDdn2/IzVRCAuS+8s5Zz1F2+Gp3/MXzFP2whryasTa3GQIhAJKWFtb7jGnL8krnR4CwVYr/jbtZuHtlX7TpNPtEP67R","Payload":"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MDRiZWI5M2Q0OGVhYzA4ZmE3OTQzNWNhNTVlZmQyNTE4ODhlN2NmZmMzODJlZTE0MmRjMzZkZDExMzhkYzFjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURVVUdHOEJOZnRoeDBrZGxzWGpvZzZQaFRENmFsNUo4Y3F0WnFFOFJQY3BBSWdMYlFRd2pLT2I0VU9OS05DZ2hvNnlENDNSNHl4TVU2QldtYllBQmVTQXhnPSIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVU53UkVORFFXbHRaMEYzU1VKQlowbFZTVmhtYW5nME1sTnNhQzl5TW5CTlNYUjFRMVJHVjNWVGNUTnJkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BKZDA1NlFYcE5SRVY1VFVSVk5GZG9ZMDVOYWtsM1RucEJlazFFUlhwTlJGVTBWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVVMk9HWkZabkJqWVZSaE1XUjRlVXQxU0RsbGVIcFJSM2MyWWtaelRDOTJVelkxZENzS01WWnNaSEJFZFRWaVMwcFJjbVozVjA1SFEzZ3Zia3RzYUVaS09VZDZhV1JpTUZkYWJtZFJTVUpsU25GcVRtMTVjVFpQUTBGVlozZG5aMFpGVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWTlRTdG9Da1ZsVDBGUkszaEpTUzlxVVZvMWJrbE5ObEpaWWxadmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQwbG5XVVJXVWpCU1FWRklMMEpDWjNkR2IwVlZXa2RXZFdSdFZubGFSMngxWWpCQ2JtSlhSbkJpUXpWcVlqSXdkMHhCV1V0TGQxbENRa0ZIUkFwMmVrRkNRVkZSWldGSVVqQmpTRTAyVEhrNWJtRllVbTlrVjBsMVdUSTVkRXd5ZUhaYU1teDFUREk1YUdSWVVtOU5TVWRMUW1kdmNrSm5SVVZCWkZvMUNrRm5VVU5DU0hkRlpXZENORUZJV1VGRFIwTlRPRU5vVXk4eWFFWXdaRVp5U2pSVFkxSlhZMWx5UWxrNWQzcHFVMkpsWVRoSloxa3lZak5KUVVGQlIwSUtkMkZYUlVGM1FVRkNRVTFCVW5wQ1JrRnBRazVLWVVKMVJqUk1OVFJsUnpGRlFYVlJTMHh3WTNFNGNtdFlSbXB5TlRoeE1EZHpNazE1ZVVOcFJXZEphQXBCU1hCc1luZHpNVFZLV21KbmVGRTNXRGRTYlRocU5uSjBPV1pWVGxSWlJtMXdhVFJJYzBGcVNIQnRkVTFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbXRCQ2sxSFdVTk5VVU4zWWtSUVFqQXJWVUZHWkhkcWJVeHJUVEZ4VEhsbGFucGFNbEpWYURKRVEyMHdZbE5rZURSQmQwaDNkV2Q2UmsxaFlsZHpOaTlqVURFS2MxWjZOWHBTTkVOTlVVUTJaR2RVYm0wNWNIUnhVa3BTVlVkWFRGTm1lVzlqZFZoeVRqaFllR1JhU1VsMWJuQjBTek01WW1ZNVYweFdZVFJRYTFObFR3cGhUeXRzSzJvMGRHUmtWVDBLTFMwdExTMUZUa1FnUTBWU1ZFbEdTVU5CVkVVdExTMHRMUW89In19fX0=","integratedTime":1656811260,"logIndex":2824453,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d","Issuer":"https://github.com/login/oauth","Subject":"denverdino@gmail.com","critical":"identity":"docker-reference":"knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample","image":"docker-manifest-digest":"sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3","type":"cosign container image signature","optional":"Bundle":"SignedEntryTimestamp":"MEUCIBe/RXXYBuyDXJVvCwFV/vcjfiUXnNqjS7HR2TpyB6WeAiEA+4MdLCkXW1zFqo4M0cdkNcPpEQe5ZfLw5mv266ib1oE=","Payload":"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MDRiZWI5M2Q0OGVhYzA4ZmE3OTQzNWNhNTVlZmQyNTE4ODhlN2NmZmMzODJlZTE0MmRjMzZkZDExMzhkYzFjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUNwN3BUckFUMk04M3hYaFJGc1IyNERnc2dEL3dJOHFCdW1TYUdaSXhiTHVBSWdETUpCb3hNWmU0M2ZtMjJBaHR2SE5BVEFwazhteWN0Y3huaC9oUG13QmxBPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTnZla05EUVdseFowRjNTVUpCWjBsVlZHWkJRM0ZXTWtKWmJ6UjNUVEpDY2pCVU4yMW5OVWcxVjFrd2QwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcEpkMDU2UVhwTlJFVjVUa1JWTTFkb1kwNU5ha2wzVG5wQmVrMUVSWHBPUkZVelYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZxVTNSR1dtcFljbXh2U0dwaGRTOXZRMWxwWVZSVmNUbFRWMk5wWVVzd2RrSnlaMGNLVmt4WlNYbzVVbmR3UnpnM1RuTjNhV3BIZFhac1QySnlXbUkzUTFad2JtRXlSMGwyVUhSNVRFdzNaWFp5VWxOQmJtRlBRMEZWYTNkblowWkdUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlV3TUc5ekNtcFRlRnAzYmtwRWVFeDVVREl2WXl0SEwyZFNUMmR2ZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBsbldVUldVakJTUVZGSUwwSkNaM2RHYjBWVldrZFdkV1J0Vm5sYVIyeDFZakJDYm1KWFJuQmlRelZxWWpJd2QweEJXVXRMZDFsQ1FrRkhSQXAyZWtGQ1FWRlJaV0ZJVWpCalNFMDJUSGs1Ym1GWVVtOWtWMGwxV1RJNWRFd3llSFphTW14MVRESTVhR1JZVW05TlNVZE1RbWR2Y2tKblJVVkJaRm8xQ2tGblVVTkNTREJGWlhkQ05VRklZMEZEUjBOVE9FTm9VeTh5YUVZd1pFWnlTalJUWTFKWFkxbHlRbGs1ZDNwcVUySmxZVGhKWjFreVlqTkpRVUZCUjBJS2QyRnJiakZuUVVGQ1FVMUJVMFJDUjBGcFJVRm9TR3RCV21abGRWWnVNREpMUlhoU1FsSnNNVGt2Y0VsWUx5OXNMelptZFd3ekwxazNSRE5yYjNGblF3cEpVVVJHSzBWSGRFaEViMUZNT1VseWVWQnNVbk5oUlVOa1FrbGpibVphWldKWE9HMW1RMmgxVFV4dVdtRlVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXVDa0ZFUW10QmFrRXJaV1pJTlhjMlUyMVNObnBvVFM5TmQwSkJXVUY1Um10bWRVdEVOMWQwVldadlFUUTVabUUyY205MFZ6WnNjV1UwWm04eVFtbFJTVTRLUjBwYWFVcHJPRU5OU0ZGNkwwdE9aa3d5VjA4eFNFVlNVSFJWTUdoRVlYcFBORkYxUkhkSlJtdDZabFJRYlZaMFJub3JRakIxYjI1TlR5OVhVWHBuVWdwd016Vm1RVXhyWVVKQlBUMEtMUzB0TFMxRlRrUWdRMFZTVkVsR1NVTkJWRVV0TFMwdExRbz0ifX19fQ==","integratedTime":1656811517,"logIndex":2824482,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d","Issuer":"https://github.com/login/oauth","Subject":"denverdino@gmail.com"]

Sigstore 的 cosign-gatekeeper-provider 项目提供了 Cosign 与 OPA/Gatekeeper 的集成,可以在 Kubernetes 集群中 对镜像进行验签。但是目前这个版本还不支持 Keyless 签名方式。我 fork 了一个版本,支持了 Keyless 签名。

安装配置 Gatekeeper 支持 external data 特性:

$ helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
$ helm install gatekeeper/gatekeeper  \\
    --name-template=gatekeeper \\
    --namespace gatekeeper-system --create-namespace \\
    --set enableExternalData=true \\
    --set controllerManager.dnsPolicy=ClusterFirst,audit.dnsPolicy=ClusterFirst

安装 cosign-gatekeeper-provider,配置 OPA 策略,拒绝不包含合法签名的镜像。

$ git clone https://github.com/denverdino/cosign-gatekeeper-provider
$ cd cosign-gatekeeper-provider
$ kubectl apply -f manifest
$ kubectl apply -f policy/template.yaml
$ kubectl apply -f policy/constraint.yaml

我们可以验证一下,如果 Deployment 包含正确签名的镜像可以被成功部署。

$ cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
  labels:
    app: sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
        - name: sample
          image: knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample@sha256:cd1ac13d65aa8983f6c10317a09b994cd66fa46aceb1ba1eaf2cab4ee2038ec3
          ports:
            - containerPort: 8080

$ kubectl apply -f deploy.yaml
deployment.apps/sample-deployment created

如果镜像没有签名,Deployment 的部署将被阻断:

$ cat deploy-unsigned.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment-unsigned
  labels:
    app: sample-unsigned
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-unsigned
  template:
    metadata:
      labels:
        app: sample-unsigned
    spec:
      containers:
        - name: sample
          image: knative-dev-registry.cn-hangzhou.cr.aliyuncs.com/denverdino/secure-supply-chain-sample:unsigned
          ports:
            - containerPort: 8080

$ kubectl apply -f deploy-unsigned.yaml
Error from server (Forbidden): error when creating "deploy-unsigned.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [cosign-gatekeeper-provider] invalid response: "errors": [], "responses": [], "status_code": 200, "system_error": "VerifyImageSignatures: no matching signatures:\\n"

社区与展望

实现真正的端到端的软件供应链安全需要整个行业的努力,近期众多开源社区加大了相关技术的投入和合作。

随着容器技术的普及,越来越多的软件制品通过 OCI 仓库进行管理,比如 AI 模型,Helm Charts。社区的 OCI Registry As Storage ORAS 项目也应运而生,为多样化的应用制品提供统一的管理、分发能力。Cosign 等软件供应链安全能力,也可以无缝应用于这些软件制品。Kubernetes 社区也在大力推动自身项目的安全基础能力建设。从 1.21 版本开始,所有发布的组件将包含相关 SBOM 信息。KEP-3031 也在推动软件制品的签名机制,防止中间人攻击,确保组件的完整性与可信度。

除了容器镜像,Sonatype 也宣布在其 Maven Central 与 Sigstore 展开合作,来提升 Java 开发流程的供应链安全。

过去阻碍软件供应链应用的最大阻力在于其用户体验,无论是秘钥管理还是镜像 SBOM、签名等元数据管理都非常复杂,需要多个系统相互协同。Sigstore/Cosign 在简化用户体验方面有了长足的进展。然而 Cosign 目前基于约定方式,如将 sha256-IMAGE_HASH.sig 作为镜像签名的 tag。这样的设计非常简单,但是缺乏灵活性和扩展能力。OCI - Open Container Initiative 成立了 Reference Types 工作组,目标为 OCI 仓库中的软件制品间的关系提供标准化的描述和查询机制。我们拭目以待,期待可以和 Sigstore 社区共同合作在用户体验的简单性,系统的可扩展性方面达成共识,进一步推动软件供应链安全技术的普及。

软件供应链安全还是一个比较新的领域,很多最佳实践和工具链还不完善。目前 Cosign 等项目还在快速发展中,Keyless 签名机制还未达到生产可用,本文仅供大家学习参考相应的技术架构。

作者:易立

原文链接

本文为阿里云原创内容,未经允许不得转载

谈谈我对云原生的理解

这里我不想再引用Pivotal的MattStine的定义,只是想从个人角度思考一下什么是云原生。云原生是啥?在我看来是一套思想,一套完整的方法论和体系。是不是太虚了,的确,云原生就是一套指导意见。它主要有... 查看详情

华为云构建云原生devsecops平台,保障软件供应链全流程安全可信

...台,打造了创新可控的安全服务,助力企业软件供应链全生命周期安全。2022年8月13日,“2022中国DevOps社区峰会-天津站”顺利召开,邀请了行业众多大咖专家齐聚一堂分享交流,旨在传播DevOps文化、落地DevOps... 查看详情

简单谈谈对云原生领域mq组件kafka的理解

1.定义:kafka具备大吞吐量,内置分区,可以进行数据备份,同时具备数据容错性的消息系统。kafka主要特点体现如下:Kafka可以完成在线或者离线数据消费,所谓离线数据消费实际上就是kafka将消息数据保... 查看详情

代码投毒删库跑路,开源生态链安全该如何保证?(代码片段)

...,我们不妨品读一下开源社理事长庄表伟对开源软件供应链安全的看法,或许会有不一样的收获与思考。作者|庄表伟    责编|张红月之前写过一篇文章《我所理解的开源软件 查看详情

软件供应链安全及防护工具研究

...快速发展,同时带来软件设计开发复杂度不断提升,软件供应链也愈发复杂,全链路安全防护难度不断加大。近年来,软件供应链安全事件频发,对于用户隐私、财产安全乃至国家安全造成重大威胁,自动化安全工具是进行软件... 查看详情

信通院郭雪:软件供应链安全标准体系建设与洞察

...会(ISC2022)上,悬镜安全出品并主办了软件供应链安全治理与运营论坛,特邀中国信息通信研究院(以下简称“信通院”)云计算与大数据研究所开源和软件安全部副主任郭雪,发表了主题为“软件供... 查看详情

对云环境下访问控制系统的思考

本文由 网易云发布。 企业上云首当其冲的就是要考量安全性的问题。安全性范围很广,狭义上可以指云服务商的各种安全服务,如DDoS防护、其他安全性产品等,而广义上来说,安全性不仅包括基础设施的安全和稳定,... 查看详情

有a-b<c引发的安全性思考(代码片段)

  软件工程中,不论使用哪种开发语言,安全性一直是一个非常棘手却又重要的问题。安全性是软件开发领域永远的主题之一,而且随着互联网的蜂拥发展而带动的新技术的兴起与革命(比如近几年火起来的node.js,python,go等... 查看详情

kubeedge在边缘计算领域的安全防护及洞察

...,汇集了行业领军企业与机构,涵盖世界上最重要的软件供应链安全计划、开源开放的工具链、安全指南、培训等,旨在提高开源软件(OSS)的安全性。作为业界首个云原生边缘计算项目,KubeEdge社区致力于提升KubeEdge在云原生... 查看详情

谈谈我对flutter未来发展和“嵌套地狱”的浅显看法(代码片段)

Flutter未来发展提到Flutter就不得不提到Fuchsia系统,这是一个尚未正式发布的操作的系统,引用Android和Chrome的高级副总裁HiroshiLockheimer在一档播客节目中对Fuchsia的介绍是:不仅仅是手机和个人电脑,在物联网的世界里,越来越多... 查看详情

2023rsac创新沙盒大赛十强公布,软件供应链与开源软件安全再成焦点

...“十强企业”。软件安全企业EndorLabs成功入围,软件供应链安全和开源安全问题再次成为国际焦点。EndorLabs提供了一个可依赖的生命周期管理平台,旨在解决软件供应链安全中企业开源软件治理问题,帮助开发者快速... 查看详情

软件质量管理-代码质量与规范

...、发现和修复软件产品的安全漏洞。今天先到这儿,希望对云原生,技术领导力,企业管理,系统架构设计与评估,团队管理,项目管理,产品管管,团队建设有参考作用,您可能感兴趣的文章:领导人怎样带领好团队构建创业公司... 查看详情

srm供应商管理软件益处多多(代码片段)

...赢是很多中大型企业的采购管理痛点,srm供应商管理软件在进行供应商关系处理时,主要通过沟通与合作关系管理、交付与验收管理、满意度与推荐管理三个层面对供应商关系进行把控。srm供应商管理软件益处多多一、... 查看详情

新兴国家战略级安全话题-软件供应链安全

...电子商务等方面。报告认为,在安全细分领域中软件供应链安全热度处于上升阶段,SCA可以帮助应用开发团队发布更安全的代码,并为安全团队提供主动的风险管理方法。墨云科技依托对软件成分分析的技术的创新研... 查看详情

一道号称“史上最难”的java面试题引发的线程安全思考(代码片段)

...偶然间看见一道名为史上最难的java面试题,这个题让了我对线程安全的有了一些新的思考,给大家分享一下这个题吧:publicclassTestSync2implementsRunnableintb=100;synchronizedvoidm1()throwsInterruptedExceptionb=1000;Thread.sleep(500);//6System.out.p 查看详情

identityserver4实战-谈谈jwttoken的安全策略(代码片段)

一.前言众所周知,IdentityServer4默认支持两种类型的Token,一种是ReferenceToken,一种是JWTToken。前者的特点是Token的有效与否是由Token颁发服务集中化控制的,颁发的时候会持久化Token,然后每次验证都需要将Token传递到颁发服务进行... 查看详情

云原生的定义(代码片段)

...native简介RocketMQSource餐饮配送场景示例云原生先看一下CNCF对云原生的定义:云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务... 查看详情

中国软件供应链安全分享报告附下载地址

声明本文是学习​​2021年中国软件供应链安全分析报告.下载地址http://github5.com/view/1216​​而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们典型软件供应链安全风险实例分析国内某主流OA系统供应链安... 查看详情