Сканирование изображений на наличие CVE перед отправкой в ​​репозиторий изображений в рамках CI/CD с использованием Tekton и Buildah

Билдах | Инициатива открытых контейнеров (OCI)| Триви | Драйверы хранилища | КИ/CD | Тектон | Конвейеры OpenShift | Кубернетес | Уязвимости

В Инициативе открытого контейнера ОЧЕНЬ много силы. OCI управляет спецификацией среды выполнения и спецификацией образа. Эта статья будет ссылаться на спецификацию изображения на примере. Вывод спецификации изображения состоит из трех основных разделов. 1. Манифест образа, 2. Файловая система (слои в формате сериализации) и 3. Конфигурация образа. Вам не нужно знать все об этом формате, но это хороший справочник, чтобы понять, как работает сканер Trivy. Итак, начнем.

В этой статье будет использоваться Tekton Task для создания части CI/CD. Buildah, продукт Redhat/IBM, будет использоваться для создания нашего Dockerfile. Перед тем, как начать читать эту статью, рекомендуется изучить и изучить Tekton. Tekton — это облачный инструмент непрерывной интеграции/непрерывного развертывания от Google. Чтобы узнать больше об этом, вы можете посмотреть документацию. Хорошо, давайте создадим нашу задачу.

Шаг 1. Создайте задачу для сборки, сканирования и выталкивания

Создайте файл с именем buildah-task.yml и добавьте следующее:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  namespace: <your-namespace>
spec:
  params:
    - default: 'false'
      description: Identifies weather or not to use TLS for the VAPO Quay
      name: VAPO_QUAY_TLSVERIFY
      type: string
    - default: '<your-image-location>'
      description: Identifies the destination image location and tag
      name: TAG_IMAGE_NAME
      type: string
    - default: Add Image Repository
      description: Identifies the Base Images
      name: IMAGE_BASE
      type: string
    - default: Add Image Name
      description: Identifies the Image Name
      name: IMAGE_NAME
      type: string
    - default: 1.0.0
      description: The tag for the image
      name: IMAGE_TAG
      type: string
    - default: >-   registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467
      description: Identifies the Buildah Image
      name: BUILDAH_IMAGE
      type: string
    - default: vfs
      description: Buildah Storage Driver
      name: BUILDAH_STORAGE_DRIVER
      type: string
    - default: /build/<docker-filename>
      description: Identifies the location and name of the dockerfile
      name: DOCKERFILE_NAME
      type: string
    - default: .
      description: Identifies the Docker context root location
      name: DOCKER_CONTEXT_ROOT
      type: string
    - default: oci
      name: STANDARD_IMAGE_FORMAT
      type: string
    - default: /workspace/<repository git pipeline resource name>
      description: Identifies the location of the source code within the workspace
      name: WORKING_DIRECTORY
      type: string
    - default: 'quay.io/ksummersill2/trivy:0.17.2'
      description: Identifies the Trivy Image to use for scanning the OCI spec of the image
      name: TRIVY_IMAGE
      type: string
    - default: '0'
      description: Identifies if Trivy should stop the pipeline
      name: EXIT_CODE
      type: string
    - default: 'os,library'
      description: Identifies the types of vulnerabilities
      name: VUL_TYPE
      type: string
    - default: 'HIGH,CRITICAL'
      description: Identifies the severity level for the Trivy scan
      name: SEVERITY_LVL
      type: string
  resources:
    inputs:
      - description: Identifies the Pipeline Resource to Clone the Source Code
        name: source
        type: git
  steps:
    - image: $(params.BUILDAH_IMAGE)
      name: build-image
      resources: {}
      script: >
        #!/usr/bin/env bash
buildah bud --format=$(params.STANDARD_IMAGE_FORMAT)
        --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) -f
        $(params.DOCKERFILE_NAME) -t app:1.0.0 .
buildah push --format=$(params.STANDARD_IMAGE_FORMAT)
        --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) app:1.0.0
        oci:/workspace/source/image
buildah tag --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) app:1.0.0
        $(params.TAG_IMAGE_NAME)
      volumeMounts:
        - mountPath: /var/lib/containers
          name: varlibcontainers
      workingDir: $(params.WORKING_DIRECTORY)
    - image: 'quay.io/ksummersill2/ubuntu-wget:1.0.0'
      name: get-latest-cve-findings
      resources: {}
      script: >
        mkdir -p /tekton/home/.cache/trivy/db
wget -O /tekton/home/.cache/trivy/db/trivy-offline.db.tgz
        https://github.com/aquasecurity/trivy-db/releases/latest/download/trivy-offline.db.tgz
        --no-check-certificate
cd /tekton/home/.cache/trivy/db
tar xvf trivy-offline.db.tgz
    - image: $(params.TRIVY_IMAGE)
      name: initial-oci-scan
      resources: {}
      script: >
        trivy image --skip-update --input /workspace/source/image
        --exit-code=$(params.EXIT_CODE) --severity=$(params.SEVERITY_LVL)
        --vuln-type=$(params.VUL_TYPE) --format=table >
        /workspace/source/cve-report.txt
      volumeMounts:
        - mountPath: /var/lib/containers
          name: varlibcontainers
      workingDir: $(params.WORKING_DIRECTORY)
    - image: 'quay.io/ksummersill2/ubuntu-wget:1.0.0'
      name: send-cve-report-to-nexus3
      resources: {}
      script: >
        curl -v -u <nexus-username>:<nexus-password> --upload-file
        /workspace/source/cve-report.txt <nexus-repo-location>
    - image: $(params.BUILDAH_IMAGE)
      name: push-image-to-vapo-quay-dev
      resources: {}
      script: >
        buildah push --storage-driver=$(params.BUILDAH_STORAGE_DRIVER)
        --tls-verify=$(params.VAPO_QUAY_TLSVERIFY) $(params.TAG_IMAGE_NAME)
      volumeMounts:
        - mountPath: /var/lib/containers
          name: varlibcontainers
      workingDir: $(params.WORKING_DIRECTORY)
  volumes:
    - emptyDir: {}
      name: varlibcontainers

Здесь МНОГО всего происходит, так что давайте разберемся.

На самом деле эта задача состоит из 5 шагов. Это 1. Создание образа, 2. Получение последних результатов CVE, 3. Начальное сканирование OCI, 4. Отправка отчета CVE в Nexus, 5. Отправка образа в Quay. Итак, давайте разберем каждый.

1. Создайте образ

Так что этот конкретный шаг, конечно, создает образ, но если вы присмотритесь, он на самом деле делает больше.

buildah bud --format=$(params.STANDARD_IMAGE_FORMAT)
        --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) -f
        $(params.DOCKERFILE_NAME) -t app:1.0.0 .

В этой части шагов используется драйвер VFS с форматом OCI для создания образа с помощью команды «bud». Bud — это команда в Buildah, которая позволяет создавать образ из «Dockerfile». Затем изображение помечается как «приложение: 1.0.0».

Хорошо, создайте, у нас есть изображение, но теперь его нужно преобразовать в определенный формат.

buildah push --format=$(params.STANDARD_IMAGE_FORMAT)
        --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) app:1.0.0
        oci:/workspace/source/image

Следующий шаг делает именно это. В следующей части используется Buildah push для передачи изображения в формате спецификации изображения OCI в конкретный каталог с именем /workspace/source/image. Да! это правильно, это помещает весь образ приложения: 1.0.0 в каталог в рабочей области Tekton. Просто подожди, станет лучше.

Таким образом, чтобы подготовить изображение к последующей отправке, оно помечено.

buildah tag --storage-driver=$(params.BUILDAH_STORAGE_DRIVER) app:1.0.0 $(params.TAG_IMAGE_NAME)

Таким образом, этот шаг просто помечает изображение. Ничего особенного. Обратите внимание: вы должны указать драйвер хранилища, иначе образ НЕ будет найден. Давайте двигаться дальше.

2. Получите последние результаты CVE

В следующей части используется подход AirGap с Trivy. Если вы хотите узнать больше о подходе AirGap, прочитайте мою статью здесь. https://ksummersill.medium.com/setting-up-trivy-for-airgap-approach-within-ci-cd-3d429da21de4

mkdir -p /tekton/home/.cache/trivy/db
wget -O /tekton/home/.cache/trivy/db/trivy-offline.db.tgz
        https://github.com/aquasecurity/trivy-db/releases/latest/download/trivy-offline.db.tgz
        --no-check-certificate
cd /tekton/home/.cache/trivy/db
tar xvf trivy-offline.db.tgz

Этот шаг в основном создает каталог с именем /tekton/home/.cache/trivy/db. Сюда будет помещена автономная база данных. Затем автономная база данных извлекается из официального репозитория Trivy Github, а затем помещается в созданный каталог. Затем файл Tar извлекается из этого каталога для использования на следующем шаге.

3. Начальное сканирование OCI

Так вот где происходит вся магия. Большинство сканирований CVE выполняются после того, как образ находится в репозитории. Но подождите, что, если вы можете сканировать образ на наличие уязвимостей перед отправкой. Я имею в виду, что мы можем сделать это с исходным кодом, почему бы и нет с изображениями?

trivy image --skip-update --input /workspace/source/image
        --exit-code=$(params.EXIT_CODE) --severity=$(params.SEVERITY_LVL)
        --vuln-type=$(params.VUL_TYPE) --format=table >
        /workspace/source/cve-report.txt

Что ж, приведенный выше код делает именно это. Помните, что мы используем команду buildah push для отправки изображения в формате OCI с использованием спецификации изображения OCI в /workspace/source/image. Ну, угадайте что! На самом деле вы можете отсканировать это с помощью Trivy, используя:

trivy image --skip-update --input <location of image>

Обратите внимание, что вы должны использовать skip-update, иначе trivy попытается использовать обычный подход для извлечения базы данных. Единственная причина, по которой использовался подход AirGap, заключалась в ограничениях среды, в которой я работал. Итак, теперь поле ввода является ключом для определения папки, в которой находится изображение.

Теперь «код выхода» позволяет определить, обнаружены ли «результаты» для отказа конвейера CI/CD или для продвижения вперед. Это делается с помощью 0 для продвижения вперед или 1 для продолжения. Конечно, у вас также есть уровни серьезности и типы уязвимостей, из которых можно выбирать, как проводится эта «проверка ворот». Уровни серьезности: критический, высокий, средний и низкий. Принимая во внимание, что типы уязвимостей — это операционные системы (ОС) или библиотеки. Обычно это происходит, если у вас есть приложение, загруженное в образ, или вы хотите проверить наличие зависимостей, отличных от операционной системы. Триви отлично справляется с этой задачей.

4. Отправка результатов сканирования в Nexus

Теперь в этом следующем шаге нет ничего особенного, за исключением того, что вы можете отправить результаты своей команде безопасности в централизованную область.

curl -v -u <nexus-username>:<nexus-password> --upload-file
        /workspace/source/cve-report.txt <nexus-repo-location>

5. Наконец, нажмите на изображение

После того, как вы проверили все необходимые проверки ворот, теперь вы можете отправить образ в репозиторий образов.

buildah push --storage-driver=$(params.BUILDAH_STORAGE_DRIVER)
--tls-verify=$(params.VAPO_QUAY_TLSVERIFY) $(params.TAG_IMAGE_NAME)

Ну, это почти все. Конечно, если вы хотите запустить эту задачу, это будет сделано с помощью запуска задачи или запуска конвейера. Если вы хотите, чтобы я продолжил эту статью о том, как реализовать, то, пожалуйста, напишите мне, и я посмотрю, как продолжить реализацию этого. Здорово! Надеюсь, это помогло любому, кто пытается понять, как сканировать изображение перед отправкой с использованием спецификации изображения, совместимой с OCI.