当前位置:   article > 正文

【ORACLE云】通过 OCI OKE && OCIR 构建签名镜像 - 保证 CI/CD 镜像一致性_oci镜像构建

oci镜像构建

Oracle Kubernetes Engine(OKE)

Oracle Kubernetes Engine(OKE)是Oracle Cloud Infrastructure(OCI)上的托管Kubernetes服务。它为开发人员和企业提供了一种简便的方式来创建、部署和管理容器化应用程序。

Oracle Cloud Infrastructure Registry(OCIR)

Oracle Cloud Infrastructure Registry(OCIR)是Oracle Cloud提供的容器镜像存储服务。它允许用户在Oracle Cloud上存储、管理和部署Docker容器镜像。OCIR提供高度可用、安全且高性能的基础设施,支持团队协作,同时整合了OCI的身份和访问管理(IAM)服务,以确保对容器镜像的访问和管理的安全性。

镜像签名

镜像签名是一种用于验证容器镜像完整性和源信任的安全机制。在容器生态系统中,镜像签名被用于确保部署的镜像来自可信任的源,并且在传输过程中没有被篡改。这种机制有助于防范中间人攻击、确保软件供应链的安全性,并提高用户对使用的容器镜像的信任度。在CI/CD流水线中使用镜像签名可以确保从开发到生产环境的整个过程中,部署的都是经过验证和信任的容器镜像。

OCI Vault(Oracle Cloud Infrastructure Vault)

OCI Vault(Oracle Cloud Infrastructure Vault)是 Oracle 云基础设施提供的一项安全服务,用于管理和保护密钥、密码、证书等敏感信息。Vault 提供了安全的存储和访问这些加密数据的方式,并且支持密钥的生成、存储和轮换,以提高数据的安全性。

1 背景

用户出于合规和安全等原因,管理员希望我们在生产环境部署应用符合如下安全需求:

  • 应用镜像来自被信任的源地址(这里指镜像仓库)
  • 应用镜像在部署过程中的唯一性

2 应用场景

通常安全类操作会通过程序集成到开发、测试和生产环境的部署流水线中,通过钩子或者定时扫描的方式进行签名,签名是一个自动完成的过程;本文主要介绍Sign部分内容,即容器签名。

在部署中通常构建镜像的流程:

  • 在CI/CD服务器上进行容器的构建
  • 对构建成功的容器打上对应的标签
  • 通过 OCI Vault 为容器增加签名
  • OKE拉取签名镜像(此时OKE已打开镜像签名校验)

构建CI/CD流程如下:

签名校验流程:

在流程图中,虚拟机(VM)作为流程的发起者,更多地代表了 CI/CD 服务平台。示例中重点介绍了镜像签名和镜像部署的操作,在生产环境中,CI/CD 过程的负载远比示例中所展示的更加庞大。本文的目的在于提供有关与 CI/CD 操作的过程,而并非详细介绍自动化标准。

3 前提准备

3.1 Vault创建

  Oracle Cloud Infrastructure Vault 是一项密钥管理服务,用于存储和管理主加密密钥和机密以安全访问资源。**在镜像签名场景中,主要用于为容器镜像增加签名和OKE镜像通过签名验证容器镜像的一致性。**

3.1.1 创建Vault

3.1.2 创建主加密密钥

目前镜像支持RSA和ECDSA两种加密算法。

3.2 OKE镜像签名验证所需IAM策略

OKE需要可以读取镜像仓库和使用Key的权限,注意:此权限目前仅支持租户级权限

  1. Allow any-user to use keys in tenancy where request.user.id=<CLUSTER_OCID> # OKE集群OCID
  2. Allow any-user to read repos in tenancy where request.user.id=<CLUSTER_OCID> # OKE集群OCID

4 开启OKE 镜像签名验证功能

4.1 创建OKE时开启镜像签名验证功能

  1. 展开”隐藏高级选项”
  2. 勾选”在此集群上启用映像验证策略”
  3. 选择使用的KEY信息

5 构建镜像与发布

5.1 编写测试dockerfile

测试镜像,用于构建nginx镜像:

  1. FROM centos:7.9.2009
  2. RUN buildDeps='readline-devel pcre-devel openssl-devel gcc telnet wget curl make' \
  3. && useradd -M -s /sbin/nologin nginx \
  4. && mkdir -p /usr/local/nginx/conf/vhost \
  5. && mkdir -p /data/logs/nginx \
  6. && yum -y install $buildDeps \
  7. && yum clean all \
  8. && wget http://nginx.org/download/nginx-1.14.2.tar.gz \
  9. && tar zxf nginx-1.14.2.tar.gz \
  10. && cd nginx-1.14.2 \
  11. && ./configure --prefix=/usr/local/nginx \
  12. --with-http_ssl_module \
  13. --with-http_stub_status_module \
  14. && make -j 1 && make install \
  15. && rm -rf /usr/local/nginx/html/* \
  16. && echo "ok" >> /usr/local/nginx/html/status.html \
  17. && cd / && rm -rf nginx-1.14.2* \
  18. && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  19. ENV PATH /usr/local/nginx/sbin:$PATH
  20. WORKDIR /usr/local/nginx
  21. EXPOSE 80
  22. CMD ["nginx", "-g", "daemon off;"]

5.2 登录镜像仓库

  1. # 用户名有两种:
  2. # - 普通IAM用户格式:<tenancy-namespace>/<username>
  3. # - 联邦用户格式: <tenancy-namespace>/oracleidentitycloudservice/<username>
  4. #
  5. # password为认证token
  6. #1. 登录镜像仓库
  7. $root > docker login ap-tokyo-1.ocir.io
  8. username: xxx/oracleidentitycloudservice/xx.xxx@oracle.com
  9. password: <user token>

5.3 构建镜像

  1. # 构建镜像
  2. # 镜像标签的组合为<region name>/<namespace name>/<images name>
  3. docker build -t ap-tokyo-1.ocir.io/xxxxxx/dev-app:v1 -f DockerFile
  4. # 查看当前构建的镜像,标注背景色的镜像为我们要推送至仓库的镜像, xxxxxx 为客户账号的镜像仓库所在namespace
  5. [root@instance-20221212-1501 ~]# docker images
  6. Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
  7. REPOSITORY TAG IMAGE ID CREATED SIZE
  8. ap-tokyo-1.ocir.io/xxxxxx/dev-app v1 3bb00c0e9770 35 seconds ago 328 MB
  9. quay.io/centos/centos 7.9.2009 8652b9f0cb4c 2 years ago 212 MB

5.4 推送镜像至OCIR镜像仓库

推送成功后在镜像仓库中可以看到刚刚发布的v1版本镜像

  1. # 推送镜像至仓库, xxxxxx 为客户账号的镜像仓库所在namespace
  2. docker push ap-tokyo-1.ocir.io/xxxxxx/dev-app:v1

6 镜像签名

容器签名操作在每次镜像发布后进行,通过容器数字ID与主密钥生成一致性信息,保证容器的完整性。

6.1 获取容器ID

6.1.1通过console界面获取

6.1.2 通过 OCI Cli 命令行获取

注意:在使用 OCI Cli 命令行前需要添加用户认证

  1. oci artifacts container image list --compartment-id <compartment-id>
  2. {
  3. "data": {
  4. "items": [
  5. {
  6. "compartment-id": "ocid1.compartment.oc1x",
  7. "digest": "sha256:e7a4c186eef137a75caacae308765dc2fbb2f57c36d95c0b3ccf6efe6d912ec1",
  8. "display-name": "dev-app:v1",
  9. "id": "ocid1.containerimage.oc1.ap-tokyo-1.0.cnstphowy3cb.aaaaaaaakzn4quqonn7wrkys5o4ms7h6yykzkm5raggd7iwoetopyolptneq",
  10. "lifecycle-state": "AVAILABLE",
  11. "repository-id": "ocid1.containerrepo.oc1.ap-tokyo-1.0.cnstphowy3cb.aaaaaaaao5wmjdfjd7v6ivy4h4ckzquww3a7famuymokimr2n7tip54qcdsq",
  12. "repository-name": "dev-app",
  13. "time-created": "2022-12-12T10:13:24.550000+00:00",
  14. "version": "v1"
  15. }
  16. ],
  17. "remaining-items-count": 0
  18. }
  19. }

6.2 获取KEY信息

签名时需要使用密钥OCI和密钥版本

6.2.1 通过console界面获取

6.3 镜像签名

6.3.1 镜像签名

  1. oci artifacts container image-signature sign-upload --compartment-id <compartment-ocid> --kms-key-id <key-ocid> --kms-key-version-id <key-version-ocid> --signing-algorithm <signing-algorithm> --image-id <image-ocid> --description <signature-description> --metadata <image-metadata-json>
  2. oci artifacts container image-signature sign-upload --compartment-id ocid1.compartment.oc1..aaaaaaaatkzpafvu44t6gcpqk5nz7nykngxhpkzalmfn6u3wdesdm6f323ma --kms-key-id ocid1.key.oc1.ap-tokyo-1.cnrzn4zwaaeam.abxhiljre5yt3upn2bgik2lejscd7lvox7ygr4w3lh2wggey5statloap54q --kms-key-version-id ocid1.keyversion.oc1.ap-tokyo-1.cnrzn4zwaaeam.csiqmolpmhiaa.abxhiljri5uf7tw6qkrs3lcz5v764npnsk4f6cdrfpcv5sig7hcetu52vrfa --signing-algorithm SHA_256_RSA_PKCS_PSS --image-id ocid1.containerimage.oc1.ap-tokyo-1.0.cnstphowy3cb.aaaaaaaakzn4quqonn7wrkys5o4ms7h6yykzkm5raggd7iwoetopyolptneq --description "Image for DEV testing"
  3. # --ompartment-id # 镜像所在的隔间的OCID
  4. # --kms-key-id # 用于对镜像签名的主加密密钥的OCID
  5. # --kms-key-version-id # 用于对镜像进行签名的密钥版本的OCID
  6. # --signing-algorithm # 镜像签名所用的算法
  7. # --image-id # 被签名的镜像OCID
  8. # --description # 镜像签名的描述信息

执行后会返回相关的绑定信息

6.3.2 镜像签名验证

  1. # 命令
  2. oci artifacts container image-signature get-verify --compartment-id <compartment-ocid> --repo-name <repository-name> --image-digest <image-digest> --trusted-keys <key-ocid> ## --compartment-id-in-subtree true|false
  3. # 示例
  4. oci artifacts container image-signature get-verify --compartment-id ocid1.compartment.oc1..aaaaaaaatkzpafvu44t6gcpqk5nz7nykngxhpkzalmfn6u3wdesdm6f323ma --repo-name dev-app --image-digest sha256:e7a4c186eef137a75caacae308765dc2fbb2f57c36d95c0b3ccf6efe6d912ec1 --trusted-keys ocid1.key.oc1.ap-tokyo-1.cnrzn4zwaaeam.abxhiljre5yt3upn2bgik2lejscd7lvox7ygr4w3lh2wggey5statloap54q
  5. # --compartment-id 镜像所在的隔间的OCID
  6. # --repo-name # 镜像仓库名称
  7. # --image-digest # 容器数字签名
  8. # --trusted-keys # 主加密密钥OCID

签名验证通过信息如下:

7 OKE创建OCIR镜像仓库认证

通过 secret 完成标准的镜像仓库认证

  1. # 添加镜像仓库认证
  2. kubectl create secret docker-registry ocirsecret --docker-server=ap-tokyo-1.ocir.io --docker-username='cnsxxxb/oracleidentitycloudservice/xxx@jahwa.com.cn' --docker-password='xxx' --docker-email='coxxx@xx.com.cn'
  3. # --docker-server # 镜像服务器所在的region,<regionName>.ocir.io
  4. # --docker-username # 容器仓库认证用户名
  5. # --docker-password # 容器仓库认证用户token
  6. # --docker-email # 容器认证邮箱地址

8 OKE使用签名镜像进行应用部署

8.1 正确部署

只有通过签名的镜像才可以被成功部署

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. creationTimestamp: null
  5. labels:
  6. run: pod-2
  7. name: pod-2
  8. spec:
  9. containers:
  10. - image: ap-tokyo-1.ocir.io/xxxxx/dev-app@sha256:e682e7302fa2c0a444d0d05408cd5c0cd393a8481329633963d649c9dc758470 # @sha256: xxx 是数字签名
  11. name: pod-2
  12. resources: {}
  13. dnsPolicy: ClusterFirst
  14. restartPolicy: Always
  15. imagePullSecrets:
  16. - name: ocirsecret
  17. status: {}

8.2 异常部署

使用非镜像仓库的外来镜像或非签名镜像时

#####收到如下的报错:
Error from server (Forbidden): error when creating "pod-1.yaml": pods "pod" is forbidden: an error on the server ("unknown") has prevented the request from succeeding

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. creationTimestamp: null
  5. labels:
  6. run: pod
  7. name: pod
  8. #annotations:
  9. # oracle.image-policy.k8s.io/break-glass: "true"
  10. spec:
  11. containers:
  12. - image: nginx # 部署的镜像非OKE镜像仓库,且未进行签名
  13. name: pod
  14. resources: {}
  15. dnsPolicy: ClusterFirst
  16. restartPolicy: Always
  17. status: {}

8.3 通过 注解 方式声明允许构建未签名镜像

通过注解的方式,跳过签名限制

annotations:
  oracle.image-policy.k8s.io/break-glass: "true"  # 如果当前镜像部署想跳过限制,可通过oracle.image-policy.k8s.io/break-glass: "true" 注释绕过规则。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. creationTimestamp: null
  5. labels:
  6. run: pod
  7. name: pod
  8. annotations:
  9. oracle.image-policy.k8s.io/break-glass: "true"
  10. spec:
  11. containers:
  12. - image: nginx # 部署的镜像非OKE镜像仓库,且未进行签名
  13. name: pod
  14. resources: {}
  15. dnsPolicy: ClusterFirst
  16. restartPolicy: Always
  17. status: {}

9 参考内容

镜像签名

Signing Images for Security

Vault密钥管理

https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/managingkeys.htm#createnewkey

OKE通过OCIR镜像仓库拉取镜像

Pulling Images from Registry during Deployment

OKE使用镜像签名

https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengenforcingsignedimagesfromocir.htm#Enforcing_Use_of_Signed_Images_from_Registry

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/1016680
推荐阅读
相关标签