Configura la integración de CI/CD

La integración de CI/CD conecta tus canalizaciones de CI/CD a la protección de artefactos para detectar vulnerabilidades de contenedores durante la etapa de compilación.

El escáner admite GitHub Actions, Cloud Build y Jenkins. Cuando se integra en una canalización, evalúa las imágenes de contenedores según tus políticas de protección de artefactos antes de que las imágenes se envíen a un registro.

Capacidades del escáner

La integración de CI/CD se ejecuta como un objeto binario dentro de tu flujo de trabajo de CI/CD para realizar las siguientes tareas:

  • Evaluación de políticas durante la compilación: Analiza las imágenes de contenedor recién compiladas en función de las políticas de protección de artefactos configuradas.
  • Bloqueo de compilaciones: Devuelve códigos de salida a tu ejecutor de CI/CD (GitHub Actions, Cloud Build o Jenkins) para bloquear las compilaciones que incumplen tus políticas de seguridad.
  • Informes de análisis: Envía los resultados del análisis de vulnerabilidades a Security Command Center y genera informes locales en formatos JSON o SARIF.

Roles y responsabilidades objetivo

La integración de CI/CD está diseñada para los siguientes equipos:

  • Equipos de DevOps o ingeniería de plataformas: Crea conectores de canalización y agrega pasos de ejecución del analizador a la configuración del flujo de trabajo de CI/CD.
  • Administradores de seguridad: Definen las políticas de vulnerabilidades previas a la compilación que aplica el scanner.
  • Desarrolladores de aplicaciones: Revisen los registros de ejecución del análisis en los resultados de la compilación de CI/CD para identificar y corregir los incumplimientos de políticas.

Términos y conceptos clave

  • Vulnerabilidades y exposiciones comunes (CVE): Es una vulnerabilidad de seguridad informática divulgada públicamente a la que se le asigna un identificador único.
  • Lista de materiales de software (SBOM): Es un inventario legible por máquina de los componentes y las dependencias de software que se usa para identificar CVE y otros riesgos de seguridad.
  • Artefacto: En el contexto de protección de artefactos, una imagen de contenedor compilada por una canalización de CI/CD.
  • Conector: Es un recurso que vincula tu canalización de CI/CD a la protección de artefactos. Cuando se pasa desde la canalización de CI durante una exploración, el ID del conector determina qué políticas evalúan la imagen.
  • Política de CI: Es una política de vulnerabilidades que define las reglas específicas de CVE, gravedad y paquetes que se aplican durante las compilaciones de CI/CD.

Flujo de trabajo de alto nivel

Para configurar y ejecutar análisis de vulnerabilidades de CI/CD, completa el siguiente flujo de trabajo:

  1. Crea un conector de CI para tu plataforma de CI/CD de destino.
  2. Crea una política de Artifact Guard que incluya el ID del conector en su alcance de canalización.
  3. Configura tu canalización de CI/CD para autenticarte enGoogle Cloud, compilar la imagen del contenedor y ejecutar el contenedor del analizador.

Cuando se ejecuta la canalización, el escáner evalúa la imagen de contenedor en función de tu política. Si la imagen incumple la política, el verificador muestra un código de salida de falla para que la compilación falle. Luego, los desarrolladores pueden inspeccionar los registros de compilación, actualizar las dependencias vulnerables y volver a ejecutar la compilación.

Antes de comenzar

Para usar la integración de CI/CD, debes habilitar la protección de artefactos. Para obtener instrucciones, consulta Antes de comenzar en la documentación de protección de artefactos.

Crear un conector

Console

Para crear un conector en la consola de Google Cloud , sigue estos pasos:

  1. En la consola de Google Cloud , ve a Seguridad > Configuración.
  2. En la tarjeta protección de artefactos, haz clic en Administrar configuración.
  3. Haz clic en Crear conector y, luego, ingresa los siguientes detalles del conector:
    • ID del conector: Agrega un ID para el conector.
    • Descripción: Ingresa una descripción del conector.
    • Plataforma de CI/CD: Selecciona la plataforma de CI/CD correspondiente en la lista. Usa este conector solo en las canalizaciones creadas con la plataforma de CI/CD seleccionada.
  4. Haz clic en Crear.

Una notificación confirma que se creó el conector correctamente. En la tabla Connectors, se enumeran los conectores disponibles.

gcloud CLI

Para crear un conector con gcloud CLI, ejecuta el siguiente comando:

gcloud alpha scc artifact-guard connectors create CONNECTOR_ID \
    --location=LOCATION \
    (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER) \
    --pipeline-type=PIPELINE_TYPE \
    [--description=DESCRIPTION] \
    [--display-name=DISPLAY_NAME]

Reemplaza lo siguiente:

  • CONNECTOR_ID: Es un identificador del conector (por ejemplo, my-connector).
  • LOCATION: Es la ubicación de Security Command Center en la que se almacenan tus datos. Solo se admite global.
  • ORGANIZATION_ID: Es el ID de organización.
  • PROJECT_NUMBER: Es el número de proyecto numérico.
  • PIPELINE_TYPE: Es el tipo de canalización de CI/CD. Debe ser una de las siguientes opciones:
    • GOOGLE_CLOUD_BUILD
    • GITHUB_ACTIONS
    • JENKINS_PIPELINE
  • DESCRIPTION: Es una descripción de texto para el conector.
  • DISPLAY_NAME: Es un nombre visible descriptivo para el conector.

Actualiza un conector

Console

Para vincular una política a un conector en la consola de Google Cloud , sigue estos pasos:

  1. En la consola de Google Cloud , ve a Seguridad > Configuración.
  2. En la tarjeta protección de artefactos, haz clic en Administrar configuración.
  3. En la tabla Conectores, haz clic en junto al conector y selecciona Agregar política.
  4. Sigue los pasos para crear o actualizar una política de protección de artefactos. Para obtener más información, consulta Crea una política.

gcloud CLI

Para ver los conectores existentes y actualizar sus asociaciones de políticas con gcloud CLI, usa los siguientes comandos:

Enumerar conectores

gcloud alpha scc artifact-guard connectors list PARENT

Reemplaza lo siguiente:

  • PARENT: Es una organización o un proyecto. Entre los formatos aceptables para el recurso principal, se incluyen los siguientes:
    • organizations/ORGANIZATION_ID/locations/LOCATION
    • projects/PROJECT_NUMBER/locations/LOCATION

Describe un conector

gcloud alpha scc artifact-guard connectors describe CONNECTOR_ID \
    --location=LOCATION \
    (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)

Actualiza la asociación de la política del conector

Para vincular un conector a una política, incluye el ID del conector en el alcance de la canalización de tu archivo de definición de políticas y actualiza la política con el comando gcloud alpha scc artifact-guard policies update. Para obtener más información, consulta Crea una política.

Borra un conector

Console

Para borrar un conector en la consola de Google Cloud , sigue estos pasos:

  1. En la consola de Google Cloud , ve a Seguridad > Configuración.
  2. En la tarjeta protección de artefactos, haz clic en Administrar configuración.
  3. En la tabla Connectors, haz clic en junto al conector y selecciona Delete connector.
  4. Sigue las indicaciones de confirmación para borrar el conector. Haz clic en Cancelar para anular la acción.

gcloud CLI

Para borrar un conector con gcloud CLI, ejecuta el siguiente comando:

gcloud alpha scc artifact-guard connectors delete CONNECTOR_ID \
    --location=LOCATION \
    (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)

Ejecutar una evaluación

Las canalizaciones de GitHub Actions y Jenkins admiten el análisis de vulnerabilidades. Para realizar una evaluación, debes hacer lo siguiente:

  1. Crea secretos para la autenticación.
  2. Crea un archivo de plantilla de integración específico para tu canalización.
  3. Inicia una evaluación.

Configuración de Secret

Las canalizaciones de CI/CD que se ejecutan fuera de Google Cloud pueden autenticarse con claves de cuentas de servicio o con la federación de identidades para cargas de trabajo. Para obtener instrucciones detalladas sobre cómo crear secretos, consulta lo siguiente:

Claves de cuenta de servicio

Federación de identidades para cargas de trabajo (para acciones de GitHub)

Debes agregar secretos a tu entorno de CI/CD con uno de los siguientes métodos:

Método de clave de cuenta de servicio

Un secreto:

  • GCP_CREDENTIALS: Es el contenido del archivo de clave JSON de la cuenta de servicio que descargaste.

Método de federación de identidades para cargas de trabajo

Dos secretos:

  • GCP_WORKLOAD_IDENTITY_PROVIDER: Es el nombre completo del recurso de tu proveedor de identidades para cargas de trabajo. Por ejemplo, projects/12345/locations/global/workloadIdentityPools/my-pool/providers/my-provider

  • GCP_SERVICE_ACCOUNT: Es la dirección de correo electrónico de la cuenta de servicio que se representará.

Plantillas de integración de canalizaciones

Para activar una evaluación, debes crear un archivo específico para tu canalización (Cloud Build, GitHub Actions o Jenkins) con los siguientes ejemplos de plantillas:

Cloud Build

  • Consulta Definiciones de variables para obtener información sobre cada campo.

    steps:
          # Step 1: Generate auth token
          - name: 'gcr.io/cloud-builders/gcloud'
          id: 'Generate Token'
          entrypoint: 'bash'
          args:
                - '-c'
                - |
                echo "Starting token generation..."
                gcloud auth print-access-token > /workspace/gcp_token.txt
                if [ $? -eq 0 ]; then
                      echo "Token generated successfully."
                else
                      echo "Failed to generate token." >&2
                      exit 1
                fi
    
          # Step 2: Build the image locally
          - name: 'gcr.io/cloud-builders/docker'
          id: 'Build Image'
          entrypoint: 'bash'
          args:
                - '-c'
                - |
                echo "🚧 Building Docker image from source code..."
                docker build -t ${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG} .
                if [ $? -ne 0 ]; then
                      echo "❌ Docker build failed."
                      exit 1
                fi
                echo "✅ Docker image built successfully: ${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}"
    
          # Step 3: Image scan for vulnerabilities
          - id: 'Image-Analysis'
          name: '${_SCANNER_IMAGE}'
          entrypoint: 'bash'
          args:
                - '-c'
                - |
                echo "Starting image scan with scanner: ${_SCANNER_IMAGE}"
    
                exit_code=0
    
                docker run --rm \
                      -v /var/run/docker.sock:/var/run/docker.sock \
                      -v /workspace:/workspace \
                      -e GCP_PROJECT_ID="${_PROJECT_ID}" \
                      -e ORGANIZATION_ID="${_ORGANIZATION_ID}" \
                      -e IMAGE_NAME="${_IMAGE_NAME_TO_SCAN}" \
                      -e IMAGE_TAG="${_IMAGE_TAG}" \
                      -e CONNECTOR_ID="${_CONNECTOR_ID}" \
                      -e TRIGGER_ID="${_TRIGGER_ID}" \
                      -e IGNORE_ERRORS="${_IGNORE_ERRORS}" \
                      -e GCP_ACCESS_TOKEN="$(cat /workspace/gcp_token.txt)" \
                      "${_SCANNER_IMAGE}" || exit_code=$?
    
                echo "Docker run finished with exit code: $exit_code"
    
                if [ $exit_code -eq 0 ]; then
                      echo "✅ Evaluation succeeded: Conformant image."
                elif [ $exit_code -eq 1 ]; then
                      echo "❌ Scan failed: Non-conformant image."
                      exit 1
                else
                      if [ "${_IGNORE_ERRORS}" = "true" ]; then
                            echo "⚠️ Server/internal error ignored. Continuing."
                      else
                            echo "❌ Server/internal error. Exiting."
                            exit 1
                      fi
                fi
    
          # Step 4: Configure Docker authentication for Artifact Registry
          - name: 'gcr.io/cloud-builders/gcloud'
          id: 'Configure Docker Auth'
          entrypoint: 'bash'
          args:
                - '-c'
                - |
                echo "🔐 Configuring Docker authentication for Artifact Registry..."
                gcloud auth configure-docker us-east1-docker.pkg.dev -q
                echo "✅ Docker authentication configured."
    
          # Step 5: Push image to Artifact Registry
          - name: 'gcr.io/cloud-builders/docker'
          id: 'Push Image to Artifact Registry'
          entrypoint: 'bash'
          args:
                - '-c'
                - |
    
                docker tag "${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}" "us-east1-docker.pkg.dev/${_PROJECT_ID}/${_AR_REPOSITORY}/${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}"
    
                echo "🚀 Pushing $_FULL_AR_TAG..."
                docker push "us-east1-docker.pkg.dev/${_PROJECT_ID}/${_AR_REPOSITORY}/${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}"
    
                echo "✅ Image pushed successfully."
    
    substitutions:
          _IMAGE_NAME_TO_SCAN: 'checkout-image'
          _ORGANIZATION_ID: 'orgId'
          _CONNECTOR_ID: 'connectorId'
          _SCANNER_IMAGE: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest'
          _IMAGE_TAG: 'latest'
          _TRIGGER_ID: 'cloud-build-job'
          _PROJECT_ID: 'projectId'
          _AR_REPOSITORY: 'images'
          _IGNORE_ERRORS: "false"
    
    serviceAccount: "projects/projectId/serviceAccounts/id-compute@developer.gserviceaccount.com"
    
    options:
          logging: CLOUD_LOGGING_ONLY
    

Acciones de GitHub (secreto)

Esta plantilla es para las acciones de GitHub que usan una clave secreta.

  • Agrega la clave secreta de tu cuenta de servicio (GCP_CREDENTIALS).
  • Consulta Definiciones de variables para obtener información sobre los campos adicionales.

    # A workflow to BUILD the app image, RUN the scanner, and PUSH to AR if scan passes
    name: Build, Scan and Push
    
    on:
     workflow_dispatch:
       inputs:
          IMAGE_NAME_TO_SCAN:
                description: 'The tag for your application image to be built (e.g., my-app:latest)'
                required: true
                default: 'checkout-image'
          GCP_PROJECT_ID:
                description: 'GCP Project ID for authentication'
                required: true
                default: 'projectId'
          AR_REPOSITORY:
                description: 'Artifact Registry repository name (e.g., app-repo)'
                required: false
                default: 'images'
          ORGANIZATION_ID:
                description: 'Your GCP Organization ID'
                required: true
                default: 'orgId'
          CONNECTOR_ID:
                description: 'The ID for your pipeline connector'
                required: true
                default: 'connectorId'
          SCANNER_IMAGE:
                description: 'The full registry path for your PRE-BUILT scanner tool'
                required: true
                default: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest'
          IMAGE_TAG:
                description: 'The Docker image version (of the app image)'
                required: true
                default: 'latest'
          IGNORE_SERVER_ERRORS:
                description: 'Ignore server errors'
                required: false
                type: boolean
                default: false
          VERBOSITY:
                description: 'Verbosity flag'
                required: false
                default: 'HIGH'
    
    jobs:
     build-and-scan:
       runs-on: ubuntu-latest
       steps:
          # 1. Check out repository (for your app's Dockerfile)
          - name: Check out repository
            uses: actions/checkout@v4
    
          # 2. Authenticate to Google Cloud
          - name: Authenticate to GCP
            id: auth
            uses: 'google-github-actions/auth@v2'
            with:
                credentials_json: '${{ secrets.GCP_CREDENTIALS }}'
    
          # 3. Set up the gcloud CLI
          - name: Set up Cloud SDK
            uses: 'google-github-actions/setup-gcloud@v2'
            with:
                project_id: ${{ inputs.GCP_PROJECT_ID }}
    
           # 4. Configure Docker (needed to pull SCANNER_IMAGE and push app image)
          - name: Configure Docker
            run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
    
          # 5. Build Application Image Locally (IMAGE_NAME_TO_SCAN)
          - name: Build Application Image Locally
            uses: docker/build-push-action@v5
            with:
                context: .
                file: ./Dockerfile
                push: false  # <-- Do not push
                load: true   # <-- Load image into the runner's local daemon
                # Tag the image with the name the scanner will look for
                tags: |
                ${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }}
    
          # 6. Run Image Scan (Using the SCANNER_IMAGE)
          - name: 'Run Image Analysis Scan'
            if: steps.auth.outcome == 'success'
            run: |
                echo "📦 Pulling scanner image and running scan..."
    
          SCANNER_IMAGE="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.SCANNER_IMAGE || env.SCANNER_IMAGE }}"
          GCP_PROJECT_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.GCP_PROJECT_ID || env.GCP_PROJECT_ID }}"
          ORGANIZATION_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ORGANIZATION_ID || env.ORGANIZATION_ID }}"
          IMAGE_NAME="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_NAME_TO_SCAN || env.IMAGE_NAME_TO_SCAN }}"
          IMAGE_TAG="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_TAG || env.IMAGE_TAG }}"
          CONNECTOR_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.CONNECTOR_ID || env.CONNECTOR_ID }}"
          VERBOSITY="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.VERBOSITY || env.VERBOSITY }}"
          IGNORE_ERRORS="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IGNORE_SERVER_ERRORS || (env.IGNORE_SERVER_ERRORS == 'true') }}"
    
          exit_code=0
    
          # This 'docker run' pulls the SCANNER_IMAGE from the registry
          # and passes the name of the locally-built app image (IMAGE_NAME)
          docker run --rm \
                -v /var/run/docker.sock:/var/run/docker.sock \
                -v ${{ steps.auth.outputs.credentials_file_path }}:/tmp/scc-key.json \
                -e GCLOUD_KEY_PATH=/tmp/scc-key.json \
                -e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \
                -e ORGANIZATION_ID="${ORGANIZATION_ID}" \
                -e IMAGE_NAME="${IMAGE_NAME}" \
                -e IMAGE_TAG="${IMAGE_TAG}" \
                -e CONNECTOR_ID="${CONNECTOR_ID}" \
                -e BUILD_TAG="${{ github.workflow }}" \
                -e BUILD_ID="${{ github.run_number }}" \
                -e VERBOSITY="${VERBOSITY}" \
                "${SCANNER_IMAGE}" \
                || exit_code=$?
    
          echo "Docker run finished with exit code: $exit_code"
    
          # --- Replicate Jenkins Exit Code Logic ---
          if [ $exit_code -eq 0 ]; then
            echo "✅ Evaluation succeeded: Conformant image."
          elif [ $exit_code -eq 1 ]; then
            echo "❌ Scan failed: Non-conformant image (vulnerabilities found)."
            exit 1 # Fail the step
          else
           if [ "$IGNORE_ERRORS" = "true" ]; then
                echo "⚠️ Server/internal error occurred (Code: $exit_code), but IGNORE_SERVER_ERRORS=true. Proceeding."
          else
            echo "❌ Server/internal error occurred (Code: $exit_code) during evaluation. Set IGNORE_SERVER_ERRORS=true to override."
            exit 1 # Fail the step
          fi
          fi
    
          # 8. Push Application Image (ONLY if scan succeeded)
          # This step only runs if the 'Run Image Analysis Scan' step above exited with 0
          - name: Push Application Image to Artifact Registry
            run: |
            # Define the local and remote tags
            LOCAL_IMAGE_NAME="${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }}"
    
            # This path is based on your 'Configure Docker' step (us-central1)
            # and the new AR_REPOSITORY input.
            FULL_AR_TAG="us-central1-docker.pkg.dev/${{ inputs.GCP_PROJECT_ID }}/${{ inputs.AR_REPOSITORY }}/${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }}"
    
            echo "Tagging local image ${LOCAL_IMAGE_NAME} as ${FULL_AR_TAG}"
            docker tag "${LOCAL_IMAGE_NAME}" "${FULL_AR_TAG}"
    
            echo "Pushing ${FULL_AR_TAG} to Artifact Registry..."
            docker push "${FULL_AR_TAG}"
    

Acciones de GitHub (WIF)

Esta plantilla es para las acciones de GitHub que usan la federación de identidades para cargas de trabajo.

  • Agrega tu proveedor de identidades para cargas de trabajo en el secreto de GitHub (GCP_WORKLOAD_IDENTITY_PROVIDER).
  • Agrega tu cuenta de servicio en el secreto de GitHub (GCP_SERVICE_ACCOUNT).
  • Consulta Definiciones de variables para obtener información sobre los campos adicionales.

    # A workflow to BUILD the app image, RUN the scanner, and PUSH to AR if scan passes
    name: Build, Scan and Push
    
    on:
      push:
        branches:
          - main
      workflow_dispatch:
      inputs:
        IMAGE_NAME_TO_SCAN:
          description: 'The tag for your application image to be built (e.g., my-app:latest)'
          required: true
          default: 'checkout-image'
        GCP_PROJECT_ID:
          description: 'GCP Project ID for authentication and configuration'
          required: true
          default: 'projectId'
        ORGANIZATION_ID:
          description: 'Your GCP Organization ID'
          required: true
          default: 'orgId'
        CONNECTOR_ID:
          description: 'The ID for your pipeline connector'
          required: true
          default: 'connectorId'
        SCANNER_IMAGE:
          description: 'The Docker image that contains your scanner script'
          required: true
          default: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest'
        IMAGE_TAG:
          description: 'The Docker image version'
          required: true
          default: 'latest'
        IGNORE_SERVER_ERRORS:
          description: 'If true, the pipeline continues on server/internal scanner errors.'
          required: false
          type: boolean
          default: false
    
    jobs:
      image-analysis-job:
      runs-on: ubuntu-latest
      permissions:
          contents: 'read'
          id-token: 'write'
    
      env:
          IMAGE_NAME_TO_SCAN: 'webgoat/webgoat'
          GCP_PROJECT_ID: 'projectId'
          ORGANIZATION_ID: 'orgId'
          CONNECTOR_ID: 'connectorId'
          SCANNER_IMAGE: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest'
          IMAGE_TAG: 'imageTag'
          IGNORE_SERVER_ERRORS: 'false'
    
      steps:
          # Step 1: Authenticate and create credential file
          - name: 'Authenticate to Google Cloud'
          id: 'auth'
          uses: 'google-github-actions/auth@v2'
          with:
          workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
          create_credentials_file: true
    
          # Step 2: Set up gcloud SDK
          - name: 'Set up gcloud SDK'
          uses: 'google-github-actions/setup-gcloud@v2'
    
          # Step 3: Configure Docker for registries
          - name: 'Configure Docker for Artifact Registry'
          run: |
          gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
    
          # Step 4: Run Image Analysis Scan and Handle Exit Codes
          - name: 'Run Image Analysis Scan'
          run: |
          echo "📦 Running container from scanner image..."
    
          # Determine values: Use manual inputs if available (event_name=workflow_dispatch), otherwise use env defaults
          SCANNER_IMAGE="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.SCANNER_IMAGE || env.SCANNER_IMAGE }}"
          GCP_PROJECT_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.GCP_PROJECT_ID || env.GCP_PROJECT_ID }}"
          ORGANIZATION_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ORGANIZATION_ID || env.ORGANIZATION_ID }}"
          IMAGE_NAME="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_NAME_TO_SCAN || env.IMAGE_NAME_TO_SCAN }}"
          IMAGE_TAG="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_TAG || env.IMAGE_TAG }}"
          CONNECTOR_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.CONNECTOR_ID || env.CONNECTOR_ID }}"
          IGNORE_ERRORS="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IGNORE_SERVER_ERRORS || (env.IGNORE_SERVER_ERRORS == 'true') }}"
    
          # Variable to store exit code
          exit_code=0
    
          # Run docker and capture exit code using || trick
          docker run --rm \
                -v /var/run/docker.sock:/var/run/docker.sock \
                -v ${{ steps.auth.outputs.credentials_file_path }}:/gcp-creds.json \
                -e GOOGLE_APPLICATION_CREDENTIALS=/gcp-creds.json \
                -e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \
                -e ORGANIZATION_ID="${ORGANIZATION_ID}" \
                -e IMAGE_NAME="${IMAGE_NAME}" \
                -e IMAGE_TAG="${IMAGE_TAG}" \
                -e CONNECTOR_ID="${CONNECTOR_ID}" \
                -e RUN_ID="${{ github.run_number }}" \
                "${SCANNER_IMAGE}" \
                || exit_code=$?
    
          echo "Docker run finished with exit code: $exit_code"
    
          if [ $exit_code -eq 0 ]; then
                echo "✅ Evaluation succeeded: Conformant image."
          elif [ $exit_code -eq 1 ]; then
                echo "❌ Scan failed: Non-conformant image (vulnerabilities found)."
                exit 1 # Fail the step
          else
                if [ "$IGNORE_ERRORS" = "true" ]; then
                echo "⚠️ Server/internal error occurred (Code: $exit_code), but IGNORE_SERVER_ERRORS=true. Proceeding."
                # Do nothing, step passes
                else
                echo "❌ Server/internal error occurred (Code: $exit_code) during evaluation. Set IGNORE_SERVER_ERRORS=true to override."
                exit 1 # Fail the step
                fi
          fi
    

Jenkins (secreto)

  • Agrega la clave secreta de la cuenta de servicio (GCP_CREDENTIALS).
  • Consulta Definiciones de variables para obtener información sobre los campos adicionales.

    pipeline {
          agent any
    
          parameters {
                string(
                      name: 'IMAGE_NAME_TO_SCAN',
                      defaultValue: 'checkout-image',
                      description: 'The tag for your application image to be built (e.g., my-app:latest)'
                )
                string(
                      name: 'GCP_PROJECT_ID',
                      defaultValue: 'projectId',
                      description: 'GCP Project ID for authentication'
                )
                string(
                      name: 'AR_REPOSITORY',
                      defaultValue: 'images',
                      description: 'Artifact Registry repository name (e.g., app-repo)'
                )
                string(
                      name: 'ORGANIZATION_ID',
                      defaultValue: 'orgId',
                      description: 'Your GCP Organization ID'
                )
                string(
                      name: 'CONNECTOR_ID',
                      defaultValue: 'connectorId',
                      description: 'The ID for your pipeline connector'
                )
                string(
                      name: 'SCANNER_IMAGE',
                      defaultValue: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest',
                      description: 'The full registry path for your PRE-BUILT scanner tool'
                )
                string(
                      name: 'IMAGE_TAG',
                      defaultValue: 'latest',
                      description: 'The Docker image version (of the app image)'
                )
                booleanParam(
                      name: 'IGNORE_SERVER_ERRORS',
                      defaultValue: false,
                      description: 'Ignore server errors'
                )
                string(
                      name: 'VERBOSITY',
                      defaultValue: 'HIGH',
                      description: 'Verbosity flag'
                )
          }
    
    stages {
          // Stage 1: Check out the source code
          stage('Checkout') {
                steps {
                echo "Checking out source code..."
                checkout scm
                }
          }
    
          // Stage 2: Build application image
          stage('Build Application Image') {
                steps {
                echo "Building application image: ${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}"
                sh "docker build -t ${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG} -f ./Dockerfile ."
                }
          }
    
          // Stage 3: Authenticate to Google Cloud and run scanner
          stage('Scan Image') {
                steps {
                script {
                      withCredentials([file(credentialsId: 'GCP_CREDENTIALS', variable: 'GCP_KEY_FILE')]) {
                            // Authenticate
                            sh "gcloud auth activate-service-account --key-file=\"$GCP_KEY_FILE\""
                            sh 'gcloud auth list'
                            sh 'gcloud auth configure-docker gcr.io --quiet'
                            sh 'gcloud auth configure-docker us-central1-docker.pkg.dev --quiet'
    
                            // Run scanner container
                            def exitCode = sh(
                            script: """
                                  echo "📦 Running scanner container from image: ${params.SCANNER_IMAGE}"
    
                                  docker run --rm \\
                                        -v /var/run/docker.sock:/var/run/docker.sock \\
                                        -v "$GCP_KEY_FILE":/tmp/scc-key.json \\
                                        -e GCLOUD_KEY_PATH=/tmp/scc-key.json \\
                                        -e GCP_PROJECT_ID="${params.GCP_PROJECT_ID}" \\
                                        -e ORGANIZATION_ID="${params.ORGANIZATION_ID}" \\
                                        -e IMAGE_NAME="${params.IMAGE_NAME_TO_SCAN}" \\
                                        -e IMAGE_TAG="${params.IMAGE_TAG}" \\
                                        -e CONNECTOR_ID="${params.CONNECTOR_ID}" \\
                                        -e BUILD_TAG="${env.JOB_NAME}" \\
                                        -e BUILD_ID="${env.BUILD_NUMBER}" \\
                                        "${params.SCANNER_IMAGE}"
                            """,
                            returnStatus: true
                            )
    
                            if (exitCode == 0) {
                            echo "✅ Evaluation succeeded: Conformant image."
                            } else if (exitCode == 1) {
                            error("❌ Scan failed: Non-conformant image (vulnerabilities found).")
                            } else {
                            if (params.IGNORE_SERVER_ERRORS) {
                                  echo "⚠️ Server/internal error occurred, but IGNORE_SERVER_ERRORS=true. Proceeding with pipeline."
                            } else {
                                  error("❌ Server/internal error occurred during evaluation. Set IGNORE_SERVER_ERRORS=true to override.")
                            }
                            }
                      }
                }
                }
          }
    
          // Stage 4: Push Application Image
          stage('Push Application Image') {
                steps {
                script {
                      def localImage = "${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}"
                      def remoteTag = "us-central1-docker.pkg.dev/${params.GCP_PROJECT_ID}/${params.AR_REPOSITORY}/${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}"
    
                      echo "Tagging local image ${localImage} as ${remoteTag}"
                      sh "docker tag ${localImage} ${remoteTag}"
    
                      echo "Pushing ${remoteTag} to Artifact Registry..."
                      sh "docker push ${remoteTag}"
                }
                }
          }
    }
    

Definiciones de variables

En esta sección, se proporciona información sobre los campos de variables que se usan en las plantillas de integración de canalizaciones.

IMAGE_NAME_TO_SCAN (obligatorio)

  • Especifica la etiqueta de la imagen de la aplicación que se compilará.

GCP_PROJECT_ID (obligatorio)

  • Especifica el Google Cloud ID del proyecto que se usa para la autenticación y la configuración.

AR_REPOSITORY (opcional)

  • Especifica el nombre del repositorio de Artifact Registry en el que la canalización publica la imagen si la compilación se realiza correctamente.

ORGANIZATION_ID (obligatorio)

  • ID de organización Google Cloud .

CONNECTOR_ID (obligatorio)

  • Especifica el ID del conector de la canalización que se usará.

SCANNER_IMAGE (obligatorio)

  • La imagen del analizador prediseñado analiza el código, identifica vulnerabilidades evaluando imágenes en función de las políticas durante la compilación y produce un resultado de cumplimiento para determinar si la canalización de CI/CD pasa o falla.

    Detalles de la imagen: us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest

VERBOSITY (opcional)

  • El escáner admite una marca VERBOSITY opcional que controla el nivel de detalle que se muestra en el resultado del análisis. El resultado del escáner varía según el nivel de detalle y el resultado de cumplimiento (Aprobado o No aprobado).
  • La marca de verbosidad se puede establecer en LOW o HIGH. Si no se proporciona, el valor predeterminado es LOW.

Poca verbosidad (conciso)

Cumplimiento de ArtifactGuard: Aprobado

  • Detalla los nombres de las políticas.
  • Solo proporciona el recuento resumido de CVE por gravedad.

ArtifactGuard Conformance: Fail

  • Detalla el motivo del error.
  • Solo enumera los CVE específicos que causaron la falla.
  • Proporciona un recuento resumido de los CVE categorizados por gravedad.

Verbosidad alta (detallada)

Proporciona una lista completa de todas las vulnerabilidades encontradas.

Cumplimiento de ArtifactGuard: Aprobado

  • Proporciona una lista de todos los CVE detectados para la política.
  • Proporciona un recuento resumido de los CVE desglosados por gravedad.
  • Proporciona una lista completa de todas las vulnerabilidades detectadas.

ArtifactGuard Conformance: Fail

  • Incluye el motivo del error.
  • Enumera los CVE que causan la falla.
  • Proporciona una lista de todos los CVE detectados para la política.
  • Proporciona un recuento resumido de los CVE desglosados por gravedad.
  • Proporciona una lista completa de todas las vulnerabilidades detectadas.

IGNORE_SERVER_ERRORS (opcional)

  • Es una marca booleana opcional. Si es true, la canalización continúa a pesar de los errores del servidor. La configuración predeterminada es false.

Cómo iniciar una evaluación

Durante el proceso de compilación, una estrategia basada en Docker evalúa la imagen según políticas predefinidas. La lógica del análisis de vulnerabilidades se encuentra dentro de la imagen us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest.

Para iniciar un análisis de vulnerabilidades en tu canalización de CI/CD, ejecuta el siguiente comando:

docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v ${{ steps.auth.outputs.credentials_file_path }}:/gcp-creds.json \
    -e GOOGLE_APPLICATION_CREDENTIALS=/gcp-creds.json \
    -e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \
    -e ORGANIZATION_ID="${ORGANIZATION_ID}" \
    -e IMAGE_NAME="${IMAGE_NAME}" \
    -e IMAGE_TAG="${IMAGE_TAG}" \
    -e CONNECTOR_ID="${CONNECTOR_ID}" \
    -e RUN_ID="${{ github.run_number }}" \
    "${SCANNER_IMAGE}" \
    || exit_code=$?

La integración de CI/CD propaga los códigos de salida del contenedor de Docker al tiempo de ejecución de Jenkins o GitHub Actions, que luego determina el estado de aprobación o falla de la canalización.

Soluciona problemas

En esta sección, se describen los errores comunes y cómo resolverlos.

Fallas de CreateConnector

Campo Obligatorio/Opcional Limitaciones
name Obligatorio Formato: Debe coincidir con la expresión regular [a-zA-Z0-9\\-\\s_]+$
. Debe coincidir con uno o más de los siguientes elementos:
  • letras (mayúsculas o minúsculas)
  • dígitos
  • guion -
  • espacio en blanco (\s)
  • guion bajo _


Longitud máxima: 64 caracteres.
pipeline_type Obligatorio Debe ser uno de los siguientes valores de enumeración:
  • JENKINS_PIPELINE
  • GITHUB_ACTIONS
  • GOOGLE_CLOUD_BUILD
description Opcional No debe superar los 256 caracteres.
display_name Opcional No debe superar los 256 caracteres.

Otros errores

En la siguiente tabla, se describen algunos errores comunes y cómo resolverlos.

Mensaje de error Causa Acción/Resolución
Permiso artifactscanguard.connectors.create denegado en el recurso El usuario o la cuenta de servicio no tienen el permiso de IAM artifactscanguard.connectors.create en el recurso (proyecto, carpeta u organización). Otorga al llamador un rol de IAM que incluya el permiso artifactscanguard.connectors.create.
status.ErrFailedPrecondition Es posible que la incorporación esté en curso, incluso si la Google Cloud consola muestra el servicio como habilitado. Informa un problema al equipo de asistencia al cliente.
status.ErrInvalidArgument Errores de validación de campos Asegúrate de que la solicitud CreateConnector cumpla con las restricciones especificadas.