[Yandex Cloud documentation](../../index.md) > [Security in Yandex Cloud](../index.md) > [Cloud infrastructure security standard, version 1.4.2](index.md) > All sections on one page

# Yandex Cloud infrastructure security standard, version 1.4.2

## Introduction {#intro}

This document offers recommendations for means of technical protection and helps you choose adequate information security measures when deploying information systems in Yandex Cloud.

Yandex Cloud ensures the physical security of data centers. See a [detailed description of its physical security measures](../standarts.md). If critical data is transmitted outside Yandex Cloud, the customer is responsible for managing physical access at all data processing locations.

The recommendations and security measures mentioned in the standard come with links to the **Guides and solutions for setting up** secure resource configurations using standard and additional information security tools available to Yandex Cloud users.

The standard also describes the methods and means of verifying compliance with the recommendations, including:

* Management console UI
* Yandex Cloud CLI
* Manually

### Scope {#application}


These recommendations are addressed to architects, technical specialists, and information security experts who employ the following services to develop protected cloud systems and security policies for the cloud platform:

* [Yandex Application Load Balancer](../../application-load-balancer/index.md)
* [Yandex Audit Trails](../../audit-trails/index.md)
* [Yandex Certificate Manager](../../certificate-manager/index.md)
* [Yandex Cloud DNS](../../dns/index.md)
* [Yandex Cloud Logging](../../logging/index.md)
* [Yandex Identity Hub](../../organization/index.md)
* [Yandex Compute Cloud](../../compute/index.md)
* [Yandex Container Registry](../../container-registry/index.md)
* [Yandex Identity and Access Management (IAM)](../../iam/index.md)
* [Yandex Key Management Service](../../kms/index.md)
* [Yandex Lockbox](../../lockbox/index.md)
* [Yandex Managed Service for ClickHouse®](../../managed-clickhouse/index.md)
* [Yandex Managed Service for GitLab](../../managed-gitlab/index.md)
* [Yandex Managed Service for Kubernetes](../../managed-kubernetes/index.md)
* [Yandex StoreDoc](../../storedoc/index.md)
* [Yandex Managed Service for MySQL®](../../managed-mysql/index.md)
* [Yandex Managed Service for PostgreSQL](../../managed-postgresql/index.md)
* [Yandex Managed Service for Valkey™](../../managed-valkey/index.md)
* [Yandex Managed Service for YDB](../../ydb/index.md)
* [Yandex Network Load Balancer](../../network-load-balancer/index.md)
* [Yandex Object Storage](../../storage/index.md)
* [Yandex Resource Manager](../../resource-manager/index.md)
* [Yandex Smart Web Security](../../smartwebsecurity/index.md)
* [Yandex SmartCaptcha](../../smartcaptcha/index.md)
* [Yandex Virtual Private Cloud](../../vpc/index.md)

The standard can be used as the basis for developing company-specific recommendations. Not all of the information security measures and recommendations from this document are applicable. Moreover, additional measures and recommendations that are not included in the current standard may be required.

### Standard structure {#structure}

The standard describes recommendations for the following security objectives:
* Authentication and access management
* Network security
* Secure virtual environment configuration.
* Data encryption and key management
* Collecting, monitoring, and analyzing audit logs
* Backup
* Physical security
* Application security
* Kubernetes security

### Requirements and preparation {#requirements-and-preparation}

Prior to the checks, make sure that:
* You have the CLI is installed and configured according to [this guide](../../cli/quickstart.md).
* You have logged in to the [management console](https://console.yandex.cloud).
* The jq utility is installed.

You can automate the audit of compliance with all recommendations using [Yandex Security Deck](../../security-deck/index.md), a comprehensive CNAPP solution featuring the following modules:
* [Access Transparency to monitor Yandex Cloud team actions on user resources](../../security-deck/concepts/access-transparency.md).
* [Data Security Posture Management](../../security-deck/concepts/dspm.md) (DSPM).
* [Cloud Security Posture Management](../../security-deck/concepts/cspm.md) (CSPM).
* [Kubernetes Security Posture Management](../../security-deck/concepts/kspm.md) (KSPM).
* [Cloud Infrastructure Entitlement Management](../../security-deck/concepts/ciem.md) (CIEM).
* [Alerts](../../security-deck/concepts/alerts.md).

Yandex Security Deck also offers a YandexGPT-powered [AI assistant](../../security-deck/concepts/ai-assistant.md) to provide you with security recommendations.


### Limitation of responsibility {#liability-limit}

Yandex Cloud uses the [shared responsibility](https://yandex.cloud/en/security/shared-responsibility) concept. Where the lines are drawn for who is responsible for security depends on the services used by the system in the cloud, their usage model, i.e., infrastructure as a service (IaaS), platform as a service (PaaS), or software as a service (SaaS), and the security tools and policies the cloud provider has in place.

### Terms and abbreviations {#terms}

This document uses the terms and definitions introduced in ISO/IEC 27000:2018 and ISO/IEC 29100:2011.

### IDs {#ids}

Each check has an ID in the following format: `ID:IAM1`. These IDs are used to create links to sections of the standard for use in Cloud Security Posture Management (CSPM) class tools and convey no other information.

# Authentication and access management requirements

## 1. Authentication and access management {#authentication}


In Yandex Cloud, identification, authentication, and access control is performed by [Yandex Identity and Access Management (IAM)](../../iam/index.md) and [Yandex Identity Hub](../../organization/index.md).

Yandex Cloud supports four types of accounts:

* [Yandex accounts](../../iam/concepts/users/accounts.md#passport): Accounts in Yandex ID, including Yandex 360.
* [Federated accounts](../../iam/concepts/users/accounts.md#saml-federation): Accounts in a corporate [SAML-compatible identity federation](../../organization/concepts/add-federation.md), such as Active Directory.
* [Local accounts](../../iam/concepts/users/accounts.md#local): Accounts whose data is stored only in Yandex Cloud.
* [Service accounts](../../iam/concepts/users/accounts.md#sa): Accounts used by applications to manage resources.

Yandex ID and federated accounts are authenticated in their own systems. Yandex Cloud has no access to the passwords of these account users and only authenticates service accounts using IAM. For Yandex ID and Yandex 360 accounts, set up 2FA using [this guide](https://yandex.com/support/id/authorization/twofa.html).

User access to cloud resources is managed using [roles](../../iam/concepts/access-control/roles.md). Yandex Cloud services may provide different levels of granularity while granting permissions: in some cases, a role can be assigned directly to a service resource, in other cases, permissions are only granted at the level of the folder or cloud where the service resource is located.

This ensures interaction of different categories of resources, roles, and users in the Yandex Cloud infrastructure. Access to resources is managed by IAM. IAM controls each request and makes sure that all operations with resources are only run by users who have the appropriate permissions.

{% note info %}

When using Yandex Cloud together with Yandex 360, follow the Yandex 360 [security best practices](https://yandex.com/support/yandex-360/business/admin/ru/security/security-recommendations): add recovery information to Yandex ID, indicate your phone number for account recovery and notifications, and [configure](https://yandex.com/support/yandex-360/business/admin/ru/admin-audit-log) audit logs.

{% endnote %}

### Identity federations {#federations}

#### 1.1 An identity federation (single sign-on, SSO) is configured {#saml-federation}

[Yandex Identity Hub](../../organization/index.md) is a single service for managing the organizational structure, setting up integration with the employee catalog, and differentiating user access to the organization's cloud resources.

For centralized identity management, use [SAML-compatible identity federations](../../organization/concepts/add-federation.md). By using identity federations, a company can set up Single Sign-On, which is authentication in Yandex Cloud via their IdP server. With this approach, employees can use their corporate accounts that are subject to the company's security policies, such as:

* Revoking and blocking accounts.
* Password policies.
* Limiting the number of unsuccessful login attempts.
* Blocking access sessions upon expiry of a preset user's idle time.
* Two-factor authentication.

{% note tip %}

Use federated accounts instead of Yandex ID accounts whenever possible. Keep in mind that there is a separate role, `organization-manager.federations.admin`, you can use to manage a federation.

{% endnote %}

To make sure all authentication requests from Yandex Cloud contain a digital signature, enable the **Sign authentication requests** option. To complete the configuration, download and install a Yandex Cloud certificate. You can download the certificate in the **Sign authentication requests** field immediately after creating a federation.

| ID requirements | Severity |
| --- | --- |
| IAM1 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to **All services** → **Yandex Identity Hub** → **Federations**.
  1. Make sure the list contains at least one identity federation configured. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. View information about the federations configured:

      ```bash
      yc organization-manager federation saml list \
        --organization-id=<organization_ID>
      ```

  1. Make sure the list contains at least one identity federation configured. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

* [Guide on setting up SAML-based identity federations](../../organization/concepts/add-federation.md#federation-usage).
* [Guide on configuring a SAML-based federation with KeyCloak](https://www.youtube.com/watch?v=m-oe7V9PvC4).

##### 1.1.1 User group mapping is set up in an identity federation {#group-mapping}

In organizations with a lot of users, you may need to grant the same access permissions for Yandex Cloud resources to multiple users at once. In which case it is more efficient to issue roles and permissions to groups rather than individual users.

If you have created user groups in your identity provider or plan to do so, you can [map user groups](../../organization/operations/federation-group-mapping.md) between the IdP and Yandex Identity Hub. Users in the identity provider's groups will be granted the same access permissions to Yandex Cloud resources as their respective groups in Yandex Identity Hub.

| Requirement ID | Severity |
| --- | --- |
| IAM2 | Medium |

#### 1.2 Yandex ID accounts are only used in exceptional cases {#yandex-id-accounts}

The best approach to account management, in terms of security, is using identity federations (for more information, see recommendation 1.1). Therefore, you should do your best to ensure that your organization's list of users only contains federated users (those with the <q>FEDERATION ID</q> attribute) and there are as few Yandex ID accounts on the list as possible. The following exceptions are allowed:

* Account with the `billing.accounts.owner` permissions (technically, only a Yandex ID account can have this role at the moment).
* Account with the `organization-manager.organizations.owner` and `resource-manager.clouds.owner` permissions, if used in emergencies only, e.g., when configuration of your federation fails. If you need to, you can [delete](../operations/account-deletion.md) a privileged [Yandex account](../../iam/concepts/users/accounts.md#passport) with the `organization-manager.organizations.owner` role from an organization.
* External accounts, such as those of your contract partners or contractors, which, for some reason, you cannot register in your IdP.

| Requirement ID | Severity |
| --- | --- |
| IAM3 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to **All services** → **Yandex Identity Hub** → **Users**.
  1. If the **Federation** column is set to **federation** for all the accounts (but for those on the above list of exceptions allowed), the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for non-federated accounts in your organization, but for the ID of the account included in the list of valid exceptions:

      ```bash
      yc organization-manager user list --organization-id=<organization_ID> \
        --format=json | jq -r '.[] | select(.subject_claims.sub!="<ID of account from list of allowed exceptions>")' | jq -r 'select(.subject_claims.federation | not)'
      ```

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Remove all the accounts that have a Yandex ID from your organization, except those on the list of allowed exceptions. For the remaining Yandex ID accounts, set up 2FA using [this guide](https://yandex.com/support/id/authorization/twofa.html).

#### 1.3 The cookie lifetime in a federation is less than 6 hours {#cookie-timeout}

In the [identity federation](../../organization/concepts/add-federation.md) settings, make sure the **Cookie lifetime** parameter value is less than or equal to 6 hours. Thus you minimize the risk of compromising cloud users' workstations.

| Requirement ID | Severity |
| --- | --- |
| IAM4 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud management console in your browser.
  1. Go to the **Organizations** tab.
  1. Next, open the **Federations** tab and select your federation.
  1. Find the **Cookie lifetime** parameter.
  1. Make sure its value is less than or equal to 6 hours. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for accounts with primitive roles assigned at the organization level:

      ```bash
      export ORG_ID=<organization_ID>
      for FED in $(yc organization-manager federation saml list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc organization-manager federation saml get --id $FED --format=json | jq -r '. | select(.cookie_max_age>"21600s")'
      done
      ```

  1. The output should return an empty string. If the output contains the current federation's settings, where `cookie_max_age` > 21600s, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Set **Cookie lifetime** to 6 hours (21600 seconds) or less.

### Access management {#access-control}

#### 1.4 Only appropriate administrators can manage IAM group membership {#iam-admins}

You can conveniently control access to resources via [user groups](../../organization/operations/create-group.md). Make sure to control access to a group as a resource. Users with access permissions for a group can manage other users' membership in that group. Users get these permissions in the following cases:

* User has the `organization-manager.groups.memberAdmin` role for the organization.
* User has the `organization-manager.groups.memberAdmin` role for a specific group as a resource.
* User has the `organization-manager.organizations.owner` or `admin` role or another privileged role for the whole organization.
* User has the `admin` or `editor` role for a specific group as a resource (this is not recommended).

| Requirement ID | Severity |
| --- | --- |
| IAM5 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to **All services** → **Yandex Identity Hub** → **Groups** → **Select a group** → **Group access permissions**.
  1. Toggle the **Inherited roles** switch.
  1. If the list does not contain any accounts that must have no permission to manage group membership, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Remove the group access permissions from the accounts that do not require them.

#### 1.5 Service roles are used instead of primitive roles: admin, editor, viewer, auditor {#min-privileges}

The [principle of least privilege](../../iam/best-practices/using-iam-securely.md#restrict-access) requires assigning the minimum required roles. We do not recommend using primitive roles, such as `admin`, `editor`, `viewer`, and `auditor` that are valid for all services, because this contradicts the principle of least privilege. To ensure more selective access control and implementation of the principle of least privilege, use service roles that only contain permissions for a certain type of resources in a given service. You can see the list of all service roles in the [Yandex Cloud roll reference](../../iam/roles-reference.md).

Use the [auditor](../../iam/roles-reference.md#auditor) role without data access wherever possible.

| Requirement ID | Severity |
| --- | --- |
| IAM6 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to **All services** → **Yandex Identity Hub** → **Users**.
  1. Make sure no accounts in the **Access permissions** column have these primitive roles: `admin`, `editor`, or `viewer`. Otherwise, proceed to "Guides and solutions to use".
  1. Next, go to the global cloud menu (click the cloud in the initial cloud menu). Select the **Access permissions** tab.
  1. Make sure no accounts in the **Roles** column have these primitive roles: `admin`, `editor`, or `viewer`. Otherwise, proceed to "Guides and solutions to use".
  1. Next, go to each folder of each cloud and, similarly, navigate to the **Access permissions** tab.
  1. Make sure no accounts in the **Roles** column have these primitive roles: `admin`, `editor`, or `viewer`. Otherwise, proceed to "Guides and solutions to use".
 
- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for accounts with primitive roles assigned at the organization level:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      yc organization-manager organization list-access-bindings \
        --id=${ORG_ID} \
        --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="viewer")'
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      if(!(Get-Module -Name Join-Object)) {
        # Force enable TLS12 in PowerShell session (important for Windows Server 2016 and earlier)
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        Install-Module -Name Join-Object -Confirm:$false -Force
      }

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json

      $PrimitiveRoles = yc organization-manager organization list-access-bindings --id=$ORG_ID --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin" -or $_.role_id -eq "editor" -or $_.role_id -eq "viewer" -or $_.role_id -eq "auditor"} | select role_id -ExpandProperty subject

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object { $_.sub -in $PrimitiveRoles.id } ) -LeftJoinProperty sub -Right $PrimitiveRoles -RightJoinProperty id -Type OnlyIfInBoth
      $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $PrimitiveRoles.id}) -LeftJoinProperty id -Right $PrimitiveRoles -RightJoinProperty id -Type OnlyIfInBoth | Select @{n="sub";e={$_.id}}, name, preferred_username, picture, email, sub_type, type, role_id 
      $Result
      ```

      {% endcut %}

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".
  1. Run the command below to search for accounts with primitive roles assigned at the cloud level:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="viewer")'
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      Install-Module -Name Join-Object

      $ORG_ID = "<organization_ID>"

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $CloudBindings = @()
      foreach ($Cloud in $Clouds) {
        $CloudBindings += yc resource-manager cloud list-access-bindings --id $Cloud.CloudID --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin" -or $_.role_id -eq "editor" -or $_.role_id -eq "viewer" -or $_.role_id -eq "auditor"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="UserID";e={$_.id}}, type, role_id 
      }

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object {$_.sub -in $CloudBindings.UserID}) -LeftJoinProperty sub -Right $CloudBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, sub, preferred_username, email, @{n="FedID";e={$_.federation.id}}, @{n="FedName";e={$_.federation.name}}, sub_type, type, role_id
      $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $CloudBindings.UserID}) -LeftJoinProperty id -Right $CloudBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, @{n="sub";e={$_.id}}, name, preferred_username, email, @{n="FedID";e={$_.federation.id}}, @{n="FedName";e={$_.federation.name}}, sub_type, type, role_id 
      $Result
      ```

      {% endcut %}

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".
  1. Run the command below to search for accounts with primitive roles assigned at the level of all folders in your clouds:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
      do yc resource-manager folder list-access-bindings --id=$FOLDER_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="viewer")'
      done;
      done
      ```

      {% endcut %}


      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $FolderBindings = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $FolderBindings += yc resource-manager folder list-access-bindings --id $Folder.id --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin" -or $_.role_id -eq "editor" -or $_.role_id -eq "viewer" -or $_.role_id -eq "auditor"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="FolderStatus";e={$Folder.status}}, @{n="UserID";e={$_.id}}, type, role_id 
        }
      }

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object {$_.sub -in $FolderBindings.UserID}) -LeftJoinProperty sub -Right $FolderBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, FolderID, FolderName, FolderStatus, sub, name, email, sub_type, type, role_id
      $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $FolderBindings.UserID}) -LeftJoinProperty id -Right $FolderBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, FolderID, FolderName, FolderStatus, @{n="sub";e={$_.id}}, name, email, sub_type, type, role_id
      $Result
      ```

      {% endcut %}

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Analyze the accounts found with the `admin`, `editor`, and `viewer` primitive roles assigned and replace them with [service granular roles](../../iam/roles-reference.md) based on your role matrix.

Follow [this guide](../../security-deck/operations/ciem/view-permissions.md) to view the full list of a subject's access permissions.

#### 1.6 The auditor role is used to prevent access to user data {#roles-auditor}

Assign the `auditor` role to users who do not need access to data, e.g., external contractors or auditors.
`auditor` is a role with least privilege without access to service data. It grants permission to read service configurations and metadata.
The `auditor` role allows you to perform the following operations:

* View information about a resource.
* View resource metadata.
* View a list of operations with the resource.

To control access more selectively and implement the principle of least privilege, use the `auditor` role by default.

| Requirement ID | Severity |
| --- | --- |
| IAM7 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), navigate to the relevant folder.
  1. Click the **Access permissions** tab.
  1. Click **Assign roles**.
  1. In the **Configure access bindings** window, click **Select user**.
  1. Select a user from the list or use the user search option.
  1. Click **Add role**.
  1. Select the `auditor` role in the folder.
  1. Click **Save**.

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for accounts with the `auditor` role assigned at the organization level:

     ```bash
     export ORG_ID=<organization_ID>
     yc organization-manager organization list-access-bindings \
     --id=${ORG_ID} \
     --format=json | jq -r '.[] | select(.role_id=="auditor")'
     ```

     If the list of accounts is empty, proceed to "Guides and solutions to use".

  1. Run the command below to search for accounts with the `auditor` role assigned at the cloud level:

     ```bash
     export ORG_ID=<organization_ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID --format=json | jq -r '.[] | select(.role_id=="auditor")'
     done
     ```

     If the list of accounts is empty, proceed to "Guides and solutions to use".

  1. Run the command below to search for accounts with the `auditor` role assigned at the level of all folders in your clouds:

     ```bash
     export ORG_ID=<organization_ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do yc resource-manager folder list-access-bindings --id=$FOLDER_ID --format=json | jq -r '.[] | select(.role_id=="auditor")'
     done;
     done
     ```

     If the list of accounts is empty, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. [Assign](../../iam/operations/roles/grant.md) the `auditor` role to users requiring no data access.
1. Remove the excessive account permissions using IAM.

### Service accounts {#service-accounts}

#### 1.7 Cloud entities with service accounts are registered and limited {#sa}

A [service account](../../iam/concepts/users/service-accounts.md) is an account that can be used by a program to manage resources in Yandex Cloud. A service account is used to make requests as an application.

* Do not use employee accounts instead of service accounts. If, for example, an employee quits or moves to a different department, their account permissions are disabled, which may lead to an application failure.
* Do not write service account keys directly to your application's code, configuration files, or environment variables.

**When using service accounts**:

* [Assign the service account](../../compute/operations/vm-connect/auth-inside-vm.md) to the VM and get the token via the metadata service.
* Additionally, set up the local firewall on the VM to allow access to the metadata service (IP address: `169.254.169.254`) only to the appropriate processes and system users.

  Example of denying access to all users except the specified one (in this case, `root`):

  ```bash
  sudo iptables --append OUTPUT --proto tcp \
  --destination 169.254.169.254 --match owner ! --uid-owner root \
  --jump REJECT
  ```

The cloud entities with service accounts assigned must be registered and limited because, for example, if a service account is assigned to a VM, a hacker may get the service account's token from the metadata service from within the VM.

| Requirement ID | Severity |
| --- | --- |
| IAM8 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder and open the settings of the VM you need.
  1. Click **Edit**. 
  1. The service account data is displayed.
  1. Repeat the steps for all VMs in all folders.

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for VMs with assigned service accounts in your organization:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for VM_ID in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
      do yc compute instance get --id=$VM_ID --format=json | jq -r '. | select(.service_account_id)' | jq -r '.id' 
      done;
      done;
      done
      ```

  1. If there are no lines in the list or only accounted entities are output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Remove the service accounts from the cloud entities that do not require them.

#### 1.8 Service accounts have minimum privileges granted {#sa-privileges}

Follow the principle of least privilege and [assign to the service account](../../iam/operations/roles/grant.md) only the roles necessary to run the application.

| Requirement ID | Severity |
| --- | --- |
| IAM9 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder.
  1. In the list of services, select **Identity and Access Management**.
  1. In the left-hand panel, select ![FaceRobot](../../_assets/console-icons/face-robot.svg) **Service accounts**.
  1. Check the list of service accounts.
  1. Repeat the steps for other folders.
  1. Go to the **Access permissions** tab at the cloud and folder levels.

  To view organization-level access permissions, you need to use the CLI.

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to output all the service accounts of the organization in `<service_account_ID>:<service_account_name>` format:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for SA in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc iam service-account list --folder-id=$FOLDER_ID --format=json  | jq -r '.[].id + ":" + .[].name' 
      done;
      done;
      done
      ```

  1. Run the command below to output all the access permissions of a given service account assigned for the organization:

      ```bash
      export ORG_ID=<organization_ID>
      yc organization-manager organization list-access-bindings \
        --id=${ORG_ID} \
        --format=json | jq -r '.[] | select(.subject.type=="serviceAccount")'
      ```

  1. View the service account's access permissions in all clouds:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID  --format=json | jq -r '.[] | select(.subject.type=="serviceAccount")' && echo $CLOUD_ID
      done;
      ```

  1. View the service account's access permissions in all folders:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc resource-manager folder list-access-bindings --id=$FOLDER_ID  --format=json | jq -r '.[] | select(.subject.type=="serviceAccount")' && echo $FOLDER_ID
      done;
      done
      ```

  1. Make sure the lists indicate no excessive permissions. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

* Use Yandex Security Deck to [view](../../security-deck/operations/ciem/view-permissions.md) the full list of a service account's access permissions.
* Use Security Deck to [revoke](../../security-deck/operations/ciem/revoke-permissions.md) the service account’s excessive access permissions.
* [Remove](../../iam/operations/roles/revoke.md) the excessive permissions from the service account using IAM.

#### 1.9 Only trusted administrators have access to service accounts {#sa-admins}

You can grant permissions to use a service account under another user or service account.
Follow the principle of least privilege when granting access to a service account as a resource: if the user has service account permissions, they also have access to all of its permissions. [Assign](../../iam/operations/sa/set-access-bindings.md) roles that allow using and managing service accounts to a minimum number of users.
Each service account with extended permissions should be placed as a resource in a separate folder. It prevents accidental granting of permissions for this account along with the permissions for the folder with the respective service component.

| Requirement ID | Severity |
| --- | --- |
| IAM10 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder.
  1. In the list of services, select **Identity and Access Management**.
  1. In the left-hand panel, select ![FaceRobot](../../_assets/console-icons/face-robot.svg) **Service accounts**.
  1. Click the service account you need and go to the **Access permissions** tab.
  1. Check the access permissions assigned to the service account.
  1. Make sure the list only contains valid administrators. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to output all the service accounts in the clouds:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID  --format=json | jq -r '.[] | select(.subject.type=="serviceAccount")' && echo $CLOUD_ID
      done;
      ```

  1. Run the command below to output all the access permissions for a specific service account as a resource:

      ```bash
      yc iam service-account list-access-bindings \
        --id <service_account_ID>
      ```
 
  1. Make sure the list only contains valid administrators. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

[Remove](../../iam/operations/roles/revoke.md) the unnecessary service account permissions using IAM.

#### 1.10 Service account keys are rotated on a regular basis {#sa-key-rotation}

Yandex Cloud allows you to create the following access keys for service accounts:

* [IAM tokens](../../iam/concepts/authorization/iam-token.md) that are valid for 12 hours. 
* [API keys](../../iam/concepts/authorization/api-key.md): You can choose any validity period.
* [Authorized keys](../../iam/concepts/authorization/key.md) with unlimited validity.
* [AWS API-compatible static access keys](../../iam/concepts/authorization/access-key.md) with unlimited validity.

You need to rotate keys with unlimited validity yourself: delete and generate new ones. You can check out the date when a key was created in its properties. Perform key rotation at least once in 90 days as recommended in the information security standards, such as PCI DSS.

| Requirement ID | Severity |
| --- | --- |
| IAM11 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder.
  1. In the list of services, select **Identity and Access Management**.
  1. In the left-hand panel, select ![FaceRobot](../../_assets/console-icons/face-robot.svg) **Service accounts**.
  1. Click the service account you need and see the date of each key's generation under **Access key properties**.
  1. Repeat the steps for each of your folders.
  1. Make sure the keys were created less than 90 days ago. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Check when the keys were created:

      {% cut "**Bash**" %}

      [Static keys](../../iam/concepts/authorization/access-key.md): 

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for SA in $(yc iam service-account list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id');
      do yc iam access-key list --service-account-id=$SA --format=json | jq -r '.[] | "key_id" + ":" + .id + "," + "sa_id" + ":" + .service_account_id + "," + "created_at" + ":" + .created_at '
      done;
      done;
      done
      ```

      [Authorized keys](../../iam/concepts/authorization/key.md):

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for SA in $(yc iam service-account list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id');
      do yc iam key list --service-account-id=$SA --format=json | jq -r '.[] | "key_id" + ":" + .id + "," + "sa_id" + ":" + .service_account_id + "," + "created_at" + ":" + .created_at '
      done;
      done;
      done
      ```

      [API keys](../../iam/concepts/authorization/api-key.md):

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for SA in $(yc iam service-account list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id');
      do yc iam api-key list --service-account-id=$SA --format=json | jq -r '.[] | "key_id" + ":" + .id + "," + "sa_id" + ":" + .service_account_id + "," + "created_at" + ":" + .created_at '
      done;
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      if(!(Get-Module -Name Join-Object)) {
        # Force enable TLS12 in PowerShell session (important for Windows Server 2016 and earlier)
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        Install-Module -Name Join-Object -Confirm:$false -Force
      }

      $SAList = (yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json | where {$_.subject_claims.sub_type -eq "SERVICE_ACCOUNT"}).subject_claims

      $AllStaticKeys = @()
      $AllAuthKeys = @()
      $AllAPIKeys = @()

      foreach($SA in $SAList) {
        $StaticKeys = yc iam access-key list --service-account-id $SA.sub --format=json | ConvertFrom-Json

        if($StaticKeys) {
          $ExpiriedKeys = $StaticKeys | where {($(Get-Date) - $_.created_at).Days -gt 90} | Select @{n="StaticKeyID";e={$_.id}}, service_account_id, created_at, key_id, description, @{n="KeyStatus";e={"EXPIRIED"}}
          $ActualKeys = $StaticKeys | where {($(Get-Date) - $_.created_at).Days -le 90} | Select @{n="StaticKeyID";e={$_.id}}, service_account_id, created_at, key_id, description, @{n="KeyStatus";e={"VALID"}}

          if($ExpiriedKeys) {
            $AllStaticKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ExpiriedKeys.service_account_id}) -LeftJoinProperty sub -Right $ExpiriedKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, StaticKeyID, created_at, key_id, description, KeyStatus
          }

          if($ActualKeys) {
            $AllStaticKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ActialKeys.service_account_id}) -LeftJoinProperty sub -Right $ActialKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, StaticKeyID, created_at, key_id, description, KeyStatus
          }
        }

        $AuthKeys = yc iam key list --service-account-id $SA.sub --format=json | ConvertFrom-Json

        if($AuthKeys) {
          $ExpiriedKeys = $AuthKeys | where {($(Get-Date) - $_.created_at).Days -gt 90} | Select @{n="AuthKeyID";e={$_.id}}, service_account_id, created_at, @{n="KeyStatus";e={"EXPIRIED"}}, key_algorithm, last_used_at
          $ActualKeys = $AuthKeys | where {($(Get-Date) - $_.created_at).Days -le 90} | Select @{n="AuthKeyID";e={$_.id}}, service_account_id, created_at, @{n="KeyStatus";e={"VALID"}}, key_algorithm, last_used_at

          if($ExpiriedKeys) {
            $AllAuthKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ExpiriedKeys.service_account_id}) -LeftJoinProperty sub -Right $ExpiriedKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, AuthKeyID, description, created_at, KeyStatus, key_algorithm, last_used_at
          }

          if($ActualKeys) {
            $AllAuthKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ActualKeys.service_account_id}) -LeftJoinProperty sub -Right $ActualKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, AuthKeyID, description, created_at, KeyStatus, key_algorithm, last_used_at
          }
        }

        $APIKeys = yc iam api-key list --service-account-id $SA.sub --format=json | ConvertFrom-Json

        if($APIKeys) {
          $ExpiriedKeys = $APIKeys | where {($(Get-Date) - $_.created_at).Days -gt 90} | Select @{n="APIKeyID";e={$_.id}}, service_account_id, created_at, scope, expires_at, @{n="KeyStatus";e={"EXPIRIED"}}
          $ActualKeys = $APIKeys | where {($(Get-Date) - $_.created_at).Days -le 90} | Select @{n="APIKeyID";e={$_.id}}, service_account_id, created_at, scope, expires_at, @{n="KeyStatus";e={"VALID"}}

          if($ExpiriedKeys) {
            $AllAPIKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ExpiriedKeys.service_account_id}) -LeftJoinProperty sub -Right $ExpiriedKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, APIKeyID, description, created_at, KeyStatus, scope, expires_at
          }

          if($ActualKeys) {
            $AllAPIKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ActualKeys.service_account_id}) -LeftJoinProperty sub -Right $ActualKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, APIKeyID, description, created_at, KeyStatus, scope, expires_at
          }
        }
      }

      $AllStaticKeys
      $AllAuthKeys
      $AllAPIKeys
      ```

      This script returns three arrays of objects: static keys, authorized keys, and API keys. It also automatically identifies any expired keys (more than 90 days old).

      {% endcut %}

  1. Make sure no list of keys of any type contains keys with the `created_at` value older than 90 days. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Follow the [guide](../../iam/operations/compromised-credentials.md#key-reissue) for rotating keys depending on their type.

#### 1.11 The minimum required scopes for service account API keys are defined {#api-key-scopes}

A scope is the total of the actions a service account is allowed to perform with the service's resources. A service can have more than one scope. You cannot use an API key with specified scopes in other services or scopes.

In addition to service account access permissions, you can define [scopes](../../iam/concepts/authorization/api-key.md#scoped-api-keys) to restrict the use of [API keys](../../iam/concepts/authorization/api-key.md). Configuring scope limits and expiration dates will reduce the risk of unauthorized use of your keys. Assign only the strictly required scopes to API keys.

| Requirement ID | Severity |
| --- | --- |
| IAM12 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), navigate to the folder the service account belongs to.
  1. In the list of services, select **Identity and Access Management**.
  1. In the left-hand panel, select ![FaceRobot](../../_assets/console-icons/face-robot.svg) **Service accounts** and then select the required service account.
  1. Under **API keys**, check the **Scope** field in the table with your API keys’ details.
  1. If all API keys have their minimum required scopes specified, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  Run the command below and specify the name of the service account your API keys belong to:

  ```bash
  yc iam api-key list --service-account-name <service_account_name>
  ```

  If all API keys listed in the `SCOPES` filed of the command output have their minimum required scopes set, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

[Create](../../iam/operations/authentication/manage-api-keys.md#create-api-key) an API key with a specified scope.

#### 1.12 Tokens for cloud functions and VMs are issued by a service account {#func-token}

To get an IAM token when executing a function, [assign](../../functions/operations/function-sa.md) a service account to the function. In this case, the function will get an IAM token by means of built-in Yandex Cloud tools so that you do not have to provide any secrets to the function externally. Do the same [for your VMs](../../compute/operations/vm-info/get-info.md#inside-instance). For more information about getting an IAM token in a function, see [Getting a service account IAM token using a function](../../functions/operations/function-sa.md).

| Requirement ID | Severity |
| --- | --- |
| IAM13 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Analyze all of your VMs and cloud functions in terms of manually created service account tokens. Tokens are used properly if you assign a service account to an entity and use the account's token from within via the metadata service.

{% endlist %}

#### 1.13 Impersonation is used wherever possible {#impersonation}

[Impersonation](../../iam/operations/sa/impersonate-sa.md) allows a user to perform actions under a service account and to temporarily extend user permissions without generating static credentials for the user. It may be useful for use cases such as duty, local development, or permission verification.

| Requirement ID | Severity |
| --- | --- |
| IAM14 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), click the name of the cloud you need in the left-hand panel.
  1. Go to the **Access permissions** tab and check if the `iam.serviceAccounts.tokenCreator` role is there.

{% endlist %}

**Guides and solutions to use**:

If the `iam.serviceAccounts.tokenCreator` role is missing, set up impersonation for service accounts to provide temporary access to critical data by following this [guide](../../iam/operations/sa/impersonate-sa.md).


### VM metadata {#vm-metadata}

#### 1.14 There are no cloud keys represented as plain text in the VM metadata service {#cloud-keys}

Do not write service account keys and other keys to the [VM metadata](../../compute/concepts/vm-metadata.md) directly. [Assign a service account](../../compute/operations/vm-connect/auth-inside-vm.md) to a VM instance and get a token using the metadata service. You can store sensitive data in any metadata field. However, the most common one is `user-data` (due to its use in the cloud-init utility).

To get VM metadata outside the VM, run the following command:

{% cut "**Bash**" %}

```bash
yc compute instance get \
  --id <VM_ID> \
  --full \
  --format=json | jq -r '. | select(.metadata."user-data") | .metadata."user-data"'
```

{% endcut %}

{% cut "**PowerShell**" %}

```powershell
yc compute instance get `
  --id <VM_ID> `
  --full `
  --format=json | ConvertFrom-Json
```

{% endcut %}

See the list of all regular expressions used to search for cloud accounts' credential secrets:

* **yandex_cloud_iam_cookie_v1** : c1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2}
  Yandex.Cloud Session Cookie
* **yandex_cloud_iam_token_v1** : t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2}
  Yandex.Cloud IAM token
* **yandex_cloud_iam_api_key_v1** : AQVN[A-Za-z0-9_\-]{35,38}
  Yandex.Cloud API Keys (Speechkit, Vision, Translate)
* **yandex_passport_oauth_token** : y[0-6]_[-_A-Za-z0-9]{55} 
  Yandex Passport OAuth token
* **yandex_cloud_iam_access_secret** : YC[a-zA-Z0-9_\-]{38}
  Yandex.Cloud AWS API compatible Access Secret

| Requirement ID | Severity |
| --- | --- |
| IAM15 | High |

{% list tabs group=instructions %}

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Yandex Cloud works with secrets of various types, which may be explicitly included in VM metadata or environment variables. To identify VMs which may have cloud secrets in their metadata, run the following script:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      CLOUDS=$(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id')

      for CLOUD_ID in $CLOUDS
        do
        FOLDERS=$(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id')
        for FOLDER_ID in $FOLDERS
        do
          VMIDS=$(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id')

          if [[ -n "$VMIDS" ]]; then
            for VM_ID in $VMIDS
            do
              IAM_TOKEN=""
              IAM_COOKIE=""
              STATIC_KEY=""
              API_KEY=""
              OAUTH_TOKEN=""
              PRIVATE_KEY=""

              VMDATA=$(yc compute instance get --id $VM_ID --full --folder-id $FOLDER_ID --format=json)
              VM_META=$(echo $VMDATA | jq -r '. | select(.metadata."user-data") | .metadata."user-data"')

              if [[ -n $VM_META ]]; then

                # IAM Tokens
                IAM_TOKEN=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("t1\\.[A-Z0-9a-z_-]+[=]{0,2}\\.[A-Z0-9a-z_-]{86}[=]{0,2}") | .string')

                if [[ -n "$IAM_TOKEN" ]]; then
                  echo "------------"
                  echo "CLOUD_ID:" $CLOUD_ID
                  echo "FOLDER_ID:" $FOLDER_ID
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $IAM_TOKEN"
                  echo "SECRET_TYPE: IAM-Token"
                  echo "------------"
                fi

                # IAM Cookies
                IAM_COOKIE=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("c1\\.[A-Z0-9a-z_-]+[=]{0,2}\\.[A-Z0-9a-z_-]{86}[=]{0,2}") | .string')

                if [[ -n $IAM_COOKIE ]]; then
                  echo "------------"
                  echo "CLOUD_ID: $CLOUD_ID"
                  echo "FOLDER_ID: $FOLDER_ID"
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $IAM_COOKIE"
                  echo "SECRET_TYPE: IAM-Cookie"
                  echo "------------"
                fi

                # Static Keys
                STATIC_KEY=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("YC[a-zA-Z0-9_-]{38}") | .string')

                if [[ -n $STATIC_KEY ]]; then
                  echo "------------"
                  echo "CLOUD_ID:" $CLOUD_ID
                  echo "FOLDER_ID:" $FOLDER_ID
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $STATIC_KEY"
                  echo "SECRET_TYPE: Static Key"
                  echo "------------"
                fi

                # API Keys
                API_KEY=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("AQVN[A-Za-z0-9_-]{35,38}") | .string')

                if [[ -n $API_KEY ]]; then
                  echo "------------"
                  echo "CLOUD_ID:" $CLOUD_ID
                  echo "FOLDER_ID:" $FOLDER_ID
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $API_KEY"
                  echo "SECRET_TYPE: API Key"
                  echo "------------"
                fi

                # OAuth Tokens
                OAUTH_TOKEN=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("y[0-6]_[-_A-Za-z0-9]{55}") | .string')

                if [[ -n $OAUTH_TOKEN ]]; then
                  echo "------------"
                  echo "CLOUD_ID:" $CLOUD_ID
                  echo "FOLDER_ID:" $FOLDER_ID
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $OAUTH_TOKEN"
                  echo "SECRET_TYPE: OAuth Token"
                  echo "------------"
                fi

                # Private keys
                PRIVATE_KEY=$(echo $VMDATA | jq -r '. | select(.metadata."user-data")| .metadata."user-data" | match("-----BEGIN PRIVATE KEY-----") | .string')

                if [[ -n $PRIVATE_KEY ]]; then
                  echo "------------"
                  echo "CLOUD_ID:" $CLOUD_ID
                  echo "FOLDER_ID:" $FOLDER_ID
                  echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                  echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                  echo "METADATA_SECRET_ENTRY: $PRIVATE_KEY"
                  echo "SECRET_TYPE: Private Key"
                  echo "------------"
                fi
              fi
            done
          fi
        done
      done
      ```

      {% endcut %}


      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID=<organization_ID>

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $MetadataSecrets = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $VMs = yc compute instance list --folder-id $Folder.id --format=json | ConvertFrom-Json

          foreach($VM in $VMs) {
            $VMData = yc compute instance get --id $VM.id --folder-id $Folder.id --full --format=json | ConvertFrom-Json

            $SecretScanner = @()
            if($VMData.metadata."user-data") {
              $VMData.metadata."user-data" | Out-File user-data.txt

              # Checking if IAM Cookie in user-data
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern 'c1\.[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*' | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"IAM Token"}}

              # Checking if IAM Token in user-data
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern 't1\.[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*' | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"IAM Cookie"}}

              # Checking if Static Key in user-data
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern 'YC[a-zA-Z0-9_\\-]{38}'  -CaseSensitive | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"Static Key"}}

              # Checking if any API Key in user-data
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern 'AQVN[a-zA-Z0-9_-]{35}' -CaseSensitive | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"API Key"}}

              # Checking if any private key in user-data
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern "-----BEGIN PRIVATE KEY-----" -CaseSensitive | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"Private Key"}}

              # Checking if OAuth tokens
              $SecretScanner += Get-Item -Path user-data.txt | Select-String -Pattern 'y[0-6]_[a-zA-Z0-9_\\-]{58}' -CaseSensitive | Select LineNumber, @{n="Entry";e={$_.Line}}, @{n="SecretType";e={"Yandex OAuth Token"}}

              if($SecretScanner) {
                $MetadataSecrets += $SecretScanner | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}},@{n="FolderID";e={$Folder.id}},@{n="FolderName";e={$Folder.name}},@{n="VMID";e={$VMData.id}},@{n="VMName";e={$VMData.name}}, LineNumber, Entry, SecretType
              }
            }
          }
        }
      }

      $outNull = Remove-Item user-data.txt -Confirm:$false -Force

      $MetadataSecrets
      ```

      {% endcut %}

      The script searches for all secrets across all VMs in the organization and returns the occurrences of lines with secrets in `user-data`, the line number, and secret type (`IAM Token`, `Static Key`, `API Key`, or `Private Key`).

      {% cut "**Output example**" %}

      ```text
      $MetadataSecrets
      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feul********
      VMName     : test
      LineNumber : 4
      Entry      : export token="t1.9eue****"
      SecretType : IAM Token

      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feul********
      VMName     : test
      LineNumber : 5
      Entry      : export token2="t1.9eue****"
      SecretType : IAM Token

      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feulm********
      VMName     : test
      LineNumber : 3
      Entry      : export key="YCMJ5_****"
      SecretType : Static Key

      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feul********
      VMName     : test
      LineNumber : 59
      Entry      : export a="AQVN2****"  
      SecretType : API Key

      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feul********
      VMName     : test
      LineNumber : 60
      Entry      : export b="AQVN2****" 
      SecretType : API Key

      CloudID    : b1g4bj142s8d********
      CloudName  : mycloud
      FolderID   : b1gd3nedooa0********
      FolderName : myfolder
      VMID       : fhmlfad6feul********
      VMName     : test
      LineNumber : 7
      Entry      : -----BEGIN PRIVATE KEY-----
      SecretType : Private Key
      ```

      {% endcut %}

  1. If there are no lines with secrets in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Remove the keys from the metadata of the VMs with deviations found:

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder this VM belongs to.
  1. Navigate to **Compute Cloud**.
  1. In the left-hand panel, select ![image](../../_assets/console-icons/server.svg) **Virtual machines**.
  1. In the VM row, click ![image](../../_assets/console-icons/ellipsis.svg) and select ![image](../../_assets/console-icons/pencil.svg) **Edit**.
  1. Expand the **Metadata** section and remove the keys by clicking ![image](../../_assets/console-icons/xmark.svg).
  1. Click **Save changes**.

- CLI {#cli}

  If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

  The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

  1. See the description of the CLI command for removing metadata:

      ```bash
      yc compute instance remove-metadata --help
      ```

  1. Remove the keys:

      ```bash
      yc compute instance remove-metadata <VM_ID> --keys <SSH_key_name>
      ```

- API {#api}

  To remove SSH keys from the VM metadata, use the [updateMetadata](../../compute/api-ref/Instance/updateMetadata.md) REST API method for the [Instance](../../compute/api-ref/Instance/index.md) resource or the [InstanceService/UpdateMetadata](../../compute/api-ref/grpc/Instance/updateMetadata.md) gRPC API call.

  In your request, provide the `delete` parameter with the SSH key.

  **REST API request example**

  ```bash
  curl \
    --request POST \
    --header "Authorization: Bearer <IAM_token>" \
    --data '{"delete":["<SSH_key_name>"]}' \
    https://compute.api.cloud.yandex.net/compute/v1/instances/<VM_ID>/updateMetadata
  ```

{% endlist %}

#### 1.15 Getting a token via AWS IMDSv1 is disabled on the VM {#aws-token}

The cloud has a [metadata service](../../compute/concepts/vm-metadata.md) that provides information about VM performance.

From inside a VM, metadata is available in the following formats:

* Google Compute Engine (some fields are not supported).
* Amazon EC2 (some fields are not supported).

Amazon EC2 Instance Metadata Service version 1 (IMDSv1) has a number of drawbacks. The most critical of them is the risk of a service account token getting compromised through the metadata service by means of a server-side request forgery (SSRF) attack. For more information, see the [official AWS blog](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/). Therefore, AWS has released IMDSv2, the second version of the metadata service.

So far, Yandex Cloud does not support version 2, so it is strongly recommended to technically disable getting a service account token via the Amazon EC2 metadata service.

The Google Compute Engine metadata service uses an additional header to protect against SSRF and enhance security.

You can disable getting a service account token via Amazon EC2 using the [aws_v1_http_token:DISABLED](../../compute/api-ref/grpc/Instance/create.md#yandex.cloud.compute.v1.MetadataOptions) VM parameter.

| Requirement ID | Severity |
| --- | --- |
| IAM16 | High |

{% list tabs group=instructions %}

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for VMs with IMDSv1 enabled for getting a token:

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for VM_ID in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc compute instance get --id=$VM_ID --format=json | jq -r '. | select(.metadata_options.aws_v1_http_token=="ENABLED")' | jq -r '.id' 
      done;
      done;
      done
      ```

  1. If there are no lines in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Under metadata_options, set the [aws_v1_http_token](../../compute/api-ref/grpc/Instance/create.md#yandex.cloud.compute.v1.MetadataOptions) parameter to `DISABLED` for the found VMs:

```bash
yc compute instance update <VM_ID> \
  --metadata-options aws-v1-http-token=DISABLED
```

### Privileged accounts {#privileged-accounts}

#### 1.16 Two-factor authentication is set up for privileged accounts {#twofa}

We recommend using two-factor authentication (2FA) for cloud infrastructure access control to avoid the risk of compromising user accounts. Access to the Yandex Cloud management console can be based on 2FA.

To enable two-factor authentication, contact an identity provider that supports 2FA and set up a SAML-compliant identity federation. Yandex Cloud has no IdP of its own and user identification is done using external services, such as Yandex ID or corporate systems integrated via identity federations. For example, if you are using an IdP of Active Directory or Keycloak, set up 2FA in these systems. Make sure to set up 2FA at least for privileged cloud accounts.

For a Yandex ID, set up 2FA using [this guide](https://yandex.com/support/id/authorization/twofa.html).

| Requirement ID | Severity |
| --- | --- |
| IAM17 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex ID UI in your browser.
  1. Go to the [Security](https://id.yandex.ru/security) tab.
  1. Make sure login with an additional key is selected as the login option.
  1. If the key-based login is configured, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".
  1. If you are using external IdPs, follow the guides to check the settings.

{% endlist %}

**Guides and solutions to use**:

* [Two-factor authentication: Yandex ID](https://yandex.com/support/id/authorization/twofa.html)
* [KeyCloak: Creating other credentials](https://www.keycloak.org/docs/latest/server_admin/#creating-other-credentials)
* [Configure Additional Authentication Methods for AD FS](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-additional-authentication-methods-for-ad-fs).

#### 1.17 Only trusted administrators have privileged roles {#privileged-users}

Yandex Cloud privileged users include accounts with the following roles:

* `billing.accounts.owner`
* `admin` assigned for a billing account
* `organization-manager.organizations.owner`
* `organization-manager.admin`
* `resource-manager.clouds.owner`
* `admin` and `editor` assigned for an organization
* `admin` and `editor` assigned for a cloud
* `admin` and `editor` assigned for a folder

When creating your billing account, you get the `billing.accounts.owner` role automatically. Any user with the `billing.accounts.owner` role can remove this role from the billing account creator and change the owner. The role allows you to perform any action with the billing account.

The `billing.accounts.owner` role can only be assigned to a Yandex ID account. An account with the `billing.accounts.owner` role is used when setting up payment methods and adding clouds.

Make sure to properly secure this account: it offers significant privileges and cannot be federated with a corporate account.

The most appropriate approach would be to not use this account on a regular basis:

* Only use it for initial setup and updates.
* When actively using this account, enable two-factor authentication (2FA) in Yandex ID.
* After that, if you do not use the bank card payment method (only available for this role), set a strong password for this account (generated using specialized software), disable 2FA, and refrain from using this account unnecessarily.
* Change the password to a newly generated one each time you use the account.

We recommend disabling 2FA only for this account and if it is not assigned to a specific employee.<q></q> Thus you can avoid linking this critical account to a personal device.

To manage a billing account, assign the `admin` or `editor` role for the billing account to a dedicated employee with a federated account.

To view billing data, assign the `viewer` role for the billing account to a dedicated employee with a federated account.

By default, the `organization-manager.organizations.owner` role is granted to the user who creates an organization: the organization owner. The role allows you to appoint organization owners and use all the administrator privileges.

The `resource-manager.clouds.owner` role is assigned automatically when you create your first cloud in the organization. A user with this role can perform any operation with the cloud or its resources and grant cloud access to other users: assign roles and revoke them.

Assign the `resource-manager.clouds.owner` and `organization-manager.organizations.owner` roles to one or more employees with a federated account. Set a strong password for the Yandex ID account that was used to create the cloud, and use it only when absolutely necessary (for example, if the federated access fails).

Make sure to fully protect your federated account that is granted one of the privileged roles listed above:

* Enable two-factor authentication.
* Disable authentication from devices beyond the company's control.
* Configure login attempt monitoring and set alert thresholds.

Assign federated accounts the `admin` roles for clouds, folders, and billing accounts. Minimize the number of accounts with these roles and regularly review the expedience of these roles for the accounts they are assigned to.

| Requirement ID | Severity |
| --- | --- |
| IAM18 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  Checking roles for the Yandex Cloud Billing service:

  1. Open the Yandex Cloud management console in your browser.
  1. Go to [Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts).
  1. Check who is granted the roles: `billing.accounts.owner` and `admin`.

  Checking roles for an organization:

  1. Open the Yandex Cloud management console in your browser.
  1. Go to **All services** → **Yandex Identity Hub** → **Users**.
  1. Check which users have the `admin`, `organization-manager.organizations.owner`, `organization-manager.admin`, and `resource-manager.clouds.owner` roles.

  Checking roles for a cloud:

  1. Open the Yandex Cloud management console in your browser.
  1. Go to the global cloud menu: click the cloud in the initial cloud menu. Select the **Access permissions** tab.
  1. Check which users have the `admin`, `editor`, and `resource-manager.clouds.owner` roles.

  To check roles for a folder:

  1. Open the Yandex Cloud management console in your browser.
  1. Next, go to each folder of each cloud and, similarly, select the **Access permissions** tab.
  1. Check to whom the `admin` role is granted.
  1. Make sure all the privileged roles are granted to trusted administrators. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Find organization-level privileged permissions:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      yc organization-manager organization list-access-bindings
        --id=${ORG_ID} \
        --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="organization-manager.organizations.owner" or .role_id=="organization-manager.admin" or .role_id=="resource-manager.clouds.owner" or role_id=="resource-manager.clouds.editor")'
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      if(!(Get-Module -Name Join-Object)) {
        # Force enable TLS12 in PowerShell session (important for Windows Server 2016 and earlier)
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        Install-Module -Name Join-Object -Confirm:$false -Force
      }

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json

      $OrgBindings = yc organization-manager organization list-access-bindings --id=$ORG_ID --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin"-or $_.role_id -eq "editor" -or $_.role_id -eq "organization-manager.organizations.owner" -or $_.role_id -eq "organization-manager.admin" -or $_.role_id -eq "resource-manager.clouds.owner" -or $_.role_id -eq "resource-manager.clouds.editor"} | select role_id -ExpandProperty subject

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object { $_.sub -in $OrgBindings.id } ) -LeftJoinProperty sub -Right $OrgBindings -RightJoinProperty id -Type OnlyIfInBoth | Select sub, name, preferred_username, picture, email, sub_type, type, role_id 

      if($OrgGroups | Where-Object {$_.id -in $OrgBindings.id}) {
          $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $OrgBindings.id}) -LeftJoinProperty id -Right $OrgBindings -RightJoinProperty id -Type OnlyIfInBoth | Select @{n="sub";e={$_.id}}, name, preferred_username, picture, email, sub_type, type, role_id 
      }
      $Result
      ```

      {% endcut %}

  1. Find cloud-level privileged permissions:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="resource-manager.clouds.owner" or role_id=="resource-manager.clouds.editor")' && echo $CLOUD_ID
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      if(!(Get-Module -Name Join-Object)) {
        # Force enable TLS12 in PowerShell session (important for Windows Server 2016 and earlier)
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        Install-Module -Name Join-Object -Confirm:$false -Force
      }

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $CloudBindings = @()
      foreach ($Cloud in $Clouds) {
        $CloudBindings += yc resource-manager cloud list-access-bindings --id $Cloud.CloudID --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin" -or $_.role_id -eq "editor" -or $_.role_id -eq "resource-manager.clouds.owner" -or $_.role_id -eq "resource-manager.clouds.editor"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="UserID";e={$_.id}}, type, role_id 
      }

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object {$_.sub -in $CloudBindings.UserID}) -LeftJoinProperty sub -Right $CloudBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, sub, preferred_username, email, @{n="FedID";e={$_.federation.id}}, @{n="FedName";e={$_.federation.name}}, sub_type, type, role_id

      if($OrgGroups | Where-Object {$_.id -in $CloudBindings.UserID}) {
          $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $CloudBindings.UserID}) -LeftJoinProperty id -Right $CloudBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, @{n="sub";e={$_.id}}, name, preferred_username, email, @{n="FedID";e={$_.federation.id}}, @{n="FedName";e={$_.federation.name}}, sub_type, type, role_id 
      }
      $Result
      ```

      {% endcut %}

  1. Run the command below to search for privileged permissions at the level of all folders in your clouds:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc resource-manager folder list-access-bindings --id=$FOLDER_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor")' && echo $FOLDER_ID
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      if(!(Get-Module -Name Join-Object)) {
        # Force enable TLS12 in PowerShell session (important for Windows Server 2016 and earlier)
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        Install-Module -Name Join-Object -Confirm:$false -Force
      }

      $OrgUsers = yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $OrgGroups = yc organization-manager group list --organization-id $ORG_ID --format=json | ConvertFrom-Json
      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $FolderBindings = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $FolderBindings += yc resource-manager folder list-access-bindings --id $Folder.id --format=json | ConvertFrom-Json | where {$_.role_id -eq "admin" -or $_.role_id -eq "editor"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="FolderStatus";e={$Folder.status}}, @{n="UserID";e={$_.id}}, type, role_id 
        }
      }

      $Result = @()
      $Result += Join-Object -Left $($OrgUsers.subject_claims | Where-Object {$_.sub -in $FolderBindings.UserID}) -LeftJoinProperty sub -Right $FolderBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, FolderID, FolderName, FolderStatus, sub, name, email, sub_type, type, role_id

      if($OrgGroups | Where-Object {$_.id -in $FolderBindings.UserID}) {
          $Result += Join-Object -Left $($OrgGroups | Where-Object {$_.id -in $FolderBindings.UserID}) -LeftJoinProperty id -Right $FolderBindings -RightJoinProperty UserID -Type OnlyIfInBoth | Select CloudID, CloudName, FolderID, FolderName, FolderStatus, @{n="sub";e={$_.id}}, name, email, sub_type, type, role_id
      }

      $Result
      ```

      {% endcut %}

  1. Make sure all the privileged roles are granted to trusted administrators. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

If any roles granted to untrusted administrators are found, investigate why and remove the respective permissions.

### Local users of managed databases {#mdb-users} 

#### 1.18 Strong passwords are set for local users of managed databases {#mdb-auth}

To use a database at the application level, in addition to IAM service roles, a separate local user is created: the database owner. The following password policy applies to this user:

* The password must contain numbers, uppercase letters, lowercase letters, and special characters. 
* It must be at least 8 characters long.

We recommend using generated passwords. In this case, [Yandex Lockbox](../../lockbox/index.md) will [generate a secret](../../lockbox/concepts/secret.md#secret-type), and its value will be used as the DB user password.

| Requirement ID | Severity |
| --- | --- |
| IAM19 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure the password is regularly rotated in manual mode and meets your company password policies. The password is stored on the client side and cannot be viewed in the management console, CLI, and API.

{% endlist %}

### Third party access {#outstaff-access}

#### 1.19 Contractor and third-party access control is enabled {#contractors}

If you grant third-party contractors access to your clouds, make sure to follow these security measures:

* Assign permissions to contractor employees based on the principle of least privilege.
* Where possible, create a separate account for third-party employees in your corporate IdP and assign the relevant policies to this account.
* Require them to handle their account secrets with care.
* Review the relevance of external user access to your cloud infrastructure.
* Use the [auditor](../../iam/roles-reference.md#auditor) role without data access wherever possible.

| Requirement ID | Severity |
| --- | --- |
| IAM20 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Check all accounts in your organization and make sure you are aware of all contractor and third-party accounts and follow the recommendations above.

{% endlist %}

### Resource model {#resource-framework}

#### 1.20 The proper resource model is used {#resourses}

When developing an access model for your infrastructure, we recommend applying the least privilege principle and the principle of resource separation. The cloud resource model can be visualized as nested containers: organization, cloud, and folder.

An [_organization_](../../organization/concepts/organization.md) is the root container storing information about users and their roles. It may also host some services, e.g., Yandex DataLens, Yandex DataSphere, etc. Organization-level roles are automatically inherited by all subordinate containers. For this reason, we recommend assigning organization-level roles only to administrators and users of organization-level services.

A [_cloud_](../../resource-manager/concepts/resources-hierarchy.md#cloud) is a container one level below the organization. It houses folders with services. A cloud logically joins together multiple interconnected environments within its folders. However, there is no direct connectivity between two clouds. Roles assigned at the cloud level are inherited by all its folders. We do not recommend granting overly broad privileges at this level.

A [_folder_](../../resource-manager/concepts/resources-hierarchy.md#folder) is a container with resources and services. You can set up network connectivity between folders within a single cloud. This means, when organizing your infrastructure, consider placing related services and environments in nearby folders.

When developing an access model for your infrastructure, we recommend the following approaches:

* Create at least one organization per company (the root container with user roles inherited by clouds, folders, and services).
* Group resources by project. We recommend grouping resources by their intended use and storing them in separate clouds. For maximum isolation, place them in separate folders.
* If there are different teams using the services, organize these teams' resources in separate clouds.
* Place any critical resources in a separate folder or cloud. These include resources related to the processing of payment data, personal data, and trade secret data.
* Avoid granting users the `.admin` role for the folder with your product environment. Instead, consider implementing `GitOps` and using Terraform and GitLab to manage folder infrastructure.
* Host resource groups requiring different administrative permissions, e.g., DMZ, CDE, security, backoffice, etc., in different folders or clouds.
* When developing applications, make sure to isolate test and production environments.
* Put shared resources (e.g., network and security groups) into a separate shared resource folder (if you separate components into folders).

| Requirement ID | Severity |
| --- | --- |
| IAM21 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Analyze your resource model and make sure it follows the recommendations given above.

{% endlist %}

#### 1.21 There is no <q>public access</q> to your organization's resources {#public-access}

Yandex Cloud allows you to grant public access to your resources. You can grant public access by assigning access permissions to [public groups](../../iam/concepts/access-control/public-group.md) (`All authenticated users`, `All users`). 

Public group details:

* `All authenticated users`: All authenticated users. This means all registered Yandex Cloud users or service accounts, both from your clouds and other users' clouds.
* `All users`: Any user. No authentication is required.

{% note warning %}

Now `All users` is only supported in the following services: Object Storage (if ACL-based access management is used), Container Registry, and Cloud Functions. For other services, assigning a role to the `All users` group is equivalent to assigning a role to `All authenticated users`.

{% endnote %}

Make sure these groups have no public access to your resources: clouds, folders, buckets, etc.

| Requirement ID | Severity |
| --- | --- |
| IAM22 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  Checking roles in a cloud:

  1. Open the Yandex Cloud management console in your browser.
  1. Next, go to the global cloud menu (click the cloud in the initial cloud menu). Select the **Access permissions** tab.
  1. Check whether there are `All users` and `All authenticated users` among users.

  Checking roles in a folder:

  1. Open the Yandex Cloud management console in your browser.
  1. Go to the appropriate folder of the cloud you need and open the **Access permissions** tab.
  1. Check whether there are `All users` and `All authenticated users` among users.
  1. Repeat the steps for all folders in all your clouds.

  Checking roles in Object Storage:

  1. Open the Yandex Cloud management console in your browser.
  1. Go to the desired cloud and find **Object Storage**.
  1. Click the three dots next to the bucket and check its ACL for `allUsers`, `allAuthenticatedUsers`.
  1. Open the bucket and check the ACLs of each of its objects for `allUsers`, `allAuthenticatedUsers`.
  1. Open the bucket's global settings, select **Object read access**, and make sure the **Public** parameter is disabled.
  1. Repeat the steps for all the buckets and objects in all of your clouds.

  Checking roles in Container Registry:

  1. Open the Yandex Cloud management console in your browser.
  1. Next, go to each cloud and find **Container Registry**.
  1. Open the appropriate registry and click **Access permissions** on the left.
  1. Check whether there are `All users` and `All authenticated users` among users.
  1. Repeat the steps for all your clouds.

  Checking roles in Cloud Functions:

  1. Open the Yandex Cloud management console in your browser.
  1. Next, go to each cloud and find **Cloud Functions**.
  1. Open all cloud functions and make sure the **Public access** parameter is disabled.
  1. Make sure none of the specified resources contain `All users` or `All authenticated users`. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. Run the command below to search for accounts with primitive roles assigned at the organization level:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      yc organization-manager organization list-access-bindings \
        --id=${ORG_ID} \
        --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")'
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $OrgBindings = yc organization-manager organization list-access-bindings --id=$ORG_ID --format=json | ConvertFrom-Json | where {$_.subject.id -eq "allAuthenticatedUsers" -or $_.subject.id -eq "allUsers"} | select role_id -ExpandProperty subject

      $OrgBindings
      ```

      {% endcut %}

  1. Run the command below to search for cloud-level access permissions such as `allUsers` and `allAuthenticatedUsers`:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")' && echo $CLOUD_ID
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $CloudBindings = @()
      foreach ($Cloud in $Clouds) {
        $CloudBindings += yc resource-manager cloud list-access-bindings --id $Cloud.CloudID --format=json | ConvertFrom-Json | where {$_.subject.id -eq "allAuthenticatedUsers" -or $_.subject.id -eq "allUsers"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="PublicGroupID";e={$_.id}}, type, role_id
      }

      $CloudBindings
      ```

      {% endcut %}

  1. Run the command below to search for folder-level access permissions such as `allUsers` and `allAuthenticatedUsers`:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc resource-manager folder list-access-bindings --id=$FOLDER_ID --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")' && echo $FOLDER_ID
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $FolderBindings = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $FolderBindings += yc resource-manager folder list-access-bindings --id $Folder.id --format=json | ConvertFrom-Json | where {$_.subject.id -eq "allAuthenticatedUsers" -or $_.subject.id -eq "allUsers"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="FolderStatus";e={$Folder.status}}, @{n="PublicGroupID";e={$_.id}}, type, role_id 
        }
      }

      $FolderBindings
      ```

      {% endcut %}

  1. Run the command below to search for the `allUsers` and `allAuthenticatedUsers` access permissions at the Container Registry level in all folders:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for CR in $(yc container registry list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id');
      do yc container registry list-access-bindings --id $CR --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")' && echo $CR
      done;
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $CRBindings = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {

          $CRList = yc container registry list --folder-id=$Folder.id --format=json | ConvertFrom-Json

          foreach($CR in $CRList) {
              $CRBindings += yc container registry list-access-bindings --id $CR.id --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.subject.id -eq "allAuthenticatedUsers" -or $_.subject.id -eq "allUsers"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="FolderStatus";e={$Folder.status}}, @{n="PublicGroupID";e={$_.id}}, type, role_id 
          }
        }
      }

      $CRBindings
      ```

      {% endcut %}

  1. Run the command below to search for the `allUsers` and `allAuthenticatedUsers` access permissions at the Cloud Functions level in all folders:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for FUN in $(yc serverless function list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
      do yc serverless function  list-access-bindings --id $FUN --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")' && echo $FUN
      done;
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $FunctionsBindings = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {

          $FunctionsList = yc serverless function list --folder-id $Folder.id --format=json | ConvertFrom-Json

          foreach($Function in $FunctionsList) {
              $FunctionsBindings += yc serverless function  list-access-bindings --id $Function.id --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.subject.id -eq "allAuthenticatedUsers" -or $_.subject.id -eq "allUsers"} | select role_id -ExpandProperty subject | Select @{n="CloudID";e={$Cloud.CloudID}},  @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="FunctionID";e={$Function.id}}, @{n="FunctionName";e={$Function.name}}, @{n="FunctionStatus";e={$Function.status}}, @{n="PublicGroupID";e={$_.id}}, type, role_id 
          }
        }
      }

      $FunctionsBindings
      ```

      {% endcut %}

  1. Make sure none of the specified resources contain `allUsers` or `allAuthenticatedUsers`. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

If you detect that `All users` and `All authenticated users` have the access permissions that they should not have, remove these permissions.

#### 1.22 Contact information of the person in charge of your organization is valid {#org-contacts}

When registering a cloud in Yandex Cloud, customers enter their contact information. For example, an email address is used for notifications about incidents, scheduled maintenance activities, and so on.

For instance, if abnormal activities in the customer's organization are detected on the cloud side or the IAM cloud keys get available in external GitHub repositories, the customer receives a notification. This feature is implemented thanks to Yandex Cloud participating in the [Github Secret scanning partner program](https://docs.github.com/en/developers/overview/secret-scanning-partner-program) and analyzing secrets in Yandex search. If any keys are compromised in a public repository, delete the secret from the repository and its [history](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository), as well as revoke the [keys](../../iam/operations/compromised-credentials.md).

Make sure the contact information is valid and messages are sent to multiple persons in charge from the specified email address.

| Requirement ID | Severity |
| --- | --- |
| IAM23 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud management console in your browser.
  1. Go to [Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts).
  1. Go to the **Account data** tab.
  1. At the bottom, click **Edit data in Yandex Balance**.
  1. Verify the specified contact information.
  1. Make sure the contact details are valid. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Specify up-to-date contact information using the [guide](../../billing/operations/change-data.md#change-address).

#### 1.23 Resource labels are used {#labels}

[Labels](../../resource-manager/concepts/labels.md) are required to monitor data streams and tag critical resources for privilege management.
For example, to tag resources which handle personal data under Federal Law No. FZ-152 of the Russian Federation on Personal Data, select the `152-fz:true` label for:

* Folder
* Yandex Object Storage [bucket](../../storage/concepts/bucket.md)
* Yandex Lockbox [secret](../../lockbox/concepts/secret.md)
* Managed DB clusters

| Requirement ID | Severity |
| --- | --- |
| IAM24 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  The example below shows how to check if there is a label to a [Yandex Virtual Private Cloud](../../vpc/index.md) cloud network. You can perform similar checks for other resource labels.

  1. In the [management console](https://console.yandex.cloud), select a folder.
  1. Select **Virtual Private Cloud**.
  1. Check it for labels.

{% endlist %}

**Guides and solutions to use**:

[Guide on managing labels](../../resource-manager/operations/manage-labels.md)

### Notifications and audit {#notifications-and-audit}

#### 1.24 Yandex Cloud security notifications are enabled {#security-notifications}

To get notifications of security-related events, such as vulnerability detection and elimination, we recommend selecting security notifications in the management console.

| Requirement ID | Severity |
| --- | --- |
| IAM25 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), click [**Settings**](https://console.yandex.cloud/settings).
  1. Go to the **Notifications** section.
  1. In the notification settings, enable the **Security** option.

{% endlist %}

**Guides and solutions to use**:

1. [Make sure](../../resource-manager/concepts/notify.md) that notifications are set up.
1. Enable the **Security** option in the notification settings in the management console.

#### 1.25 Tracking the date of last service account authentication and last access key use in Yandex Identity and Access Management {#key-usage-control}

In the [management console](https://console.yandex.cloud), the page with service account information shows the date and time of the most recent authentication. This information helps track cases of unauthorized access to service accounts.

To ensure security and control over access to resources, monitor cases of unauthorized use of keys, and delete unused keys without the risk of disrupting Yandex Cloud services, you can track the dates of last use of service account access keys. You can find this info on the service account page in the [management console](https://console.yandex.cloud) or in the `last_used_at` field when using the API to invoke access key management methods.

For more information, see [Service account keys](../../iam/concepts/users/service-accounts.md#sa-key).

| Requirement ID | Severity |
| --- | --- |
| IAM26 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), navigate to the folder the service account with access keys belongs to.
  1. In the list of services, select **Identity and Access Management**.
  1. In the left-hand panel, select ![FaceRobot](../../_assets/console-icons/face-robot.svg) **Service accounts**.
  1. In the list that opens, select the service account you need.
  1. You can see the time of the last key use in the table with key info under **Date of last use**.

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

      ```bash
      yc organization-manager organization list
      ```

  1. To get the dates for the last service account authentication and last access key use, run this command:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for SA in $(yc iam service-account list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id');
      do yc iam key list --service-account-id=$SA --format=json | jq -r '.[] | "key_id" + ":" + .id + "," + "sa_id" + ":" + .service_account_id + "," + "created_at" + ":" + .created_at + "last_used_at" + ":" + .last_used_at' 
      done;
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"
      $SAList = (yc organization-manager users list --organization-id $ORG_ID --format=json | ConvertFrom-Json | where {$_.subject_claims.sub_type -eq "SERVICE_ACCOUNT"}).subject_claims

      $AllAuthKeys = @()

      foreach($SA in $SAList) {
        $AuthKeys = yc iam key list --service-account-id $SA.sub --format=json | ConvertFrom-Json

        if($AuthKeys) {
          $ExpiriedKeys = $AuthKeys | where {($(Get-Date) - $_.created_at).Days -gt 90} | Select @{n="AuthKeyID";e={$_.id}}, service_account_id, created_at, @{n="KeyStatus";e={"EXPIRIED"}}, key_algorithm, last_used_at
          $ActualKeys = $AuthKeys | where {($(Get-Date) - $_.created_at).Days -le 90} | Select @{n="AuthKeyID";e={$_.id}}, service_account_id, created_at, @{n="KeyStatus";e={"VALID"}}, key_algorithm, last_used_at

          if($ExpiriedKeys) {
            $AllAuthKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ExpiriedKeys.service_account_id}) -LeftJoinProperty sub -Right $ExpiriedKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, AuthKeyID, description, created_at, KeyStatus, key_algorithm, last_used_at
          }

          if($ActualKeys) {
            $AllAuthKeys += Join-Object -Left $($SAList | Where-Object {$_.sub -in $ActualKeys.service_account_id}) -LeftJoinProperty sub -Right $ActualKeys -RightJoinProperty service_account_id -Type OnlyIfInBoth | Select @{n="service_account_id";e={$_.sub}}, name, sub_type, AuthKeyID, description, created_at, KeyStatus, key_algorithm, last_used_at
          }
        }
      }

      $AllAuthKeys
      ```

      {% endcut %}

{% endlist %}

#### 1.26 Access permissions of users and service accounts are regularly audited using the Yandex Security Deck CIEM {#ciem-access-control}

To ensure data and cloud infrastructure security, you need to regularly audit the access permissions of users and service accounts.

[Cloud Infrastructure Entitlement Management](https://center.yandex.cloud/security/iam-diagnostics/), or CIEM, is a tool providing a centralized view of the full list of accesses to the organization's [resources](../../iam/concepts/access-control/resources-with-access-control.md) available to the [subjects](../../iam/concepts/access-control/index.md#subject), i.e., users, service accounts, [user groups](../../organization/concepts/groups.md), [system groups](../../iam/concepts/access-control/system-group.md), and [public groups](../../iam/concepts/access-control/public-group.md). The tool also makes it easy to revoke excessive access permissions from subjects.

For more information, see [Cloud Infrastructure Entitlement Management (CIEM)](../../security-deck/concepts/ciem.md).

| Requirement ID | Severity |
| --- | --- |
| IAM27 | Informational |

**Guides and solutions to use**:

[Viewing a list of a subject's accesses](../../security-deck/operations/ciem/view-permissions.md).
[Revoking subject's access](../../security-deck/operations/ciem/revoke-permissions.md).

# Network security requirements

## 2. Network security {#network-security}


This section provides users with recommendations on security settings in [Yandex Virtual Private Cloud](../../vpc/index.md).


To isolate applications from each other, put resources in different [security groups](../../vpc/concepts/security-groups.md), and, if strict isolation is required, in different [networks](../../vpc/concepts/network.md#network). By default, internal network traffic is allowed, while traffic between networks is not. Traffic between networks is only allowed via [VMs](../../compute/concepts/vm.md) with two network interfaces in different networks, VPN, or [Yandex Cloud Interconnect](../../interconnect/index.md).

### Overview {#general}

#### 2.1 Cloud objects use a firewall or security groups {#firewall}

With built-in security groups, you can manage VM access to resources and security groups in Yandex Cloud or resources on the internet. A security group is a set of rules for incoming and outgoing traffic that can be assigned to a VM's network interface. Security groups work like a stateful firewall: they monitor the status of sessions and, if a rule allows a session to be created, they automatically allow response traffic. For a guide on how to set up security groups, see [Creating a security group](../../vpc/operations/security-group-create.md). You can specify a security group in the VM settings.

You can use security groups to protect:
* VM.
* [Managed databases](https://yandex.cloud/en/services#data-platform).
* [Yandex Application Load Balancer](../../application-load-balancer/index.md) [load balancers](../../application-load-balancer/concepts/application-load-balancer.md).
* [Yandex Managed Service for Kubernetes](../../managed-kubernetes/index.md) [clusters](../../managed-kubernetes/concepts/index.md#kubernetes-cluster).

The list of available services is being extended.

You can manage network access without security groups, e.g., by using a separate VM as a firewall based on an [NGFW](https://yandex.cloud/en/marketplace/products/usergate/ngfw) image from Yandex Cloud Marketplace or a custom image. Using the NGFW can be critical to customers if they need the following features:
* Logging network connections.
* Streaming traffic analysis for malicious content.
* Detecting network attacks by signature.
* Other features of conventional NGFW solutions.

Make sure that your [clouds](../../resource-manager/concepts/resources-hierarchy.md#cloud) use any of the following:

* Security groups in each cloud object.
* A separate NGFW VM from Cloud Marketplace.
* [BYOI](https://en.wikipedia.org/wiki/Bring_your_own_operating_system) principle, e.g., [your own disk image](../../compute/operations/image-create/upload.md).

| Requirement ID | Severity |
| --- | --- |
| NET1 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  Check if there are security groups in different objects:
  1. Open the [Yandex Cloud management console](https://console.yandex.cloud) in your browser.
  1. Go to each cloud and [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) and open all resources listed in "Objects that security groups can be applied to", one by one.
  1. In the object settings, find the **Security group** parameter and make sure that at least one security group is assigned.
  1. If the parameters of each object with security group support have at least one group set, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  Check whether the NGFW is used instead of security groups:
  1. Open the Yandex Cloud management console in your browser.
  1. Go to each cloud and folder and open all VM [disks](../../compute/concepts/vm.md) one by one.
  1. In the disk settings, find the **Marketplace** product parameter.
  1. If the disk's **Marketplace product** parameters have one of the NGFW product names specified: Check Point CloudGuard IaaS — Firewall & Threat Prevention PAYG or UserGate NGFW, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the `ID` you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for cloud objects with no security group:

     ```bash
     export ORG_ID=<Organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for VM_ID in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc compute instance get --id=$VM_ID --format=json | jq -r '. | select(.network_interfaces[].security_group_ids | not)' | jq -r '.id'
     done;
     done;
     done
     ```

  1. If an empty string is output, the recommendation is fulfilled. If you get the cloud resource `ID` in the output, proceed to "Guides and solutions to use".

  Check whether the NGFW is used instead of a security group:
  1. Run the command to search for the NGFW in the cloud. By default, the command searches for Checkpoint or Usergate. If you use a custom image, specify it.

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id');
     do for DISK_ID in $(yc compute disk list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc compute disk get --id=$DISK_ID --format=json | jq -r '. | select(.product_ids[0]=="f2ecl4ak62mjbl13qj5f" or .product_ids[0]=="f2eqc5sac8o5oic7m99k")' | jq -r '.id'
     done;
     done;
     done
     ```

  1. If you get the `ID` of a VM with the NGFW in the output, the recommendation is fulfilled. If you get an empty string, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:
* Apply security groups to any objects that have no group.
* To apply security groups through Terraform, [set up security groups (dev/stage/prod) using Terraform](https://github.com/yandex-cloud/yc-solution-library-for-security/tree/master/network-sec/segmentation).
* To use the NGFW, [install](https://github.com/yandex-cloud/yc-solution-library-for-security/tree/master/network-sec/checkpoint-1VM) the NGFW on your VM: Check Point.
* Refer to [this guide](https://docs.google.com/document/d/1yYwHorzkwXwIUGeG3n_K6Zo-07BVYowZJL7q2bAgVR8/edit?usp=sharing) on using the UserGate NGFW in the cloud.
* Use NGFW in [active-passive](https://github.com/yandex-cloud/yc-solution-library-for-security/blob/master/network-sec/checkpoint-2VM_active-active/README.md) mode.

#### 2.2 In Virtual Private Cloud, a security group is created; the default security group is not used {#vpc-sg}

A *security group* (SG) is a resource created at the [cloud network](../../vpc/concepts/network.md#network) level. Once created, a [security group](../../vpc/concepts/security-groups.md) can be used in Yandex Cloud [services](../../vpc/concepts/security-groups.md#security-groups-apply) to control network access to an object it applies to.

A *default security group* (DSG) is created automatically while creating a [new cloud network](../../vpc/concepts/network.md#network). The default security group has the following properties:

* It will allow any network traffic, both egress and ingress, in the new cloud network.
* It applies to traffic passing through all subnets in the network where the DSG is created.
* It is only used if no security group is explicitly assigned to the object yet.
* You cannot delete the DSG: it is deleted automatically when deleting the network.

The default security group is a convenient but insecure mechanism that automatically allows all network traffic (incoming and outgoing) for your network objects. While simplifying the initial setup, such openness creates significant risks:

* Attackers can get access to resources through public interfaces.
* Uncontrolled traffic makes your network more vulnerable to DDoS attacks and port scanning.
* The DSG remains active until you assign another security group to the object.

We recommend you to [create](../../vpc/operations/security-group-create.md) a security group of your own with [rules](../../vpc/concepts/security-groups.md#security-groups-rules) explicitly allowing only the traffic you need (e.g., `HTTP/HTTPS` for web servers or `SSH` for administration) and assign this group to your cloud [objects](../../vpc/concepts/security-groups.md#security-groups-apply) ([VMs](../../compute/concepts/vm.md), [Kubernetes clusters](../../managed-kubernetes/concepts/index.md#kubernetes-cluster), etc.) to override the DSG.

This is important because without your rules cloud resources remain open to all and any connections from the internet, whereas security groups of your own enable the [principle of least privilege](../../iam/best-practices/using-iam-securely.md#restrict-access), thus reducing the attack surface.

You can combine security groups by assigning up to five groups per object for more flexible access control.

| Requirement ID | Severity |
| --- | --- |
| NET2 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to each cloud and then to each folder and each Virtual Private Cloud.
  1. Go to **Security groups**.
  1. If at least one security group is found for each Virtual Private Cloud network in addition to the default security group, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the `ID` you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for folders with no security group:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do echo "SG_ID: " && yc vpc security-group list --folder-id=$FOLDER_ID --format=json | jq -r '.[] | select(.id)' | jq -r '.id' && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done
     ```

  1. If each `SG_ID` combination has the `ID` specified in front of the `FOLDER_ID` of the folder it resides in, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Create a security group in each Virtual Private Cloud with restricted access rules, so that it can be assigned to cloud objects.

#### 2.3 Security groups have no access rule that is too broad {#access-rule}

A security group lets you grant network access to absolutely any IP address on the internet as well as across all port ranges. A dangerous rule looks as follows:
* Port range: 0 to 65535 or empty.
* Protocol: Any or TCP/UDP.
* Source: CIDR.
* CIDR blocks: 0.0.0.0/0 (access from any IP address) or ::/0 (ipv6).

{% note warning %}

If no port range is set, it is considered that access is granted across all ports (0-65535).

{% endnote %}

Make sure to only allow access through the ports that your application requires to run and from the IPs to connect to your objects from.

| Requirement ID | Severity |
| --- | --- |
| NET3 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to each cloud and then to each folder and each Virtual Private Cloud.
  1. Go to **Security groups**.
  1. If there is no security group containing network access rules that allow access through any port and from any IP address (for explanation, see above), the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the `ID` you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Find security groups with a dangerous access rule:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do echo "SG_ID: " && yc vpc security-group list --folder-id=$FOLDER_ID \
     --format=json | jq -r '.[] | select(.rules[].direction=="INGRESS" and .rules[].ports.to_port=="65535" and .rules[].cidr_blocks.v4_cidr_blocks[]=="0.0.0.0/0")' | jq -r '.id' \
     && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done
     ```

  1. If an empty value is set in `SG_ID` next to `FOLDER_ID`, the recommendation is fulfilled. If you see a non-empty `SG_ID`, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Delete the dangerous rule in each security group or edit it by specifying trusted IPs.

#### 2.4 Access through control ports is only allowed for trusted IPs {#trusted-ip}

We recommend that you only allow access to your cloud infrastructure through control ports from trusted IP addresses. Make sure your access rules specified in the security group contain no broad rules that allow access through control ports:
* Port range: 22, 3389, or 21.
* Protocol: TCP.
* Source: CIDR.
* CIDR blocks: 0.0.0.0/0 (access from any IP address) or ::/0 (ipv6).

| Requirement ID | Severity |
| --- | --- |
| NET4 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to each cloud and then to each folder and each Virtual Private Cloud.
  1. Go to **Security groups**.
  1. If there is no security group containing network access rules that allow access through control ports from any IP address (for explanation, see above), the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the `ID` you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for security groups with dangerous access rules:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do echo "SG_ID: " && yc vpc security-group list --folder-id=$FOLDER_ID \
     --format=json | jq -r '.[] | select(.rules[].direction=="INGRESS" and (.rules[].ports.to_port=="22" or .rules[].ports.to_port=="3389" or .rules[].ports.to_port=="21") and .rules[].cidr_blocks.v4_cidr_blocks[]=="0.0.0.0/0")' | jq -r '.id' \
     && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done
     ```

  1. If an empty value is set in `SG_ID` next to `FOLDER_ID`, the recommendation is fulfilled. If the `SG_ID` is not empty, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

[Delete](../../cli/cli-ref/vpc/cli-ref/security-group/index.md) the dangerous rule in each security group or specify trusted IPs.

#### 2.5 Protection against DDoS attacks is enabled {#ddos-protection}

Yandex Cloud provides basic and advanced DDoS protection as well as application level protection with Yandex Smart Web Security. Make sure to use at least basic protection.

* [Yandex Smart Web Security](../../smartwebsecurity/quickstart.md) is a service for protection against DDoS attacks and bots at application level L7 of the [OSI model](https://en.wikipedia.org/wiki/OSI_model). Smart Web Security [connects](../../smartwebsecurity/quickstart.md) to Yandex Application Load Balancer. In a nutshell, the service checks the HTTP requests sent to the protected resource against the [rules](../../smartwebsecurity/concepts/rules.md) configured in the [security profile](../../smartwebsecurity/concepts/profiles.md). Depending on the results of the check, the requests are forwarded to the protected resource, blocked, or sent to [Yandex SmartCaptcha](../../smartcaptcha/index.md) for additional verification.
* [Yandex DDoS Protection](../../vpc/ddos-protection/index.md) is a Virtual Private Cloud component that safeguards cloud resources from DDoS attacks. DDoS Protection is provided in partnership with Curator. You can enable it yourself for an external [IP address](../../vpc/concepts/address.md) through cloud administration tools. Supported up to OSI L4.
* [Advanced](https://yandex.cloud/en/services/ddos-protection) DDoS protection is available at OSI layers 3, 4, and 7. You can also track load and attack metrics and enable Solidwall WAF in your Curator account. To enable advanced protection, contact your manager or technical support.

| Requirement ID | Severity |
| --- | --- |
| NET5 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  * To make sure you are using DDoS protection at the application level:

      1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where you want to check the Smart Web Security status.
      1. In the list of services, select **Smart Web Security**.
      1. In the left-hand panel, select ![shield-check](../../_assets/console-icons/shield-check.svg) **Security profiles**.
      1. Make sure you have security profiles created.
      1. If you have security profiles, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  * To make sure you are using basic DDoS protection:

      1. In the [management console](https://console.yandex.cloud), open all the created networks.
      1. Go to **IP addresses**.
      1. If all the public IP addresses have the **DDoS protection** column set to **Enabled**, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Manual check {#manual}

  Contact your account manager to make sure you have advanced DDoS protection activated. 

- Performing a check via the CLI {#cli}

  * To make sure you are using DDoS protection at the application level, run this command:

      ```bash
      yc smartwebsecurity security-profile list
      ```

      If the command returns information about the existing security profiles, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  * To make sure you are using basic DDoS protection:

      1. See what organizations are available to you and write down the `ID` you need:

           ```bash
           yc organization-manager organization list
           ```

      1. Run the command below to search for IP addresses with no DDOS protection:

           ```bash
           export ORG_ID=<organization ID>
           for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
           do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
           do echo "Address_ID: " && yc vpc address list --folder-id=$FOLDER_ID \
           --format=json | jq -r '.[] | select(.external_ipv4_address.requirements.ddos_protection_provider=="qrator" | not)' | jq -r '.id' \
           && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
           done;
           done
           ```

      1. If an empty value is set in `Address_ID` next to `FOLDER_ID`, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

* [How to create a security profile in Smart Web Security](../../smartwebsecurity/operations/profile-create.md).
* All [materials](../../vpc/ddos-protection/index.md) about DDoS protection in Yandex Cloud.

#### 2.6 Protected remote access is used {#secure-access}

To enable administrators to establish remote connections to your cloud resources, use one of the following:
* Site-to-site VPN between a remote site, e.g., your office, and a cloud. As a remote access gateway, use a VM featuring a site-to-site VPN based on an [image](https://yandex.cloud/en/marketplace?categories=network) from Cloud Marketplace.

  **Setup options**:
  * [Creating an IPsec VPN tunnel using the strongSwan](../../tutorials/routing/ipsec/index.md).
  * [Creating a site-to-site VPN connection to Yandex Cloud using Terraform](https://github.com/yandex-cloud-examples/yc-site-to-site-vpn-with-ipsec-strongswan).
  * Client VPN between remote devices and Yandex Cloud. As a remote access gateway, use a VM featuring a client VPN based on an [image](https://yandex.cloud/en/marketplace?categories=network) from Cloud Marketplace.

  See the guide in [Creating a VPN connection using OpenVPN](../../tutorials/routing/openvpn.md). You can also use certified cryptographic information protection tools.
* Dedicated private connection between a remote site and Yandex Cloud using Cloud Interconnect.

To access the infrastructure using control protocols (such as SSH or RDP), create a bastion VM. You can do this using a free [Teleport](https://goteleport.com/) solution. Access to the bastion VM or VPN gateway from the internet must be restricted.

For better control of administrative actions, we recommend that you use PAM (Privileged Access Management) solutions that support administrator session logging (for example, Teleport). For SSH and VPN access, we recommend that you avoid using passwords and use public keys, X.509 certificates, and SSH certificates instead. When setting up SSH for your VMs, we recommend that you use the SSH certificates (including for the SSH host).

To access web services deployed in the cloud, use TLS version 1.2 or higher.

| Requirement ID | Severity |
| --- | --- |
| NET6 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Open all created networks.
  1. Go to the **Route tables** section.
  1. If routes to remote sites' private networks through VMs with a VPN gateway are found, the recommendation is fulfilled.
  1. Check the VMs in each cloud for VPN gateways. In addition, check if their security groups have open ports for the VPN.

- Manual check {#manual}

  Contact your account manager to find out if you have Cloud Interconnect activated. If yes, check if remote access is used.

{% endlist %}

#### 2.7 Employees use Yandex Cloud Desktop for remote access {#use-cloud-desktop}

Yandex Cloud Desktop is a virtual [desktop](../../cloud-desktop/concepts/desktops-and-groups.md) infrastructure management service.

Use this service to:

* Quickly create virtual workspaces for new employees.
* Securely connect remote employees to the corporate network.
* Allow your employees to work from any modern internet-enabled device, including a privately owned one ([BYOD](https://en.wikipedia.org/wiki/Bring_your_own_device)).
* Manage desktop computing resources.
* Administer desktops remotely.
* Create desktop groups with the same computing resources and cloud [network](../../vpc/concepts/network.md).

| Requirement ID | Severity |
| --- | --- |
| NET7 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder you want to check for the presence of [desktops](../../cloud-desktop/concepts/desktops-and-groups.md).
  1. In the list of services, select **Cloud Desktop**.
  1. In the left-hand panel, select ![image](../../_assets/console-icons/display.svg) **Desktops**.
  1. If the list contains at least one created desktop, the recommendation is fulfilled; Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. [Create a desktop group](../../cloud-desktop/operations/desktop-groups/create.md).
1. If you have any specific OS configuration requirements, you can use your own OS image by following the [Creating an image from a Compute Cloud Linux instance](../../cloud-desktop/operations/images/create-from-compute-linux.md) guide or [create](../../cloud-desktop/operations/images/create-from-desktop.md) an image based on the existing desktop and reuse it for the group.
1. After you create a desktop group, the administrator can [create](../../cloud-desktop/operations/desktops/create.md) the required number of desktops and assign users for them. Alternatively, the desktop group users can use the [user desktop showcase](../../cloud-desktop/concepts/showcase.md) to get a desktop by themselves.

#### 2.8 Secure Yandex Browser is used for remote access to Cloud Desktop {#use-yandex-browser}

Employees working remotely via Cloud Desktop should use the [Secure Yandex Browser](https://browser.yandex.ru/corp) to access the corporate resources. This requirement enforces data security for protection against [phishing](https://en.wikipedia.org/wiki/Phishing), malicious websites, and data leaks. The browser has built-in tools for traffic encryption, blocking of dangerous resources, and integration with corporate authentication systems.

| Requirement ID | Severity |
| --- | --- |
| NET9 | Low |

#### 2.9 Outbound internet access control is performed {#outgoing-access}

Possible options for setting up outbound internet access:
* [Public IP address](../../vpc/concepts/address.md#public-addresses). Assigned to a VM according to the one-to-one NAT rule.
* [Egress NAT (NAT gateway)](../../vpc/operations/create-nat-gateway.md). Enables internet access for a subnet through a shared pool of Yandex Cloud public IP addresses. We do not recommend using an Egress NAT for critical interactions because the NAT gateway's IP address can be used by several clients at the same time. This feature must be taken into account when modeling threats for your infrastructure.
* [NAT instance](../../tutorials/routing/nat-instance/index.md). The NAT function is performed by a separate VM. You can create this VM using a [NAT instance](https://yandex.cloud/en/marketplace/products/yc/nat-instance-ubuntu-18-04-lts) image from Cloud Marketplace.

**Comparison of internet access methods**:

| | Public IP address | Egress NAT | NAT instance |
| --- | --- | --- | --- |
| **Advantages:** | | | |
| | * No setup required<br>* Dedicated IP address for each VM | * No setup required<br>* Only works for outgoing connections | * Traffic filtering on a NAT instance<br>* Ability to use your own firewall<br>* Effective use of IP addresses |
| **Disadvantages:** | | | |
| | * It might be unsafe to expose a VM directly to the internet<br>* Cost of reserving each IP address | * Shared pool of IP addresses<br>* The feature is at the [Preview](../../overview/concepts/launch-stages.md) stage; therefore, it is not recommended for production environments | * Setup required<br>* VM cost (vCPU, RAM, disk space) |

Regardless of which option you select for setting up outbound internet access, be sure to limit traffic using one of the mechanisms described above. To build a secure system, use static IP addresses because they can be added to the list of exceptions of the receiving party's firewall.

| Requirement ID | Severity |
| --- | --- |
| NET10 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder.
  1. Go to **IP addresses**.
  1. If all the public IP addresses have the **DDoS protection** column set to **Enabled**, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the `ID` you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for all VMs with public IPs:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id');
     do echo "VM_ID: " && yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[] | select(.network_interfaces[].primary_v4_address.one_to_one_nat.address)' | jq -r '.id' \
     && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done
     ```

  1. If an empty value is set in `VM_ID` next to `FOLDER_ID`, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".
  1. Run the command below to see if there is Egress NAT (NAT gateway):

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do echo "NAT_GW: " && yc vpc gateway list --folder-id=$FOLDER_ID --format=json | jq -r '.[] | select(.id)' | jq -r '.id' && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done
     ```

  1. If an empty value is set in `NAT_GW` next to `FOLDER_ID`, the recommendation is fulfilled. Otherwise, proceed to `Guides and solutions to use`.
  1. Run the command below to see if there is a NAT instance:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id');
     do for DISK_ID in $(yc compute disk list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc compute disk get --id=$DISK_ID --format=json | jq -r '. | select(.product_ids[0]=="fd8v7ru46kt3s4o5f0uo")' | jq -r '.id'
     done;
     done;
     done
     ```

  1. If an empty string is output, the recommendation is fulfilled. If you see the NAT instance `ID`, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:
* If any VM has public IPs, make sure they are required. Otherwise, delete an external IP address in the VM settings.
* If any NAT-Gateway is found, make sure it is required. Otherwise, delete it.
* If any NAT instance is found, make sure it is required. Otherwise, delete it.

#### 2.10 DNS queries are not provided to third-party recursive resolvers {#recursive-resolvers}

To increase fault tolerance, some traffic may be routed to third-party recursive resolvers. To avoid this, contact [support](../../support/overview.md).

| Requirement ID | Severity |
| --- | --- |
| NET8 | Low |

# Virtual environment configuration requirements

## 3. Secure virtual environment configuration {#virtualenv-safe-config}


This section recommends customers on how to configure secure Yandex Cloud services and employ additional virtual environment data protection tools.

### Overview {#general}

#### 3.1 Antivirus protection is used {#antivirus}

Make sure to provide anti-malware protection within your scope of responsibility. You can use a variety of solutions from our partners in [Yandex Cloud Marketplace](https://yandex.cloud/en/marketplace).
[Antivirus solution images](https://yandex.cloud/en/marketplace/products/kaspersky/kaspersky-linux-hybrid-cloud-security-byol) are available in Yandex Cloud Marketplace. License types and other required information are available in the product descriptions.

| Requirement ID | Severity |
| --- | --- |
| ENV38 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that critical systems are protected with antivirus solutions.

{% endlist %}

**Guides and solutions to use**:

Follow the vendor guide to install the AV solution.

#### 3.2 The serial console is either controlled or not used {#serial-console}

On VMs, access to the serial console is disabled by default. For risks of using the serial console, see [VM serial console](../../compute/concepts/serial-console.md) in the Yandex Compute Cloud documentation.

When working with a serial console:

* Make sure that critical data is not output to the serial console.
* If SSH access to the serial console is enabled, make sure that both the credentials management routine and the password used to log in to the operating system locally are as per the regulatory standards. For example, in an infrastructure for storing payment card data, passwords must meet the PCI DSS requirements: they must contain both letters and numbers, be at least 7 characters long, and be changed at least once every 90 days.

{% note info %}

According to PCI DSS, VM access via a serial console is _non-console_ access, so Yandex Cloud applies TLS encryption for it.

{% endnote %}

We do not recommend using access to the serial console unless it is absolutely necessary.

| Requirement ID | Severity |
| --- | --- |
| ENV1 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder to check the VMs in.
  1. In the list of services, select **Compute Cloud**.
  1. Open the settings of all the necessary VMs.
  1. Under **Access**, find the **Additional** parameter.
  1. **Serial console access** must be disabled.
  1. If it is disabled for all the VMs, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:
    
     ```bash
     yc organization-manager organization list
     ```

  1. Find a VM with access to the serial console enabled:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for VM_ID in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do echo "VM_ID: " && yc compute instance get --id=$VM_ID --full --format=json | jq -r '. | select(.metadata."serial-port-enable"=="1")' | jq -r '.id' && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done;
     done
     ```

  1. If an empty value is set in VM_ID next to FOLDER_ID, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

If you don't intend to use serial console on the VM, disable it.

#### 3.3 A benchmark image is used for VM deployment {#standard-image}

When deploying virtual machines, we recommend:

* Preparing a VM image whose system settings correspond to your information security policy. You can create an image using Packer. See [Getting started with Packer](../../tutorials/infrastructure-management/packer-quickstart.md).
* Use this image to create a virtual machine or [instance group](../../compute/concepts/instance-groups/index.md).
* Look up the virtual machine's information to check that it was created using this image.

| Requirement ID | Severity |
| --- | --- |
| ENV2 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder to check the VMs in.
  1. In the list of services, select **Compute Cloud**.
  1. Go to the **Disks** tab.
  1. Open the settings of all disks.
  1. Under **Source**, find the **Identifier** parameter.
  1. If every disk displays the ID of your benchmark image, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for the VM disks that do not contain the ID of your benchmark image:

     ```bash
     export ORG_ID=<organization ID>
     export IMAGE_ID=<ID of your benchmark image>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DISK_ID in $(yc compute disk list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do echo "DISK_ID: " && yc compute disk get --id=$DISK_ID \
     --format=json | jq -r --arg IMAGE_ID $IMAGE_ID '. | select(."source_image_id"==$IMAGE_ID | not)' | jq -r '.id' && echo "FOLDER_ID: " $FOLDER_ID && echo "-----"
     done;
     done;
     done
     ```

  1. If an empty value is set in DISK_ID next to FOLDER_ID, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. Find out why these VM disks use an image different from the benchmark one.
1. Recreate the VMs with the appropriate image.

#### 3.4 Terraform is used in accordance with best information security practices {#tf-using}

With Terraform, you can manage a cloud infrastructure using configuration files. If you change the files, Terraform will automatically detect which part of your configuration is already deployed, and what should be added or removed. For more information, see [Getting started with Terraform](../../tutorials/infrastructure-management/terraform-quickstart.md).

We do not recommend using private information in Terraform configuration files, such as passwords, secrets, personal data, payment system data, etc. Instead, you should use services to store and use secrets in the configuration, such as [HashiCorp Vault](https://yandex.cloud/en/marketplace/products/yc/vault-yckms) from Cloud Marketplace or [Lockbox](https://yandex.cloud/en/services/lockbox) (to transfer secrets to the target object without using Terraform).

If you still need to enter private information in the configuration, you should take the following security measures:

* Use [sensitive = true](https://www.terraform.io/docs/language/values/outputs.html#sensitive-suppressing-values-in-cli-output) for private information to exclude it from the console output of the `terraform plan` and `terraform apply` commands.
* Use [terraformremotestate](https://www.terraform.io/docs/language/state/remote.html). We recommend [uploading](../../tutorials/infrastructure-management/terraform-state-storage.md) a Terraform state to Object Storage and [setting up](https://github.com/yandex-cloud-examples/yc-terraform-state) configuration locks using Managed Service for YDB to prevent simultaneous edits by administrators.
* Use the [mechanism for transferring secrets to Terraform via env](https://www.terraform.io/docs/cli/config/environment-variables.html#tf_var_name) instead of plain text or use built-in KeyManagementService features for [encrypting data in Terraform](../../kms/tutorials/terraform-secret.md) using a separate file with private data. [Learn more about this technique](https://blog.gruntwork.io/a-comprehensive-guide-to-managing-secrets-in-your-terraform-code-1d586955ace1#3073).

For more information about Object Storage security, see [Object Storage](#objstorage) below.

{% note info %}

When a configuration is deployed, you can delete the configuration file with private data.

{% endnote %}

Scan your Terraform manifests using [Checkov](https://github.com/bridgecrewio/checkov) with Yandex Cloud support.

* [Example: Scanning .tf files with Checkov](https://github.com/yandex-cloud/yc-solution-library-for-security/tree/master/terraform-sec/checkov-yc)
* [Example: Storing a Terraform state in Object Storage](https://github.com/yandex-cloud-examples/yc-terraform-state).

| Requirement ID | Severity |
| --- | --- |
| ENV3 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Collect data about using the Terraform best security practices from different points.

{% endlist %}

#### 3.5 Integrity control is performed {#integrity-control}

| Requirement ID | Severity |
| --- | --- |
| ENV5 | Low |

##### 3.5.1 File integrity control {#file-integrity-control}

Numerous information security standards require integrity control of critical files. To do this, you can use free host-based solutions:

* [Wazuh](https://documentation.wazuh.com/current/learning-wazuh/detect-fs-changes.html)
* [Osquery](https://osquery.readthedocs.io/en/stable/deployment/file-integrity-monitoring/)

Yandex Cloud's marketplace also offers paid solutions, such as [Kaspersky Security](https://yandex.cloud/en/marketplace/products/kaspersky/kaspersky-linux-hybrid-cloud-security-byol).

| Requirement ID | Severity |
| --- | --- |
| ENV5.1 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Collect data about using integrity control from different points.

{% endlist %}

##### 3.5.2 VM runtime environment integrity control {#vm-integrity-control}

If you need to control a VM runtime environment (e.g., for access from the VM to a secure repository only when run in the Yandex Cloud CLI cloud), there is the [identity document](../../compute/concepts/metadata/identity-document.md) mechanism. When you create a VM, an identity document that stores information about the VM is generated. It contains the IDs of the VM, [Yandex Cloud Marketplace](https://yandex.cloud/en/marketplace) product, disk image, etc. This document is signed with a Yandex Cloud certificate. The document and its [signature](../../compute/concepts/metadata/identity-document.md#signed-identity-documents) are available to VM processes through the metadata service. Thus, the processes identify the VM runtime environment, disk image, etc., to restrict access to the resources under monitoring.

| Requirement ID | Severity |
| --- | --- |
| ENV5.2 | Low |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that critical VMs have identity documents signed.

{% endlist %}

#### 3.6 Principles of protection against side-channel attacks are followed {#side-channel-protection}

To ensure the best protection against CPU level side-channel attacks (such as Spectre or Meltdown):

* Use full-core virtual machines (instances with a CPU share of 100%).
* Install updates for your operating system and kernel that ensure side-channel attack protection (for example, [Kernel page-table isolation for Linux](https://en.wikipedia.org/wiki/Kernel_page-table_isolation), applications built using [Retpoline](https://en.wikipedia.org/wiki/Spectre_%28security_vulnerability%29)).

We recommend that you use [dedicated hosts](../../compute/concepts/dedicated-host.md) for the most security-critical resources.

[Learn more](https://www.youtube.com/watch?v=VSP_cp6vDQQ&list=PL1x4ET76A10a9Jr6six11s0kRxeQ3fgom&index=17) about side-channel attack protection in cloud environments.

| Requirement ID | Severity |
| --- | --- |
| ENV6 | Informational |

#### 3.7 The corporate Yandex Cloud users have the Yandex Cloud Certified Security Specialist certification {#security-specialist-certificate}

The Yandex Cloud Certified Security Specialist certification exam evaluates the competencies of Yandex Cloud users involved in information security and cloud system protection.

| Requirement ID | Severity |
| --- | --- |
| ENV39 | Informational |

**Guides and solutions to use**:

1. See the [description of competencies](https://yandex.cloud/ru/certification/security-specialist-competencies) tested during the Yandex Cloud Certified Security Specialist exam.
1. Study the [materials](https://yandex.cloud/ru/certification/security-specialist-prerequisites) to help you pass the exam.
1. Fill out [this form](https://yandex.cloud/ru/certification#certification-security-form) to sign up for the exam.

### Yandex Object Storage {#objstorage}

#### 3.8 No public access to the Object Storage bucket {#bucket-access}

We recommend assigning minimum roles for a bucket using IAM and supplementing or itemizing them using a bucket policy (for example, to restrict access to the bucket by IP, grant granular permissions for objects, and so on).

Access to Object Storage resources is verified at three levels:

* [IAM verification](../../iam/concepts/index.md)
* [Bucket policy](../../storage/concepts/policy.md)
* [Access Control Lists (ACLs)](../../storage/concepts/acl.md)

**Verification procedure:**

1. If a request passes the IAM check, the next step is the bucket policy check.
1. Bucket policy rules are checked in the following order:

   1. If the request meets at least one of the Deny rules, access is denied.
   1. If the request meets at least one of the Allow rules, access will be allowed.
   1. If the request does not meet any of the rules, access will be denied.

1. If the request fails the IAM or bucket policy check, access verification is performed based on an object's ACL.

In IAM, a bucket inherits the same access permissions as those of the folder and cloud where it is located. For more information, see [Inheritance of bucket access permissions by Yandex Cloud public groups](../../storage/concepts/acl.md#inheritance). Therefore, we recommend that you only assign the minimum required roles to certain buckets or objects in Object Storage.

Bucket policies are used for additional data protection, for example, to restrict access to a bucket by IP, issue granular permissions to objects, and so on.

With ACLs, you can grant access to an object bypassing IAM verification and bucket policies. We recommend setting strict ACLs for buckets.

 [Example of a secure Object Storage configuration: Terraform](https://github.com/yandex-cloud-examples/yc-s3-secure-bucket)

| Requirement ID | Severity |
| --- | --- |
| ENV7 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the buckets in.
  1. In the list of services, select **Object Storage**.
  1. Click the three dots next to each bucket and check its ACL for `allUsers` and `allAuthenticatedUsers`.
  1. Open the bucket and check the ACL of each of its objects for `allUsers` and `allAuthenticatedUsers`.
  1. Check that the object **Read access** section has the **Public** parameter enabled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. [Configure](../../storage/tools/aws-cli.md) the AWS CLI to work with a cloud.
  1. Run the command below to check the bucket ACL for `allUsers` and `allAuthenticatedUsers`:

     ```bash
     aws --endpoint-url=https://storage.yandexcloud.net s3api get-bucket-acl  <name of your bucket>
     ```

{% endlist %}

**Guides and solutions to use**:

If public access is enabled, [remove](../../iam/operations/roles/revoke.md) it or perform access control (grant permission to access public data consciously).

#### 3.9 Object Storage uses bucket policies {#bucket-policy}

[Bucket policies](../../storage/concepts/policy.md) set permissions for actions with buckets, objects, and object groups. A policy applies when a user makes a request to a resource. As a result, the request is either executed or rejected.

Bucket policy [examples](../../storage/concepts/policy.md#config-examples):

* Policy that only enables object download from a specified range of IP addresses.
* Policy that prohibits downloading objects from the specified IP address.
* Policy that provides different users with full access only to certain folders, with each user being able to access their own.
* Policy that gives each user and service account full access to a folder named the same as the user ID or service account ID.

We recommend making sure that your Object Storage bucket uses at least one policy.

| Requirement ID | Severity |
| --- | --- |
| ENV8 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the bucket policies in.
  1. In the list of services, select Object Storage.
  1. Go to **Bucket policy**.
  1. Make sure that at least one policy is enabled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. [Configure](../../storage/tools/aws-cli.md) the AWS CLI to work with a cloud.
  1. Run the command below to check the bucket ACL for `allUsers` and `allAuthenticatedUsers`:

     ```bash
     aws --endpoint-url=https://storage.yandexcloud.net s3api get-bucket-policy --bucket <name of your bucket>
     ```

{% endlist %}

**Guides and solutions to use**:

[Enable](../../storage/concepts/policy.md#config-examples) the required policy.

#### 3.10 The **Object lock** feature is enabled in Object Storage {#object-lock}

When processing critical data in buckets, you must ensure that data is protected from deletion and that versions are backed up. This can be achieved by versioning and lifecycle management mechanisms, as well as by using object locks.

Bucket versioning allows keeping a version history of an object. Each version is a complete copy of an object and occupies space in Object Storage. Using version control protects your data from both accidental user actions and application faults.

If you delete or modify an object with versioning enabled, the action will create a new object version with a new ID. In the case of deletion, the object becomes unreadable, but its version is kept and can be restored.

For more information about setting up versioning, see [Bucket versioning](../../storage/concepts/versioning.md) in the Object Storage guide.

For more information about lifecycles, see [Bucket object lifecycles](../../storage/concepts/lifecycles.md) and [Bucket object lifecycle configuration](../../storage/s3/api-ref/lifecycles/xml-config.md) in the Object Storage guide.

In addition, to protect object versions against deletion, use [object locks](../../storage/concepts/object-lock.md). For more information about object lock types and how to enable them, refer to the guide.

The storage period of critical data in a bucket is determined by the customer's information security requirements and the information security standards. For example, the PCI DSS standard states that audit logs should be stored for at least one year and be available online for at least three months.

| Requirement ID | Severity |
| --- | --- |
| ENV9 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the buckets in.
  1. In the list of services, select **Object Storage**.
  1. Open the settings of all buckets.
  1. Go to the **Versioning** tab and make sure it is enabled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. [Configure](../../storage/tools/aws-cli.md) the AWS CLI to work with a cloud.
  1. Run the command below to check whether versioning is enabled:

     ```bash
     aws --endpoint https://storage.yandexcloud.net \
     s3api get-bucket-versioning \
     --bucket <name of your bucket>
     ```

  1. Run the command below to check whether versioning is enabled:

     ```bash
     aws --endpoint-url=https://storage.yandexcloud.net/ \
     s3api get-object-lock-configuration \
     --bucket <name of your bucket>
     ```

{% endlist %}

**Guides and solutions to use**:

If public access is enabled, remove it or use access control (by only enabling it when necessary and if approved).

#### 3.11 Logging of actions with buckets is enabled in Object Storage {#bucket-logs}

When using Object Storage to store critical data, be sure to enable logging of actions with buckets. For more information, see the Object Storage documentation, [Logging actions with a bucket](../../storage/concepts/server-logs.md).

This makes sure that data-plane logs with the following objects are written: PUT, DELETE, GET, POST, OPTIONS, HEAD.

You can get log data [writing](../../audit-trails/concepts/events.md#objstorage) (except for bucket object read events) in Audit Trails. You can use the `traffic` metric in [Monitoring](../../storage/metrics.md) to view the amount of outgoing traffic from the bucket. In the future, all logs will be written to Audit Trails.

You can also analyze Object Storage logs in DataLens. For more information, see [Analyzing Object Storage logs using DataLens](../../tutorials/datalens/storage-logs-analysis.md).

| Requirement ID | Severity |
| --- | --- |
| ENV10 | Low |

**Guides and solutions to use**:

You can check if logging is enabled only via Terraform/API by following [this guide](../../storage/operations/buckets/enable-logging.md).

#### 3.12 Cross-origin resource sharing (CORS) is set up in Object Storage {#cors}

If you need [cross-domain requests](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) to objects in buckets, you should configure the Cross-Origin Resource Sharing (CORS) policy in accordance with your corporate information security requirements. For more information, see the Object Storage documentation, [CORS configuration of buckets](../../storage/s3/api-ref/cors/xml-config.md).

| Requirement ID | Severity |
| --- | --- |
| ENV11 | Low |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the buckets in.
  1. In the list of services, select **Object Storage**.
  1. Open the settings of all buckets.
  1. Go to the **CORS** tab and make sure that the configuration is set up. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

[Set up](../../storage/s3/api-ref/cors/xml-config.md) CORS. 

#### 3.13 Yandex Security Token Service is used to get access keys to Object Storage {#use-sts-for-storage-keys}

[Yandex Security Token Service](../../iam/concepts/authorization/sts.md): Yandex Identity and Access Management component used to get _temporary access keys_ compatible with [AWS S3 API](../../storage/s3/index.md).

Temporary access keys as an authentication method are only supported in [Yandex Object Storage](../../storage/index.md).

With temporary keys, you can set up granular access to [buckets](../../storage/concepts/bucket.md) for multiple users with a single [service account](../../iam/concepts/users/service-accounts.md). The service account permissions must include all the permissions you want to grant using temporary keys.

A temporary access key is created based on a [static key](../../iam/concepts/authorization/access-key.md), but, unlike it, it has a limited lifetime and access permissions. Access permissions and lifetime are set for each temporary key individually. The maximum key lifetime is 12 hours.

To set up access permissions for the key, you need an [access policy](../../storage/security/policy.md) in JSON format based on [this schema](../../storage/s3/api-ref/policy/scheme.md).

Temporary Security Token Service keys inherit the access permissions of the service account but are limited by the access policy. If you set up a temporary key's access policy to allow operations not allowed for the service account, such operations will not be performed.

| Requirement ID | Severity |
| --- | --- |
| ENV12 | Low |

**Guides and solutions to use**:

[Create](../../iam/operations/sa/create-sts-key.md) a temporary access key using Security Token Service.

#### 3.14 Pre-signed URLs are generated for one-off accesses to specific objects in Object Storage private buckets {#use-presigned-urls}

Object Storage incorporates several access management mechanisms. To learn how these mechanisms interact, see [Access management methods in Object Storage: Overview](../../storage/security/overview.md).

With pre-signed URLs, any web user can perform various operations in Object Storage, such as:
* Downloading an object
* Uploading an object
* Creating a bucket

A [pre-signed URL](../../storage/concepts/pre-signed-urls.md) is a URL containing request authentication data in its parameters. Pre-signed URLs can be created by users with static access keys.

We recommend using pre-signed URLs to users who are not authorized in the [cloud](../../resource-manager/concepts/resources-hierarchy.md#cloud) but need access to specific objects in the bucket. This way you follow the principle of least privilege and avoid opening access to all the objects in the bucket.

| Requirement ID | Severity |
| --- | --- |
| ENV13 | Low |

**Guides and solutions to use**:

[Create](../../storage/concepts/pre-signed-urls.md#creating-presigned-url) a pre-signed URL and communicate it to the user.

### Managed Services for Databases {#managed-databases}

#### 3.15 A security group is assigned in managed databases {#db-security-group}

We recommend prohibiting internet access to databases that contain critical data, in particular PCI DSS data or private data. Configure security groups to only allow connections to the DBMS from particular IP addresses. To do this, follow the steps in [Creating a security group](../../vpc/operations/security-group-create.md). You can specify a security group in the cluster settings or when creating the cluster in the network settings section.

| Requirement ID | Severity |
| --- | --- |
| ENV14 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the databases in.
  1. In the list of services, select a service or services with managed databases.
  1. In the object settings, find the **Security group** parameter and make sure that at least one security group is assigned.
  1. If the parameters of each object have at least one security group set, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. Run the command below to search for Managed PostgreSQL DBs with no SG:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-postgresql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-postgresql cluster get --id=$DB_ID --format=json | jq -r '. | select(.security_group_ids | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. The output should return an empty string. Otherwise, proceed to "Guides and solutions to use".

- Checking if managed databases have SGs {#db-check}

  1. Run the command below to search for Managed MySQL DBs with no SG:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-mysql cluster get --id=$DB_ID --format=json | jq -r '. | select(.security_group_ids | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. The output should return an empty string. Otherwise, proceed to _Guides and solutions to use_.

{% endlist %}

**Guides and solutions to use**:

If any databases without security groups are found, assign them or enable the **Default security group** [functionality](../../vpc/concepts/security-groups.md#default-security-group.md).

#### 3.16 No public IP address is assigned in managed databases {#db-ip}

Assigning a public IP to a managed database raises information security risks. We do not recommend assigning an external IP unless it is absolutely necessary.

| Requirement ID | Severity |
| --- | --- |
| ENV15 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the databases in.
  1. In the list of services, select a service or services with managed databases.
  1. In the object settings, go to the **Hosts** tab.
  1. If the parameters of each object have the **Public access** option disabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for managed DB clusters with public IPs:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-mysql hosts list --cluster-id=$DB_ID --format=json | jq -r '.[] | select(.assign_public_ip)' | jq -r '.cluster_id' 
     done;
     done;
     done
     ```

  1. If an empty string is output, the recommendation is fulfilled. Otherwise, proceed to _Guides and solutions to use_.

{% endlist %}

**Guides and solutions to use**:

Disable public access if it is not required.

#### 3.17 The deletion protection feature is enabled {#deletion-protection}

In Yandex Cloud managed databases, you can enable deletion protection. The deletion protection feature safeguards the cluster against accidental deletion by a user. Even with cluster deletion protection enabled, you can still connect to the cluster manually and delete the data.

| Requirement ID | Severity |
| --- | --- |
| ENV16 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the databases in.
  1. In the list of services, select a service or services with managed databases.
  1. In the object settings, go to the **Advanced settings** tab.
  1. If the parameters of each object have the **Deletion protection** option enabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for managed DB clusters with deletion protection disabled:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-mysql cluster get --id=$DB_ID --format=json | jq -r '. | select(.deletion_protection | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. The output should return an empty string. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. In the management console, select the cloud or folder to enable deletion protection in.
1. In the list of services, select a service or services with managed databases.
1. In the object settings, go to the **Advanced settings** tab.
1. In the object parameters, enable **Deletion protection**.

#### 3.18 The setting for access from DataLens is not active if not needed {#db-datalens-access}

Do not enable access to databases containing critical data from the management console, [DataLens](../../datalens/index.md), or other services unless you have to. Access from DataLens may be required for data analysis and visualization. For such access, the Yandex Cloud service network is used, with authentication and TLS encryption. You can enable and disable access from DataLens or other services in the cluster settings or when creating it in the advanced settings section.

| Requirement ID | Severity |
| --- | --- |
| ENV17 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the databases in.
  1. In the list of services, select a service or services with managed databases.
  1. In the object settings, go to the **Advanced settings** tab.
  1. If the parameters of each object have **Access from DataLens** disabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Find managed DB clusters with enabled access from DataLens:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-mysql cluster get --id=$DB_ID --format=json | jq -r '. | select(.config.access.data_lens)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. The output should return an empty string. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. In the management console, select the cloud or folder to disable access from DataLens in.
1. In the list of services, select a service or services with managed databases.
1. In the object settings, go to the **Advanced settings** tab.
1. In the object parameters, disable **Access from DataLens**.

#### 3.19 Access from the management console is disabled in managed databases {#db-console-access}

You may need access to the database from the management console to send [SQL queries](../../managed-postgresql/operations/web-sql-query.md) to the database and visualize the data structure.

We recommend that you enable this type of access only if needed, because it raises information security risks. In normal mode, use a standard DB connection as a DB user.

| Requirement ID | Severity |
| --- | --- |
| ENV18 | Low |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the databases in.
  1. In the list of services, select a service or services with managed databases.
  1. In the object settings, go to the **Advanced settings** tab.
  1. If the parameters of each object have **Access from the management console** disabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for managed DB clusters with access from the management console enabled:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>

      # MySQL
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '. | select(.config.access.web_sql)' | jq -r '.id' 
      done;
      done

      # PostgreSQL
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc managed-postgresql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '. | select(.config.access.web_sql)' | jq -r '.id' 
      done;
      done

      # ClickHouse
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc managed-clickhouse cluster list --folder-id=$FOLDER_ID --format=json | jq -r '. | select(.config.access.web_sql)' | jq -r '.id' 
      done;
      done

      # Redis
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc managed-redis cluster list --folder-id=$FOLDER_ID --format=json | jq -r '. | select(.config.access.web_sql)' | jq -r '.id' 
      done;
      done

      # MongoDB
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do yc managed-mongodb cluster list --folder-id=$FOLDER_ID --format=json | jq -r '. | select(.config.access.web_sql)' | jq -r '.id' 
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $MDBClusters = @()

      foreach ($Cloud in $Clouds) {
          $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

          foreach($Folder in $Folders) {
              # Getting Postgre
              $MDBName = "Managed PostgreSQL"
              $MDBClusters += yc managed-postgresql cluster list --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.config.access.web_sql -eq $True} | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="MDB";e={$MDBName}}, @{n="ClusterID";e={$_.id}}, @{n="ClusterName";e={$_.name}}, @{n="ClusterEnv";e={$_.environment}}, @{n="ClusterStatus";e={$_.status}}, network_id, health, @{n="WebSQLAccess";e={$_.config.access.web_sql}}

              # Getting MySQL
              $MDBName = "Managed MySQL"
              $MDBClusters += yc managed-mysql cluster list --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.config.access.web_sql -eq $True} | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="MDB";e={$MDBName}}, @{n="ClusterID";e={$_.id}}, @{n="ClusterName";e={$_.name}}, @{n="ClusterEnv";e={$_.environment}}, @{n="ClusterStatus";e={$_.status}}, network_id, health, @{n="WebSQLAccess";e={$_.config.access.web_sql}}

              # Getting ClickHouse
              $MDBName = "Managed ClickHouse"
              $MDBClusters += yc managed-clickhouse cluster list --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.config.access.web_sql -eq $True} | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="MDB";e={$MDBName}}, @{n="ClusterID";e={$_.id}}, @{n="ClusterName";e={$_.name}}, @{n="ClusterEnv";e={$_.environment}}, @{n="ClusterStatus";e={$_.status}}, network_id, health, @{n="WebSQLAccess";e={$_.config.access.web_sql}} 

              # Getting Redis
              $MDBName = "Managed Redis"
              $MDBClusters += yc managed-redis cluster list --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.config.access.web_sql -eq $True} | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="MDB";e={$MDBName}}, @{n="ClusterID";e={$_.id}}, @{n="ClusterName";e={$_.name}}, @{n="ClusterEnv";e={$_.environment}}, @{n="ClusterStatus";e={$_.status}}, network_id, health, @{n="WebSQLAccess";e={$_.config.access.web_sql}} 

              # Getting MongoDB
              $MDBName = "Managed MongoDB"
              $MDBClusters += yc managed-mongodb cluster list --folder-id $Folder.id --format=json | ConvertFrom-Json | where {$_.config.access.web_sql -eq $True} | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="MDB";e={$MDBName}}, @{n="ClusterID";e={$_.id}}, @{n="ClusterName";e={$_.name}}, @{n="ClusterEnv";e={$_.environment}}, @{n="ClusterStatus";e={$_.status}}, network_id, health, @{n="WebSQLAccess";e={$_.config.access.web_sql}} 
          }
      }

      $MDBClusters
      ```

      {% endcut %}

  1. If an empty string is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. In the management console, select the cloud or folder to disable access from the management console in.
1. In the list of services, select a service or services with managed databases.
1. In the object settings, go to the **Advanced settings** tab.
1. In the object parameters, disable **Access from console**.

### Yandex Cloud Functions {#functions}

#### 3.20 Serverless Containers/Cloud Functions uses the VPC internal network {#vpc-functions}

By default, the function is launched in the isolated IPv4 network with the enabled NAT gateway. For this reason, only public IPv4 addresses are available. You cannot fix the address.

Networking between two functions, as well as between functions and user resources, is limited:

* Incoming connections are not supported. For example, you cannot access the internal components of a function over the network, even if you know the IP address of its instance.
* Outgoing connections are supported via TCP, UDP, and ICMP. For example, a function can access a Yandex Compute Cloud VM or a Yandex Managed Service for YDB DB on the user's network.
* Function is cross-zoned: you cannot explicitly specify a subnet or select an availability zone to run a function.

If necessary, you can specify a cloud network in the function settings. In which case:

* The function will be executed in the specified cloud network. 
* While being executed, the function will get an IP address in the relevant subnet and access to all the network resources.
* The function will have access not only to the internet but also to user resources located in the specified network, such as databases, virtual machines, etc. 
* The function will have an IP address within the `198.19.0.0/16` range when accessing user resources.

You can only specify a single network for functions, containers, and API gateways that reside in the same cloud.

| Requirement ID | Severity |
| --- | --- |
| ENV19 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the functions in.
  1. In the list of services, select Cloud Functions.
  1. Open all the functions.
  1. In the object settings, go to the **Edit function version** tab.
  1. If the parameters of each object have **Network — VPC** set, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. Run the command below to search for any cloud functions that have no network settings specified in VPC:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for VER in $(yc serverless function version list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc serverless function version get $VER --format=json | jq -r '. | select(.connectivity.network_id | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. If an empty string is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. Select the cloud or folder to check the functions in.
1. Select **Cloud Functions** in the list of services.
1. Open the function.
1. In the object settings, go to the **Edit function version** tab.
1. Set **Network — VPC**.

For more information about tracking function versions, see [Backups in Cloud Functions](../../functions/concepts/backup.md).

#### 3.21 Functions are configured in terms of access control, secret and environment variable management, and DBMS connection {#function-access-and-env}

In cases where the use of public functions is not explicitly required, we recommend that you use private functions. For more information about setting up access to functions, see [Managing function access permissions](../../functions/operations/function/function-public.md). We recommend using private functions and assigning rights to invoke functions to specific cloud users.

A [service account](../../iam/concepts/users/service-accounts.md) is an account that can be used by programs or functions to manage resources in Yandex Cloud. If the function version was created with a service account, you can [get](../../functions/operations/function-sa.md) an IAM token for service account from the function invocation context.

Make sure to assign [roles](../../iam/concepts/access-control/roles.md) to the service account. A role is a set of permissions that defines the allowed scope of operations with cloud resources. A function automatically inherits roles assigned for a folder, cloud, or organization. However, they are not displayed in the list of assigned roles.

Do not store secrets and sensitive data in the function code and environment variables. Use [Yandex Lockbox](../../lockbox/index.md) to store and rotate secrets. You can provide a Yandex Lockbox secret to a function via an environment variable.

For a function to get access to a secret, edit its parameters to specify a service account with the following roles assigned:

* `lockbox.payloadViewer` [for a secret](../../lockbox/operations/secret-access.md).
* `kms.keys.encrypterDecrypter` [for an encryption key](../../kms/operations/key-access.md) if the secret was created using a [Yandex Key Management Service](../../kms/index.md) encryption key.

A Yandex Lockbox secret provided to a function is cached in Cloud Functions. After you revoke a service account's access to a secret, the function may continue to store the secret for up to 5 minutes.

Transmitting secrets creates a new function version. You cannot transmit secrets to an existing function version. 

You can add other environment variables when creating a function version. The maximum size of environment variables, including their names, is limited to 4 KB.

You cannot calculate environment variables. Environment variable values are string constants. You can only calculate these within function code. You can retrieve environment variables using standard programming language tools.

You can access the DB cluster hosts from the function only via the [SSL protocol](https://ru.wikipedia.org/wiki/SSL), with the help of a [DB connection](../../functions/operations/database-connection.md#connect), or by specifying a cloud network in the function settings. Use a service account with a role assigned and enable access for functions on the DBMS side.

| Requirement ID | Severity |
| --- | --- |
| ENV20 | Medium |

**Guides and solutions to use**:

* [Disable](../../functions/operations/function/function-private.md) public access to a function.
* [View](../../functions/operations/function/role-list.md) a list of roles assigned to a function.
* [Get](../../functions/operations/function-sa.md) a service account IAM token using a function.
* [Revoke](../../functions/operations/function/role-revoke.md) a role assigned to a function.
* [Connect](../../functions/operations/database-connection.md) to a database from a function.

For more information about roles and resources you can assign roles for in Cloud Functions, see [Access management in Cloud Functions](../../functions/security/index.md).

#### 3.22 Aspects of time synchronization in Cloud Functions are addressed {#ntp-functions}

Cloud Functions does not guarantee time synchronization prior to or during execution of requests by functions. To get a function log with exact timestamps on the Cloud Functions side, use a cloud logging service. For more information on function logging, see [Function logs](../../functions/concepts/logs.md).

| Requirement ID | Severity |
| --- | --- |
| ENV22 | Informational |

#### 3.23 Aspects of header management in Cloud Functions are addressed {#http-functions}

If the function is called to process an HTTP request, the returned result should be a JSON document containing the HTTP response code, response headers, and response content. Cloud Functions automatically processes this JSON document and returns data in a standard HTTP response to the user. It is the customer's responsibility to manage the response headers according to the regulatory requirements and the threat model. For more information on how to process an HTTP request, refer to the Cloud Functions manual, [Function calling in Cloud Functions](../../functions/concepts/function-invoke.md).

You can run a function by specifying the `?integration=raw` string query parameter. When invoked this way, a function cannot parse or set HTTP headers:

* HTTPS request body content is provided as the first argument (without converting to a JSON structure).
* HTTPS request body content is the same as the function's response (without converting and checking the structure); the HTTP response status is `200`.

The request must be a JSON structure which contains:

* `httpMethod`: HTTP method: `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, or `PUT`.
* `headers`: Dictionary of strings with HTTP request headers and their values. If the same header is provided multiple times, the dictionary contains the last provided value.
* `multiValueHeaders`: Dictionary with HTTP request headers and lists of their values. It contains the same keys as the `headers` dictionary; however, if any of the headers was repeated multiple times, its list will contain all the values provided for this header. If the header was provided only once, it gets included into this dictionary and its list will contain only one value.
* `queryStringParameters`: Dictionary with the query parameters. If the same parameter is specified multiple times, the dictionary will contain the last specified value.
* `multiValueQueryStringParameters`: Dictionary with the list of all specified values for each query parameter. If the same parameter is specified multiple times, the dictionary will contain all the specified values.
* `requestContext`: Request context.

For the purpose of debugging a function, you can use special requests that return the JSON structure of the request and the result you need for debugging. For more information, see [function debugging](../../functions/concepts/function-invoke.md#example).

| Requirement ID | Severity |
| --- | --- |
| ENV23 | Informational |

### Managed Service for YDB {#ydb-access}

#### 3.24 Recommendations for using confidential data in YDB are followed {#ydb-confidential-data}

It is prohibited to use confidential data for names of databases, tables, columns, folders, and so on. Do not send critical data, e.g., payment card details, to Managed Service for YDB (both Dedicated and Serverless) in plain text. Prior to sending data, be sure to encrypt it at the application level. For this you can use the KMS service or any other method compliant with the regulator standard. For data where the storage period is known in advance, we recommend that you configure the [Time To Live](https://ydb.tech/docs/en//concepts/ttl) option.

| Requirement ID | Severity |
| --- | --- |
| ENV24 | High |

#### 3.25 Recommendations for SQL injection protection in YDB are followed {#ydb-sql-injection}

When working with the database, use [parameterized prepared statements](https://ydb.tech/docs/en//reference/ydb-sdk/example/#param-queries) to protect against SQL injection. If the application dynamically generates query templates, you must prevent the injection of untrusted user input into the SQL query template.

| Requirement ID | Severity |
| --- | --- |
| ENV25 | High |

#### 3.26 There is no public access for YDB {#ydb-public}

When accessing the database in dedicated mode, we recommend that you use it inside VPC and disable public access to it from the internet. In serverless mode, the database can be accessed from the internet. You must therefore take this into account when modeling threats to your infrastructure. For more information about the operating modes, see the [Serverless and dedicated modes](../../ydb/concepts/serverless-and-dedicated.md) section in the Managed Service for YDB documentation.

When setting up database permissions, use the principle of least privilege.

| Requirement ID | Severity |
| --- | --- |
| ENV26 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the database in. 
  1. In the list of services, select **Managed Service for YDB**.
  1. Open all the databases.
  1. In the database settings, go to the **Network** tab.
  1. If the parameters of each object have the **Public IP addresses** option disabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for managed DB clusters with public IPs:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for DB_ID in $(yc managed-mysql cluster list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc managed-mysql hosts list --cluster-id=$DB_ID --format=json | jq -r '.[] | select(.assign_public_ip)' | jq -r '.cluster_id' 
     done;
     done;
     done
     ```

  1. The output should return an empty string. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Disable public access if it is not required.

#### 3.27 YDB backup recommendations are followed {#ydb-backup}

When creating [on-demand backups](../../ydb/pricing/serverless.md), make sure that the backup data is properly protected.

When creating backups on demand in Object Storage, follow the recommendations in the Object Storage subsection above (for example, use the built-in bucket encryption feature).

| Requirement ID | Severity |
| --- | --- |
| ENV27 | Low |

### Yandex Container Registry {#container-registry}

#### 3.28 ACL by IP address is set up for Yandex Container Registry {#acl-container-registry}

We recommend that you limit access to your Container Registry to specific IPs.

| Requirement ID | Severity |
| --- | --- |
| ENV28 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the registry in.
  1. In the list of services, select **Container Registry**.
  1. In the settings of the specific registry, go to the **Access for IP address** tab.
  1. If specific IPs to allow access for are set in the parameters, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for CRs that are not filtered by IP:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
      do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
      do for CR in $(yc container registry list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); do yc container registry list-ip-permissions --id=$CR --format=json | jq -r '.[] | select(.ip)' | jq -r '.action' && echo $CR "IF ACTION PULL/PUSH exist before CR then OK"
      done;
      done;
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id $ORG_ID --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $CRIPPermissions = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $CRList = yc container registry list --folder-id $Folder.id --format=json | ConvertFrom-Json

          if($CRList) {
            foreach($CR in $CRList) {
              $IPPermissions = yc container registry list-ip-permissions --id $CR.id --format=json | ConvertFrom-Json

              if($IPPermissions) {
                $CRIPPermissions += $CR | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="CRID";e={$_.id}}, @{n="CRName";e={$_.name}}, @{n="CRStatus";e={$_.status}},@{n="Lables";e={$_.labels}},@{n="IPPermissionsList";e={$IPPermissions}}
              }
            }
          }
        }
      }

      $CRIPPermissions
      ```

      {% endcut %}

  1. If PULL/PUSH is output before each registry ID, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Specify the IP addresses for registry access.

#### 3.29 Requirements for application protection in Yandex Container Registry are met {#app-container-registry}

| Requirement ID | Severity |
| --- | --- |
| ENV40 | Medium |

##### 3.29.1. Docker images are scanned when uploaded to Yandex Container Registry {#upload--policy}

[Auto scans](../../container-registry/operations/scanning-docker-image.md#automatically) of Docker images on push are critical for early detection and elimination of vulnerabilities to ensure secure deployment of containers. Reports on completed scans provide a brief description of detected vulnerabilities and issues and help you set priorities and eliminate security risks in containerized applications.

| Requirement ID | Severity |
| --- | --- |
| ENV41 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder the registry with Docker images belongs to.
  1. Select the appropriate registry in **Container Registry**.
  1. Navigate to the **Vulnerability scanner** tab and click **Edit settings**.
  1. Make sure Docker image scans on push are enabled.

{% endlist %}

**Guides and solutions to use:**

[Guide on scanning Docker images on push](../../container-registry/operations/scanning-docker-image.md#automatically).

**Guides and solutions to use**:

[Guide on scanning Docker images on push](../../container-registry/operations/scanning-docker-image.md#automatically).

##### 3.29.2 Docker images stored in Container Registry are regularly scanned {#periodic--scan}

Scheduled scanning of Docker images is an automated process that checks containerized images for vulnerabilities and compliance with security standards. Such scans are regular and automatic to ensure the consistency of image checks for vulnerabilities and maintain a high security level in the long run. Reports on completed scans provide a brief description of detected vulnerabilities and issues and help you set priorities and eliminate security risks in containerized applications.

We recommend setting up a schedule for scans to be run at least once a week.

| Requirement ID | Severity |
| --- | --- |
| ENV42 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder the registry with Docker images belongs to.
  1. Select the appropriate registry in **Container Registry**.
  1. Navigate to the **Vulnerability scanner** tab and click **Edit settings**.
  1. Make sure that scheduled Docker image scans are enabled with a frequency of at least once a week.

{% endlist %}

**Guides and solutions to use:**

[Guide on scheduled scanning of Docker images](../../container-registry/operations/scanning-docker-image.md#scheduled).

##### 3.29.3 Artifact integrity is ensured {#pipeline-artifacts-cosign}

Signing artifacts enhances security to ensure your software validity, integrity, reliability, and compliance with the requirements.

| Requirement ID | Severity |
| --- | --- |
| ENV43 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that artifacts are signed while building an application.

{% endlist %}

**Guides and solutions to use:**

To sign artifacts within a pipeline, you can use [Cosign](https://github.com/sigstore/cosign), a third-party command line utility for signing [artifacts](https://docs.sigstore.dev/signing/quickstart/), images, and [in-to-to attestations](https://github.com/in-toto/attestation/tree/main/spec/predicates). Then you can upload these artifacts to Yandex Container Registry.

A special build of Cosign allows you to store the created [digital signature key pair](../../kms/concepts/asymmetric-signature-key.md) in [Yandex Key Management Service](../../kms/quickstart/index.md), sign files and artifacts with the private key of the pair, and verify a digital signature using its public key.

For more information, see [Signing and verifying Container Registry Docker images in Yandex Managed Service for Kubernetes](../../container-registry/tutorials/sign-cr-with-cosign.md).

### Yandex Container Solution {#container-solution}

#### 3.30 Privileged containers are not used in Yandex Container Solution {#vip-containers}

We do not recommend that you use privileged containers to run loads that process untrusted user input. Privileged containers should be used for the purposes of administering VMs or other containers.

| Requirement ID | Severity |
| --- | --- |
| ENV44 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the VMs in.
  1. In the list of services, select **Compute Cloud**.
  1. Open the settings of a specific VM with a **Container Optimized Image**.
  1. In the Docker container's **Settings**, find the **Privileged mode** parameter.
  1. If it is disabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for CRs that are not filtered by IP:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for VM_ID in $(yc compute instance list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc compute instance get --id=$VM_ID --full --format=json | jq -r '. | select(.metadata."docker-container-declaration")| .metadata."docker-container-declaration" | match("privileged: true") | .string' && echo $VM_ID
     done;
     done;
     done
     ```

  1. If there is no `privileged: true` in front of each VM ID, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

1. In the management console, select the cloud or folder to check the VMs in.
1. In the list of services, select **Compute Cloud**.
1. Open the settings of a specific VM with a **Container Optimized Image**.
1. In the Docker container's Settings, disable the **Privileged mode** parameter.

#### 3.31 The Yandex Certificate Manager certificate is valid for at least 30 days {#certificate-validity}

You can use Yandex Certificate Manager to manage TLS certificates for your API gateways in the API Gateway, as well as your websites and buckets in Object Storage. Application Load Balancer is integrated with Certificate Manager for storing and installing certificates. We recommend that you use Certificate Manager to obtain your certificates and rotate them automatically.

When using TLS in your application, we recommend that you limit the list of your trusted root certificate authorities (root CA).

When using certificate pinning, keep in mind that Let's Encrypt certificates are [valid for 90 days](https://letsencrypt.org/docs/faq/#what-is-the-lifetime-for-let-s-encrypt-certificates-for-how-long-are-they-valid).

We recommend that you update certificates in advance if they are not [updated automatically](../../certificate-manager/concepts/challenges.md#auto).

| Requirement ID | Severity |
| --- | --- |
| ENV29 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the VMs in.
  1. In the list of services, select **Yandex Certificate Manager**.
  1. Open the settings of each certificate and find the **End date** parameter.
  1. If the parameter shows that the certificate will be valid for at least 30 days more, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Search for any of your organization's certificates with the end date:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for CERT_ID in $(yc certificate-manager certificate list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc certificate-manager certificate get --id $CERT_ID --format=json | jq -r '. | "Date of the end " + .not_after + " --- Cert_ID " + .id'
     done;
     done;
     done
     ```

  1. If the certificate expires in more than 30 days, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use**:

Update the certificate or set up auto updates.

### Yandex Managed Service for GitLab {#git-lab-service}

#### 3.32 GitLab instance security setup guidelines are followed {#git-lab-secure}

See the recommendations [here](../../managed-gitlab/concepts/security.md#secure-instance). 

| Requirement ID | Severity |
| --- | --- |
| ENV30 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 3.33 Requirements for application protection in GitLab are met {#gl-app-container-registry}

| Requirement ID | Severity |
| --- | --- |
| ENV45 | Medium |

##### 3.33.1 Protected secure pipeline templates are used {#pipeline-blocks}

When working with Managed Service for GitLab, make sure you use built-in GitLab security mechanisms to secure your pipeline. You can integrate a pipeline into your projects in the [following ways](../../managed-gitlab/concepts/security.md#security-pipeline-usage):

* Creating a pipeline in an individual project and connecting it to other projects using the [`include`](https://docs.gitlab.com/ee/ci/yaml/includes.html) function. This option is available for all license types.
* Using the [`Compliance framework and pipeline`](https://docs.gitlab.com/ee/user/project/settings/index.html#compliance-frameworks) mechanism that you can run in any group project. It is available for the `Ultimate` license.
* Copying pipeline sections to `.gitlab-ci.yml` files in your projects.

| Requirement ID | Severity |
| --- | --- |
| ENV46 | Informational |

##### 3.33.2 Approval rules are configured {#setup-code-review}

With [Yandex Managed Service for GitLab](../../managed-gitlab/index.md), you can flexibly set up required [approval rules](../../managed-gitlab/concepts/approval-rules.md) before the code can be added to the target project branch. This feature is an alternative to the GitLab Enterprise Edition’s [Approval Rules](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/rules.html) tool and is available regardless of the GitLab [version](https://about.gitlab.com/pricing).

If a [GitLab instance](../../managed-gitlab/concepts/index.md#instance) has the approval rules enabled, Managed Service for GitLab analyzes approvals from reviewers for compliance with the specified rules. If there are not enough approvals, a thread is created in a merge request that blocks it from being merged to the target branch. When the merge request is updated, a comment with the current compliance status is created or updated in the thread. Once all required approvals are obtained, the thread is resolved.

If you manually resolve the thread, it will be recreated. If the merge request is approved regardless of the existing rules, users with the `Maintainer` role or higher will receive an email notification about the violated approval workflow.

| Requirement ID | Severity |
| --- | --- |
| ENV47 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where your GitLab instance is located.
  1. In the list of services, select **Managed Service for&nbsp;GitLab**.
  1. Select the instance you need and click **Edit** in the top-right corner of the page.
  1. Make sure to select a configured approval rule [configuration](../../managed-gitlab/concepts/approval-rules.md#packages) in the **Approval rules** field.

{% endlist %}

**Guides and solutions to use**:

[Enabling approval rules in the GitLab instance](../../managed-gitlab/operations/approval-rules.md#enable)

#### 3.34 Yandex Managed Service for Kubernetes security guidelines are used {#k8s-security}

Check the recommendations in [Kubernetes security requirements](kubernetes-security.md).

| Requirement ID | Severity |
| --- | --- |
| ENV32 | Medium |

#### 3.35 OS Login is used for connection to a VM or Kubernetes node {#os-login-onto-hosts}

[OS Login](../../organization/concepts/os-login.md) is a convenient way to manage connections to Yandex Managed Service for Kubernetes [VMs](../../compute/concepts/vm.md) and [cluster](../../managed-kubernetes/concepts/index.md#kubernetes-cluster) nodes over SSH via the [CLI](../../cli/quickstart.md) or a standard SSH client with an SSH certificate or SSH key, which you first need to add to the OS Login profile of organization user or [service account](../../iam/concepts/users/service-accounts.md) in Yandex Identity Hub.

OS Login links the account of a virtual machine or Kubernetes node user with that of an organization or service account user. To manage access to virtual machines and Kubernetes nodes, [enable](../../organization/operations/os-login-access.md) the OS Login access option at the organization level and then [activate](../../compute/operations/vm-connect/enable-os-login.md) OS Login access on each virtual machine or Kubernetes node separately.

Thus, you can easily manage access to virtual machines and Kubernetes nodes by assigning appropriate roles to users or service accounts. If you revoke the roles from a user or service account, they will lose access to all virtual machines and Kubernetes nodes with OS Login access enabled.

| Requirement ID | Severity |
| --- | --- |
| ENV33 | Low |

**Guides and solutions to use**:

* [Enabling OS Login access at the organization level](../../organization/operations/os-login-access.md).
* [Setting up OS Login access on an existing VM](../../compute/operations/vm-connect/enable-os-login.md).
* [Connect to the virtual machine via OS Login](../../compute/operations/vm-connect/os-login.md).
* [Connecting to a Kubernetes node via OS Login](../../managed-kubernetes/operations/node-connect-oslogin.md).

#### 3.36 Vulnerability scanning is performed at the cloud IP level {#ip-level}

We recommend that customers should scan their hosts for vulnerabilities by themselves. Cloud resources support the installation of custom virtual images of vulnerability scanners or software agents on hosts. There are many paid and free scanning solutions on the market.

Network scanners scan hosts that are accessible over a network. Generally, authentication can be configured on network scanners. 

Examples of free network scanners:
- [Nmap](https://nmap.org/)
- [OpenVAS](https://www.openvas.org/)
- [OWASP ZAP](https://www.zaproxy.org/)

Example of a free scanner operating as an agent on hosts: [Wazuh](https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/how_it_works.html). Wazuh can also be used as a host-based intrusion detection system (IDS).

You can also use a [solution](https://yandex.cloud/en/marketplace/products/scanfactory/scanfactory-saas) from Cloud Marketplace.

| Requirement ID | Severity |
| --- | --- |
| ENV34 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 3.37 External security scans are performed according to the Yandex Cloud rules {#external-security-scans}

Customers hosting their own software in Yandex Cloud can perform external security scans for the hosted software, including penetration tests. You can run your own scans or use contractors. For more information, see [Rules for performing external security scans](../compliance/pentest.md).

| Requirement ID | Severity |
| --- | --- |
| ENV35 | Informational |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 3.38 The security updates process has been set up {#security-updates}

Customers must perform security updates themselves within their [scope of responsibility](../respons.md). Various automated tools are available for centralized automated OS and software updates.

Yandex Cloud publishes [security bulletins](../security-bulletins/index.md) to notify customers of newly discovered vulnerabilities and security updates.

| Requirement ID | Severity |
| --- | --- |
| ENV36 | Medium |

### Backups {#backup}

#### 3.39 Cloud Backup or scheduled snapshots are used {#snapshot}

Make sure to back up all VMs in your organization using one of these options:
* Scheduled snapshots
* Cloud Backup

| Requirement ID | Severity |
| --- | --- |
| ENV37 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the VMs in.
  1. In the list of services, select Compute Cloud.
  1. Make sure that the scheduled snapshot policy is set up on the VMs.
  1. In the list of services, select Cloud Backup.
  1. Make sure that it is enabled.

{% endlist %}


### Yandex API Gateway {#api-gateway}

An API gateway is an interface for working with services in Yandex Cloud or on the internet. A gateway is specified declaratively using [OpenAPI 3.0](https://www.openapis.org/what-is-openapi) specifications.


#### 3.40 Access management in API Gateway is configured {#api-gateway-access-managment}

Yandex Cloud users can only perform operations on resources within the permissions of the [roles](../../iam/concepts/access-control/roles.md) assigned to them. With no roles assigned, almost no operations are allowed.

[Yandex Identity and Access Management](../../iam/index.md) checks all operations in Yandex Cloud. If an entity does not have required permissions, IAM returns an error.

Make sure that the Yandex Cloud user has access to the [API Gateway](../../api-gateway/concepts/index.md) resources. The user needs proper roles for it. Roles for an API gateway can be issued by users with the `api-gateway.admin` role or one of the following roles:

* `admin`
* `resource-manager.admin`
* `organization-manager.admin`
* `resource-manager.clouds.owner`
* `organization-manager.organizations.owner`

| Requirement ID | Severity |
| --- | --- |
| ENV48 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud and folder to check the API gateway access in.
  1. Select the **Access permissions** tab.
  1. Make sure that users have the roles required to access the gateway.

{% endlist %}

You can also assign a role for an API gateway via the Yandex Cloud [CLI](../../cli/cli-ref/serverless/cli-ref/api-gateway/add-access-binding.md) or [API](../../api-gateway/api-ref/apigateway/authentication.md).

To learn more about roles in API Gateway, see [Roles available in the service](../../api-gateway/security/index.md#roles-list).


#### 3.41 Networking is configured in API Gateway {#networking}

By default, an API gateway resides in an isolated IPv4 network with a [NAT gateway](../../vpc/concepts/gateways.md) enabled. For this reason, it can only access public IPv4 addresses.

For the gateway to have access not just to the internet but to the user resources as well, [specify](../../api-gateway/operations/api-gw-network-add.md) the [cloud network](../../vpc/concepts/network.md#network) those resources reside in in the API gateway settings.

A cloud network must have:
* [Subnets](../../vpc/concepts/network.md#subnet) in all [availability zones](../../overview/concepts/geo-scope.md).
* At least one resource with an IP address in the specified cloud network.

{% note info %}

If the network does not meet the conditions above, the service does not guarantee it will function properly.

{% endnote %}

If you specify a network in the API gateway settings, this will create an auxiliary subnet with addresses from the `198.19.0.0/16` range in each availability zone. The API gateway will get an IP address from the respective subnet and will have access to all network resources.

| Requirement ID | Severity |
| --- | --- |
| ENV49 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. Make sure the cloud network is specified in the **Overview** section.

{% endlist %}

**Guides and solutions to use**:

If the API gateway does not require access to resources from the specified cloud network, delete it from the gateway settings. For more information, see [Updating an API gateway](../../api-gateway/operations/api-gw-update.md).

#### 3.42 Recommendations for using custom domains are followed {#using-own-domain}

API Gateway is integrated with the Certificate Manager domain management system.

If you are using your own domains in API Gateway with confirmed permissions when accessing the API:

* Regularly [check the validity](../../certificate-manager/operations/managed/cert-update.md) of the TLS certificate linked to your domain.
* Use [TLS](../../storage/concepts/tls.md) version 1.2 or higher.
* Use [additional protection tools](../../api-gateway/concepts/extensions/index.md), such as intrusion detection and DDoS protection systems.

| Requirement ID | Severity |
| --- | --- |
| ENV50 | Informational |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check of the TLS version and the validity of the TLS connection certificate.

{% endlist %}

For more information about domains, see [Integration of the domain management system with Yandex Cloud services](../../certificate-manager/concepts/domains/services.md).

#### 3.43 Recommendations for using Websocket are followed {#websocket}

For two-way asynchronous communication between clients and an API gateway, API Gateway supports the [WebSocket](https://en.wikipedia.org/wiki/WebSocket) protocol. To connect to an API gateway using WebSocket, you can use a service domain allocated when creating the API gateway or any other domain added to the API gateway.

You can manage web sockets using the [API](../../api-gateway/api-ref/websocket/authentication.md) that receives information about a connection, sends data to the client side, and closes the connection.

We recommend that you use the following when connecting to the API gateway via WebSocket:
* [TLS](../../storage/concepts/tls.md) version 1.2 or higher (regularly [check the validity](../../certificate-manager/operations/managed/cert-update.md) of the TLS connection certificate).
* OpenAPI 3.0 [authentication and authorization mechanisms](#authorization).
* [API gateway specification extensions](../../api-gateway/concepts/extensions/index.md), which can help you enhance your virtual environment security.

| Requirement ID | Severity |
| --- | --- |
| ENV51 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. Set up integrations in the OpenAPI specification using the following operations: `x-yc-apigateway-websocket-message`, `x-yc-apigateway-websocket-connect`, or `x-yc-apigateway-websocket-disconnect`.

{% endlist %}

For more information, see [Working with an API gateway via WebSocket](../../api-gateway/tutorials/api-gw-websocket.md).

#### 3.44 API gateway interaction with {yandex-cloud} services is configured {#inter-cloud-services}

Make sure that security enhancement extensions were added to the API Gateway specification.

| Requirement ID | Severity |
| --- | --- |
| ENV52 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. OpenAPI 3.0 is used in the **Specification** section.

{% endlist %}

#### 3.45 API gateway security is enhanced with extensions {#inter-cloud-services}

The `x-yc-apigateway:smartWebSecurity` extension uses [Yandex Smart Web Security profile](../../smartwebsecurity/concepts/profiles.md) rules with conditions for actions to apply to HTTP requests received by the protected resource:
* The [basic rules](../../smartwebsecurity/concepts/rules.md#base-rules) block unwanted traffic.
* The [Smart Protection](../../smartwebsecurity/concepts/rules.md#smart-protection-rules) rule for the whole traffic provides the fullest and transparent protection.
* [Advanced Rate Limiter](../../smartwebsecurity/concepts/arl.md) sets request number limits, thus reducing workload on web apps and protecting the backend from depleting resources.
* The [WAF](../../smartwebsecurity/concepts/waf.md) profile analyzes web app's incoming HTTP requests based on pre-configured rules for DoS/DDoS protection.

| Requirement ID | Severity |
| --- | --- |
| ENV53 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. Make sure the **Specification** section uses the `x-yc-apigateway:smartWebSecurity` extension, which protects the API gateway as well as your application, function, or container from DDoS attacks based on the Yandex Smart Web Security profile rules.

{% endlist %}

#### 3.46 Authorization in the API gateway is configured {#authorization}

We recommend using the OpenAPI 3.0 authentication and authorization mechanisms that are standard for API Gateway. Currently, you can use authorization via a function and via a JWT.

* [Authorization via Cloud Functions](../../api-gateway/concepts/extensions/function-authorizer.md). For HTTP request authorization, API Gateway calls the `x-yc-apigateway-authorizer:function` extension. Currently these three types are supported: `HTTP Basic`, `HTTP Bearer`, and `API Key`.
* [Authorization via a JWT](../../api-gateway/concepts/extensions/jwt-authorizer.md). For HTTP request authorization, API Gateway validates a token and verifies its signature using the following supported public keys: address, place, fields, body, time, caching mode, and cache retention period.

| Requirement ID | Severity |
| --- | --- |
| ENV54 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. Make sure that the **Specification** section has the `x-yc-apigateway-authorizer:jwt` or `x-yc-apigateway-authorizer:function` extension configured.

{% endlist %}

#### 3.47 Authorization context is used {#auth-context}

We recommend using an [authorization context](../../api-gateway/concepts/extensions/function-authorizer.md#context) in the [request](../../functions/concepts/function-invoke.md#request) inside the `requestContext.authorizer` field. This helps preserve data integrity and prevents unauthorized access.

| Requirement ID | Severity |
| --- | --- |
| ENV55 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure an authorization context is configured in the API gateway specification settings when the `x-yc-apigateway-authorizer:function` extension is used.

{% endlist %}

#### 3.48 Logging is on {#api-logs}

We recommend to keep logging enabled when creating an API gateway. For more information, see [Writing to the execution log in API Gateway](../../api-gateway/operations/api-gw-logs-write.md).

| Requirement ID | Severity |
| --- | --- |
| ENV56 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the folder containing the API gateway.
  1. In the list of services, select **API Gateway**.
  1. Select the API gateway you need from the list.
  1. Make sure that the **Write logs** option is enabled in the **Logging** section and that the gateway logging level and destination are set up.

{% endlist %}

Use audit logs that go to [Yandex Audit Trails](../../api-gateway/at-ref.md) for the API gateway performance analysis.

# Requirements for data encryption and key and secret management

## 4. Data encryption and key management {#data-encryption-and-key-management}


Yandex Cloud provides built-in encryption features for a number of services. It is the customer's responsibility to enable encryption in these services and implement encryption in other components for processing critical data. Data encryption and encryption key management are performed by [Key Management Service](../../kms/index.md) (KMS).

Yandex Cloud APIs support cipher suites in specific TLS versions that are compliant with PCI DSS and other standards.

### At-rest encryption {#at-rest}

By default, all user data at rest is encrypted at the Yandex Cloud level. Encryption at the Yandex Cloud level implements one of the best practices for protecting user data and is performed using Yandex Cloud keys.

If your corporate information security policy specifies key size and [rotation](../../kms/operations/key.md#rotate) frequency requirements, you can encrypt data using your own keys. You can do this by using KMS and its integration with other Yandex Cloud services or by implementing Data plane encryption yourself.

Yandex Cloud provides at-rest encryption for the following services:
* Compute Cloud (VM disk encryption)
* Object Storage (bucket encryption)
* Managed Service for Kubernetes (secret encryption)

#### 4.1 Disk encryption is enabled in Yandex Compute Cloud {#compute-encryption}

| Requirement ID | Severity |
| --- | --- |
| CRYPT17 | High |

**Searching for encrypted VM disks:**

{% list tabs group=instructions %}

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run this command to search for encrypted disks:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      CLOUDS=$(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id')

      echo "Encrypted disks:"
      for CLOUD_ID in $CLOUDS
        do
        FOLDERS=$(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id')
        for FOLDER_ID in $FOLDERS
        do
          DISKS=$(yc compute disk list --folder-id $FOLDER_ID --format=json | jq -r '.[] | select(.kms_key.key_id)' | jq -r '.id')

          if [[ -n "$DISKS" ]]; then
            for DISK in $DISKS
            do
              DISKDATA=$(yc compute disk get --id $DISK --folder-id $FOLDER_ID --format=json)
              VM_ID=$(echo $DISKDATA| jq -r '.instance_ids[]')

              VMDATA=""

              if [[ -n "$VM_ID" ]]; then
                VMDATA=$(yc compute instance get --id $VM_ID --folder-id $FOLDER_ID --format=json)
              fi

              echo "------------"
              echo "CLOUD_ID:" $CLOUD_ID
              echo "FOLDER_ID:" $FOLDER_ID
              echo "DISK_ID: "$(echo $DISKDATA | jq -r '.id')
              echo "DISK_NAME: "$(echo $DISKDATA | jq -r '.name')
              echo "DISK_TYPE: "$(echo $DISKDATA | jq -r '.type_id')
              echo "DISK_ZONE: "$(echo $DISKDATA | jq -r '.zone_id')
              echo "DISK_SIZE: "$(echo $DISKDATA | jq -r '.size')
              echo "DISK_KEY: "$(echo $DISKDATA | jq -r '.kms_key')

              if [[ -n "$VMDATA" ]]; then
                echo "VM_ID: "$(echo $VMDATA | jq -r '.id')
                echo "VM_NAME: "$(echo $VMDATA | jq -r '.name')
                echo "VM_STATUS: "$(echo $VMDATA | jq -r '.status')
              fi
              echo "------------"
            done
          fi
        done
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id=$ORG_ID --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $EncryptedVMs = @()
      $VMDisks = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $FolderDiskList = yc compute disk list --folder-id $Folder.id --format=json | ConvertFrom-Json | where{$_.kms_key}

          foreach($Disk in $FolderDiskList) {
            $VMData = $null

            if($Disk.instance_ids) {
              $VMData = yc compute instance get --id $Disk.instance_ids --folder-id $Folder.id --format=json | ConvertFrom-Json
            }

            $EncryptedVMs += $Disk | Select @{n="CloudID";e={$Cloud.CloudID}}, @{n="CloudName";e={$Cloud.CloudName}}, @{n="FolderID";e={$Folder.id}}, @{n="FolderName";e={$Folder.name}}, @{n="DiskID";e={$_.id}}, @{n="DiskName";e={$_.name}}, @{n="DiskType";e={$_.type_id}}, zone_id, @{n="DiskSize";e={$_.size/1GB}}, kms_key, @{n="VMID";e={$VMData.id}}, @{n="VMName";e={$VMData.name}}, @{n="VMStatus";e={$VMData.status}}
          }
        }
      }

      $EncryptedVMs
      ```

      {% endcut %}

{% endlist %}

Check the list of returned encrypted disks. If the list matches your threat model, no additional actions are required. If you find that some disks are missing from the list, follow the steps below:

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder containing the disk.
  1. In the list of services, select **Compute Cloud**.
  1. In the left-hand panel, select ![image](../../_assets/console-icons/hard-drive.svg) **Disks** and find the disk you want to encrypt in the list.

      If the disk is attached to a VM and the VM is on, it is recommended to turn it off.
  1. [Create](../../compute/operations/disk-control/create-snapshot.md) a snapshot of the disk.
  1. Create a new encrypted disk from the snapshot:

      1. Click **Create disk**.
      1. In the dialog that opens:
          1. Name the disk in the **Name** field.
          1. Specify the preferred [availability zone](../../overview/concepts/geo-scope.md) in the **Availability zone** field.
          1. In the **Contents** field, go `Snapshot` and select the snapshot you created earlier.
          1. In the **Type** field, specify the preferred [disk type](../../compute/concepts/disk.md#disks-types).
          1. Under **Encryption**, enable **Encrypted disk** and select or create a KMS [encryption key](../../kms/concepts/key.md).
          1. Click **Create disk**.
  1. After you create an encrypted disk, attach it to the VM instead of the unencrypted one.

{% endlist %}

#### 4.2 At-rest encryption with a KMS key is enabled in Yandex Object Storage {#storage-kms}

To protect critical data in Yandex Object Storage, we recommend using bucket server-side encryption with Yandex Key Management Service keys. This encryption method protects against accidental or intentional publication of the bucket content on the web. For more information, see [Encryption](../../storage/concepts/encryption.md) in the Object Storage documentation.

| Requirement ID | Severity |
| --- | --- |
| CRYPT1 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the buckets in.
  1. In the list of services, select **Object Storage**.
  1. Go to the bucket settings.
  1. Go to the **Encryption** tab.
  1. Make sure that encryption is enabled and the KMS encryption key is specified.
  1. If encryption is enabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. [Configure](../../storage/tools/aws-cli.md) the AWS CLI to work with a cloud.
  1. Run the command below to check whether encryption is enabled:

     ```bash
     aws --endpoint-url=https://storage.yandexcloud.net/ \
     s3api get-bucket-encryption \
     --bucket <bucket_name>
     ```

  1. If encryption is enabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

Configure bucket encryption using the [guide](../../storage/operations/buckets/encrypt.md).

### Encryption in transit {#in-transit}

In most cases, you can only connect to Yandex Cloud services over HTTPS. However, some scenarios allow data plane access to services over HTTP, without connection encryption at the application level. In all these scenarios, the user can choose the protocol to be used for data plane operations in the service settings: HTTP or HTTPS, and specify their own TLS certificate if HTTPS is selected.

{% note info %}

When working with (or connecting to) Yandex Cloud APIs, make sure to use TLS 1.2 or higher, since its prior versions are vulnerable.

For example, by using the gRPC interfaces of Yandex Cloud, you can enforce TLS 1.2 or higher. That's because gRPC is based on HTTP/2 where TLS 1.2 is the minimum supported TLS version.

Support for legacy TLS protocols in Yandex Cloud services will [gradually be discontinued](../security-bulletins/index.md).

{% endnote %}

Yandex Cloud allows you to use your own TLS certificates for the following services:
* Object Storage
* Application Load Balancer
* API Gateway
* Cloud CDN

#### 4.3 HTTPS for static website hosting is enabled in Yandex Object Storage {#storage-https}

[Object Storage](../../storage/index.md) supports secure connections over HTTPS. You can upload your own security certificate if a connection to your Object Storage website requires HTTPS access. Integration with [Certificate Manager](../../certificate-manager/index.md) is also supported. See the instructions in the Object Storage documentation:
* [Configuring HTTPS](../../storage/operations/hosting/certificate.md)
* [Bucket](../../storage/concepts/bucket.md)

When using [Object Storage](../../storage/index.md), make sure that support for TLS protocols below version 1.2 is disabled at the client level. Use the [`aws:securetransport`](../../storage/s3/api-ref/policy/conditions.md) bucket policy to make sure running without TLS is disabled for the bucket.

| Requirement ID | Severity |
| --- | --- |
| CRYPT2 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select **Object Storage** from the list of services and go to the bucket in question.
  1. In the left-hand panel, select ![image](../../_assets/console-icons/persons-lock.svg) **Security**.
  1. Select the **HTTPS** tab.
  1. Make sure you have enabled access over HTTPS and specified a TLS certificate.
  1. If access over HTTPS is enabled, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  Run the command below by specifying the bucket name:

  ```bash
  yc storage bucket get-https <bucket_name>
  ```

  If the command returns a certificate ID in the `certificate_id` field, it means access over HTTPS is enabled and the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

[Enable](../../storage/operations/hosting/certificate.md) access over HTTPS if the bucket is used to host a static website.

#### 4.4 Yandex Application Load Balancer uses HTTPS {#alb-https}

[Application Load Balancer](../../application-load-balancer/index.md) supports an HTTPS listener with a [certificate](../../certificate-manager/concepts/imported-certificate.md) uploaded from Certificate Manager. See [listener setup description](../../application-load-balancer/concepts/application-load-balancer.md#listener) in the Yandex Application Load Balancer documentation.

| Requirement ID | Severity |
| --- | --- |
| CRYPT3 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}
 
  1. In the management console, select the cloud or folder to check the load balancers in.
  1. In the list of services, select **Application Load Balancer**.
  1. Go to the load balancer settings.
  1. Make sure that **HTTPS** is specified for the load balancer.
  1. If HTTPS is specified, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all load balancers without HTTPS:

      {% cut "**Bash**" %}

      ```bash
      export ORG_ID=<organization_ID>
      CLOUDS=$(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id')
      for CLOUD_ID in $CLOUDS
      do
        FOLDERS=$(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id')
        for FOLDER_ID in $FOLDERS
        do
          yc application-load-balancer load-balancer list --folder-id $FOLDER_ID --format=json | jq -r '.[] | select(.listeners[0].tls | not)' | jq -r '.'
        done
      done
      ```

      {% endcut %}

      {% cut "**PowerShell**" %}

      ```powershell
      $ORG_ID = "<organization_ID>"

      $Clouds = yc resource-manager cloud list --organization-id $ORG_ID --format=json | ConvertFrom-Json | Select @{n="CloudID";e={$_.id}}, created_at, @{n="CloudName";e={$_.name}}, organization_id

      $ALBWithoutTLS = @()

      foreach ($Cloud in $Clouds) {
        $Folders = yc resource-manager folder list --cloud-id $Cloud.CloudID --format=json | ConvertFrom-Json

        foreach($Folder in $Folders) {
          $ALBWithoutTLS += yc application-load-balancer load-balancer list --folder-id $Folder.id --format=json | ConvertFrom-Json | where{!$_.listeners.tls}
        }
      }

      $ALBWithoutTLS
      ```

      {% endcut %}

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

Enable an HTTPS listener using [this guide](../../application-load-balancer/tutorials/tls-termination/index.md).

#### 4.5 Yandex API Gateway uses HTTPS and its own domain {#api-gateway-https}

[API Gateway](../../api-gateway/index.md) supports secure connections over HTTPS. You can link your own domain and upload your own security certificate to access your [API gateway](../../api-gateway/concepts/index.md) over HTTPS.

| Requirement ID | Severity |
| --- | --- |
| CRYPT4 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the gateways in.
  1. In the list of services, select **API Gateway → Gateway settings → Domains**.
  1. Make sure the domain and certificate are enabled.
  1. If the domain and certificate are active, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all API gateways without any domains and certificates enabled:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for APIGW in $(yc serverless api-gateway list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc serverless api-gateway get --id $APIGW --format json | jq -r '. | select(.attached_domains[0].certificate_id | not)' | jq -r '.id'
     done;
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

1. In the management console, select the cloud or folder to enable domains and certificates in.
1. In the list of services, select **API Gateway → Gateway settings → Domains**.
1. Enable the domains and certificates.

#### 4.6 Yandex Cloud CDN uses HTTPS and its own SSL certificate {#cdn-https}

[Cloud CDN](../../cdn/index.md) supports secure connections to origins over HTTPS. You can also upload your own security certificate to access your [CDN resource](../../cdn/concepts/resource.md) over HTTPS.

| Requirement ID | Severity |
| --- | --- |
| CRYPT5 | Low |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the resources in.
  1. In the list of services, select **Cloud CDN**.
  1. Go to the resource settings, the **Additional** tab.
  1. Make sure the **Origin request protocol** field is set to **HTTPS**.
  1. Make sure the **Certificate** field specifies your own certificate or a **Let’s encrypt** certificate.
  1. If HTTPS and your own certificate are specified, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all resources without any certificates and HTTPS to origins enabled:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for CDN in $(yc cdn resource list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc cdn resource get --id $CDN --format json | jq -r '. | select(.origin_protocol=="HTTPS" and .ssl_certificate.type=="CM" | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

[Enable](../../cdn/operations/resources/configure-basics.md) a certificate and HTTPS using the instructions.

### Providing encryption on your own {#self-encryption}

**When using services without built-in encryption, it is the customer's responsibility to ensure that critical data is encrypted.**

#### 4.7 Data encryption at the application level is used {#self-data-app}

For client-side encryption before uploading data to a Yandex Object Storage bucket, you can use the following approaches:
* Integrating Object Storage with the Key Management Service service for client-side encryption. For more information, see "Recommended cryptographic libraries".
* Using third-party client-side encryption libraries prior to sending data to Object Storage. If you use third-party data encryption libraries and your own key management methods, make sure your operation scheme, algorithms, and key lenghts comply with regulatory requirements.

For client-side encryption, we recommend that you use the following libraries:
* AWS Encryption SDK and its [KMS integration](../../kms/tutorials/encrypt/aws-encryption-sdk.md).
* Google Tink and its [KMS integration](../../kms/tutorials/encrypt/google-tink.md).
* [Yandex Cloud SDK](../../kms/tutorials/encrypt/sdk.md) with any other cryptographic library compatible with PCI DSS or any standards used in your company.

For a comparison of libraries, see the KMS documentation, [Which encryption method should I choose?](../../kms/tutorials/encrypt/index.md).

| Requirement ID | Severity |
| --- | --- |
| CRYPT7 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that the stored data is encrypted.

{% endlist %}

#### 4.8 Encryption of disks and virtual machine snapshots is used {#managed-vm-kms}

By default, all data on Yandex Compute Cloud disks is encrypted at the storage database level using a system key. This protects your data from being compromised in the event of a physical theft of disks from the Yandex Cloud data centers. 

We also recommend encrypting disks and [disk snapshots](../../compute/concepts/snapshot.md) using Yandex Key Management Service custom [symmetric keys](../../kms/concepts/key.md). This approach allows you to:
* Protect against the potential threats of data isolation breach and compromise at the virtual infrastructure level.
* Control the encryption and lifecycle of KMS keys, as well as manage them. For more information, see [Key management](../../kms/operations/key.md).
* Improve access control to the data on your disk by setting permissions for KMS keys. For more information, see [Configuring access permissions for a symmetric encryption key](../../kms/operations/key-access.md).
* Use Yandex Audit Trails to track encryption and decryption operations performed using your KMS key. For more information, see [Key usage audit](../../kms/concepts/index.md#keys-audit).

You can encrypt the following types of disks:
* Network SSD (`network-ssd`)
* Network HDD (`network-hdd`)
* Non-replicated SSD (`network-ssd-nonreplicated`)
* Ultra high-speed network storage with three replicas (SSD) (`network-ssd-io-m3`)

| Requirement ID | Severity |
| --- | --- |
| CRYPT8 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  When [creating a disk](../../compute/operations/disk-create/empty.md), make sure to enable **Encrypted disk**.

{% endlist %}

**Guides and solutions to use:**

[Encrypt](../../compute/operations/disk-control/disk-encrypt.md) the disk of your Yandex Compute Cloud VM.

### Managing keys {#keys}

We recommend using [Key Management Service](../../kms/tutorials/encrypt/sdk.md) for data encryption and key management. Made to protect data in the Yandex Cloud infrastructure, KMS can also encrypt and decrypt any of your data.

KMS uses AES-GCM encryption mode. You can select the key length: 128/192/256 and set up the preferred key rotation period.

#### 4.9 Key Management Service keys are stored in a hardware security module (HSM) {#keys-hsm}

In production environments, we recommend using separate keys whose every cryptographic operation will only be handled inside a HSM. For more information, see [Hardware security module (HSM)](../../kms/concepts/hsm.md).

To use the HSM, when creating a key, select AES-256 HSM as the algorithm type. The HSM will handle all operations with this key internally, and no additional actions are required.

We recommend using HSMs for KMS keys to enhance the security level.

| Requirement ID | Severity |
| --- | --- |
| CRYPT9 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the keys in.
  1. In the list of services, select **Key Management Service**.
  1. Go to the **Keys** tab.
  1. Make sure the **Encryption algorithm** field is set to **AES-256 HSM**.
  1. If AES-256 HSM is specified, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all of your organization's KMS keys and their encryption algorithms:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do yc kms symmetric-key list --folder-id=$FOLDER_ID --format json | jq -r '.[] | "KEY_ID " + .id + "FOLDER_ID " + .folder_id + "ALGORITM_ID " + .default_algorithm' 
     done;
     done
     ```

  1. If the encryption algorithm contains AES-256 HSM, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

[Set](../../kms/operations/symmetric-encryption.md) the encryption algorithm for KMS keys to AES-256 HSM.

#### 4.10 Permissions to manage keys in KMS are granted to controlled users {#keys-controlled-users}

To access the KMS service, you need an [IAM token](../../iam/concepts/authorization/iam-token.md).

To automate operations with KMS, we recommend that you create a [service account](../../iam/concepts/users/service-accounts.md) and run commands and scripts under it. If you use VMs, get an IAM token for your service account using the mechanism of [assigning a service account](../../compute/operations/vm-connect/auth-inside-vm.md) to your VM. For other ways to get an IAM token for your service account, see the IAM documentation, [Getting an IAM token for a service account](../../iam/operations/iam-token/create-for-sa.md).

We recommend that you grant granular permissions for specific keys in the KMS service to your users and service accounts. For more information, see the KMS documentation, [Access management in Key Management Service](../../kms/security/index.md).

For more information about security measures for access control, see [Authentication and access control](authentication.md).

To check the KMS key access permissions, check who has access permissions for:
* Organization, cloud, or folder (such permissions as `admin`, `editor`, `kms.admin`, `kms.editor`, or `kms.keys.encrypterDecrypter`).
* Keys (`kms.keys.encrypterDecrypter` and `kms.editor`).

| Requirement ID | Severity |
| --- | --- |
| CRYPT10 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}
 
  1. In the management console, select the cloud or folder to check the key access permissions in.
  1. Click the **Access permissions** tab.
  1. Make sure the `admin`, `editor`, `kms.admin`, `kms.editor`, and `kms.keys.encrypterDecrypter` roles are only granted to controlled users.
  1. You can check the actual key access permissions only via the CLI.

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for accounts at the organization level:

     ```bash
     export ORG_ID=<organization ID>
     yc organization-manager organization list-access-bindings --id=${ORG_ID} --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="kms.admin" or .role_id=="kms.editor" or .role_id=="kms.keys.encrypterDecrypter")'
     ```

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  1. Find accounts with roles assigned at the cloud level:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do yc resource-manager cloud list-access-bindings --id=$CLOUD_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="kms.admin" or .role_id=="kms.editor" or .role_id=="kms.keys.encrypterDecrypter")'
     done
     ```

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  1. Run the command below to search for accounts with primitive roles assigned at the level of all folders in your clouds:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); \
     do yc resource-manager folder list-access-bindings --id=$FOLDER_ID --format=json | jq -r '.[] | select(.role_id=="admin" or .role_id=="editor" or .role_id=="kms.admin" or .role_id=="kms.editor" or .role_id=="kms.keys.encrypterDecrypter")' && echo $FOLDER_ID
     done;
     done
     ```

  1. If there are no accounts in the list, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

  1. Find accounts with roles assigned at the key level:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for KEY in $(yc kms symmetric-key list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc kms symmetric-key list-access-bindings --id $KEY --format json 
     done;
     done;
     done
     ```

{% endlist %}

**Guides and solutions to use:**

Check out who is granted access to KMS keys.

#### 4.11 For KMS keys, rotation is enabled {#keys-rotation}

To improve the security of your infrastructure, we recommend that you categorize your encryption keys into two groups:
* Keys for services that process critical data but do not store it, such as Message Queue or Cloud Functions.
* Keys for services storing critical data, e.g., Managed Services for Databases.

For the first group, we recommend that you set up automatic key rotation with a rotation period longer than the data processing period in these services. When the rotation period expires, the old key versions must be deleted. In the case of automatic rotation and the deletion of old key versions, previously processed data cannot be restored and decrypted.

For data storage services, we recommend that you either manually rotate keys or use automatic key rotation, depending on your internal procedures for processing critical data.

A secure value for AES-GCM mode is encryption using 4294967296 (= 2<sup>32</sup>) blocks. Having reached this number of encrypted blocks, you need to create a new DEK version. For more information about the AES-GCM operating mode, see the [NIST materials](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf).

{% note info %}

Destroying any version of a key means destroying all data encrypted with it. You can protect a key against deletion by setting the deletionProtection parameter. However, it does not protect against deleting individual versions.

{% endnote %}

For more information about key rotation, see the KMS documentation, [Key version](../../kms/concepts/version.md).

| Requirement ID | Severity |
| --- | --- |
| CRYPT11 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the keys in.
  1. In the list of services, select **Key Management Service**.
  1. Go to the key settings.
  1. Find the **Rotation period** parameter.
  1. If the parameter is set to any value different from **No rotation**, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all of your organization's KMS keys and their encryption algorithms:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do yc kms symmetric-key list --folder-id=$FOLDER_ID --format=json | jq -r '.[] | select(.rotation_period | not)' | jq -r '.id' 
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

Set the key rotation period.

#### 4.12 The deletion protection is enabled for KMS keys {#keys-deletion-protection}

Deleting a KMS key always means destroying data. Therefore, make sure to protect the keys against accidental deletion. KMS has the necessary feature.

| Requirement ID | Severity |
| --- | --- |
| CRYPT12 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the keys in.
  1. In the list of services, select **Key Management Service**.
  1. Go to the key settings.
  1. Find the **Deletion protection** parameter.
  1. If it is set to **Yes**, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to output the list of all KMS keys without protection against deletion:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do yc kms symmetric-key list --folder-id=$FOLDER_ID --format=json | jq -r '.[] | select(.deletion_protection | not)' | jq -r '.id' 
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

Enable deletion protection.

### Managing secrets {#secrets}

Critical data and access secrets (authentication tokens, API keys, and encryption keys, etc.) should not be used in plain text in code, cloud object names and descriptions, VM metadata, etc. Use secret storage services instead, e.g., Lockbox or HashiCorp Vault.

#### 4.13 The organization uses Yandex Lockbox for secure secret storage {#secrets-lockbox}

Critical data and access secrets (authentication tokens, API keys, and encryption keys, etc.) should not be used in plain text in code, cloud object names and descriptions, VM metadata, etc. Use secret storage services instead, e.g., Lockbox.

Lockbox securely stores secrets in an encrypted form only. Encryption is performed using KMS. For secret access control, use service roles.

You can learn how to use the service in the [Lockbox documentation](../../lockbox/index.md).

{% note info %}

When working in Terraform, we recommend using a script to [fill in](../../terraform/resources/lockbox_secret_version.md) the contents of a secret. This ensures that its contents do not remain in the `.tfstate` file.

{% endnote %}

| Requirement ID | Severity |
| --- | --- |
| CRYPT13 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the secrets in.
  1. In the list of services, select **Lockbox**.
  1. Make sure that at least one Lockbox secret is used.
  1. If Lockbox is used, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. See what organizations are available to you and write down the ID you need:

     ```bash
     yc organization-manager organization list
     ```

  1. Run the command below to search for at least one Lockbox secret:
 
     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do yc lockbox secret list --folder-id=$FOLDER_ID --format=json 
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to _Guides and solutions to use_.

{% endlist %}

**Guides and solutions to use:**

Keep secrets in Lockbox.

#### 4.14 For Serverless Containers and Cloud Functions, Lockbox secrets are used {#secrets-serverless-functions}

When working with Serverless Containers or Cloud Functions, it is often necessary to use a secret (such as a token or password).

If you specify secret information in environment variables, it can be viewed by any cloud user with permissions to view and use a function, which causes information security risks.

We recommend using Serverless integration with Lockbox for that. You can specify a particular secret from Yandex Lockbox and a service account with access permissions for this secret to use it in a function or container. 

Make sure that the secrets are used as described above. 

| Requirement ID | Severity |
| --- | --- |
| CRYPT14 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the functions in.
  1. In the list of services, select **Cloud Functions**.
  1. Go to the function settings, the **Editor** tab.
  1. Find the **Lockbox secrets** parameter.
  1. If the parameters of each object specify **Lockbox** secrets or there are no environment variables with secret data, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Performing a check via the CLI {#cli}

  1. Run the command below to search for all the cloud functions that use no Lockbox secrets and make sure that these functions use no secret data in environment variables:

     ```bash
     export ORG_ID=<organization ID>
     for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
     do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
     do for VER in $(yc serverless function version list --folder-id=$FOLDER_ID --format=json | jq -r '.[].id'); \
     do yc serverless function version get $VER --format=json | jq -r '. | select(.secrets | not)' | jq -r '.id' 
     done;
     done;
     done
     ```

  1. If an empty list is output, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

{% endlist %}

**Guides and solutions to use:**

Delete secret data from env and use the Lockbox integration functionality:
* [Providing Yandex Lockbox secrets to a container](../../serverless-containers/operations/lockbox-secret-transmit.md).
* [Providing Yandex Lockbox secrets to a function](../../functions/operations/function/lockbox-secret-transmit.md).

#### 4.15 When working with Container Optimized Image, secret encryption is used {#secrets-coi}

KMS supports the encryption of secrets used in a Terraform configuration, e.g., for transferring secrets to a VM in encrypted form. See [Encrypting secrets in Hashicorp Terraform](../../kms/tutorials/terraform-secret.md) in the KMS documentation. It is not safe to openly provide secrets through environment variables, because they are displayed in the VM properties.

| Requirement ID | Severity |
| --- | --- |
| CRYPT15 | High |

**Guides and solutions to use:**

[Encrypting secrets in Terraform to transfer them to a VM from a Container Optimized Image](https://github.com/yandex-cloud-examples/yc-encrypt-coi-secrets).

For other recommendations on how to use Terraform safely, see [Secure configuration: Terraform](virtualenv-safe-config.md#tf-using).

#### 4.16 There is a guide for cloud administrators on handling compromised secrets {#secrets-scanning}

In Yandex Cloud, the [Secret Scanning Service](../operations/search-secrets.md) is enabled for everyone by default.
Sources for detecting publicly available cloud structured secrets:

* [Yandex Cloud secret scanning partner program](../operations/search-secrets.md#leak-detection-affiliate-program).
* [GitHub Secret scanning partner program](../operations/search-secrets.md#github-secret-scanning).
* [GitLab Secret Detection](../operations/search-secrets.md#gitlab-secret-detection).
* [Yandex search index](../operations/search-secrets.md#secret-is-leaked).
* [Helm charts in Yandex Cloud Marketplace](../operations/search-secrets.md#helm-charts).

The following cloud secrets are detected:

* [API keys](../../iam/concepts/authorization/api-key.md)
* [IAM Cookies](../../iam/concepts/authorization/cookie.md)
* [IAM tokens](../../iam/concepts/authorization/iam-token.md)
* [Static access keys](../../iam/concepts/authorization/access-key.md)
* [OAuth token](../../iam/concepts/authorization/oauth-token.md)

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

* [SmartCaptcha server keys](../../smartcaptcha/concepts/keys.md)
* [Refresh tokens](../../iam/concepts/authorization/refresh-token.md)
* [OIDC app secrets](../../organization/concepts/applications.md#oidc-secret)

The service automatically notifies a customer of any found secrets belonging to their infrastructure:

* By email
* Using Yandex Audit Trails [events](../../audit-trails/concepts/events.md)

| Requirement ID | Severity |
| --- | --- |
| CRYPT16 | Informational |

**Guides and solutions to use:**

Make sure that:

* [Contact information of the person in charge of an organization is valid](authentication.md#org-contacts).
* [Yandex Audit Trails is enabled at the organization level](audit-logs.md#audit-trails).
* The administrator has read the [guide](../operations/search-secrets.md#secret-is-leaked) to follow if secrets are compromised.

# Requirements for collecting, monitoring, and analyzing audit logs

## 5. Collecting, monitoring, and analyzing audit logs {#audit--logs}


An audit log is a record of all events in the system, including access to it and operations performed. By collecting and verifying audit logs, you can monitor compliance with the established security procedures and standards and identify vulnerabilities in your security mechanisms.

There are different levels of audit log events:
* [Yandex Cloud level](#audit-trails): Events related to Yandex Cloud resources.
* [OS level](#os-level).
* [Application level](#app-level).
* [Network level](#network-level) (Flow Logs).

{% note info %}

For more information about Kubernetes events, see [Collecting, monitoring, and analyzing audit logs in Yandex Managed Service for Kubernetes](../domains/kubernetes.md#collection-monitoring-analysis-audit-logs).

{% endnote %}

### Overview {#general}

#### 5.1 Yandex Audit Trails is enabled at the organization level {#audit-trails}

The main tool for collecting Yandex Cloud level logs is [Yandex Audit Trails](../../audit-trails/concepts/index.md). This service allows you to collect audit logs about events happening to Yandex Cloud resources and upload these logs to Yandex Object Storage buckets or Cloud Logging log groups for further analysis or export. For information on how to start collecting logs, see [this guide](../../audit-trails/quickstart.md).

Audit Trails audit logs may contain two types of events: [management events](../../audit-trails/concepts/events.md) and [data events](../../audit-trails/concepts/events-data-plane.md).

[Management events](../../audit-trails/concepts/format.md) are actions you take to configure Yandex Cloud resources, such as creating, updating, or deleting infrastructure components, users, or policies. [Data events](../../audit-trails/concepts/format-data-plane.md) are updates and actions performed on data and resources within Yandex Cloud services. By default, Audit Trails does not log data events. You need to [enable](../../audit-trails/quickstart.md#the-trail-creation) collection of data event audit logs individually for each supported service.

For more information, see [Comparing management and data event logs](../../audit-trails/concepts/control-plane-vs-data-plane.md).

 To collect metrics, analyze Yandex Cloud-level events, and set up notifications, we recommend using [Yandex Monitoring](../../monitoring/index.md).  For example, it can help you track spikes in Compute Cloud workload, Application Load Balancer RPS, or significant changes in Identity and Access Management event statistics.

You can also use Monitoring to monitor the health of the Audit Trails service itself and track security events. You can export metrics to a SIEM system via the API, see [this guide](../../monitoring/operations/metric/get.md). 

[Solution: Monitoring Audit Trails and security events using Monitoring](https://github.com/yandex-cloud-examples/yc-audit-trails-monitoring)

You can export audit logs to a [Cloud Logging](../../logging/index.md) or Data Streams log group and to a customer's SIEM system to analyze information about events and incidents.

List of important Yandex Cloud-level events to search for in audit logs:

[Solution: Searching for important security events in audit logs](https://github.com/yandex-cloud/yc-solution-library-for-security/tree/master/auditlogs/_use_cases_and_searches)

You can enable Yandex Audit Trails at the folder, cloud, and organization level. We recommend enabling Yandex Audit Trails at the level of the entire organization. Thus you will be able to collect audit logs in a centralized manner, e.g., to a separate security cloud.

| Requirement ID | Severity |
| --- | --- |
| AUDIT1 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the management console, select the cloud or folder to check the functions in.
  1. In the list of services, select Yandex Audit Trails.
  1. Make sure the Filter parameter is set to Organization.
  1. In addition, check that the destination of logs is Yandex Object Storage bucket, [Cloud Logging](../../logging/index.md) log group, and Data Streams, that they are up and running, and that the logs are available for further analysis.

{% endlist %}

#### 5.2 Yandex Audit Trails events are exported to SIEM systems {#events}

Solutions for exporting Yandex Cloud audit logs are available for the following SIEM systems:


* ArcSight: [Collecting, monitoring, and analyzing audit logs in ArcSight SIEM](https://github.com/yandex-cloud-examples/yc-export-auditlogs-to-arcsight)

* Splunk: [Collecting, monitoring, and analyzing audit logs in Splunk SIEM](https://github.com/yandex-cloud-examples/yc-export-auditlogs-to-splunk)

* MaxPatrol SIEM: [Collecting, monitoring, and analyzing audit logs in MaxPatrol SIEM](../../audit-trails/tutorials/maxpatrol/index.md)

* Wazuh: [Collecting, monitoring, and analyzing audit logs in Wazuh](https://github.com/yandex-cloud-examples/yc-export-auditlogs-to-wazuh/blob/main/README-en.md)

* KUMA: [Collecting, monitoring, and analyzing audit logs in KUMA](../../tutorials/security/audit-trails-events-to-kuma/index.md)

For more information about MaxPatrol, see this [section](../../audit-trails/tutorials/maxpatrol/index.md).

You can set up export to any SIEM using [GeeseFS](../../storage/tools/geesefs.md) or [s3fs](../../storage/tools/s3fs.md). These utilities allow mounting a Yandex Object Storage bucket as a VM local disk. Next, you need to install a SIEM connector on the VM and configure reading JSON files from the bucket. You can also use utilities compatible with AWS Kinesis datastreams if sending audit logs to Yandex Data Streams.


If you have no SIEM, you can also analyze audit logs manually using Yandex Cloud [event search](../../audit-trails/tutorials/search-events-audit-logs/index.md) in Yandex Query, Cloud Logging, or Object Storage.


| Requirement ID | Severity |
| --- | --- |
| AUDIT2 | Informational |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that audit logs from Yandex Audit Trails are exported for analysis to a SIEM system or analyzed in the cloud using one of the available methods.

{% endlist %}

#### 5.3 Responding to Yandex Audit Trails events is set up {#reaction}

You can respond to Yandex Audit Trails events using your SIEM tools or manually. You can also use automatic responses.

With Yandex Cloud Functions, you can set up Audit Trails event alerts and automatic response to malicious actions, e.g., deletion of dangerous rules or access permissions.

[Solution: Notifications and responses to Audit Trails information security events using IAM / Cloud Functions + Telegram](https://github.com/yandex-cloud-examples/yc-audit-trails-automatic-response)

| Requirement ID | Severity |
| --- | --- |
| AUDIT3 | Medium |

#### 5.4 The Object Storage bucket that stores the Yandex Audit Trails audit logs has been hardened {#hardering}

If you write Yandex Audit Trails audit logs to a Yandex Object Storage bucket, make sure the bucket is set up using security best practices, such as:

* [There is no public access to the Yandex Object Storage bucket](virtualenv-safe-config.md#bucket-access).
* [Yandex Object Storage uses bucket policies](virtualenv-safe-config.md#bucket-policy).
* [The **Object lock** feature is enabled in Yandex Object Storage](virtualenv-safe-config.md#object-lock).
* [Logging of actions with buckets is enabled in Yandex Object Storage](virtualenv-safe-config.md#bucket-logs).
* [At-rest encryption with a KMS key is enabled in Yandex Object Storage](encryption.md#storage-kms).

You can use a solution for secure Yandex Object Storage bucket setup with Terraform.

| Requirement ID | Severity |
| --- | --- |
| AUDIT4 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 5.5 Audit logs are collected at the OS level {#os-level}

When using IaaS cloud services and Kubernetes node groups, the customer is responsible for ensuring OS security and collecting OS-level events on their own. Free tools for collecting standard OS-generated events and exporting them to the customer's SIEM system include:
  * [Osquery](https://osquery.io/)
  * [Filebeat (ELK)](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-system.html)
  * [Wazuh](https://documentation.wazuh.com/current/getting-started/use_cases/log_analysis.html)

Additional event generation options can be implemented using Auditd for Linux or Sysmon for Windows.

You can collect Linux system metrics (CPU, RAM, and disk space usage) with [Unified Agent](../../monitoring/concepts/data-collection/unified-agent/index.md) in Monitoring.

You can also export OS events to Cloud Logging using a [Fluent Bit plugin](https://github.com/yandex-cloud/fluent-bit-plugin-yandex) or to Data Streams.

To describe events to be searched for in audit logs, we recommend using [Sigma](https://github.com/SigmaHQ/sigma) format, which is supported by popular SIEM systems. The Sigma repository contains a [library of events](https://github.com/SigmaHQ/sigma/tree/master/rules) described in this format.

To get the exact time of OS- and application-level events, configure clock synchronization by following [this guide](../../compute/tutorials/ntp.md).

We additionally recommend to increase the logging level inside virtual machines to at least [`VERBOSE`](https://en.wikipedia.org/wiki/Verbose_mode).

| Requirement ID | Severity |
| --- | --- |
| AUDIT5 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 5.6 Audit logs are collected at the application level {#app-level}

Customers may collect events that occur at the level of applications deployed on Compute Cloud resources on their own. For example, save application logs to files and transfer them to a SIEM system using the tools listed in the subsection above.

Enable audit log collection in your unmanaged DBMS:

* Enable logging of all authentication actions (successful and failed).
* Activate logging of data modification operations (`INSERT`, `UPDATE`, `DELETE`).
* Configure logging of schema modification operations (`ALTER`, `CREATE`, `DROP`).
* Record permission and privilege changes.
* Configure events to track queries.

| Requirement ID | Severity |
| --- | --- |
| AUDIT6 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 5.7 Logs are collected at the network level {#network-level}

Currently, VPC network traffic event logs (Flow Logs) can only be collected by customers. You can use Yandex Cloud Marketplace solutions (such as [NGFW](https://yandex.cloud/en/marketplace?tab=software&search=NGFW), [IDS/IPS](https://yandex.cloud/en/marketplace?tab=software&search=IDS%2FIPS), or [network products](https://yandex.cloud/en/marketplace?categories=network)) or free software for collecting and transmitting events. You can also collect network-level logs using different agents, e.g., HIDS.

| Requirement ID | Severity |
| --- | --- |
| AUDIT7 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Run a manual check.

{% endlist %}

#### 5.8 Data events are monitored {#data-plane-events}

A [data event audit log](../../audit-trails/concepts/format-data-plane.md) is a JSON object with a record of events related to Yandex Cloud resources. Data event monitoring makes it easier for you to collect additional events from cloud services and, as a result, effectively respond to security incidents in clouds. This also helps you ensure your cloud infrastructure meets regulatory requirements and industry standards. For example, you can keep track of your employees' access permissions to sensitive data stored in [buckets](../../storage/concepts/bucket.md).

You need to enable collection of data event audit logs individually for each [supported service](../../audit-trails/concepts/control-plane-vs-data-plane.md#data-plane-events).

We recommend to enable **all events** for [Yandex Identity and Access Management](../../audit-trails/concepts/events-data-plane.md#iam) and [Yandex Cloud DNS](../../audit-trails/concepts/events-data-plane.md#dns), as well as all **all events** for the following services, if used:

* [Yandex Certificate Manager](../../audit-trails/concepts/events-data-plane.md#certificate-manager)
* [Yandex Compute Cloud](../../audit-trails/concepts/events-data-plane.md#compute)
* [Yandex Key Management Service](../../audit-trails/concepts/events-data-plane.md#kms)
* [Yandex Lockbox](../../audit-trails/concepts/events-data-plane.md#lockbox)
* [Yandex Managed Service for ClickHouse®](../../audit-trails/concepts/events-data-plane.md#mch)
* [Yandex Managed Service for Kubernetes](../../audit-trails/concepts/events-data-plane.md#managed-service-for-kubernetes)
* [Yandex StoreDoc](../../audit-trails/concepts/events-data-plane.md#mmg)
* [Yandex Managed Service for MySQL®](../../audit-trails/concepts/events-data-plane.md#mmy)
* [Yandex Managed Service for PostgreSQL](../../audit-trails/concepts/events-data-plane.md#mpg)
* [Yandex Managed Service for Valkey™](../../audit-trails/concepts/events-data-plane.md#mrd)
* [Yandex Object Storage](../../audit-trails/concepts/events-data-plane.md#objstorage)
* [Yandex Smart Web Security](../../audit-trails/concepts/events-data-plane.md#sws)
* [Yandex WebSQL](../../audit-trails/concepts/events-data-plane.md#websql)

| Requirement ID | Severity |
| --- | --- |
| AUDIT8 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where your [trail](../../audit-trails/concepts/trail.md) is located.
  1. In the list of services, select **Audit Trails**.
  1. Select the trail you need.
  1. Make sure the trail info page in **Collecting data events** lists all the services you want to collect data event logs for, specifying the correct audit log [scope](../../audit-trails/concepts/trail.md#collecting-area) for each service.

      For the list of supported services, see [Data event reference](../../audit-trails/concepts/events-data-plane.md).

{% endlist %}

#### 5.9 Access Transparency Security Deck is on for inspection of Yandex Cloud employees' actions with the infrastructure {#access-transparency-enabled}

All Yandex Cloud employees' actions are logged and monitored with the help of [bastion hosts](../../tutorials/routing/bastion.md) – recorders of operations with the user data processing resources.

With [Access Transparency](../../security-deck/concepts/access-transparency.md), you can check why your infrastructure was accessed by the provider's employees. For example, the reasons may include additional IT system diagnostics by support engineers or software updates. ML models analyze these actions. Integrated into Access Transparency, YandexGPT generates access event summaries to improve visibility. Suspicious sessions are automatically sent to the Yandex Cloud security teams for review.

| Requirement ID | Severity |
| --- | --- |
| AUDIT9 | Low |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Go to [Yandex Security Deck](https://center.yandex.cloud/security/).
  1. In the left-hand panel, select ![CloudCheck](../../_assets/console-icons/cloud-check.svg) **Access Transparency**.
  1. If you are prompted to enable Access Transparency, it means the module is not active yet; proceed to _Guides and solutions to use_.

{% endlist %}

**Guides and solutions to use**:

Click **Connect** to activate the `Access Transparency` module.


# Application security requirements

## 6. Application security {#app-security}

### Bot protection {#protecting-recommendations}

#### 6.1 Yandex SmartCaptcha is used {#use-smartcaptcha}

To mitigate the risks associated with automated attacks on applications, we recommend using [Yandex SmartCaptcha](https://yandex.cloud/en/services/smartcaptcha). The service checks user requests with its ML algorithms and only shows challenges to those users whose requests it considers suspicious. You do not have to place the **"I’m not a robot"** button on the page.

| Requirement ID | Severity |
| --- | --- |
| APPSEC1 | Informational |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select a folder.
  1. Select **Yandex SmartCaptcha**.
  1. Make sure at least one CAPTCHA is [created](../../smartcaptcha/operations/create-captcha.md) for your application.

{% endlist %}

**Guides and solutions to use**:

[Guide on creating a CAPTCHA in Yandex SmartCaptcha](../../smartcaptcha/operations/create-captcha.md).

### Building a secure pipeline {#pipeline-recommendations}

Yandex Cloud allows customers to achieve compliance of software they develop at all [Supply-chain Levels for Software Artifacts (SLSA)](https://slsa.dev/), provided that they follow the guidelines given in this section. When using [Yandex Managed Service for GitLab](../../managed-gitlab/index.md), a customer automatically achieves [SLSA Level 2 compliance](https://about.gitlab.com/blog/2022/11/30/achieve-slsa-level-2-compliance-with-gitlab/).

#### 6.2 When creating a registry in Yandex Container Registry, keep the safe registry settings by default {#keep-safe-cr-settings}

When creating a new [registry](../../container-registry/concepts/registry.md), use the default options to make sure it meets the Yandex Cloud security standard:

* Docker images are automatically scanned as they are uploaded to the registry.
* Docker images in the registry are regularly re-scanned, i.e., every 7 days with an option to switch to daily scanning in the settings.

| Requirement ID | Severity |
| --- | --- |
| APPSEC14 | Medium |

**Guides and solutions to use**:

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder where you want to create a registry.
  1. In the list of services, select **Container Registry**.
  1. Click **Create registry**.
  1. In the **Name** field, enter a name for the registry. Follow these naming requirements:
      
      * Length: between 3 and 63 characters.
      * It can only contain lowercase Latin letters, numbers, and hyphens.
      * It must start with a letter and cannot end with a hyphen.
  1. Under **Automatic scanning**:

      * Keep **Scan Docker images on push** enabled to scan Docker images at their upload to the repository.
      * Keep **Scan all Docker images in the registry** enabled. Adjust the scanning frequency if you need to.

  1. Click **Create registry**.

- CLI {#cli}

  To create a registry with safe image scanning settings used by default, run this command:

  ```bash
  yc container registry create \
    --name <registry_name> \
    --secure
  ```

{% endlist %}

#### 6.3 Docker images are scanned when uploaded to Container Registry {#upload-policy}

[Auto scans](../../container-registry/operations/scanning-docker-image.md#automatically) of Docker images on push are critical for early detection and elimination of vulnerabilities to ensure secure deployment of containers. Reports on completed scans provide a brief description of detected vulnerabilities and issues and help you set priorities and eliminate security risks in containerized applications.

| Requirement ID | Severity |
| --- | --- |
| APPSEC2 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder the registry with Docker images belongs to.
  1. Select the appropriate registry in **Container Registry**.
  1. Navigate to the **Vulnerability scanner** tab and click **Edit settings**.
  1. Make sure Docker image scans on push are enabled.

{% endlist %}

**Guides and solutions to use:**

[Guide on scanning Docker images on push](../../container-registry/operations/scanning-docker-image.md#automatically).

#### 6.4 Docker images stored in Container Registry are regularly scanned {#periodic-scan}

Scheduled scanning of Docker images is an automated process that checks containerized images for vulnerabilities and compliance with security standards. Such scans are regular and automatic to ensure the consistency of image checks for vulnerabilities and maintain a high security level in the long run. Reports on completed scans provide a brief description of detected vulnerabilities and issues and help you set priorities and eliminate security risks in containerized applications.

We recommend setting up a schedule for scans to be run at least once a week.

| Requirement ID | Severity |
| --- | --- |
| APPSEC3 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder the registry with Docker images belongs to.
  1. Select the appropriate registry in **Container Registry**.
  1. Navigate to the **Vulnerability scanner** tab and click **Edit settings**.
  1. Make sure that scheduled Docker image scans are enabled with a frequency of at least once a week.

{% endlist %}

**Guides and solutions to use:**

[Guide on scheduled scanning of Docker images](../../container-registry/operations/scanning-docker-image.md#scheduled).

#### 6.5 Container images used in the production environment have the last scan date of one week ago or less {#last-scan-date}

Checking Docker images used in production environments with the last scan date not older than a week ensures that you continuously monitor and update security measures, eliminating potential vulnerabilities that might have occurred since the last scan. This also helps you make sure you are not deploying containers with recently detected vulnerabilities and enhance the security level. You can automate this process by [setting up a schedule](#periodic-scan) in the Vulnerability scanner.

| Requirement ID | Severity |
| --- | --- |
| APPSEC4 | Medium |

{% list tabs group=instructions %}

- Performing a check via the CLI {#cli}

  Run the command below to search for containerized images with the last scan date a week ago or less:

  ```bash
  export ORG_ID=<organization_ID>
  for CLOUD_ID in $(yc resource-manager cloud list --organization-id=${ORG_ID} --format=json | jq -r '.[].id');
  do for FOLDER_ID in $(yc resource-manager folder list --cloud-id=$CLOUD_ID --format=json | jq -r '.[].id'); 
  do for REGISTRY_ID in $(yc container registry list --folder-id $FOLDER_ID --format=json | jq -r '.[].id');
  do for IMAGE_ID in $(yc container image list --registry-id $REGISTRY_ID --format=json | jq -r '.[].id';)
  do LAST_SCAN_DATE=$(yc container image get-last-scan-result --image-id $IMAGE_ID --format=json 2>/dev/null | jq -r '.scanned_at');
  [ ! -z "$LAST_SCAN_DATE" ] && [ $(date --date "$LAST_SCAN_DATE" +'%s') -lt $(date --date '7 days ago' +'%s') ] && echo "Regitry ID - $REGISTRY_ID, Image ID - $IMAGE_ID, Last scan date - $LAST_SCAN_DATE"
  done;
  done;
  done;
  done
  ```

{% endlist %}

#### 6.6 Attestations are used when building artifacts {#provenance-attestation}

Attestations used when building software artifacts help ensure a secure and verifiable record of an artifact's origin, integrity, and SBOM compliance. This helps ensure the artifact reliability throughout its lifecycle. A software bill of materials (SBOM) is required to secure a supply chain, manage vulnerabilities, comply with requirements, assess risks, ensure transparency, and respond to incidents in an effective way.

With Managed Service for GitLab, attestations are easier to use, as the service has a feature for generating a [provenance attestation](https://about.gitlab.com/releases/2022/06/22/gitlab-15-1-released/#slsa-2-attestation-included-for-build-artifacts). An SBOM can be generated using [syft](https://github.com/anchore/syft), a third-party software tool.

| Requirement ID | Severity |
| --- | --- |
| APPSEC5 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that artifact attestation is performed while building an application.

{% endlist %}

**Guides and solutions to use**:

[Gitlab guide for software artifact attestation](https://docs.gitlab.com/ee/ci/runners/configure_runners.html#artifact-attestation).

#### 6.7 Artifact integrity is ensured {#pipeline-artifacts-cosign}

Signing artifacts enhances security to ensure your software validity, integrity, reliability, and compliance with the requirements.

| Requirement ID | Severity |
| --- | --- |
| APPSEC6 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that artifacts are signed while building an application.

{% endlist %}

**Guides and solutions to use:**

To sign artifacts within a pipeline, you can use [Cosign](https://github.com/sigstore/cosign), a third-party command line utility for signing [artifacts](https://docs.sigstore.dev/signing/quickstart/), images, and [in-to-to attestations](https://github.com/in-toto/attestation/tree/main/spec/predicates). Then you can upload these artifacts to Yandex Container Registry.

A special build of Cosign allows you to store the created [digital signature key pair](../../kms/concepts/asymmetric-signature-key.md) in [Yandex Key Management Service](../../kms/quickstart/index.md), sign files and artifacts with the private key of the pair, and verify a digital signature using its public key.

For more information, see [Signing and verifying Container Registry Docker images in Yandex Managed Service for Kubernetes](../../container-registry/tutorials/sign-cr-with-cosign.md).

#### 6.8 Artifacts are checked for authenticity on deployment {#artifacts-checked}

To ensure the reliability, security, and compatibility of applications in [Managed Service for Kubernetes](../../managed-kubernetes/index.md), a service for automatic scaling and deployment of applications, you need to minimize the risk of issues, vulnerabilities, and failures during your application deployment and runtime. To do this, use [signatures and signature verification](../../container-registry/tutorials/sign-cr-with-cosign.md) in Managed Service for Kubernetes with Cosign and [Kyverno](../../managed-kubernetes/operations/applications/kyverno.md).

| Requirement ID | Severity |
| --- | --- |
| APPSEC7 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that artifacts are verified while building an application.

{% endlist %}

**Guides and solutions to use**:

[Guide on setting up the artifact signature](../../container-registry/tutorials/sign-cr-with-cosign.md).

#### 6.9 Protected secure pipeline templates are used {#pipeline-blocks}

When working with Managed Service for GitLab, make sure you use built-in GitLab security mechanisms to secure your pipeline. You can integrate a pipeline into your projects in the [following ways](../../managed-gitlab/concepts/security.md#security-pipeline-usage):

* Creating a pipeline in an individual project and connecting it to other projects using the [`include`](https://docs.gitlab.com/ee/ci/yaml/includes.html) function. This option is available for all license types.
* Using the [`Compliance framework and pipeline`](https://docs.gitlab.com/ee/user/project/settings/index.html#compliance-frameworks) mechanism that you can run in any group project. It is available for the `Ultimate` license.
* Copying pipeline sections to `.gitlab-ci.yml` files in your projects.

| Requirement ID | Severity |
| --- | --- |
| APPSEC8 | Informational |

#### 6.10 A Yandex Smart Web Security security profile is used {#use-sws}

[Yandex Smart Web Security](../../smartwebsecurity/quickstart.md) protects you against DDoS attacks, web attacks, and bots at application level L7 of the [OSI model](https://en.wikipedia.org/wiki/OSI_model). Smart Web Security [connects](../../smartwebsecurity/quickstart.md) to Yandex Application Load Balancer.

In a nutshell, the service checks the HTTP requests sent to the protected resource against the [rules](../../smartwebsecurity/concepts/rules.md) configured in the [security profile](../../smartwebsecurity/concepts/profiles.md). Depending on the results of the check, the requests are forwarded to the protected resource, blocked, or sent to [Yandex SmartCaptcha](../../smartcaptcha/index.md) for additional verification.

| Requirement ID | Severity |
| --- | --- |
| APPSEC9 | High |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where you want to check the Smart Web Security status.
  1. In the list of services, select **Smart Web Security**.
  1. In the left-hand panel, select ![shield-check](../../_assets/console-icons/shield-check.svg) **Security profiles**.
  1. Make sure you have security profiles created.
  1. If you have security profiles, the recommendation is fulfilled. Otherwise, proceed to _Guides and solutions to use_.

- Performing a check via the CLI {#cli}

  Run this command:

  ```bash
  yc smartwebsecurity security-profile list
  ```

  If the command returns information about the existing security profiles, the recommendation is fulfilled. Otherwise, proceed to _Guides and solutions to use_.

{% endlist %}

**Guides and solutions to use**:

[Creating a security profile and connecting it to a virtual host of an L7 load balancer](../../smartwebsecurity/quickstart.md).

#### 6.11 A web application firewall is used {#use-waf}

To mitigate risks associated with web attacks, we recommend using the Yandex Smart Web Security web application firewall (WAF). A web application firewall analyzes HTTP requests to a web app according to pre-configured rules. Based on the analysis results, certain [actions](../../smartwebsecurity/concepts/rules.md#rule-action) are applied to HTTP requests.

You can manage the web application firewall using a [WAF profile](../../smartwebsecurity/concepts/waf.md) that connects to a [security profile](../../smartwebsecurity/concepts/profiles.md) in Smart Web Security as a separate [rule](../../smartwebsecurity/concepts/rules.md).

| Requirement ID | Severity |
| --- | --- |
| APPSEC10 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where you want to check a security profile for a WAF rule.
  1. In the list of services, select **Smart Web Security**.
  1. Make sure your security profile has a security rule of the **web application firewall** type.

{% endlist %}

**Guides and solutions to use**:

[Creating a WAF profile and connecting it to a security profile in Smart Web Security](../../smartwebsecurity/quickstart.md#waf).

#### 6.12 Advanced Rate Limiter is used {#use-arl}

[Advanced Rate Limiter (ARL)](../../smartwebsecurity/concepts/arl.md) is a Yandex Smart Web Security module used to monitor and limit web app loads. It allows you to set a limit on the number of HTTP requests over a certain period of time. All requests above the limit will get blocked. You can set a single limit for all traffic or configure specific limits to segment requests by certain parameters. For the purpose of limits, you can count requests one by one or group them together based on specified property.

You need to connect your ARL profile to the [security profile](../../smartwebsecurity/concepts/profiles.md) in Smart Web Security.

| Requirement ID | Severity |
| --- | --- |
| APPSEC11 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) you want to check for ARL profiles.
  1. In the list of services, select **Smart Web Security**.
  1. In the left-hand panel, select ![image](../../_assets/smartwebsecurity/arl.svg) **ARL profiles** and make sure you have ARL profiles connected to your security profile.

{% endlist %}

**Guides and solutions to use**:

[Creating an ARL profile and connecting it to a security profile in Smart Web Security](../../smartwebsecurity/quickstart.md#arl).

#### 6.13 Approval rules are configured {#setup-code-review}

With [Yandex Managed Service for GitLab](../../managed-gitlab/index.md), you can flexibly set up required [approval rules](../../managed-gitlab/concepts/approval-rules.md) before the code can be added to the target project branch. This feature is an alternative to the GitLab Enterprise Edition’s [Approval Rules](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/rules.html) tool and is available regardless of the GitLab [version](https://about.gitlab.com/pricing).

If a [GitLab instance](../../managed-gitlab/concepts/index.md#instance) has the approval rules enabled, Managed Service for GitLab analyzes approvals from reviewers for compliance with the specified rules. If there are not enough approvals, a thread is created in a merge request that blocks it from being merged to the target branch. Editing the merge request creates or updates a comment in the thread with its current compliance status. Once all the required approvals are obtained, the thread is closed.

If you close a thread manually, it will be created again. If a merge request is approved regardless of the existing rules, users with the `Maintainer` role or higher will receive an email notification about the violated code approval workflow.

| Requirement ID | Severity |
| --- | --- |
| APPSEC12 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where your GitLab instance is located.
  1. In the list of services, select **Managed Service for&nbsp;GitLab**.
  1. Select the instance you need and click **Edit** in the top-right corner of the page.
  1. Make sure to select a configured approval rule [configuration](../../managed-gitlab/concepts/approval-rules.md#packages) in the **Approval rules** field.

{% endlist %}

**Guides and solutions to use**:

[Enabling approval rules in the GitLab instance](../../managed-gitlab/operations/approval-rules.md#enable)

#### 6.14 Trusted and unwanted IP addresses are grouped into lists {#app-sws-lists}

[Yandex Smart Web Security](../../smartwebsecurity/index.md) supports grouping IP addresses into [custom lists](../../smartwebsecurity/concepts/lists.md#user-rules). Add those lists as [conditions](../../smartwebsecurity/concepts/conditions.md) in [rules](../../smartwebsecurity/concepts/rules.md) to allow, block, or forward some traffic to [SmartCaptcha](../../smartcaptcha/index.md) during IP address verification.

| Requirement ID | Severity |
| --- | --- |
| APPSEC13 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. Open the Yandex Cloud console in your browser.
  1. Go to the appropriate folder.
  1. In the list of services, select **Smart Web Security**.
  1. Go to **Lists**.
  1. Check that the lists have been created.
  1. If there are such lists, the recommendation is fulfilled. Otherwise, proceed to "Guides and solutions to use".

- Manual check {#manual}

  Contact your account manager to make sure you have Smart Web Security lists.

{% endlist %}

**Guides and solutions to use**:

Whitelist and blacklist IP addresses to filter traffic. For more information, see [Managing lists](../../smartwebsecurity/operations/list-create.md).


# Kubernetes security requirements

## 7. Kubernetes security {#kubernetes-security}


[Yandex Managed Service for Kubernetes](../../managed-kubernetes/index.md) provides an environment for managing containerized applications in the Yandex Cloud infrastructure. Deploy, scale, and manage applications in containers using Kubernetes.

The user is responsible for all actions made inside the Kubernetes node. The user is responsible for the security of the nodes and their proper setup in accordance with PCI DSS requirements and other security standards.

Yandex Cloud is responsible for the Kubernetes API security.

The user is responsible for correctly choosing security settings in Managed Service for Kubernetes, including selecting the [channel](../../managed-kubernetes/concepts/release-channels-and-updates.md) and the update schedule.

### Overview {#general}

#### 7.1 The use of sensitive data is limited {#not-use-critical-data}

To comply with PCI DSS or other security standards when using Managed Service for Kubernetes, do not:

* Use sensitive data in names and descriptions of clusters, node groups, namespaces, services, and pods.
* Use sensitive data in [Kubernetes](../../managed-kubernetes/concepts/index.md#node-labels) node labels and [Yandex Cloud](../../resource-manager/concepts/labels.md) service resource labels.
* Use sensitive data in pod manifests.
* Use sensitive data in etcd in clear text.
* Write sensitive data to Managed Service for Kubernetes logs.

| ID requirements | Severity |
| --- | --- |
| K8S1 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  * Make sure that names and descriptions of clusters, node groups, namespaces, services, and pods contain no sensitive data.
  * Check configuration files for critical data

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where your Managed Service for Kubernetes instance is located.
  1. In the list of services, select **Managed Service for&nbsp;Kubernetes**.
  1. Make sure that [Kubernetes node labels](../../managed-kubernetes/concepts/index.md#node-labels) and [Yandex Cloud service resource labels](../../resource-manager/concepts/labels.md) contain no sensitive data.

{% endlist %}

**Guides and solutions to use:**

Manually edit the names or contents of manifests and other configuration files if they use sensitive data.

#### 7.2 Resources are isolated from each other {#maximum-isolation}

Wherever possible, ensure maximum isolation between resources:

* Use a separate organization for each "big" project.
* Use a separate cloud for each development team.
* Use a separate Kubernetes cluster located in a separate folder for each service.
* Use a separate namespace for each microservice.
* Your clouds must have no shared resources. Cloud members must have access only to their clouds.

Less strict isolation models are also possible, e.g., where:

* Projects are deployed in different clouds.
* Development teams use independent folders.
* Services have separate Kubernetes clusters.
* Microservices use different namespaces.

| ID requirements | Severity |
| --- | --- |
| K8S2 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Wherever possible, ensure maximum isolation between resources.

{% endlist %}

#### 7.3 There is no access to the Kubernetes API and node groups from untrusted networks {#api-security}

We do not recommend granting access to the Kubernetes API and node groups from non-trusted networks, e.g., from the internet. Use firewall protection where needed (for example, [security groups](../../vpc/concepts/security-groups.md)).

| ID requirements | Severity |
| --- | --- |
| K8S3 | Medium |

**Guides and solutions to use:**

* [Guide on creating a cluster with no internet access](../../managed-kubernetes/tutorials/k8s-cluster-with-no-internet.md).
* [Security group setup guide](../../managed-kubernetes/operations/connect/security-groups.md).
* Use network policy configuration tools via the [Calico](../../managed-kubernetes/concepts/network-policy.md#calico) (basic) or [Cilium CNI](../../managed-kubernetes/concepts/network-policy.md#cilium) (advanced) plugins in Yandex Cloud. By default, apply the `default deny` rules for incoming and outgoing traffic with only the relevant traffic allowed.
* For online endpoints, allocate an independent Kubernetes cluster or independent node groups (using such mechanisms as [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#:~:text=Node%20affinity%20is%20a%20property,onto%20nodes%20with%20matching%20taints) + [Node affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/)). By doing this, you establish a DMZ so that if your nodes are compromised online, your attack surface is small.
* To enable incoming network access to your workloads via HTTP/HTTPS, use the [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) resource. There are at least two controller options that you can use in Yandex Cloud:

  * [Yandex Cloud Gwin Controller](../../managed-kubernetes/alb-ref/gwin-index.md).
  * [Application Load Balancer of an Ingress controller](../../application-load-balancer/tools/k8s-ingress-controller/index.md).

#### 7.4 Authentication and access management are configured in Managed Service for Kubernetes {#kubernetes-auth}

You need two service accounts for your Kubernetes cluster: [cluster service account and node group service account](../../managed-kubernetes/security/index.md#sa-annotation). The access of IAM accounts to Managed Service for Kubernetes resources is managed at the following levels:

* Managed Service for Kubernetes service roles (access to the Yandex Cloud API). These allow you to control clusters and node groups (e.g., create a cluster, create/edit/delete a node group, and so on).
* Service roles required to access the Kubernetes API. These allow you to control cluster resources via the Kubernetes API (e.g., perform standard actions with Kubernetes: create, delete, view namespaces, work with pods, deployments, create roles, and so on). Only the basic global roles are available at cluster level: `k8s.cluster-api.cluster-admin`, `k8s.cluster-api.editor`, or `k8s.cluster-api.viewer`.
* Primitive roles. These are global primitive IAM roles that comprise service roles (e.g., the primitive admin role comprises both the service administration role and the administration role for access to the Kubernetes API).
* Standard Kubernetes roles. Inside the Kubernetes cluster itself, the Kubernetes tools can help you create both regular roles and cluster roles. Thus you can manage access for IAM accounts at the namespace level. To assign IAM roles at the namespace level, you can manually create RoleBinding objects in a relevant namespace stating the cloud user's IAM ID in the **subjects name** field.

| ID requirements | Severity |
| --- | --- |
| K8S4 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure the above recommendations are met.

{% endlist %}

#### 7.5 Managed Service for Kubernetes uses a safe configuration {#kubernetes-safe-config}

In Managed Service for Kubernetes, the user is fully in control of all node group settings, but only partially in control of the [master](../../managed-kubernetes/concepts/index.md#master) settings. The user is responsible for the whole cluster's security.

The [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes) standard is designed to build a secure Kubernetes configuration, including node configurations. In Yandex Cloud, the Kubernetes node groups are deployed by default with the configuration that complies with CIS Kubernetes Benchmark.

| ID requirements | Severity |
| --- | --- |
| K8S5 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  * Using the [kube-bench](https://github.com/aquasecurity/kube-bench) tool, check whether the node group configuration is compliant with CIS Kubernetes Benchmark. The tool officially supports the Yandex Cloud node groups.
  * [Starboard Operator](https://blog.aquasec.com/automate-kubernetes-compliance) is a free tool that helps you automate scanning of images for vulnerabilities and checking that the configuration is compliant with CIS Kubernetes Benchmark. Starboard Operator supports integration with kube-bench and is used for its automatic startup.

{% endlist %}

#### 7.6 Managed Service for Kubernetes data encryption and secret management are done in _ESO as a Service_ format {#data-encryption}

At the Kubernetes etcd level, encrypt secrets using an in-built [mechanism from Yandex Cloud](../../managed-kubernetes/concepts/encryption.md).

We recommend that you use SecretManager solutions to work with Kubernetes secrets. [Yandex Lockbox](../../lockbox/index.md) is such a solution in Yandex Cloud.

 Yandex Lockbox was integrated with Kubernetes using the [External Secrets](https://external-secrets.io/latest/) open-source project. In Cloud Marketplace, the solution is available in the basic simplified scenario: [External Secrets Operator with Yandex Lockbox support](https://yandex.cloud/en/marketplace/products/yc/external-secrets).

The most secure recommended option for encrypting secrets is ESO as a Service (External Secrets Operator as a service). When using ESO, the global administrator has access to the namespace where ESO is installed, and administrators of individual namespaces create their own [SecretStore](https://external-secrets.io/latest/api/secretstore/) objects (where they specify IAM-authorized access keys for their Lockbox secrets). If this SecretStore object is compromised, the authorized key of only one namespace will be compromised – not all of them, as in the case of Shared ClusterSecretStore.

| ID requirements | Severity |
| --- | --- |
| K8S6 | Medium |

**Guides and solutions to use:**

* [Guide on External Secrets and Yandex Lockbox from the project description](https://external-secrets.io/latest/provider/yandex-lockbox/).
* [Guide on External Secrets and Yandex Lockbox from the Yandex Cloud documentation](../../lockbox/tutorials/kubernetes-lockbox-secrets.md).

#### 7.7 Docker images are stored in a Container Registry registry configured for regular image scanning {#docker-images-periodic-scan}

To ensure effective security, we recommend using [Container Registry](../../container-registry/index.md) to store Docker images to be deployed in Managed Service for Kubernetes. This allows you to quickly respond to new vulnerabilities in images using built-in recurrent vulnerability scanning.

You should perform vulnerability scanning at least once a week. This will help you detect and eliminate vulnerabilities in images in a timely manner, which significantly reduces risks of unauthorized access to your resources and increases security level of your infrastructure.

Using Container Registry to store images will also provide centralized image version control for simpler updates and security management.

| ID requirements | Severity |
| --- | --- |
| K8S7 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder the registry with Docker images belongs to.
  1. Select the appropriate registry in **Container Registry**.
  1. Navigate to the **Vulnerability scanner** tab and click **Edit settings**.
  1. Make sure that scheduled Docker image scans are enabled with a frequency of at least once a week.

{% endlist %}

**Guides and solutions to use:**

* [Guide on scheduled scanning of Docker images](../../container-registry/operations/scanning-docker-image.md#scheduled).

#### 7.8 One of the three latest Kubernetes versions is used, updates are monitored {#version-update}

For Kubernetes, both automatic and manual updates are available for [clusters](../../managed-kubernetes/concepts/index.md#kubernetes-cluster) and [node groups](../../managed-kubernetes/concepts/index.md#node-group). You can request a manual update of the Kubernetes cluster or its nodes to the latest supported [version](../../managed-kubernetes/concepts/release-channels-and-updates.md) at any time. Manual updates bypass any configured maintenance windows and maintenance exceptions. Kubernetes issues updates in a regular manner. To meet the Information Security standards:

* Select a relevant update channel and enable either automatic installation of updates, or manual installation immediately after publication in the selected channel.
* Check that the update settings meet the Information Security standards.
* Use one of the three latest Kubernetes versions, because updates (including security updates) are only released for these versions.

| ID requirements | Severity |
| --- | --- |
| K8S8 | Medium |

{% list tabs group=instructions %}

- Performing a check in the management console {#console}

  To get a list of available versions for a Kubernetes cluster:
  1. Navigate to the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) dashboard and select **Managed Service for&nbsp;Kubernetes**.
  1. Click the name of the Kubernetes cluster.
  1. Click **Edit** in the top-right corner.
  1. View the list of available versions in the **Kubernetes version** field under **Master configuration**.

  To get a list of available versions for a Kubernetes node group:
  1. Navigate to the folder dashboard and select **Managed Service for&nbsp;Kubernetes**.
  1. Click the name of the Kubernetes cluster you need and go to the **Node management** tab.
  1. Select the Kubernetes node group from the list and click **Edit** in the top-right corner.
  1. Get a list of available versions in the **Kubernetes version** field.

- Performing a check via the CLI {#cli}

  If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

  The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

  To get a list of available versions, run the following command:

  ```bash
  yc managed-kubernetes list-versions
  ```

- Checking via the API {#api}

  To get a list of available versions, use the [list](../../managed-kubernetes/managed-kubernetes/api-ref/Version/list.md).

{% endlist %}

**Guides and solutions to use:**

* [Guide on how to update a cluster automatically](../../managed-kubernetes/operations/update-kubernetes.md#cluster-upgrade).
* [Guide on how to update a cluster manually](../../managed-kubernetes/operations/update-kubernetes.md#cluster-manual-upgrade).

#### 7.9 Backup is configured {#backup}

To ensure continuous operation and data protection, we recommend using backups in Managed Service for Kubernetes. With backups, you can quickly recover the service without experiencing any data or time loss in the wake of a malfunction or accident. The Yandex Cloud infrastructure provides secure storage and replication for data in [Kubernetes](../../managed-kubernetes/concepts/index.md#kubernetes-cluster) clusters. However, you can back up data from [Kubernetes cluster node groups](../../managed-kubernetes/concepts/index.md#node-group) at any time and store them in [Yandex Object Storage](../../storage/index.md) or other types of storage.

| ID requirements | Severity |
| --- | --- |
| K8S9 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that you have backups of your data from node groups of Kubernetes clusters.

{% endlist %}

**Guides and solutions to use:**

You can create backups of Kubernetes cluster node group data using [Velero](https://velero.io/). It supports Yandex Cloud [disks](../../compute/concepts/disk.md) through the Kubernetes CSI driver and helps create [disk and volume snapshots](../../compute/concepts/snapshot.md).

If installed manually, Velero allows you to use [nfs](https://kubernetes.io/docs/concepts/storage/volumes/#nfs), [emptyDir](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir), [local](https://kubernetes.io/docs/concepts/storage/volumes/#local), or any other volume type without built-in support for snapshots. To use one of these volume types, install Velero with the [restic plugin](https://velero.io/docs/v1.8/restic/). Velero installed from [Cloud Marketplace](https://yandex.cloud/en/marketplace/products/yc/velero-yc-csi) does not include the `restic` plugin.

* [Guide on Kubernetes cluster backup in Object Storage](../../managed-kubernetes/tutorials/kubernetes-backup.md#backup).

#### 7.10 Check lists are in place for security when creating and using Docker images {#check-list}

Secure Docker image creation and operation practices ensure protection against potential vulnerabilities, malware, and unauthorized access to data. They ensure image integrity and security compliance while also preventing potential threats coming from its deployment in the infrastructure. Use these check lists to meet requirements for secure creation of images:

* [Dockerfile best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/).
* [Kubernetes Security Checklist and Requirements](https://github.com/Vinum-Security/kubernetes-security-checklist/blob/main/README.md).

You can control Dockerfile in your CI/CD pipeline using the [Conftest](https://www.conftest.dev/) utility.

When using minimal images or distroless images without a shell, we recommend using [ephemeral containers](https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/).

| ID requirements | Severity |
| --- | --- |
| K8S10 | Informational |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure you have the check lists in place to meet the requirements for secure creation of images.

{% endlist %}

#### 7.11 The Kubernetes security policy is in place {#security-standards}

The requirements listed in [Kubernetes Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) allow you to prevent threats related to Kubernetes objects, such as unauthorized access to confidential data and execution of malicious code.

These requirements allow you to ensure security and reliability of applications in a Kubernetes cluster. To achieve compliance, you can either use the built-in Kubernetes tool called [Pod Security Admission Controller](https://kubernetes.io/docs/setup/best-practices/enforcing-pod-security-standards/) or open-source software, e.g., [OPA Gatekeeper](https://github.com/open-policy-agent/gatekeeper) or [Kyverno](https://yandex.cloud/en/marketplace/products/yc/kyverno).

| ID requirements | Severity |
| --- | --- |
| K8S11 | Medium |

{% list tabs group=instructions %}

- Manual check {#manual}

  Verify compliance with the Kubernetes Pod Security Standards.

{% endlist %}

**Guides and solutions to use:**

* To control compliance with Pod Security Standards, you can also use the following tools within CI/CD:

  * [Kyverno CLI](https://kyverno.io/docs/kyverno-cli/)
  * The gator CLI

* [Kubesec](https://kubesec.io/)

#### 7.12 Audit log collection is set up for incident investigation {#audit-logs}

Events available to the user in the Managed Service for Kubernetes service can be classified as levels:

* Kubernetes API events (Kubernetes audit logging)
* Kubernetes node events
* Kubernetes pod events
* Kubernetes metrics
* Kubernetes flow logs

For more information about setting up audit event logging at various levels, see [Collecting, monitoring, and analyzing Managed Service for Kubernetes audit logs](../domains/kubernetes.md#collection-monitoring-analysis-audit-logs).

In Managed Service for Kubernetes, you can audit the current role model used in the service. To do this, open the Kubernetes cluster page in the [management console](https://console.yandex.cloud), and go to the **Access management** tab.

You can also use:

* [KubiScan](https://github.com/cyberark/KubiScan)
* [Krane](https://github.com/appvia/krane)
* Yandex Audit Trails [audit logs](../../managed-kubernetes/at-ref.md)

| ID requirements | Severity |
| --- | --- |
| K8S12 | High |

{% list tabs group=instructions %}

- Manual check {#manual}

  Make sure that audit logs are being collected.

{% endlist %}

_ClickHouse® is a registered trademark of [ClickHouse, Inc](https://clickhouse.com)._