Podman签署和分发容器镜像

Podman签署和分发容器镜像

签署容器镜像的动机是只信任专门的镜像提供者以减轻中间人 (MITM) 攻击或对容器注册表的攻击。签署镜像的一种方法是使用 GNU Privacy Guard ( GPG ) 密钥。这种技术通常与任何符合 OCI 的容器注册表兼容,例如:Quay.io。值得一提的是,OpenShift 集成容器注册表开箱即用地支持这种签名机制,这使得单独的签名存储变得不必要。

从技术角度来看,我们可以利用 Podman 对镜像进行签名,然后再将其推送到远程注册表。之后,所有运行 Podman 的系统都必须配置为从远程服务器检索签名,远程服务器可以是任何简单的 Web 服务器。这意味着在镜像拉取操作期间,每个未签名的镜像都将被拒绝。

在使用 Podman 和 GPG 对容器镜像进行签名时,通常需要考虑四个主要事项:

1.我们需要签名机器上的有效 GPG 私钥和每个系统上的相应公钥,这将拉取镜像
2.Web 服务器必须在可以访问签名存储的地方运行
3.必须在任何 /etc/containers/registries.d/*.yaml文件中配置 Web 服务器
4.每个镜像拉取系统都必须配置为包含强制策略配置policy.conf

  • 生成GPG密钥
//生成GPG密钥
[root@loaclhost ~]# gpg --full-gen-key
gpg (GnuPG) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? //默认回车
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) //默认回车
Requested keysize is 2048 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) //默认回车
Key does not expire at all
Is this correct? (y/N) y //按y该密钥不会过期

GnuPG needs to construct a user ID to identify your key.

Real name: zhang //设置用户id
Email address: zhang123@163.com //设置邮箱,不能设置太简易
Comment: jb //注释
You selected this USER-ID:
    "zhang (jb) <zhang123@163.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o //按O提交

//第一个方框是设置给密钥设置密码(密码不能过于简单),第二个是确认密码
                                 ┌──────────────────────────────────────────────────────┐
                                 │ Please enter the passphrase to                       │
                                 │ protect your new key                                 │
                                 │                                                      │
                                 │ Passphrase: ********________________________________ │
                                 │                                                      │
                                 │       <OK>                              <Cancel>     │
                                 └──────────────────────────────────────────────────────┘

                                 ┌──────────────────────────────────────────────────────┐
                                 │ Please re-enter this passphrase                      │
                                 │                                                      │
                                 │ Passphrase: ********________________________________ │
                                 │                                                      │
                                 │       <OK>                              <Cancel>     │
                                 └──────────────────────────────────────────────────────┘

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 31A2E228392F5A26 marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/0B38BB0F0DB829E878CC194531A2E228392F5A26.rev'
public and secret key created and signed.

pub   rsa2048 2022-08-16 [SC]
      0B38BB0F0DB829E878CC194531A2E228392F5A26
uid                      zhang (jb) <1@2.com>
sub   rsa2048 2022-08-16 [E]

//查看已有的密钥
[root@loaclhost ~]# gpg --list-keys zhang123@163.com
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   rsa2048 2022-08-16 [SC]
      0B38BB0F0DB829E878CC194531A2E228392F5A26
uid           [ultimate] zhang (jb) <1@2.com>
sub   rsa2048 2022-08-16 [E]
  • 部署私有仓库
//直接在本机部署私有仓库
[root@loaclhost ~]# podman run -d -p 5000:5000 docker.io/registry
Trying to pull docker.io/library/registry:latest...
Getting image source signatures
Copying blob 3790aef225b9 done  
Copying blob e2ead8259a04 done  
Copying blob 0d96da54f60b done  
Copying blob 79e9f2f55bf5 done  
Copying blob 5b27040df4a2 done  
Copying config b8604a3fe8 done  
Writing manifest to image destination
Storing signatures
06160d0c5430348a5c11de1c297ba5e02f67f7b0ae9fad6a3ee423ef7707ade0
[root@loaclhost ~]# podman ps -a
4CONTAINER ID  IMAGE                              COMMAND               CREATED         STATUS             PORTS                   NAMES
06160d0c5430  docker.io/library/registry:latest  /etc/docker/regis...  16 seconds ago  Up 15 seconds ago  0.0.0.0:5000->5000/tcp  loving_lehmann

拉取alpine镜像作为本次用作测试的镜像

[root@loaclhost ~]# podman pull docker://docker.io/alpine:latest
Trying to pull docker.io/library/alpine:latest...
Getting image source signatures
Copying blob 59bf1c3509f3 done  
Copying config c059bfaa84 done  
Writing manifest to image destination
Storing signatures
c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18
  • 给alpine打上标签指向本地的私有仓库
[root@loaclhost ~]# podman tag alpine localhost:5000/alpine

为了让镜像能上传至本地的私有仓库,修改/etc/containers/registries.d/default.yaml文件

我们可以看到我们配置了两个签名存储:

  • sigstore: 引用 Web 服务器进行签名读取
  • sigstore-staging: 引用文件路径进行签名写入
[root@loaclhost ~]# vim /etc/containers/registries.d/default.yaml
sigstore: http://localhost:8000 //添加这一行
  • 推送alpine镜像至本地的私有仓库
//--tls-verify是访问私有仓库时需要https验证,=false是关闭https验证。
//--sign-by是使用指定的密钥在目标处添加签名,这里填生成该密钥的邮箱
[root@loaclhost ~]# podman push --tls-verify=false --sign-by zhang123@163.com localhost:5000/alpine
Getting image source signatures
Copying blob 8d3ac3489996 done  
Copying config c059bfaa84 [=================================] 1.4KiB / 1.4KiB
Writing manifest to image destination
Signing manifest
Storing signatures
                            ┌────────────────────────────────────────────────────────────────┐
                            │ Please enter the passphrase to unlock the OpenPGP secret key:  │
                            │ "guguniao (xxxx) <zhang123@163.com>"                             │
                            │ 2048-bit RSA key, ID 75A8BC88C9C0AC53,                         │
                            │ created 2022-08-15.                                            │
                            │                                                                │
                            │                                                                │
                            │ Passphrase: ********__________________________________________ │
                            │                                                                │
                            │         <OK>                                    <Cancel>       │
                            └────────────────────────────────────────────────────────────────┘

现在看一下系统签名存储,我们会看到有一个新的签名可用,这是由镜像推送引起的。每推送一个镜像就会生成一个签名

[root@loaclhost ~]# ls /var/lib/containers/sigstore
'alpine@sha256=964248be4bb8e3052c8b411271126f70c5c5015df31e014bfc41fad50edf78d8'

前面编辑的默认签名存储 /etc/containers/registries.d/default.yaml引用了一个正在监听的 Web 服务器 http://localhost:8000。我们只需在本地临时签名存储中启动一个新服务器:

//下载python3
[root@loaclhost ~]# dnf -y install python36

//启动用来读取签名的web服务器
[root@loaclhost ~]# bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server'
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
192.168.188.1 - - [16/Aug/2022 13:19:36] "GET / HTTP/1.1" 200 -
192.168.188.1 - - [16/Aug/2022 13:19:37] code 404, message File not found
192.168.188.1 - - [16/Aug/2022 13:19:37] "GET /favicon.ico HTTP/1.1" 404 -

浏览器测试访问

删除本地镜像用来进行拉取镜像验证

[root@loaclhost ~]# podman rmi docker.io/alpine localhost:5000/alpine
Untagged: docker.io/library/alpine:latest
Untagged: localhost:5000/alpine:latest
Deleted: c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18

编写一个策略来强制签名必须是有效的。这可以通过在 中添加新规则来完成/etc/containers/policy.json

[root@loaclhost ~]# vim /etc/containers/policy.json
{
    "default": [
        {
            "type": "insecureAcceptAnything"
        }
    ],
    "transports": {
        "docker": {
            "localhost:5000": [ //把这一行修改为localhost:5000
                {
                    "type": "signedBy",
                    "keyType": "GPGKeys",
                    "keyPath": "/tmp/key.gpg"
                }
            ],
            "registry.redhat.io": [
                {
                    "type": "signedBy",
                    "keyType": "GPGKeys",
                    "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"  //修改为密钥所在的位置
                }
            ]
        },

这个/tmp/key.gpg位置的密钥不存在,因此我们必须将GPG密钥放在那里

[root@loaclhost ~]# gpg --output /tmp/key.gpg --armor --export zhang123@163.com

拉取本地私有仓库中的alpine镜像

//需要另外在打开一个终端读取web服务器才能拉取镜像
[root@loaclhost ~]# bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server'

//拉取镜像
[root@loaclhost ~]# podman pull --tls-verify=false localhost:5000/alpine
Trying to pull localhost:5000/alpine:latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob 3c4e9198e8c1 done  
Copying config c059bfaa84 done  
Writing manifest to image destination
Storing signatures
c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18

拉取镜像后我们可以在web服务器的日志中看到签名被访问过

[root@loaclhost ~]# bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server'
127.0.0.1 - - [16/Aug/2022 13:35:04] "GET /alpine@sha256=964248be4bb8e3052c8b411271126f70c5c5015df31e014bfc41fad50edf78d8/signature-2 HTTP/1.1" 404 -

服务器的日志中看到签名被访问过

[root@loaclhost ~]# bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server'
127.0.0.1 - - [16/Aug/2022 13:35:04] "GET /alpine@sha256=964248be4bb8e3052c8b411271126f70c5c5015df31e014bfc41fad50edf78d8/signature-2 HTTP/1.1" 404 -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随便投投

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值