介绍
本文主要介绍Docker+Harbor实现对镜像进行签名,Docker 集成了Notary的客户端,Docker Hub、Harbor等镜像仓库又集成了Notary Server,Docker 通过Notary进行镜像的签名;
Notary是一个基于 TUF 项目的用于软件制品签名的开源软件;Notary同时也是一个用于建立内容之间信任的平台,在容器镜像中可以对镜像进行加密签名用来保证镜像件来源和镜像内容防篡改。
| 软件名称 | 软件版本 |
|---|---|
| Harbor | 2.0.0 |
Harbor初始化
Harbor启动开启Notary
./install --with-notary
harbor安装时可以添加--with-notary参数来使得harbor具有签名的功能,实际上就是会多启两个容器,分别为:goharbor/notary-server-photon:v2.0.0、goharbor/notary-signer-photon:v2.0.0
Harbor创建项目
新建个test项目配置内容信任,阻止没有签名的镜像下载
未开启DCT时推送镜像
docker push data01.com/test/mybox:1.0.0
此时在Harbor中看见镜像是未签名状态
这里我发现了一个个问题,无论我勾不勾选内容信任,本地只要开启了DCT,未签名的镜像都拉不下来;我觉得理论上来说应该没勾选的话,即使本地开启了DCT,未签名的镜像应该都能拉下来;这里小编也不清楚具体原因,所以不再继续深入研究了。
镜像推送
Docker 开启DCT(即开始镜像签名功能)
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://data01.com:4443
DOCKER_CONTENT_TRUST=1:表示开启Docker内容信任模式
DOCKER_CONTENT_TRUST_SERVER:指定认证服务器,其实就是对应harbor notary服务的地址和端口
如果Harbor使用自签名证书,则需要将对应的ca证书放置到
docker所在主机的~/.docker/tls/data01.com:4443/目录,证书名为ca.crt。
data01.com:4443为你的notary节点域名(ip)和端口
原理就是使用目录下ca证书进行镜像的签发密钥和验证(当然也可以根据ca证书再给data01.com:4443签发一张二级证书)。
继续推送镜像
[root@data01 ~]# docker push data01.com/test/nginx:1.14.2
The push refers to repository [data01.com/test/busybox]
432b65032b94: Pushed
1.14.2: digest: sha256:74f634b1bc1bd74535d5209589734efbd44a25f4e2dc96d78784576a3eb5b335 size: 527
Signing and pushing trust metadata
Enter passphrase for root key with ID 0e17f94:
Enter passphrase for new repository key with ID 027f454:
Repeat passphrase for new repository key with ID 027f454:
Finished initializing "data01.com/test/nginx"
Successfully signed data01.com/test/nginx:1.14.2
输入密码对镜像进行签名,后续镜像上传都是使用此密码进行镜像签署。
root key:在 ~/.docker/trust 目录中生成一个根密钥
repository key:在 ~/.docker/trust 目录中生成一个镜像签署密钥
推送成功后查看
查看镜像签名
docker trust inspect data01.com/test/nginx:1.14.2
[root@data01 private]# docker trust inspect data01.com/test/nginx:1.14.2
[
{
"Name": "data01.com/test/nginx:1.14.2",
"SignedTags": [
{
"SignedTag": "1.14.2",
"Digest": "706446e9c6667c0880d5da3f39c09a6c7d2114f5a5d6b74a2fafd24ae30d2078",
"Signers": [
"Repo Admin"
]
}
],
"Signers": [],
"AdminstrativeKeys": [
{
"Name": "Root",
"Keys": [
{
"ID": "03fef8621852c225d1067b3dc85ff367725e895124f83bd62255c24e4c16e5d6"
}
]
},
{
"Name": "Repository",
"Keys": [
{
"ID": "035e330d979bddb427f6f06f4a951102bd762d1cfc082eed417e5b51695636e2"
}
]
}
]
}
]
镜像拉取
如果节点docker开启了DCT
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://data01.com:4443
拉取镜像需要进行证书签名比对,若harbor使用的是自签名证书,此时需要节点~/.docker/tls/上放置了CA证书 若节点没有配置docker内容信任,则拉取镜像时不需要做签名验证(也不用在~/.docker/tls/目录放证书)。
注意:这里记录一个坑,就是当开启DCT后(即 DOCKER_CONTENT_TRUST=1),DOCKER_CONTENT_TRUST_SERVER的值配的前面的registory(data01.com)和 拉取镜像时的registory 不对应的时候会报一个错,例如当DOCKER_CONTENT_TRUST_SERVER为如上配置时,我执行docker pull data06.com/test/nginx:1.14.2 时就会报这个错
docker: Error: error contacting notary server: received unexpected HTTP status: 500 Internal Server Error.
如果~/.docker/tls/ 证书没配置,则会报如下错误:
Error: error contacting notary server: x509: certificate signed by unknown authority
镜像删除
签名了的镜像无法直接通过Harbor进行删除,在Harbor中删除时报如下错误
先删除tag的签名
删除签名时需要输入一下repository key的密码
[root@data01 private]# docker trust revoke data01.com/test/nginx:1.14.2
Enter passphrase for repository key with ID 035e330:
Successfully deleted signature for data01.com/test/nginx:1.14.2
删除成功后,可以看到Harbor上的签名状态已经变成未签名了
注意:俗话说的好,解铃还须系铃人,docker客户端1的签名只能在docker客户端1移除该tag上的签名,不能由客户端2去移除,否则会报错:
[root@k8s-node1 ~]# docker trust revoke data01.com/test/nginx:1.14.2
ERRO[0000] couldn't remove target from targets: could not find necessary signing keys, at least one of these keys must be available: 035e330d979bddb427f6f06f4a951102bd762d1cfc082eed417e5b51695636e2
could not remove signature for data01.com/test/nginx:1.14.2: could not find necessary signing keys, at least one of these keys must be available: 035e330d979bddb427f6f06f4a951102bd762d1cfc082eed417e5b51695636e2
再删除tag
删除签名成功后,即可以再Harbor上删除这个tag了(或调用Harbor api删除)