手记

使用Cosign和Kyverno来签名和验证ECR图像

请参考:

使用 Docker、Cosign 和 Kyverno 簽名和驗證容器鏡像:完整指南:🔗 保护 CI/CD 管道以供生产部署 🔗medium.com 亚马逊EKS集群上的软件供应链安全,Nirmata 发布了这篇博客文章,描述了如何在Amazon EKS集群上使用Kyverno和Cosign进行镜像验证的方法……更多详情请参阅nirmata.com

https://kyverno.io/docs/writing-policies/verify-images/sigstore/

前提条件:

1-创建一个具有管理员权限的用户(在实际使用中,应适当限制访问权限)并生成访问密钥和秘密访问密钥,或为EC2实例创建一个具有同样权限的IAM角色。

2-ECR registry 应该已经在您的 AWS 账户中,或者您可以创建一个。我们将使用 us-east-1 地区进行设置。

步骤 1: 启动一个 Amazon Linux 2 AMI 的 EC2 实例,并配置 AWS CLI 和 EC2 IAM 角色。

连接到此实例并运行以下指令来安装所需的包。

sudo yum install -y git docker jq  # 安装必要的工具
sudo service docker start
sudo curl --silent --location -o /usr/local/bin/kubectl \  
   https://s3.us-west-2.amazonaws.com/amazon-eks/1.28.5/2024-01-04/bin/linux/amd64/kubectl  # 下载并安装 kubectl 客户端
sudo chmod +x /usr/local/bin/kubectl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/eksctl /usr/local/bin
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3  # 下载 Helm 安装脚本
chmod 700 get_helm.sh  # 设置脚本可执行权限
./get_helm.sh
sudo usermod -aG docker ec2-user  # 将 ec2-user 用户添加到 docker 组
sudo su - $USER  # 切换到当前用户
docker ps  # 列出正在运行的容器

步骤 2: 按照 https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions 操作,将 AWS CLI 升级到 v2。

接下来,创建一个名为 eks-cluster-config.yaml 的文件,并包含以下内容。

# 集群API版本
apiVersion: eksctl.io/v1alpha5
# 资源类型
kind: ClusterConfig
# 元数据
metadata:
  # 集群名称
  name: eks-cluster
  # 地域
  region: us-east-1
  # Kubernetes版本
  version: '1.28'
# IAM配置
iam:
  # 开启OIDC身份验证
  withOIDC: true
# 可用区
availabilityZones: ['us-east-1a','us-east-1b','us-east-1c']
# Fargate配置文件
fargateProfiles:
  - # 名称
    name: defaultfp
    # 选择器
    selectors:
      - # 命名空间
        namespace: default
      - # 命名空间
        namespace: kube-system
      - # 命名空间
        namespace: kyverno
#  uninterrupted original English fields
cloudWatch:
  # 集群日志
  clusterLogging:
    # 启用的日志类型
    enableTypes: ["*"]

接下来运行以下命令来创建我们的EKS集群(Amazon Elastic Kubernetes Service集群)。

    eksctl 创建集群 -f eks-cluster-config.yaml

大约需要20分钟才能准备好。

步骤 4: 能否通过以下命令连接到您的集群:

    aws eks update-kubeconfig --region us-east-1 --name eks-cluster  
    kubectl get nodes

步骤5: 创建一个名为index.html的文件,文件内容如下:

    <!doctype html>  
    <html lang="zh">  
    <head>  
      <meta charset="utf-8">  
      <title>使用Docker的Nginx</title>  
    </head>  
    <body>  
      <h2>Nginx容器v1的问候</h2>  
    </body>  
    </html>

有一个内容如下所示的Dockerfile:

从最新的nginx镜像开始,然后复制当前目录下的index.html到nginx服务器的指定位置。

构建并推送镜像到ECR注册表。

首先,运行命令 `aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <账号ID>.dkr.ecr.us-east-1.amazonaws.com` 以完成身份验证。
然后,构建 Docker 镜像 `docker build -t app-api:v1 .`。
接下来,为镜像添加标签 `docker tag app-api:v1 <账号ID>.dkr.ecr.us-east-1.amazonaws.com/app-api:v1`。
最后,推送镜像到 Amazon ECR `docker push <账号ID>.dkr.ecr.us-east-1.amazonaws.com/app-api:v1`。
# app-api 是应用API的镜像名称。

步骤 6:创建名为 deployment.yaml 的文件,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: <ECR_IMAGE_URL>
        ports:
        - containerPort: 80

通过运行 kubectl apply -f deployment.yaml 这条命令来创建部署。

第七步: 运行以下命令来安装该工具 kyverno。

    kubectl create namespace kyverno  # 创建名为kyverno的命名空间
    kubectl create secret docker-registry aws-registry -n kyverno \  
    --docker-server=<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com \  
    --docker-username=AWS \  
    --docker-password=demo   # 创建名为aws-registry的docker注册表密钥

    helm repo add kyverno https://kyverno.github.io/kyverno/  # 添加kyverno Helm仓库
    helm repo update  # 更新Helm仓库

    helm install kyverno --namespace kyverno kyverno/kyverno --create-namespace --set 'extraArgs={--imagePullSecrets=aws-registry}'  # 安装kyverno并设置额外的参数
    eksctl create iamserviceaccount  --name kyverno-admission-controller --namespace kyverno --cluster eks-cluster --attach-policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly --override-existing-serviceaccounts --approve  # 创建IAM服务账户并附加权限策略
    kubectl edit deployment kyverno-admission-controller -n kyverno  # 编辑名为kyverno-admission-controller的部署

在参数部分这一行代码

    --镜像拉取凭证=aws-registry

到目前为止,我们已经部署了nginx和kyverno。

第八步:我们需要部署一个定时任务来定期获取 ECR 注册表凭证。

创建一个名为cron.yaml的文件,并将以下内容写入文件。请将<AWS_ACCOUNT_ID>替换为您的AWS账户ID。

apiVersion: rbac.authorization.k8s.io/v1  
kind: 角色  
metadata:  
  namespace: kyverno  
  name: secret-creator-role  
rules:  
- apiGroups: [""]  
  resources: ["secrets"]  
  verbs: ["create", "get", "update", "delete", "list", "watch"]  
---  
apiVersion: rbac.authorization.k8s.io/v1  
kind: 角色绑定  
metadata:  
  name: secret-creator-binding  
  namespace: kyverno  
subjects:  
- kind: 服务账号  
  name: kyverno-admission-controller  
  namespace: kyverno  
roleRef:  
  kind: 角色  
  name: secret-creator-role  
  apiGroup: rbac.authorization.k8s.io  
---  
apiVersion: batch/v1  
kind: 定时作业  
metadata:  
  name: aws-registry-credential-cron  
  namespace: kyverno  
spec:  
  调度: "* */8 * * *"  
  successfulJobsHistoryLimit: 2  
  暂停: false  
  jobTemplate:  
    spec:  
      template:  
        spec:  
          serviceAccountName: kyverno-admission-controller   
          containers:  
          - name: ecr-registry-helper  
            image: omarxs/awskctl:v1.0  
            imagePullPolicy: IfNotPresent  
            command:  
              - /bin/bash  
              - -c  
              - |-  
                DOCKER_REGISTRY_SERVER=https://<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com  
                DOCKER_USER=AWS  
                AWS_REGION=us-east-1  
                ECR_TOKEN="$(aws ecr get-login-password --region ${AWS_REGION})"  
                kubectl 删除密钥 --ignore-not-found aws-registry -n kyverno  
                kubectl 创建密钥 docker-registry aws-registry -n kyverno --docker-server=${DOCKER_REGISTRY_SERVER} --docker-username=${DOCKER_USER} --docker-password=${ECR_TOKEN}  
                echo "密钥已成功更新,更新时间:$(date)"  
          restartPolicy: Never

要应用它,可以通过 kubectl apply -f cron.yaml 命令。

我们也需要手动运行此任务一次以获取到ECR凭证。请运行以下命令,以执行此操作。

kubectl create job \  
--from=cronjob/aws-registry-credential-cron -n kyverno aws-registry-credential-cron-manual-001
# 手动创建一个作业以刷新 AWS 注册表凭证

使用以下命令来检查任务日志。

运行以下命令来查看日志:

    kubectl logs job/aws-registry-credential-cron-manual-001 -n kyverno

步骤9: 我们现在将使用以下命令来安装 cosign。

curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64" cosign-linux-amd64  # 下载最新版本的cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign  # 将cosign-linux-amd64移动到/usr/local/bin目录下
sudo chmod +x /usr/local/bin/cosign  # 设置cosign文件的执行权限

使用以下命令生成密钥对

# Your command to generate a key pair goes here
    运行 `cosign generate-key-pair` #您可以选择不为私钥设置密码

步骤 10: 接下来,我们将创建一个集群策略,限制在 EKS 集群中部署未签名的镜像。请创建一个名为 cluster-policy.yaml 的文件,并包含以下内容。相应地替换 <AWS_ACCOUNT_ID> 和 <ECR_REGISTRY_NAME>。请使用步骤 9 中生成的 cosign.pub 文件中的公钥内容。

apiVersion: kyverno.io/v1  
kind: ClusterPolicy  
metadata:  
  name: 检查签名镜像  
spec:  
  validationFailureAction: 强制执行  
  background: false  
  webhookTimeoutSeconds: 30  
  failurePolicy: 失败策略  
  rules:  
    - name: 检查镜像签名  
      match:  
        any:  
        - resources:  
            kinds:  
              - Pod  
      verifyImages:  
      - image: "<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/*"  
      # 请用自己的公钥替换  
        key: |-  
          -----BEGIN 公钥-----  
          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM1z+vdFrcLuuxHjQdmLFn3icm0Xq  
          Rr4bTktxmpzITojnPDTiMcQBIXZY4o/+hrZ09GJ7rXEcYLns/q/iWWBiGQ==  
          -----END 公钥-----

运行 kubectl apply -f cluster-policy.yaml

步骤 11: 如下重新启动 nginx 服务
``nginx命令```

kubectl 滚动更新 deployment/nginx-deployment

它会被阻止

由于用于Nginx部署的ECR图像(<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/app-api:v1)没有经过签名。

步骤12: 让我们用以下命令签名ECR镜像,并相应替换<AWS_ACCOUNT_ID>和<ECR_REGISTRY_NAME>的值。

    cosign sign --key cosign.key  <AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/<ECR_REGISTRY_NAME>:v1.

上传至“https://rekor.sigstore.dev”的透明日志记录时按 y 确认。

现在如果你检查你的Amazon ECR注册表,你会看到你的镜像及其对应的SHA256哈希值。

步骤13: 使用如下命令现在重新启动nginx。

kubectl rollout restart deployment/nginx-deployment

此命令用于重启名为 nginx-deployment 的部署。

它会成功重启的。

注意: 如果 rollout 重启失败了,尝试创建一个新的部署或更改现有部署的镜像名称为。

这是一条用于访问Amazon ECR仓库的URL,格式为:<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/<ECR_REPO>:<TAG>

    <AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/<ECR_REPO>:<TAG>@sha256:<SHA>

rollout重新启动可能失败的原因在于,在重新启动过程中,图像标签未能自动更新为图像SHA。要解决此问题,您可以这样创建另一个策略:

apiVersion: kyverno.io/v1  
kind: ClusterPolicy  
metadata:  
  name: 将镜像解析为摘要  
spec:  
  background: false  
  rules:  
  - name: 解析为摘要值  
    match:  
      any:  
      - resources:  
          kinds:  
          - Pod  
    preconditions:  
      all:  
      - key: "{{ request.operation || 'BACKGROUNDED'}}"  
        operator: NotEquals  
        value: DELETE  
    mutate:  
      foreach:  
      - list: "request.object.spec.containers"  
        context:  
          - name: 解析引用  
            imageRegistry:  
              reference: "{{ element.image }}"  
              jmesPath: "resolvedImage"  
        patchStrategicMerge:  
          spec:  
            containers:  
            - name: "{{ element.name }}"             
              image: "{{ 解析引用 }}"

现在重新启动应该没问题了。

0人推荐
随时随地看视频
慕课网APP