Sincroniza artefactos OCI desde Artifact Registry

En esta página, se muestra cómo crear y publicar tu imagen en un repositorio en Artifact Registry con crane y oras.

Puedes configurar el Sincronizador de configuración para que se sincronice desde imágenes de OCI con Artifact Registry. Para usar esta función, debes habilitar las API de RootSync y RepoSync.

Acerca de Artifact Registry

Artifact Registry es un servicio completamente administrado que admite imágenes de contenedores y artefactos que no son de contenedores. Te recomendamos que uses Artifact Registry para el almacenamiento y la administración de imágenes de contenedores en Cloud de Confiance by S3NS. Hay muchas herramientas disponibles para enviar artefactos a Artifact Registry. Por ejemplo, puedes enviar una imagen de Docker o usar la biblioteca go-containerregistry para trabajar con registros de contenedores. Elige la herramienta que te resulte más conveniente.

Antes de comenzar

  1. Instala Google Cloud CLI.

  2. Configura gcloud CLI para usar tu identidad federada.

    Para obtener más información, consulta Accede a la gcloud CLI con tu identidad federada.

  3. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  4. Crea o selecciona un Cloud de Confiance proyecto.

    Roles necesarios para seleccionar o crear un proyecto

    • Selecciona un proyecto: Para seleccionar un proyecto, no se requiere un rol de IAM específico. Puedes seleccionar cualquier proyecto en el que se te haya otorgado un rol.
    • Crear un proyecto: Para crear un proyecto, necesitas el rol de Creador de proyectos (roles/resourcemanager.projectCreator), que contiene el permiso resourcemanager.projects.create. Obtén más información para otorgar roles.
    • Crea un proyecto de Cloud de Confiance :

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto Cloud de Confiance que estás creando.

    • Selecciona el proyecto Cloud de Confiance que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre de tu Cloud de Confiance proyecto.

  5. Verifica que la facturación esté habilitada para tu proyecto de Cloud de Confiance .

  6. Habilita las APIs de GKE, Sincronizador de configuración y Artifact Registry:

    Roles necesarios para habilitar las APIs

    Para habilitar las APIs, necesitas el rol de IAM de administrador de Service Usage (roles/serviceusage.serviceUsageAdmin), que contiene el permiso serviceusage.services.enable. Obtén más información para otorgar roles.

    gcloud services enable container.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  7. Crea un clúster que cumpla con los requisitos del Sincronizador de configuración y que tenga la versión más reciente del Sincronizador de configuración, o bien accede a uno.
  8. Instala la CLI de nomos o actualízala a la versión más reciente.
  9. (Opcional) Si deseas usar Cosign para verificar las firmas de imágenes de OCI, instala lo siguiente:
    • Cosign para firmar imágenes de OCI
    • OpenSSL para generar credenciales para el servidor de webhook
    • Docker para compilar y enviar la imagen del servidor de webhook de admisión

Costos

En este documento, usarás los siguientes componentes facturables de Cloud de Confiance by S3NS:

Crea un repositorio de Artifact Registry

En esta sección, crearás un repositorio de Artifact Registry. Para obtener más información sobre cómo crear repositorios de Artifact Registry, consulta Crea repositorios.

  1. Crea un repositorio de Artifact Registry:

    gcloud artifacts repositories create AR_REPO_NAME \
       --repository-format=docker \
       --location=AR_REGION \
       --description="Config Sync repo" \
       --project=PROJECT_ID
    

Reemplaza lo siguiente:

  • PROJECT_ID: El ID del proyecto de la organización.
  • AR_REPO_NAME: Es el ID del repositorio.
  • AR_REGION: es la ubicación regional o multirregional del repositorio.

Variables que se usan en las siguientes secciones:

  • FLEET_HOST_PROJECT_ID: Si usas Workload Identity Federation for GKE, esto es lo mismo que PROJECT_ID. Si usas la flota Workload Identity Federation for GKE, este es el ID del proyecto de la flota en la que está registrado tu clúster.
  • GSA_NAME: Es el nombre de la cuenta de servicio personalizada de Google que deseas usar para conectarte a Artifact Registry.
  • KSA_NAME: Es la cuenta de servicio de Kubernetes para el conciliador.
    • Para los repositorios raíz, si el nombre RootSync es root-sync, agrega root-reconciler. De lo contrario, agrega root-reconciler-ROOT_SYNC_NAME.
    • Para los repositorios de espacios de nombres, si el nombre de RepoSync es repo-sync, agrega ns-reconciler-NAMESPACE. De lo contrario, agrega ns-reconciler-NAMESPACE-REPO_SYNC_NAME-REPO_SYNC_NAME_LENGTH, donde REPO_SYNC_NAME_LENGTH es la cantidad de caracteres en REPO_SYNC_NAME.

Otorga permiso de lector

Para autenticarte en Artifact Registry con una cuenta de servicio de Kubernetes, completa los siguientes pasos:

Otorga el rol de IAM de lector de Artifact Registry (roles/artifactregistry.reader) a la cuenta de servicio de Kubernetes que tiene el grupo de Workload Identity Federation for GKE:

gcloud artifacts repositories add-iam-policy-binding AR_REPO_NAME \
   --location=AR_REGION \
   --member="serviceAccount:FLEET_HOST_PROJECT_ID.s3ns.svc.id.goog[config-management-system/KSA_NAME]" \
   --role=roles/artifactregistry.reader \
   --project=PROJECT_ID

Envía una imagen al repositorio de Artifact Registry

En esta sección, crearás una imagen de OCI y la enviarás a Artifact Registry.

  1. Crea un archivo de manifiesto Namespace:

    cat <<EOF> test-namespace.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: test
    EOF
    
  2. Accede a Artifact Registry:

    gcloud auth configure-docker AR_REGION-docker.pkg.dev
    
  3. Compila y envía la imagen a Artifact Registry:

    crane

    Los comandos de esta sección usan crane para interactuar con imágenes y registros remotos.

    1. Empaqueta el archivo:

      tar -cf test-namespace.tar test-namespace.yaml
      
    2. Instala la herramienta crane.

    3. Envía la imagen a Artifact Registry:

      crane append -f test-namespace.tar -t AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
      

    oras

    Los comandos de esta sección usan oras para interactuar con imágenes y registros remotos.

    1. Empaqueta el archivo:

      tar -czf test-namespace.tar.gz test-namespace.yaml
      
    2. Instala la herramienta oras.

    3. Envía la imagen a Artifact Registry:

      oras push AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1 test-namespace.tar.gz
      

Configura el Sincronizador de configuración para que se sincronice desde tu imagen

En esta sección, crearás un objeto RootSync y configurarás el Sincronizador de configuración para sincronizar desde la imagen de OCI.

  1. Crea un objeto RootSync con un nombre único:

    cat <<EOF>> ROOT_SYNC_NAME.yaml
    apiVersion: configsync.gke.io/v1beta1
    kind: RootSync
    metadata:
      name: ROOT_SYNC_NAME
      namespace: config-management-system
    spec:
      sourceFormat: unstructured
      sourceType: oci
      oci:
        image: AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
        dir: .
        auth: k8sserviceaccount
    EOF
    

    Reemplaza ROOT_SYNC_NAME por el nombre del objeto RootSync. El nombre debe ser único en el clúster y no debe tener más de 26 caracteres. Para obtener la lista completa de opciones cuando configures objetos RootSync, consulta Campos RootSync y RepoSync.

  2. Aplica el objeto RootSync:

    kubectl apply -f ROOT_SYNC_NAME.yaml
    
  3. Verifica que el Sincronizador de configuración se sincronice desde la imagen:

    nomos status --contexts=$(kubectl config current-context)
    

    Deberías ver un resultado similar al siguiente:

    Connecting to clusters...
    
    *publish-config-registry
       --------------------
       <root>:root-sync-test   AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1   
       SYNCED                  05e6a6b77de7a62286387cfea833d45290105fe84383224938d7b3ab151a55a1
       Managed resources:
          NAMESPACE   NAME             STATUS    SOURCEHASH
                      namespace/test   Current   05e6a6b
    

    Ya sincronizaste correctamente una imagen con tu clúster.

Verifica las firmas de origen de OCI (opcional)

Puedes verificar la autenticidad de las imágenes fuente de OCI antes de que se apliquen las configuraciones a tus clústeres. Este método usa un objeto ValidatingWebhookConfiguration y un servidor de webhook de validación para interceptar solicitudes de actualización de objetos RootSync y RepoSync. El Sincronizador de configuración actualiza la anotación configsync.gke.io/image-to-sync de los objetos RootSync y RepoSync después de recuperar correctamente un nuevo resumen de la imagen. El servidor de webhook de validación compara los valores entre la anotación anterior y la nueva, y ejecuta la validación con una herramienta de validación como Cosign cuando se detecta un cambio.

Configura un servidor de verificación de firmas

Para garantizar la autenticidad de tus fuentes de OCI, necesitas un servidor HTTP para verificar las firmas. Puedes usar las muestras del repositorio de muestras de Sincronizador de configuración o tu propia imagen de Docker.

  1. Si quieres usar la muestra proporcionada, completa los siguientes pasos:

    1. Clona el repositorio de ejemplo:

      git clone https://github.com/GoogleCloudPlatform/anthos-config-management-samples/
      
    2. Cambia al directorio que contiene las muestras del servidor de verificación de firmas:

      cd anthos-config-management-samples/tree/main/pre-sync/oci-image-verification
      
  2. Para crear una imagen de Docker para el servidor de verificación de firmas y enviarla a un registro de imágenes, ejecuta el siguiente comando:

    docker build -t SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest . && docker push SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest
    

    Reemplaza SIGNATURE_VERIFICATION_SERVER_IMAGE_URL por la URL de la imagen de tu servidor de verificación de firmas.

Autenticación en servicios

Para configurar tu servidor de verificación de firmas, debes autenticarte en Artifact Registry, el cliente de Cosign y el servidor de webhook.

  1. Crea un espacio de nombres:

    kubectl create ns signature-verification
    
  2. Para autenticarte en Artifact Registry con una ServiceAccount de Kubernetes, completa los siguientes pasos:

    1. Crea una ServiceAccount de Kubernetes en el espacio de nombres que creaste:

      kubectl create sa signature-verification-sa -n signature-verification
      
    2. Agrega la vinculación de la política de IAM para el rol de lector de Artifact Registry (roles/artifactregistry.reader):

      gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
         --location=REPOSITORY_LOCATION \
         --member="serviceAccount:PROJECT_ID.s3ns.svc.id.goog[signature-verification/signature-verification-sa]" \
         --role=roles/artifactregistry.reader \
         --project=PROJECT_ID
      

      Reemplaza lo siguiente:

      • REPOSITORY_NAME: Es el nombre de tu repositorio de Artifact Registry en el que almacenas tus imágenes de OCI.
      • REPOSITORY_LOCATION: Es la ubicación de tu repositorio de Artifact Registry.
  3. Para autenticarte en el cliente de Cosign, completa los siguientes pasos:

    1. Genera un par de claves de Cosign. Este comando genera una clave pública y una privada:

      cosign generate-key-pair
      
    2. Almacena la clave pública en un Secret de Kubernetes en el espacio de nombres que creaste:

      kubectl create secret generic cosign-key --from-file=cosign.pub -n signature-verification
      
  4. Para autenticar el servidor de verificación de firmas, completa los siguientes pasos:

    1. Para encriptar la comunicación dentro del servidor de verificación de firmas, genera un certificado TLS y una clave privada con OpenSSL:

      openssl req -nodes -x509 -sha256 -newkey rsa:4096 \
      -keyout tls.key \
      -out tls.crt \
      -days 356 \
      -subj "/CN=signature-verification-service.signature-verification.svc"  \
      -addext "subjectAltName = DNS:signature-verification-service,DNS:signature-verification-service.signature-verification.svc,DNS:signature-verification-service.signature-verification"
      
    2. Almacena las credenciales que generaste en un Secret de Kubernetes:

      kubectl create secret tls webhook-tls --cert=tls.crt --key=tls.key -n signature-verification
      
    3. Obtén el contenido codificado en Base64 de tls.cert. Esto es necesario para la configuración del webhook de validación que crearás en la siguiente sección:

      cat tls.crt | base64 -w 0.
      

Implementa el webhook de admisión

Puedes usar los siguientes ejemplos para crear una implementación para el servidor de verificación de firmas y una configuración de webhook de validación.

  1. Para crear una implementación para el servidor de verificación de firmas, guarda el siguiente archivo:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: signature-verification-server
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: signature-verification-server
      template:
        metadata:
          labels:
            app: signature-verification-server
        spec:
          serviceAccountName: signature-verification-sa
          containers:
          - name: signature-verification-server
            command:
            - /signature-verification-server
            image: SIGNATURE_VERIFICATION_SERVER_IMAGE_URL
            imagePullPolicy: Always
            ports:
            - containerPort: 10250
            volumeMounts:
            - name: tls-certs
              mountPath: "/tls"
            - name: cosign-key
              mountPath: "/cosign-key"
          volumes:
          - name: cosign-key
            secret:
              secretName: cosign-key
          - name: tls-certs
            secret:
              secretName: webhook-tls
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: signature-verification-service
    spec:
      ports:
      - port: 10250
        targetPort: 10250
      selector:
        app: signature-verification-server

    Reemplaza SIGNATURE_VERIFICATION_SERVER_IMAGE_URL por la URL completa de la imagen del servidor de verificación de firmas.

  2. Aplica la implementación al clúster:

    kubectl apply -f signature-verification-deployment.yaml -n signature-verification
    
  3. Para crear una configuración de webhook de validación, guarda el siguiente archivo:

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: image-verification-webhook
    webhooks:
    - name: imageverification.webhook.com
      clientConfig:
        service:
          name: signature-verification-service
          namespace: signature-verification
          path: "/validate"
          port: 10250
        caBundle: CA_BUNDLE
      rules:
      - apiGroups:
        - configsync.gke.io
        apiVersions:
        - v1beta1
        - v1alpha1
        operations:
        - UPDATE
        resources:
        - 'rootsyncs'
        - 'reposyncs'
        scope: '*'
      admissionReviewVersions: ["v1", "v1beta1"]
      sideEffects: None

    Reemplaza CA_BUNDLE por el contenido codificado en base64 de tls.cert.

  4. Aplica la configuración del webhook de validación al clúster:

    kubectl apply -f signature-verification-validatingwebhookconfiguration.yaml
    

Revisa los registros en busca de errores de verificación de imágenes

Una vez que configures tu servidor de verificación de imágenes, fallarán todos los intentos de sincronización desde imágenes OCI sin firma.

Para comprobar si hay errores de verificación de firma, ejecuta los siguientes comandos para ver los registros del servidor de verificación de firma:

  1. Verifica los registros de kubectl:

    kubectl logs deployment  signature-verification-server -n  signature-verification
    

    Los errores de kubectl relacionados con la verificación de firmas se parecen a los siguientes:

    main.go:69: error during command execution: no signatures found
    
  2. Verifica los registros del Sincronizador de configuración:

    nomos status
    

    Los errores del Sincronizador de configuración relacionados con la verificación de firmas se parecen a los siguientes:

    Error:   KNV2002: admission webhook "imageverification.webhook.com" denied the request: Image validation failed: cosign verification failed: exit status 10, output: Error: no signatures found
    

Si no recibes ningún error, puedes confirmar que la imagen firmada es el objeto que se sincroniza inspeccionando tu configuración de RootSync o RepoSync:

RootSync

 kubectl get rootsync ROOTSYNC_NAME -n config-management-system -oyaml

Reemplaza ROOTSYNC_NAME por el nombre de tu RootSync.

RepoSync

 kubectl get reposync REPOSYNC_NAME -n REPOSYNC_NAMESPACE -oyaml

Reemplaza lo siguiente:

  • REPOSYNC_NAME: El nombre de tu RepoSync.
  • REPOSYNC_NAMESPACE: Es el nombre del espacio de nombres asociado a tu RepoSync.

Deberías ver la anotación configsync.gke.io/image-to-sync agregada a tu objeto RootSync o RepoSync. La anotación contiene la URL de la imagen de OCI de origen y el resumen más reciente recuperado por el Sincronizador de configuración.

¿Qué sigue?