Configurar a integração de CI/CD

A integração de CI/CD conecta seus pipelines de CI/CD à proteção de artefatos para detectar vulnerabilidades de contêineres durante a fase de build.

O scanner é compatível com as ações do GitHub, o Cloud Build e o Jenkins. Quando integrado a um pipeline, ele avalia as imagens de contêiner em relação às políticas de proteção de artefatos antes que as imagens sejam enviadas para um registro.

Recursos do scanner

A integração de CI/CD é executada como um binário no seu fluxo de trabalho de CI/CD para realizar as seguintes tarefas:

  • Avaliação de políticas no momento da build: verifica as imagens de contêiner recém-criadas em relação às políticas de proteção de artefatos configuradas.
  • Bloqueio de build: retorna códigos de saída para o executor de CI/CD (GitHub Actions, Cloud Build ou Jenkins) para bloquear builds que violam suas políticas de segurança.
  • Relatórios de verificação: envia os resultados da verificação de vulnerabilidades para o Security Command Center e gera relatórios locais nos formatos JSON ou SARIF.

Funções e responsabilidades de destino

A integração de CI/CD foi projetada para as seguintes equipes:

  • Equipes de DevOps ou engenharia de plataforma: crie conectores de pipeline e adicione etapas de execução do scanner às configurações de fluxo de trabalho de CI/CD.
  • Administradores de segurança: definem as políticas de vulnerabilidade de tempo de build que o scanner aplica.
  • Desenvolvedores de aplicativos: analise os registros de execução da verificação nas saídas de build de CI/CD para identificar e corrigir violações da política.

Principais termos e conceitos

  • Vulnerabilidades e exposições comuns (CVE): uma vulnerabilidade de segurança de computador divulgada publicamente que recebe um identificador exclusivo.
  • Lista de materiais de software (SBOM): um inventário legível por máquina de componentes de software e dependências usadas para identificar CVEs e outros riscos de segurança.
  • Artefato: no contexto da proteção de artefatos, uma imagem de contêiner criada por um pipeline de CI/CD.
  • Conector: um recurso que vincula seu pipeline de CI/CD ao artifact guard. Quando transmitido do pipeline de CI durante uma verificação, o ID do conector determina quais políticas avaliam a imagem.
  • Política de CI: uma política de vulnerabilidade que define o CVE, a gravidade e as regras de pacote específicos aplicados durante os builds de CI/CD.

Fluxo de trabalho de alto nível

Para configurar e executar verificações de vulnerabilidade de CI/CD, siga este fluxo de trabalho:

  1. Crie um conector de CI para sua plataforma de CI/CD de destino.
  2. Crie uma política de proteção de artefato que inclua o ID do conector no escopo do pipeline.
  3. Configure seu pipeline de CI/CD para autenticar em Google Cloud, crie a imagem do contêiner e execute o contêiner do scanner.

Quando o pipeline é executado, o scanner avalia a imagem do contêiner em relação à sua política. Se a imagem violar a política, o scanner vai retornar um código de saída de falha para que a build falhe. Em seguida, os desenvolvedores podem inspecionar os registros de build, atualizar dependências vulneráveis e executar o build novamente.

Antes de começar

Para usar a integração de CI/CD, é necessário ativar a proteção de artefatos. Para instruções, consulte Antes de começar na documentação do Artifact Guard.

Criar um conector

Console

Para criar um conector no console do Google Cloud , siga estas etapas:

  1. No console Google Cloud , acesse Segurança > Configurações.
  2. No card Proteção de artefatos, clique em Gerenciar configurações.
  3. Clique em Criar conector e insira os seguintes detalhes:
    • ID do conector: adicione um ID para o conector.
    • Descrição: insira uma descrição do conector.
    • Plataforma de CI/CD: selecione a plataforma de CI/CD correspondente na lista. Use esse conector apenas em pipelines criados com a plataforma de CI/CD selecionada.
  4. Clique em Criar.

Uma notificação confirma a criação do conector. A tabela Conectores lista os conectores disponíveis.

CLI da gcloud

Para criar um conector usando a CLI gcloud, execute o seguinte 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]

Substitua:

  • CONNECTOR_ID: um identificador do conector (por exemplo, my-connector).
  • LOCATION: o local do Security Command Center onde seus dados são armazenados. Somente global é aceito.
  • ORGANIZATION_ID: o ID da organização.
  • PROJECT_NUMBER: o número numérico do projeto.
  • PIPELINE_TYPE: o tipo de pipeline de CI/CD. Deve ser um dos seguintes:
    • GOOGLE_CLOUD_BUILD
    • GITHUB_ACTIONS
    • JENKINS_PIPELINE
  • DESCRIPTION: uma descrição textual do conector.
  • DISPLAY_NAME: um nome de exibição fácil de usar para o conector.

Atualizar um conector

Console

Para vincular uma política a um conector no console do Google Cloud , siga estas etapas:

  1. No console Google Cloud , acesse Segurança > Configurações.
  2. No card Proteção de artefatos, clique em Gerenciar configurações.
  3. Na tabela Conectores, clique em ao lado do conector e selecione Adicionar política.
  4. Siga as etapas para criar ou atualizar uma política de proteção de artefatos. Para mais informações, consulte Criar uma política.

CLI da gcloud

Para conferir os conectores atuais e atualizar as associações de políticas usando a CLI gcloud, use os seguintes comandos:

Listar conectores

gcloud alpha scc artifact-guard connectors list PARENT

Substitua:

  • PARENT: uma organização ou um projeto. Formatos aceitos para o recurso pai:
    • organizations/ORGANIZATION_ID/locations/LOCATION
    • projects/PROJECT_NUMBER/locations/LOCATION

Descrever um conector

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

Atualizar associação de política de conector

Para vincular um conector a uma política, inclua o ID do conector no escopo do pipeline do arquivo de definição de política e atualize a política usando o comando gcloud alpha scc artifact-guard policies update. Para mais informações, consulte Criar uma política.

Excluir um conector

Console

Para excluir um conector no Google Cloud console, siga estas etapas:

  1. No console Google Cloud , acesse Segurança > Configurações.
  2. No card Proteção de artefatos, clique em Gerenciar configurações.
  3. Na tabela Conectores, clique em ao lado do conector e selecione Excluir conector.
  4. Siga as instruções de confirmação para excluir o conector. Clique em Cancelar para interromper.

CLI da gcloud

Para excluir um conector usando a CLI gcloud, execute o seguinte comando:

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

Executar uma avaliação

Os pipelines do GitHub Actions e do Jenkins oferecem suporte à verificação de vulnerabilidades. Para realizar uma avaliação, faça o seguinte:

  1. Crie secrets para autenticação.
  2. Crie um arquivo de modelo de integração específico para seu pipeline.
  3. Inicie uma avaliação.

Configuração de secrets

Os pipelines de CI/CD executados fora do Google Cloud podem ser autenticados usando chaves de conta de serviço ou a federação de identidade da carga de trabalho. Para instruções detalhadas sobre como criar secrets, consulte:

Chaves da conta de serviço

Federação de identidade da carga de trabalho (para o GitHub Actions)

Adicione secrets ao ambiente de CI/CD usando um dos seguintes métodos:

Método de chave da conta de serviço

Um secret:

  • GCP_CREDENTIALS: o conteúdo do arquivo de chave JSON da conta de serviço baixado.

Método de federação de identidade da carga de trabalho

Dois secrets:

  • GCP_WORKLOAD_IDENTITY_PROVIDER: o nome completo do recurso do provedor de identidade de carga de trabalho. Por exemplo, projects/12345/locations/global/workloadIdentityPools/my-pool/providers/my-provider.

  • GCP_SERVICE_ACCOUNT: o endereço de e-mail da conta de serviço a ser personificada.

Modelos de integração de pipeline

Para acionar uma avaliação, crie um arquivo específico para seu pipeline (Cloud Build, GitHub Actions ou Jenkins) usando os seguintes exemplos de modelo:

Cloud Build

  • Consulte Definições de variáveis para informações 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
    

GitHub Actions (secreto)

Este modelo é para o GitHub Actions usando uma chave secreta.

  • Adicione sua chave secreta da conta de serviço (GCP_CREDENTIALS).
  • Consulte Definições de variáveis para informações sobre campos adicionais.

    # 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}"
    

GitHub Actions (WIF)

Este modelo é para o GitHub Actions usando a federação de identidade da carga de trabalho.

  • Adicione seu provedor de identidade de carga de trabalho no segredo do GitHub (GCP_WORKLOAD_IDENTITY_PROVIDER).
  • Adicione sua conta de serviço ao segredo do GitHub (GCP_SERVICE_ACCOUNT).
  • Consulte Definições de variáveis para informações sobre campos adicionais.

    # 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 (secret)

  • Adicione a chave secreta da conta de serviço (GCP_CREDENTIALS).
  • Consulte Definições de variáveis para informações sobre campos adicionais.

    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}"
                }
                }
          }
    }
    

Definições de variáveis

Esta seção fornece informações sobre os campos de variáveis usados nos modelos de integração de pipeline.

IMAGE_NAME_TO_SCAN (obrigatório)

  • Especifica a tag da imagem do aplicativo a ser criada.

GCP_PROJECT_ID (obrigatório)

  • Especifica o ID do projeto Google Cloud usado para autenticação e configuração.

AR_REPOSITORY (opcional)

  • Especifica o nome do repositório do Artifact Registry em que o pipeline publica a imagem se o build for bem-sucedido.

ORGANIZATION_ID (obrigatório)

  • O ID da organização Google Cloud .

CONNECTOR_ID (obrigatório)

  • Especifica o ID do conector do pipeline a ser usado.

SCANNER_IMAGE (obrigatório)

  • A imagem do scanner pré-criado analisa o código, identifica vulnerabilidades avaliando imagens em relação às políticas durante o build e produz um resultado de conformidade para determinar se o pipeline de CI/CD é aprovado ou reprovado.

    Detalhes da imagem: us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest

VERBOSITY (opcional)

  • O scanner é compatível com uma flag VERBOSITY opcional que controla o nível de detalhes mostrado na saída da verificação. A saída do scanner varia de acordo com o nível de detalhamento e o resultado de conformidade (Aprovado ou Reprovado).
  • A flag de verbosidade pode ser definida como LOW ou HIGH. O padrão é LOW se não for fornecido.

Baixa verbosidade (conciso)

Conformidade do ArtifactGuard: aprovado

  • Detalha os nomes das políticas.
  • Fornece apenas a contagem resumida de CVEs por gravidade.

Conformidade do ArtifactGuard: falha

  • Detalha o motivo da falha.
  • Lista apenas os CVEs específicos que causaram a falha.
  • Fornece uma contagem resumida de CVEs categorizadas por gravidade.

Alta verbosidade (detalhada)

Fornece uma lista completa de todas as vulnerabilidades encontradas.

Conformidade do ArtifactGuard: aprovado

  • Fornece uma lista de todas as CVEs detectadas para a política.
  • Fornece uma contagem resumida de CVEs divididas por gravidade.
  • Fornece uma lista completa de todas as vulnerabilidades detectadas.

Conformidade do ArtifactGuard: falha

  • Inclui o motivo da falha.
  • Lista as CVEs que causam a falha.
  • Fornece uma lista de todas as CVEs detectadas para a política.
  • Fornece uma contagem resumida de CVEs divididas por gravidade.
  • Fornece uma lista completa de todas as vulnerabilidades detectadas.

IGNORE_SERVER_ERRORS (opcional)

  • Uma flag booleana opcional. Se true, o pipeline vai continuar apesar dos erros do servidor. O padrão é false.

Iniciar uma avaliação

Durante o processo de build, uma estratégia baseada em Docker avalia a imagem em relação a políticas predefinidas. A lógica de verificação de vulnerabilidades está contida na imagem us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest.

Para iniciar uma verificação de vulnerabilidades no pipeline de CI/CD, execute o seguinte 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=$?

A integração de CI/CD propaga os códigos de saída do contêiner do Docker para o tempo de execução do Jenkins ou das ações do GitHub, que determinam o estado de aprovação ou falha do pipeline.

Solução de problemas

Esta seção descreve erros comuns e como resolvê-los.

Falhas de CreateConnector

Campo Obrigatório/opcional Restrições
name Obrigatório Formato:precisa corresponder à expressão regular [a-zA-Z0-9\\-\\s_]+$
Corresponda a um ou mais dos seguintes:
  • letras (maiúsculas ou minúsculas)
  • dígitos
  • hífen -
  • espaço em branco (\s)
  • sublinhado _


Comprimento máximo:64 caracteres.
pipeline_type Obrigatório Precisa ser um dos seguintes valores de enumeração:
  • JENKINS_PIPELINE
  • GITHUB_ACTIONS
  • GOOGLE_CLOUD_BUILD
description Opcional Não pode exceder 256 caracteres.
display_name Opcional Não pode exceder 256 caracteres.

Outros erros

A tabela a seguir descreve alguns erros comuns e como resolvê-los.

Mensagem de erro Causa Ação/Resolução
Permissão artifactscanguard.connectors.create negada no recurso O usuário ou a conta de serviço não tem a permissão artifactscanguard.connectors.create do IAM no recurso (projeto, pasta ou organização). Conceda ao autor da chamada um papel do IAM que inclua a permissão artifactscanguard.connectors.create.
status.ErrFailedPrecondition A integração pode estar em andamento mesmo que o console Google Cloud mostre o serviço como ativado. Informe um problema à equipe de suporte.
status.ErrInvalidArgument Falhas na validação de campo Verifique se a solicitação CreateConnector atende às restrições especificadas.