Jenkins

Introducción

Un test puede ser realizado de manera externa autenticando una cuenta de StrikeOne Admin desde su herramienta de CI/CD preferida.

Ejecución Remota de un Test

Introducción

Para ejecutar un test, usted requiere de un token de autorización. Usted puede generar un API Token desde el apartado de Integraciones de su perfil de StrikeOne Admin. El token de autorización permitirá realizar llamadas subsecuentes a otros endpoints.

Después, se debe llamar al orquestrador de tests. Esta request POST requiere un body que incluya el campo externalData que contenga los campos testName, parsedDomainId y tool. La ID parseadas del dominio se puede obtener directamente yendo a la pestaña Dominios de un activo.

Los siguientes valores son válidos para el campo tool:

  • openvas
  • owasp_zap
  • sonarqube
  • dep_check
  • nuclei
  • gitleaks
  • horusec

IMPORTANTE

Algunas herramientas requieren, o aceptan, más argumentos para su ejecución. La lista es la siguiente:

  • SonarQube (sonarqube), OWASP Dependency Check (dep_check), GitLeaks (gitleaks) y Horusec (horusec) requieren un objeto toolData adicional que sea includo además de externalData. Este objeto contendrá el campo projectUrl (la URL del repositorio, incluyendo el usuario y el token), projectName (el nombre del repositorio) y projectRepo (la rama a clonar, si se está usando curl el campo es opcional).

  • Nuclei (nuclei) acepta un objeto toolData adicional que sea incluido además de externalData. Este objeto puede contener el campo templates que corresponde a un string con la lista de templates a utilizar por Nuclei. Este campo es concatenado al argumento -nts para ser utilizado por Nuclei al ejecutarse.

Si el test fue creado con éxito, /api/vm/tests/external/execute retornará un código 200. Si desea asegurarse de que el stage de Jenkins solo se complete (o falle) dependiendo del estado final del test, puede realizar una llamada adicional a /api/vm/tests/external/status/:testId usando el Test ID retornado por el endpoint de ejecución para revisar si el test está completo, o ha fallado.

Jenkins

Requisitos

El stage de ejemplo requiere el plugin de httpRequest instalado en Jenkins. Adicionalmente, jsonSlurperClassic necesitará ser autorizado para correr el script de manera correcta. Puede ejecutar el script una vez para que la autorización aparezca en la lista correspondiente.

Ejemplo de Stage con Scripted Pipeline

import groovy.json.JsonSlurperClassic

node {

    env.NODEJS_HOME = "${tool 'nodejs_14.18.0'}"
    env.PATH = "${env.NODEJS_HOME}/bin:${env.PATH}"

    environment {
        SO_CREDENTIALS = credentials('so_api_token')
    }

    stage('Clean Workspace') {
        cleanWs()
    }

    stage('SCM') {
        checkout scm
    }

    stage('StrikeOne Admin Analysis') {
            withCredentials([string(credentialsId: 'so_api_token', variable: 'SO_API_TOKEN')]) {

                def toJson = {
                    input ->
                    groovy.json.JsonOutput.toJson(input)
                }

                def testBody = [
                    externalData: [
                        testName: 'Test iniciado desde Jenkins',
                        parsedDomainId: '192079240',
                        tool: 'owasp_zap'
                    ]
                ]

                // EXECUTE VM TEST
                def testRes = httpRequest contentType: 'APPLICATION_JSON', httpMode: 'POST', requestBody: toJson(testBody), customHeaders: [[name:'Authorization', value: "Bearer $SO_API_TOKEN"]], url: 'https://assessment.strikeone.io/api/vm/tests/external/execute'
                def testJson = new JsonSlurperClassic().parseText(testRes.content)
                def testId = testJson.payload.testId

                def maximumChecks = 30

                def checkTestStatus = {
                    String test ->

                    if (maximumChecks > 30) {
                        echo "StrikeOne Vulnerability Management test took too long to complete."
                        return true
                    }

                    sleep 60

                    def statusRes = httpRequest httpMode: 'GET', customHeaders: [[name:'Authorization', value: "Bearer ${SO_API_TOKEN}"]], url: "https://assessment.strikeone.io/api/vm/tests/external/status/${test}"
                    def statusJson = new JsonSlurperClassic().parseText(statusRes.content)
                    if (statusJson.payload.status == 'done') {
                        echo "StrikeOne Vulnerability Management test completed."
                        return true
                    }

                    if (statusJson.payload.status == 'failed') {
                        error "StrikeOne Vulnerability Management test failed."
                    }

                    maximumChecks++

                    checkTestStatus(test)
                }

                checkTestStatus(testId)

            }

        }
}

GitHub Actions

Requisitos

El workflow de ejemplo hace uso de HTTP Request Action.

Ejemplo de Job de GitHub Actions

  execute_so_test:
    name: Execute StrikeOne Test
    runs-on: self-hosted

    steps:
      - name: StrikeOne Test Execution
        id: strikeone_test_execution
        uses: fjogeleit/http-request-action@v1
        with:
          url: "https://assessment.strikeone.io/api/vm/tests/external/execute"
          method: "POST"
          customHeaders: '{"Content-Type": "application/json"}'
          bearerToken: ${{ secrets.SO_API_TOKEN }}
          data: '{"externalData": { "parsedDomainId": "192079240", "tool": "owasp_zap", "testName": "Test iniciado desde GitHub Actions" } }'
      - name: Show Response
        run: |
          echo ${{ steps.strikeone_test_execution.outputs.response }}

GitLab CI/CD

Requisitos

Ninguno.

Ejemplo de Job de GitLab CI/CD

strikeone-test:
  stage: test
  script:
    - echo "Ejecutar Test de StrikeOne"
    - RES=$(curl --request POST https://assessment.strikeone.io/api/vm/tests/external/execute --header "Content-Type:application/json" --header "Authorization:Bearer ${SO_API_TOKEN}" --data-raw '{"externalData":{"testName":"Test iniciado desde GitLab","parsedDomainId":"192079240","tool":"owasp_zap"}}')
    - echo RES is $RES
Last Updated: