Saltar al contenido principal

Integraciones monitorización

Para centralizar los posibles problemas de seguridad que puedan surgir en las diferentes fases del pipeline, se realiza la integración con herramientas de monitorización.

DefectDojo

Para integrar DefectDojo, el primer paso es crear un proyecto. Una vez creado el proyecto, se requieren dos componentes en el pipeline. El primero consiste en crear un stage previo que genere un engagement para esa ejecución. Posteriormente, se desarrolla una función reutilizable para importar los diferentes análisis.

En ambos casos, se utiliza la API de DefectDojo, que requiere autenticación. Esta información se encuentra en la parte superior derecha de la interfaz de DefectDojo.

Menú API Key

En ese apartado se puede ver la API Key, que debe incluirse en las solicitudes bajo el encabezado Authorization: Token XXXXXXXXXXXXXX.

Show API Key

La URL base de la API v2 corresponde a la URL base de la instancia de DefectDojo seguida de /api/v2.

El identificador del producto se obtiene a partir de la URL al acceder al producto en la interfaz de usuario.

Id producto

GitLab

Engagement

Una vez disponibles los datos, se crea un engagement mediante un stage denominado .pre, que devuelve un ID almacenado en una variable de entorno. Este ID se transfiere a las siguientes tareas relacionadas con DefectDojo utilizando el artefacto 'artifacts:reports:dotenv'.

Las variables necesarias en el CI son:

  • DD_SERVER: Dirección del servidor de DefectDojo.
  • DD_API_KEY: Clave de la API para autenticarse en DefectDojo. Se recomienda marcar el atributo 'mask' para que no se muestre en los registros.
  • DD_PRODUCTID: ID del producto en el que se crea el engagement.

GitLab CI/CD Variables

Se crea un archivo llamado defectdojo-engagement.sh en la carpeta .gitlab-ci, que contiene la llamada curl para crear el engagement en esta ejecución del CI.

.gitlab-ci/defectdojo-engagement.sh
#!/bin/bash

TODAY=$(date +%Y-%m-%d)
ENDDAY=$(date -d "+${DD_ENGAGEMENT_PERIOD} days" +%Y-%m-%d)

ENGAGEMENTID=$(curl --fail --location --request POST "${DD_SERVER}/api/v2/engagements/" \
-H "Authorization: Token ${DD_API_KEY}" \
-H 'Content-Type: application/json' \
--data-raw "{
\"tags\": [\"GITLAB-CI\"],
\"name\": \"#${CI_PIPELINE_ID}\",
\"description\": \"${CI_COMMIT_DESCRIPTION}\",
\"version\": \"${CI_COMMIT_REF_NAME}\",
\"first_contacted\": \"${TODAY}\",
\"target_start\": \"${TODAY}\",
\"target_end\": \"${ENDDAY}\",
\"reason\": \"string\",
\"tracker\": \"${CI_PROJECT_URL}/-/issues\",
\"threat_model\": \"${DD_ENGAGEMENT_THREAT_MODEL}\",
\"api_test\": \"${DD_ENGAGEMENT_API_TEST}\",
\"pen_test\": \"${DD_ENGAGEMENT_PEN_TEST}\",
\"check_list\": \"${DD_ENGAGEMENT_CHECK_LIST}\",
\"status\": \"${DD_ENGAGEMENT_STATUS}\",
\"engagement_type\": \"CI/CD\",
\"build_id\": \"${CI_PIPELINE_ID}\",
\"commit_hash\": \"${CI_COMMIT_SHORT_SHA}\",
\"branch_tag\": \"${CI_COMMIT_REF_NAME}\",
\"deduplication_on_engagement\": \"${DD_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT}\",
\"product\": \"${DD_PRODUCTID}\",
\"source_code_management_uri\": \"${CI_PROJECT_URL}\",
\"build_server\": ${DD_ENGAGEMENT_BUILD_SERVER},
\"source_code_management_server\": ${DD_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER},
\"orchestration_engine\": ${DD_ENGAGEMENT_ORCHESTRATION_ENGINE}
}" | jq -r '.id')

echo "DD_ENGAGEMENTID=${ENGAGEMENTID}" >> defectdojo.env

Desde el stage .pre se lanza la creación del engagement llamando al script anterior.

.gitlab-ci.yml
defectdojo_create_engagement:
stage: .pre
image: alpine
variables:
DD_NOT_ON_MASTER: "false"
DD_ENGAGEMENT_PERIOD: 7
DD_ENGAGEMENT_STATUS: "Not Started"
DD_ENGAGEMENT_BUILD_SERVER: "null"
DD_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER: "null"
DD_ENGAGEMENT_ORCHESTRATION_ENGINE: "null"
DD_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT: "false"
DD_ENGAGEMENT_THREAT_MODEL: "true"
DD_ENGAGEMENT_API_TEST: "true"
DD_ENGAGEMENT_PEN_TEST: "true"
DD_ENGAGEMENT_CHECK_LIST: "true"
rules:
- if: '$DD_NOT_ON_MASTER == "true" && $CI_COMMIT_BRANCH == "master"'
when: never
- when: always
before_script:
- apk add curl jq coreutils
script:
- sh .gitlab-ci/defectdojo-engagement.sh
artifacts:
reports:
dotenv: defectdojo.env

Este stage en el archivo de configuración de GitLab CI/CD se denomina "defectdojo_create_engagement".

  • stage: .pre: Se ubica en la etapa .pre del pipeline, ejecutándose antes de otros stages.
  • image: alpine: Utiliza la imagen Alpine Linux.
  • variables: Define variables de entorno para configurar el engagement en DefectDojo.
  • rules: Determina cuándo se ejecuta el stage.
  • before_script: Instala las herramientas necesarias.
  • script: Ejecuta el script para crear el engagement.
  • artifacts: Genera un archivo .env que se utilizará en otros stages.

Findings

Para enviar los resultados de las diferentes herramientas, se utiliza un archivo en la carpeta .gitlab-ci llamado defectdojo-finding.sh, que envía los resultados a DefectDojo y al engagement correspondiente.

.gitlab-ci/defectdojo-finding.sh
#!/bin/bash

TODAY=$(date +%Y-%m-%d)

curl --location --request POST "${DD_SERVER}/api/v2/import-scan/" \
-H 'accept: application/json' \
-H "Authorization: Token ${DD_API_KEY}" \
-F "scan_date=${TODAY}" \
-F "minimum_severity=${DD_SCAN_MINIMUM_SEVERITY}" \
-F "active=${DD_SCAN_ACTIVE}" \
-F "verified=${DD_SCAN_VERIFIED}" \
-F "scan_type=${DD_SCAN_TYPE}" \
-F "engagement=${DD_ENGAGEMENTID}" \
-F "file=@${REPORT};type=application/json" \
-F "close_old_findings=${DD_SCAN_CLOSE_OLD_FINDINGS}" \
-F "environment=${DD_SCAN_ENVIRONMENT}" \
-F "product_name=${DD_PRODUCT_NAME}" \
-F 'create_finding_groups_for_all_findings=true' \
-F 'group_by=component_name+component_version'

GitHub

Engagement

Una vez disponibles los datos, se crea un engagement mediante un job llamado create_engagement, que devuelve un ID almacenado en una variable de entorno. Este ID se transfiere a las siguientes tareas relacionadas con DefectDojo utilizando outputs.

Las variables necesarias en el CI son:

  • DD_SERVER: Dirección del servidor de DefectDojo.
  • DD_API_KEY: Clave de la API para autenticarse en DefectDojo. Se almacena como secreto para no exponerla en el CI.
  • DD_PRODUCTID: ID del producto en el que se crea el engagement.

GitHub Secrets GitHub Variables

Se crea un archivo llamado defectdojo-engagement.sh en la carpeta .github/scripts, que contiene la llamada curl para crear el engagement en esta ejecución del CI.

.github/scripts/defectdojo-engagement.sh
#!/bin/bash
set -e
TODAY=$(date +%Y-%m-%d)
ENDDAY=$(date -d "+${DD_ENGAGEMENT_PERIOD} days" +%Y-%m-%d)
BRANCH_NAME=${GITHUB_REF##*/}
COMMIT_DESC=$(jq -r .head_commit.message < "$GITHUB_EVENT_PATH")
COMMIT_SHA_SHORT=${GITHUB_SHA:0:8}

curl --location --request POST "${DD_SERVER}/api/v2/engagements/" \
-H "Authorization: Token ${DD_API_KEY}" \
-H 'Content-Type: application/json' \
--data-raw "{
\"tags\": [\"GITHUB-ACTIONS\"],
\"name\": \"#${GITHUB_RUN_ID}\",
\"description\": \"${COMMIT_DESC}\",
\"version\": \"${BRANCH_NAME}\",
\"first_contacted\": \"${TODAY}\",
\"target_start\": \"${TODAY}\",
\"target_end\": \"${ENDDAY}\",
\"reason\": \"CI/CD via Actions\",
\"tracker\": \"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues\",
\"threat_model\": \"${DD_ENGAGEMENT_THREAT_MODEL}\",
\"api_test\": \"${DD_ENGAGEMENT_API_TEST}\",
\"pen_test\": \"${DD_ENGAGEMENT_PEN_TEST}\",
\"check_list\": \"${DD_ENGAGEMENT_CHECK_LIST}\",
\"status\": \"${DD_ENGAGEMENT_STATUS}\",
\"engagement_type\": \"CI/CD\",
\"build_id\": \"${GITHUB_RUN_ID}\",
\"commit_hash\": \"${COMMIT_SHA_SHORT}\",
\"branch_tag\": \"${BRANCH_NAME}\",
\"deduplication_on_engagement\": \"${DD_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT}\",
\"product\": \"${DD_PRODUCTID}\",
\"source_code_management_uri\": \"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}\",
\"build_server\": ${DD_ENGAGEMENT_BUILD_SERVER},
\"source_code_management_server\": ${DD_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER},
\"orchestration_engine\": ${DD_ENGAGEMENT_ORCHESTRATION_ENGINE}
}" | jq -r '.id' > defectdojo.env

Desde el job create_engagement se lanza la creación del engagement llamando al script anterior.

.github/workflows/ci.yml
 create_engagement:
name: DefectDojo crear engagement
runs-on: ubuntu-latest
container:
image: alpine:latest
steps:

- name: Instalar dependencias
run: apk add --no-cache coreutils jq curl git

- name: Checkout repo
uses: actions/checkout@v4
with:
sparse-checkout: .github/

- name: Crear engagement en DefectDojo
id: dojo_eng
run: |
sh .github/scripts/defectdojo-engagement.sh
export ENGAGEMENTID=$(cat defectdojo.env)
echo "ENGAGEMENTID=$ENGAGEMENTID" >> $GITHUB_OUTPUT

outputs:
ENGAGEMENTID: ${{ steps.dojo_eng.outputs.ENGAGEMENTID }}

Este job en el archivo de configuración de GitHub Actions se denomina create_engagement.

  • name: DefectDojo crear engagement: Nombre del job.
  • runs-on: ubuntu-latest: Se ejecuta en un runner de GitHub Actions con Ubuntu.
  • container: image: alpine:latest: Utiliza una imagen Alpine Linux.
  • steps: Define los pasos del job.
    • Instalar dependencias: Instala las herramientas necesarias.
    • Checkout repo: Clona el repositorio.
    • Crear engagement en DefectDojo: Ejecuta el script para crear el engagement y extrae el ID.
  • outputs: Define una salida llamada ENGAGEMENTID para su uso en otros jobs.

Findings

Para enviar los resultados de las diferentes herramientas, se utiliza un archivo en la carpeta .github/scripts llamado defectdojo-finding.sh, que envía los resultados a DefectDojo y al engagement correspondiente.

.github/scripts/defectdojo-finding.sh
#!/bin/bash
set -e
TODAY=$(date +%Y-%m-%d)

curl --location --request POST "${DD_SERVER}/api/v2/import-scan/" \
-H 'accept: application/json' \
-H "Authorization: Token ${DD_API_KEY}" \
-F "scan_date=${TODAY}" \
-F "minimum_severity=${DD_SCAN_MINIMUM_SEVERITY}" \
-F "active=${DD_SCAN_ACTIVE}" \
-F "verified=${DD_SCAN_VERIFIED}" \
-F "scan_type=${DD_SCAN_TYPE}" \
-F "engagement=${DD_ENGAGEMENTID}" \
-F "file=@${DD_SCAN_FILE};type=application/json" \
-F "close_old_findings=${DD_SCAN_CLOSE_OLD_FINDINGS}" \
-F "environment=${DD_SCAN_ENVIRONMENT}" \
-F "product_name=${DD_PRODUCT_NAME}" \
-F 'create_finding_groups_for_all_findings=true' \
-F 'group_by=component_name+component_version'

Jenkins

Engagement

Una vez disponibles los datos, se crea un engagement mediante un stage denominado Create Engagement, que devuelve un ID almacenado en una variable de entorno. Este ID se transfiere a las siguientes tareas relacionadas con DefectDojo utilizando el artefacto 'artifacts:reports:dotenv'.

Es necesario instalar el plugin Pipeline Utility Steps para poder analizar los datos del artefacto.

Las variables necesarias en el CI son:

DD_API_KEY: Clave de la API para autenticarse en DefectDojo.

Jenkins Credentials

Se crea un archivo llamado defectdojo-engagement.sh en la carpeta .jenkins-ci, que contiene la llamada curl para crear el engagement en esta ejecución del CI.

.jenkins-ci/defectdojo-engagement.sh
#!/bin/bash

TODAY=$(date +%Y-%m-%d)
ENDDAY=$(date -d "+${DD_ENGAGEMENT_PERIOD} days" +%Y-%m-%d)

CI_PROJECT_URL='https://example.com/osdo'

CI_COMMIT_DESCRIPTION=$(git log -1 --pretty=%B)

ENGAGEMENTID=$(curl --location --request POST "${DD_SERVER}/api/v2/engagements/" \
-H "Authorization: Token ${DD_API_KEY}" \
-H 'Content-Type: application/json' \
--data-raw "{
\"tags\": [\"GITLAB-CI\"],
\"name\": \"#${BUILD_NUMBER}\",
\"description\": \"${CI_COMMIT_DESCRIPTION}\",
\"version\": \"${GIT_BRANCH}\",
\"first_contacted\": \"${TODAY}\",
\"target_start\": \"${TODAY}\",
\"target_end\": \"${ENDDAY}\",
\"reason\": \"string\",
\"tracker\": \"${CI_PROJECT_URL}/-/issues\",
\"threat_model\": \"${DD_ENGAGEMENT_THREAT_MODEL}\",
\"api_test\": \"${DD_ENGAGEMENT_API_TEST}\",
\"pen_test\": \"${DD_ENGAGEMENT_PEN_TEST}\",
\"check_list\": \"${DD_ENGAGEMENT_CHECK_LIST}\",
\"status\": \"${DD_ENGAGEMENT_STATUS}\",
\"engagement_type\": \"CI/CD\",
\"build_id\": \"${BUILD_NUMBER}\",
\"commit_hash\": \"${GIT_COMMIT:0:7}\",
\"branch_tag\": \"${GIT_BRANCH}\",
\"deduplication_on_engagement\": \"${DD_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT}\",
\"product\": \"${DD_PRODUCTID}\",
\"source_code_management_uri\": \"${CI_PROJECT_URL}\",
\"build_server\": ${DD_ENGAGEMENT_BUILD_SERVER},
\"source_code_management_server\": ${DD_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER},
\"orchestration_engine\": ${DD_ENGAGEMENT_ORCHESTRATION_ENGINE}
}" | jq -r '.id')

echo "DD_ENGAGEMENTID=${ENGAGEMENTID}" > defectdojo.env

Desde el stage Create Engagement se lanza la creación del engagement llamando al script anterior.

Jenkinsfile
pipeline {
agent any
environment {
DD_SERVER='https://defectd.opensecdevops.com'
}
stages {
stage('Create Engagement') {
environment {
DD_ENGAGEMENT_PERIOD = '7'
DD_ENGAGEMENT_STATUS = 'Not Started'
DD_ENGAGEMENT_BUILD_SERVER = 'null'
DD_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER = 'null'
DD_ENGAGEMENT_ORCHESTRATION_ENGINE= 'null'
DD_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT = 'false'
DD_ENGAGEMENT_THREAT_MODEL = 'true'
DD_ENGAGEMENT_API_TEST = 'true'
DD_ENGAGEMENT_PEN_TEST = 'true'
DD_ENGAGEMENT_CHECK_LIST = 'true'
DD_PRODUCTID = '1'
}
steps {
sh 'chmod +x .jenkis-ci/defectdojo-engagement.sh'
withCredentials([string(credentialsId: 'DD_API_KEY', variable: 'DD_API_KEY')]) {
sh './.jenkis-ci/defectdojo-engagement.sh'
}
archiveArtifacts artifacts: 'defectdojo.env', fingerprint: true
}
}
}
}

Este stage en el archivo de configuración de Jenkins se denomina Create Engagement.

  • environment: Define variables de entorno para configurar el engagement en DefectDojo.
  • steps: Ejecuta el script para crear el engagement.

Findings

Para enviar los resultados de las diferentes herramientas, se utiliza un archivo en la carpeta .jenkins-ci llamado defectdojo-finding.sh, que envía los resultados a DefectDojo y al engagement correspondiente.

.jenkins-ci/defectdojo-finding.sh
#!/bin/bash

TODAY=$(date +%Y-%m-%d)

curl --location --request POST "${DD_SERVER}/api/v2/import-scan/" \
-H 'accept: application/json' \
-H "Authorization: Token ${DD_API_KEY}" \
-F "scan_date=${TODAY}" \
-F "minimum_severity=${DD_SCAN_MINIMUM_SEVERITY}" \
-F "active=${DD_SCAN_ACTIVE}" \
-F "verified=${DD_SCAN_VERIFIED}" \
-F "scan_type=${DD_SCAN_TYPE}" \
-F "engagement=${DD_ENGAGEMENTID}" \
-F "file=@${REPORT};type=application/json" \
-F "close_old_findings=${DD_SCAN_CLOSE_OLD_FINDINGS}" \
-F "environment=${DD_SCAN_ENVIRONMENT}" \
-F "product_name=${DD_PRODUCT_NAME}" \
-F 'create_finding_groups_for_all_findings=true' \
-F 'group_by=component_name+component_version'

Dependency-track

Para integrar Dependency-track, el primer paso es crear un proyecto.

Para esta integración, se utiliza la API de Dependency-Track, que requiere autenticación. La información necesaria se encuentra en Administration > Access Management > Teams. Se puede utilizar el equipo Automation o crear uno propio. Al hacer clic en el equipo, se obtiene una API KEY y los permisos mínimos necesarios para la integración.

API KEY

También es necesario el ID del proyecto, que se obtiene de la URL al acceder al proyecto correspondiente.

Project ID

GitLab

Las variables necesarias en el CI son:

  • DT_SERVER: Dirección del servidor de Dependency-Track.
  • DT_API_KEY: Clave de la API para autenticarse en Dependency-Track. Se recomienda marcar el atributo 'mask' para que no se muestre en los registros.
  • DT_PROJECT_ID: ID del proyecto a integrar.

GitLab CI/CD Variables

Para enviar los resultados a Dependency-Track, se utiliza un archivo en la carpeta .gitlab-ci llamado dependency-track.sh, que envía los resultados a Dependency-Track y al proyecto correspondiente.

.gitlab-ci/dependency-track.sh
#!/bin/bash

curl --location --request "POST" "${DT_SERVER}/api/v1/bom" \
-H "X-Api-Key: ${DT_API_KEY}" \
-F "project=${DT_PROJECT_ID}" \
-F "projectVersion=${CI_COMMIT_BRANCH}" \
-F "bom=@${REPORT}" -f

GitHub

Las variables necesarias en el CI son:

  • DT_SERVER: Dirección del servidor de Dependency-Track.
  • DT_API_KEY: Clave de la API para autenticarse en Dependency-Track. Se almacena como secreto para no exponerla en el CI.
  • DT_PROJECT_ID: ID del proyecto a integrar.

GitHub Secrets GitHub Variables

Se crea un archivo llamado dependency-track.sh en la carpeta .github/scripts, que contiene la llamada curl para enviar los resultados a Dependency-Track y al proyecto correspondiente.

.github/scripts/dependency-track.sh
#!/bin/bash
set -e

curl -i --location --request POST "${DT_SERVER}/api/v1/bom" \
-H "X-Api-Key: ${DT_API_KEY}" \
-F "project=${DT_PROJECT_ID}" \
-F "bom=@${REPORT}" -f

Jenkins

Las variables necesarias en el CI son:

  • DT_API_KEY: Clave de la API para autenticarse en Dependency-Track.

Jenkins Credentials

Para enviar los resultados a Dependency-Track, se utiliza un archivo en la carpeta .jenkins-ci llamado dependency-track.sh, que envía los resultados a Dependency-Track y al proyecto correspondiente.

.jenkins-ci/dependency-track.sh
#!/bin/bash

curl --location --request "POST" "${DT_SERVER}/api/v1/bom" \
-H "X-Api-Key: ${DT_API_KEY}" \
-F "project=${DT_PROJECT_ID}" \
-F "projectVersion=${CI_COMMIT_BRANCH}" \
-F "bom=@${REPORT}" -f