由于近些年针对软件的供应链的攻击越来越频繁,因此 Google 在 2021 提出的解决方案是软件工件供应链级别(Supply chain Levels for Software Artifacts,"SLSA")
本篇将介绍在非 GitHub 生态系统中,我们如何生成和验证软件工件的来源,从而提高你的项目的 SLSA Level。
Witness 是一个可插拔的软件供应链风险管理框架,它能自动、规范和验证软件工件出处。它是 in-toto 是 CNCF[1] 下的项目之一。它的最初作者是 Testifysec,后来捐赠给了 in-toto[2]。
Witness 是一个可插拔的供应链安全框架,可创建整个软件开发生命周期(SDLC)的证据(Provenance)跟踪,确保软件从源代码到目标的完整性。它支持大多数主要的 CI 和基础架构提供商,是确保软件供应链安全的多功能、灵活的解决方案。
安全 PKI (Public Key Infrastructure - 公钥基础设施)分发系统的使用和验证 Witness 元数据的能力进一步增强了流程的安全性,并有助于减少许多软件供应链攻击向量。
Witness 的工作原理是封装在持续集成流程中执行的命令,为软件开发生命周期(SDLC)中的每个操作提供证据跟踪,这样就可以详细、可验证地记录软件是如何构建的、由谁构建以及使用了哪些工具。
这些证据可用于评估政策合规性,检测任何潜在的篡改或恶意活动,并确保只有授权用户或机器才能完成流程中的某一步骤。
总结 - Witness 可以做什么
主要分三步:
witness run
- 运行提供的命令并记录有关执行的证词。witness sign
- 使用提供的密钥签署提供的文件。witness verify
- 验证 witness 策略。这是我创建的 Witness Demo 仓库[3]用于演示 witness 的工作流程,具体可以根据如下步骤进行。
安装 witnesss,下载 demo 项目
bash <(curl -s https://raw.githubusercontent.com/in-toto/witness/main/install-witness.sh)
Latest version of Witness is 0.1.14
Downloading for linux amd64 from https://github.com/in-toto/witness/releases/download/v0.1.14/witness_0.1.14_linux_amd64.tar.gz
expected checksum: f9b67ca04cb391cd854aec3397eb904392ff689dcd3c38305d38c444781a5a67
file checksum: f9b67ca04cb391cd854aec3397eb904392ff689dcd3c38305d38c444781a5a67
witness v0.1.14-aa35c1f
Witness v0.1.14 has been installed at /usr/local/bin/witness
git clone https://github.com/shenxianpeng/witness-demo.git
openssl genpkey -algorithm ed25519 -outform PEM -out witness-demo-key.pem
openssl pkey -in witness-demo-key.pem -pubout > witness-demo-pub.pem
.witness.yaml
run:
signer-file-key-path: witness-demo-key.pem
trace: false
verify:
attestations:
- "witness-demo-att.json"
policy: policy-signed.json
publickey: witness-demo-pub.pem
witness run --step build -o witness-demo-att.json -- python3 -m pip wheel --no-deps -w dist .
INFO Using config file: .witness.yaml
INFO Starting environment attestor...
INFO Starting git attestor...
INFO Starting material attestor...
INFO Starting command-run attestor...
Processing /tmp/witness-demo
Building wheels for collected packages: witness-demo
Running setup.py bdist_wheel for witness-demo: started
Running setup.py bdist_wheel for witness-demo: finished with status 'done'
Stored in directory: /tmp/witness-demo/dist
Successfully built witness-demo
INFO Starting product attestor...
即在之前的 build command 中加入 witness run
的相关命令。
因为 Attestation 数据是进行的 base64 编码,因此需要解码进行查看
cat witness-demo-att.json | jq -r .payload | base64 -d | jq
# 以下是部分输出
{
"type": "https://witness.dev/attestations/command-run/v0.1",
"attestation": {
"cmd": [
"python3",
"-m",
"pip",
"wheel",
"--no-deps",
"-w",
"dist",
"."
],
"stdout": "Processing /tmp/witness-demo\nBuilding wheels for collected packages: witness-demo\n Running setup.py bdist_wheel for witness-demo: started\n Running setup.py bdist_wheel for witness-demo: finished with status 'done'\n Stored in directory: /tmp/witness-demo/dist\nSuccessfully built witness-demo\n",
"exitcode": 0
},
"starttime": "2023-11-29T05:15:19.227943473-05:00",
"endtime": "2023-11-29T05:15:20.078517025-05:00"
},
{
"type": "https://witness.dev/attestations/product/v0.1",
"attestation": {
"dist/witness_demo-1.0.0-py3-none-any.whl": {
"mime_type": "application/zip",
"digest": {
"gitoid:sha1": "gitoid:blob:sha1:b4b7210729998829c82208685837058f5ad614ab",
"gitoid:sha256": "gitoid:blob:sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813",
"sha256": "471985cd3b0d3e0101a1cbba8840819bfdc8d8f8cc19bd08add1e04be25b51ec"
}
}
},
"starttime": "2023-11-29T05:15:20.078579187-05:00",
"endtime": "2023-11-29T05:15:20.081170078-05:00"
}
policy.json
用来定义或要求一个步骤由具有特定属性或满足一些特殊的值,从而要求验证 Attestation 才能成功。比如这里的 expires
字段过期了即小于当前的时间,那么在执行 witness verify
的时候就会失败。
{
"expires": "2033-12-17T23:57:40-05:00",
"steps": {
"build": {
"name": "build",
"attestations": [
{
"type": "https://witness.dev/attestations/material/v0.1",
"regopolicies": []
},
{
"type": "https://witness.dev/attestations/command-run/v0.1",
"regopolicies": []
},
{
"type": "https://witness.dev/attestations/product/v0.1",
"regopolicies": []
}
],
"functionaries": [
{
"publickeyid": "{{PUBLIC_KEY_ID}}"
}
]
}
},
"publickeys": {
"{{PUBLIC_KEY_ID}}": {
"keyid": "{{PUBLIC_KEY_ID}}",
"key": "{{B64_PUBLIC_KEY}}"
}
}
}
更多关于 policy 的属性和设置可以参考这里:https://github.com/in-toto/witness/blob/main/docs/policy.md
在签名之前需要先替换到 Policy 文件的变量
id=`sha256sum witness-demo-pub.pem | awk '{print $1}'` && sed -i "s/{{PUBLIC_KEY_ID}}/$id/g" policy.json
pubb64=`cat witness-demo-pub.pem | base64 -w 0` && sed -i "s/{{B64_PUBLIC_KEY}}/$pubb64/g" policy.json
然后使用 witness sign
来做签名
witness sign -f policy.json --signer-file-key-path witness-demo-key.pem --outfile policy-signed.json
INFO Using config file: .witness.yaml
witness verify -f dist/witness_demo-1.0.0-py3-none-any.whl -a witness-demo-att.json -p policy-signed.json -k witness-demo-pub.pem
INFO Using config file: .witness.yaml
INFO Verification succeeded
INFO Evidence:
INFO 0: witness-demo-att.json
以上就是使用 witness 针对 Non-GitHub 项目的演示。
如果你的项目代码是放在 GitHub 上的,目前最容易、最流行的方式就是使用 slsa-github-generator[4] 一个由 SLSA Framework[5] 官方提供的工具,然后使用 slsa-verifier[6] 来验证 Provenance。具体可以参考我的上一篇文章 Python 和 SLSA💃
[1]
CNCF: https://www.cncf.io/projects/in-toto/
[2]
in-toto: https://in-toto.io/
[3]
Witness Demo 仓库: https://github.com/shenxianpeng/witness-demo
[4]
slsa-github-generator: https://github.com/slsa-framework/slsa-github-generator
[5]
SLSA Framework: https://github.com/slsa-framework
[6]
slsa-verifier: https://github.com/slsa-framework/slsa-verifier