diff --git a/scout/ci.md b/scout/ci.md index 76334da4c7..9856b3154d 100644 --- a/scout/ci.md +++ b/scout/ci.md @@ -6,21 +6,22 @@ title: Using Docker Scout in continuous integration {% include scout-early-access.md %} -Using the Docker Scout CLI plugin, you can analyze Docker images in -continuous integration pipelines as you build them. +You can analyze Docker images in continuous integration pipelines as you build +them using a GitHub action or the Docker Scout CLI plugin. ## GitHub Actions You can use [the Docker Scout GitHub action](https://github.com/docker/scout-action) to run Docker Scout CLI commands as part of a workflow. -The following example works in a repository containing a Docker image's definition and contents. Triggered by a pull request, the action builds the +The following example works in a repository containing a Docker image's +definition and contents. Triggered by a pull request, the action builds the image and uses Docker Scout to compare the new version to the current published version. -First, set up the rest of the workflow. There's a lot that's not specific to Docker -Scout but needed to create the images to compare. For more details on those actions and using GitHub Actions -with Docker in general, see [the GitHub Actions documentation](../build/ci/github-actions/index.md). +First, set up the rest of the workflow. There's a lot that's not specific to +Docker Scout but needed to create the images to compare. For more details on +those actions and using GitHub Actions with Docker in general, see [the GitHub Actions documentation](../build/ci/github-actions/index.md). Add the following to a GitHub action YAML file: @@ -60,37 +61,37 @@ Add the following to the YAML file: {% raw %} ```yaml - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - ref: ${{ env.SHA }} +steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ env.SHA }} - - name: Setup Docker buildx - uses: docker/setup-buildx-action@v2.5.0 + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2.5.0 - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - uses: docker/login-action@v2.1.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PAT }} + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + uses: docker/login-action@v2.1.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PAT }} - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v4.4.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - labels: | - org.opencontainers.image.revision=${{ env.SHA }} - tags: | - type=edge,branch=$repo.default_branch - type=semver,pattern=v{{version}} - type=sha,prefix=,suffix=,format=short + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4.4.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + labels: | + org.opencontainers.image.revision=${{ env.SHA }} + tags: | + type=edge,branch=$repo.default_branch + type=semver,pattern=v{{version}} + type=sha,prefix=,suffix=,format=short ``` {% endraw %} @@ -140,10 +141,259 @@ Add the following to the YAML file: {% endraw %} This final step uses the Docker Scout CLI to run [the `compare` command](../engine/reference/commandline/scout_compare.md), comparing the new -image to the published one. It only shows critical or high-severity vulnerabilities and -ignores vulnerabilities that haven't changed since the last analysis. +image to the published one. It only shows critical or high-severity +vulnerabilities and ignores vulnerabilities that haven't changed since the last +analysis. -The GitHub Action outputs the comparison results as a table and a summary -in the action output. +The GitHub Action outputs the comparison results as a table and a summary in the +action output.  + +## GitLab + +The following examples runs in GitLab CI in a repository containing a Docker +image's definition and contents. Triggered by a commit, the pipeline builds the +image. If the commit was to the default branch, it uses Docker Scout to get a +CVE report. If the commit was to a different branch, it uses Docker Scout to +compare the new version to the current published version. + +First, set up the rest of the workflow. There's a lot that's not specific to +Docker Scout but needed to create the images to compare. + +Add the following to a _.gitlab-ci.yml_ file at the root of your repository. + +```yaml +docker-build: + image: docker:latest + stage: build + services: + - docker:dind + before_script: + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + + # Install curl and the Docker Scout CLI + - | + apk add --update curl + curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- + apk del curl + rm -rf /var/cache/apk/* + # Login to Docker Hub required for Docker Scout CLI + - docker login -u "$DOCKER_HUB_USER" -p "$DOCKER_HUB_PAT" +``` + +This sets up the workflow to build Docker images with GitLabs's +"Docker-in-Docker" mode to run Docker inside a container. + +It then downloads curl and the Docker CLI and logs into the Gitlab CI registry +and the Docker registry using environment variables defined in your repository's +settings. + +Add the following to the YAML file: + +{% raw %} +```yaml +script: + - | + if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then + tag="" + echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'" + else + tag=":$CI_COMMIT_REF_SLUG" + echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag" + fi + - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" . + - | + if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then + # Get a CVE report for the built image and fail the pipeline when critical or high CVEs are detected + docker scout cves "$CI_REGISTRY_IMAGE${tag}" --exit-code --only-severity critical,high + else + # Compare image from branch with latest image from the default branch and fail if new critical or high CVEs are detected + docker scout compare "$CI_REGISTRY_IMAGE${tag}" --to "$CI_REGISTRY_IMAGE:latest" --exit-code --only-severity critical,high --ignore-unchanged + fi + + - docker push "$CI_REGISTRY_IMAGE${tag}" +``` +{% endraw %} + +This creates the flow mentioned previously. If the commit was to the default +branch, Docker Scout generates a CVE report. If the commit was to a different +branch, Docker Scout compares the new version to the current published version. +It only shows critical or high-severity vulnerabilities and ignores +vulnerabilities that haven't changed since the last analysis. + +Add the following to the YAML file: + +```yaml +rules: + - if: $CI_COMMIT_BRANCH + exists: + - Dockerfile +``` + +These final lines ensure that the pipeline only runs if the commit contains a +Dockerfile and if the commit was to the CI branch. + +_The following is a video walkthrough of the process of setting up the workflow with GitLab._ + +
+ +## Microsoft Azure DevOps Pipelines + +The following examples runs in an Azure DevOps-connected repository containing a +Docker image's definition and contents. Triggered by a commit to the main +branch, the pipeline builds the image and uses Docker Scout to create a CVE +report. + +First, set up the rest of the workflow and set up the variables available to all +pipeline steps. Add the following to an _azure-pipelines.yml_ file: + +```yaml +trigger: + - main + +resources: + - repo: self + +variables: + tag: "$(Build.BuildId)" + image: "vonwig/nodejs-service" +``` + +This sets up the workflow to use a particular container image for the +application and tag each new image build with the build ID. + +Add the following to the YAML file: + +```yaml +stages: + - stage: Build + displayName: Build image + jobs: + - job: Build + displayName: Build + pool: + vmImage: ubuntu-latest + steps: + - task: Docker@2 + displayName: Build an image + inputs: + command: build + dockerfile: "$(Build.SourcesDirectory)/Dockerfile" + repository: $(image) + tags: | + $(tag) + - task: CmdLine@2 + displayName: Find CVEs on image + inputs: + script: | + # Install the Docker Scout CLI + curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- + # Login to Docker Hub required for Docker Scout CLI + docker login -u $(DOCKER_HUB_USER) -p $(DOCKER_HUB_PAT) + # Get a CVE report for the built image and fail the pipeline when critical or high CVEs are detected + docker scout cves $(image):$(tag) --exit-code --only-severity critical,high +``` + +This creates the flow mentioned previously. It builds and tags the image using +the checked-out Dockerfile, downloads the Docker Scout CLI, and then runs the +`cves` command against the new tag to generate a CVE report. It only shows +critical or high-severity vulnerabilities. + +## CircleCI + +The following examples runs when triggered in CircleCI. When triggered, it +checks out the "docker/scout-demo-service:latest" image and tag and then uses +Docker Scout to create a CVE report. + +Add the following to a _.circleci/config.yml_ file. + +First, set up the rest of the workflow. Add the following to the YAML file: + +```yaml +version: 2.1 + +jobs: + build: + docker: + - image: cimg/base:stable + environment: + IMAGE_TAG: docker/scout-demo-service:latest +``` + +This defines the container image the workflow uses and an environment variable +for the image. + +Add the following to the YAML file to define the steps for the workflow: + +```yaml +steps: + # Checkout the repository files + - checkout + + # Set up a separate Docker environment to run `docker` commands in + - setup_remote_docker: + version: 20.10.24 + + # Install Docker Scout and login to Docker Hub + - run: + name: Install Docker Scout + command: | + env + curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /home/circleci/bin + echo $DOCKER_HUB_PAT | docker login -u $DOCKER_HUB_USER --password-stdin + + # Build the Docker image + - run: + name: Build Docker image + command: docker build -t $IMAGE_TAG . + + # Run Docker Scout + - run: + name: Scan image for CVEs + command: | + docker-scout cves $IMAGE_TAG --exit-code --only-severity critical,high +``` + +This checks out the repository files and then sets up a separate Docker +environment to run commands in. + +It installs Docker Scout, logs into Docker Hub, builds the Docker image, and +then runs Docker Scout to generate a CVE report. It only shows critical or +high-severity vulnerabilities. + +Finally, add a name for the workflow and the workflow's jobs: + +```yaml +workflows: + build-docker-image: + jobs: + - build +``` + +## Jenkins + +You can add the following stage and steps definition to a `Jenkinsfile` to run +Docker Scout as part of a Jenkins pipeline. The pipeline needs two secrets +defined to authenticate with Docker Hub: `DOCKER_HUB_USER` and `DOCKER_HUB_PAT` +It also needs an environment variable defined for the image and tag. + +```groovy +… +stage('Analyze image') { + steps { + // Install Docker Scout + sh 'curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /usr/local/bin' + + // Log into Docker Hub + sh 'echo $DOCKER_HUB_PAT | docker login -u $DOCKER_HUB_USER --password-stdin' + + // Analyze and fail on critical or high vulnerabilities + sh 'docker-scout cves $IMAGE_TAG --exit-code --only-serverity critical,high' + } +} +``` + +This installs Docker Scout, logs into Docker Hub, and then runs Docker Scout to +generate a CVE report for an image and tag. It only shows critical or +high-severity vulnerabilities. \ No newline at end of file diff --git a/scout/images/gha-output.png b/scout/images/gha-output.png index 90b2c526fc..614c5de597 100644 Binary files a/scout/images/gha-output.png and b/scout/images/gha-output.png differ