[Yandex Cloud documentation](../../../index.md) > [Yandex Container Registry](../../index.md) > [Tutorials](../index.md) > [Automatic Docker image scan on push](index.md) > Terraform

# Automatic Docker image scan on push using Terraform


{% note info %}

You can enable auto [scans](../../concepts/vulnerability-scanner.md) of [Docker images](../../concepts/docker-image.md) for vulnerabilities on push to [Yandex Container Registry](../../index.md) in the [vulnerability scanner settings](../../operations/scanning-docker-image.md#automatically) without creating any [Yandex Cloud Functions](../../../functions/index.md) [functions](../../../functions/concepts/function.md) and [triggers](../../../functions/concepts/trigger/index.md).

{% endnote %}

To configure automatic vulnerability [scans](../../concepts/vulnerability-scanner.md) of [Docker images](index.md) on push to [Yandex Container Registry](../../index.md) using Terraform:

1. [Get your cloud ready](#before-you-begin).
1. [Set up your environment](#prepare).
1. [Create the infrastructure](#deploy).
1. [Push the Docker image](#download-image).
1. [Check the result](#check-result).

If you no longer need the resources you created, [delete them](#clear-out).

## Get your cloud ready {#before-begin}

Sign up for Yandex Cloud and create a [billing account](../../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../../billing/quickstart/index.md) and [link](../../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../../resource-manager/concepts/resources-hierarchy.md).

### Required paid resources {#paid-resources}

The infrastructure support cost includes:
* Fee for storing a Docker image in the [registry](../../concepts/registry.md), a vulnerability scanner, and outgoing traffic (see [Yandex Container Registry pricing](../../pricing.md)).
* Fee for [function](../../../functions/concepts/function.md) calls (see [Yandex Cloud Functions pricing](../../../functions/pricing.md)).

## Set up your environment {#prepare}

1. [Install and configure](../../operations/configure-docker.md) Docker.

## Create the infrastructure {#deploy}

With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.

Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.

For more information about the provider resources, see the guides on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

To create an infrastructure to automatically scan a Docker image on push using Terraform:
1. [Install Terraform](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform) and [get the authentication data](../../../tutorials/infrastructure-management/terraform-quickstart.md#get-credentials).
1. Specify the source for installing the Yandex Cloud provider (see [Configure your provider](../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider), step 1).
1. Prepare your infrastructure description files:

   {% list tabs group=infrastructure_description %}

   - Ready-made configuration {#ready}

     1. Clone the repository containing the configuration files.

        ```bash
        git clone https://github.com/yandex-cloud-examples/yc-cr-image-scanning
        ```

     1. Navigate to the repository directory. It should now contain the following files:
        * `image-auto-scan.tf`: New infrastructure configuration.
        * `image-auto-scan.auto.tfvars`: User data file.
        * `function.zip`: ZIP archive with the function code.

   - Manually {#manual}

     1. Create a folder for configuration files.
     1. Create a configuration file named `image-auto-scan.tf` in the folder:

        {% cut "image-auto-scan.tf" %}

        ```hcl
        # Declaring variables for custom parameters
        
        variable "zone" {
          type = string
        }
        
        variable "folder_id" {
          type = string
        }
        
        # Adding other variables
        
        locals {
          sa_scanner_name    = "scanner"
          sa_invoker_name    = "invoker"
          registry_name      = "my-registry"
          function_name      = "scan-on-push"
          trigger_name       = "trigger-for-reg"
        }
        
        # Configuring a provider 
        
        terraform {
          required_providers {
            yandex    = {
              source  = "yandex-cloud/yandex"
              version = ">= 0.47.0"
            }
          }
        }
        
        provider "yandex" {
          folder_id = var.folder_id
        }
        
        # Creating service accounts
        
        resource "yandex_iam_service_account" "scanner" {
          name        = local.sa_scanner_name
          description = "SA for Container Registry"
          folder_id   = var.folder_id
        }
        
        resource "yandex_iam_service_account" "invoker" {
          name        = local.sa_invoker_name
          description = "SA for Cloud Functions"
          folder_id   = var.folder_id
        }
        
        # Assigning roles to service accounts
        
        resource "yandex_resourcemanager_folder_iam_member" "sa-role-scanner" {
          folder_id   = var.folder_id
          role        = "container-registry.images.scanner"
          member      = "serviceAccount:${yandex_iam_service_account.scanner.id}"
        }
        
        resource "yandex_resourcemanager_folder_iam_member" "sa-role-invoker" {
          folder_id   = var.folder_id
          role        = "functions.functionInvoker"
          member      = "serviceAccount:${yandex_iam_service_account.invoker.id}"
        }
        
        # Creating a registry in Container Registry
        
        resource "yandex_container_registry" "my-reg" {
          name      = local.registry_name
          folder_id = var.folder_id
        }
        
        # Creating a function
        
        resource "yandex_function" "test-function" {
          name               = local.function_name
          user_hash          = "my-first-function"
          runtime            = "bash"
          entrypoint         = "handler.sh"
          memory             = "128"
          execution_timeout  = "60"
          service_account_id = yandex_iam_service_account.scanner.id
          content {
            zip_filename   = "function.zip"
          }
        }
        
        # Creating a trigger
        
        resource "yandex_function_trigger" "my-trigger" {
        
          name = local.trigger_name
          function {
            id                 = yandex_function.test-function.id
            service_account_id = yandex_iam_service_account.invoker.id
          }
          container_registry {
            registry_id      = yandex_container_registry.my-reg.id
            create_image_tag = true
            batch_cutoff     = "10"
            batch_size       = "1"
          }
        }
        ```

        {% endcut %}

     1. Create a file with user data named `image-auto-scan.auto.tfvars`:

        {% cut "image-auto-scan.auto.tfvars" %}

        ```hcl
        zone      = "<availability_zone>"
        folder_id = "<folder_ID>"
        ```

        {% endcut %}

     1. Prepare a ZIP archive with the function code.
        1. Create the `handler.sh` file and paste the following code to it:

           {% cut "handler.sh" %}

           {% note warning %}
           
           If you are creating a file in Windows, make sure that newline characters are in `\n` Unix format rather than `\r\n`. You can replace line breaks in a text editor, such as [Notepad++](https://notepad-plus-plus.org/), or with such tools as [dos2unix](https://waterlan.home.xs4all.nl/dos2unix.html) or [Tofrodos](https://www.thefreecountry.com/tofrodos/).
           
           {% endnote %}

           ```bash
           DATA=$(cat | jq -sr '.[0].messages[0].details')
           ID=$(echo $DATA | jq -r '.image_id')
           NAME=$(echo $DATA | jq -r '.repository_name')
           TAG=$(echo $DATA | jq -r '.tag')
           yc container image scan --id ${ID} --async 1>&2
           ```

           {% endcut %}

        1. Create a ZIP archive named `function.zip` with the `handler.sh` file.

   {% endlist %}

   Learn more about the properties of resources in these Terraform provider guides:
   * [Service account](../../../iam/concepts/users/service-accounts.md): [yandex_iam_service_account](../../../terraform/resources/iam_service_account.md).
   * [Assigning access permissions for a folder](../../../iam/concepts/access-control/index.md#access-bindings): [yandex_resourcemanager_folder_iam_member](../../../terraform/resources/resourcemanager_folder_iam_member.md).
   * [Registry](../../concepts/registry.md): [yandex_container_registry](../../../terraform/resources/container_registry.md).
   * [Function](../../../functions/concepts/function.md): [yandex_function](../../../terraform/resources/function.md).
   * [Trigger](../../../functions/concepts/trigger/index.md): [yandex_function_trigger](../../../terraform/resources/function_trigger.md).

1. In the `image-auto-scan.auto.tfvars` file, set the following user-defined properties:
   * `zone`: [Availability zone](../../../overview/concepts/geo-scope.md) to create the infrastructure in.
   * `folder_id`: [ID of the folder](../../../resource-manager/operations/folder/get-id.md) to create the infrastructure in.

1. Create the resources:

   1. In the terminal, navigate to the configuration file directory.
   1. Make sure the configuration is correct using this command:
   
      ```bash
      terraform validate
      ```
   
      If the configuration is valid, you will get this message:
   
      ```bash
      Success! The configuration is valid.
      ```
   
   1. Run this command:
   
      ```bash
      terraform plan
      ```
   
      You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
   1. Apply the configuration changes:
   
      ```bash
      terraform apply
      ```
   
   1. Type `yes` and press **Enter** to confirm the changes.

## Push the Docker image {#download-image}

1. Run Docker Desktop.
1. Log in to the registry under your username with:

   {% list tabs group=registry_auth %}

   - Docker credential helper {#docker}

     1. Configure Docker to use `docker-credential-yc`:

        ```bash
        yc container registry configure-docker
        ```

        Result:

        ```text
        Credential helper is configured in '/home/<user>/.docker/config.json'
        ```

        The current user’s profile stores the settings.

        {% note warning %}
        
        The credential helper only works if you use Docker without `sudo`. To learn how to configure Docker to run on behalf of the current user without `sudo`, see [this Docker guide](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
        
        {% endnote %}

     1. Make sure Docker is configured.

        The `/home/<user>/.docker/config.json` configuration file should now contain this line:

        ```json
        "cr.yandex": "yc"
        ```

     1. You can now use Docker, e.g., to [push Docker images](../../operations/docker-image/docker-image-push.md). You do not need to run the `docker login` command for that.

   - OAuth token {#oauth-token}

     {% note info "OAuth token authentication is deprecated" %}
     
     This authentication method will no longer be supported. Consider using [IAM tokens](../../../iam/concepts/authorization/iam-token.md) or [API keys](../../../iam/concepts/authorization/api-key.md).
     
     {% endnote %}

     1. If you do not have an [OAuth token](../../../iam/concepts/authorization/oauth-token.md) yet, get one at [this link](https://oauth.yandex.com/authorize?response_type=token&client_id=1a6990aa636648e9b2ef855fa7bec2fb).
     1. Run this command:

        ```bash
        echo <OAuth_token> | docker login --username oauth --password-stdin cr.yandex
        ```
 
        Result:

        ```text
        Login Succeeded
        ```

   - IAM token {#iam-token}

     {% note info %}

     The IAM token has a short [lifetime](../../../iam/concepts/authorization/iam-token.md#lifetime) of up to 12 hours. This makes it a good method for applications that automatically request an IAM token.

     {% endnote %}

     1. [Get](../../../iam/operations/iam-token/create.md) an [IAM token](../../../iam/concepts/authorization/iam-token.md).
     1. Run this command:

        ```bash
        yc iam create-token | docker login --username iam --password-stdin cr.yandex
        ```

        Result:

        ```text
        Login Succeeded
        ```

   {% endlist %}

1. Pull a Docker image from [Docker Hub](https://hub.docker.com/):

   ```bash
   docker pull ubuntu:20.04
   ```

   Result:

   ```text
   20.04: Pulling from library/ubuntu
   Digest: sha256:cf31af331f38d1d7158470e095b132acd126a7180a54f263d386da88********
   Status: Image is up to date for ubuntu:20.04
   docker.io/library/ubuntu:20.04
   ```

1. Assign a tag to the Docker image:

   ```bash
   docker tag ubuntu:20.04 cr.yandex/<registry_ID>/ubuntu:20.04
   ```

1. Push the Docker image to Container Registry:

   ```bash
   docker push cr.yandex/<registry_ID>/ubuntu:20.04
   ```

   Result:

   ```text
   The push refers to repository [cr.yandex/crpu20rpdc2f********/ubuntu]
   2f140462f3bc: Layer already exists
   63c99163f472: Layer already exists
   ccdbb80308cc: Layer already exists
   20.04: digest: sha256:86ac87f73641c920fb42cc9612d4fb57b5626b56ea2a19b894d0673f******** size: 943
   ```

## Check the result {#check-result}

1. View the logs of the `scan-on-push` function and make sure it has executed.

   {% list tabs group=instructions %}

   - Management console {#console}

     1. In the [management console](https://console.yandex.cloud), select **Cloud Functions**.
     1. Go to the **Functions** section and select the `scan-on-push` function.
     1. In the window that opens, go to **Logs** and specify the time period. The default time period is one hour.

   - CLI {#cli}

     To find out the name or ID of a function, [get](../../../functions/operations/function/function-list.md) the list of functions in the folder.

     View the function execution log:

     ```bash
     yc serverless function logs scan-on-push
     ```

     Result:

     ```text
     2021-05-18 09:27:43  START RequestID: 34dc9533-ed6e-4468-b9f2-2aa0******** Version: b09i2s85a0c1********
     2021-05-18 09:27:43  END RequestID: 34dc9533-ed6e-4468-b9f2-2aa0********
     2021-05-18 09:27:43  REPORT RequestID: 34dc9533-ed6e-4468-b9f2-2aa0******** Duration: 538.610 ms Billed Duration: 538.700 ms Memory Size: 128 MB Max Memory Used: 13 MB
     2021-05-18 09:29:25  START RequestID: 5b6a3779-dcc8-44ec-8ee2-2e7f******** Version: b09i2s85a0c1********
     2021-05-18 09:29:26  END RequestID: 5b6a3779-dcc8-44ec-8ee2-2e7f********
     2021-05-18 09:29:26  REPORT RequestID: 5b6a3779-dcc8-44ec-8ee2-2e7f******** Duration: 554.904 ms Billed Duration: 555.000 ms Memory Size: 128 MB Max Memory Used: 13 MB
     ...
     ```

   {% endlist %}

1. Make sure that a new scan started when you pushed the Docker image.

   {% list tabs group=instructions %}

   - Management console {#console}

     1. In the [management console](https://console.yandex.cloud), select the parent folder of the registry containing the Docker image.
     1. Select **Container Registry**.
     1. Select the registry where you pushed your Docker image.
     1. Open the repository with the Docker image.
     1. Select the relevant Docker image and check the **Date of last scan** parameter value.

   - CLI {#cli}

     To view scans by Docker image, run the command:

     ```bash
     yc container image list-scan-results --repository-name=<registry_ID>/<Docker_image_name>
     ```

     Result:

     ```text
     +----------------------+----------------------+---------------------+--------+--------------------------------+
     |          ID          |        IMAGE         |     SCANNED AT      | STATUS |        VULNERABILITIES         |
     +----------------------+----------------------+---------------------+--------+--------------------------------+
     | crpu20rpdc2f******** | crpqmsqp5mtb******** | 2021-05-18 14:34:02 | READY  | medium:6, low:13, negligible:3 |
     +----------------------+----------------------+---------------------+--------+--------------------------------+
     ```

   {% endlist %}

## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:

1. Open the `image-auto-scan.tf` file and delete your infrastructure description from it.
1. Apply the changes:

    1. In the terminal, navigate to the configuration file directory.
    1. Make sure the configuration is correct using this command:
    
       ```bash
       terraform validate
       ```
    
       If the configuration is valid, you will get this message:
    
       ```bash
       Success! The configuration is valid.
       ```
    
    1. Run this command:
    
       ```bash
       terraform plan
       ```
    
       You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
    1. Apply the configuration changes:
    
       ```bash
       terraform apply
       ```
    
    1. Type `yes` and press **Enter** to confirm the changes.

#### Useful links {#see-also}

* [Automatic Docker image scans on push using the management console, CLI, and API](console.md)