Требования к аутентификации и управлению доступом
1. Аутентификация и управление доступом
В Yandex Cloud управление идентификацией, аутентификацией и контролем доступа выполняется сервисами Yandex Identity and Access Management (IAM) и Yandex Cloud Organization.
Платформа работает с тремя категориями пользователей:
- аккаунты на Яндексе — учетные записи в системе Яндекс ID;
- федеративные аккаунты — учетные записи в корпоративной SAML-совместимой федерации удостоверений, например Active Directory;
- сервисные аккаунты — учетные записи, от имени которых программы могут управлять ресурсами.
Аккаунты Яндекс ID и федеративные аккаунты аутентифицируются в собственных системах. Yandex Cloud не имеет доступа к паролям этих пользователей и аутентифицирует только сервисные аккаунты с помощью сервиса IAM.
Доступ пользователей к ресурсам облака регулируется с помощью ролей. Сервисы Yandex Cloud могут предлагать разный уровень гранулярности назначения прав: в одних случаях роль можно назначить непосредственно на сам ресурс в сервисе, в других случаях права назначаются только на уровне каталога или облака, в котором размещен ресурс сервиса.
Таким образом, в инфраструктуре Yandex Cloud взаимодействуют различные категории ресурсов, ролей и пользователей. Контроль доступа к ресурсам выполняется сервисом IAM. Сервис IAM контролирует каждый запрос, чтобы все операции над ресурсами выполнялась только пользователями с необходимыми правами.
Федерации удостоверений
1.1 Настроена федерация удостоверений (Single Sign-On, SSO)
Yandex Cloud Organization — это единый сервис для управления составом организации, настройки интеграции с каталогом сотрудников и разграничения доступов пользователей к облачным ресурсам организации.
Для централизованного управления учетными данными используйте SAML-совместимые федерации удостоверений. С помощью федераций удостоверений компания может настроить Single Sign-On аутентификацию в Yandex Cloud через свой сервер IdP. При таком подходе сотрудники имеют возможность использовать свои корпоративные аккаунты, на которые распространяются политики безопасности компании, такие как:
- отзыв и блокирование аккаунтов;
- парольные политики;
- ограничение количества неуспешных попыток входа;
- блокирование сеанса доступа после установленного времени бездействия;
- двухфакторная аутентификация.
Совет
Используйте федеративные аккаунты вместо аккаунтов Яндекс ID, где это возможно. Помните, что для управления федерацией существует отдельная роль organization-manager.federations.admin
.
Чтобы все запросы аутентификации от Yandex Cloud содержали цифровую подпись, включите опцию Подписывать запросы аутентификации. Для завершения настройки потребуется скачать и установить сертификат Yandex Cloud. Скачать сертификат можно в поле Подписывать запросы аутентификации сразу после сохранения федерации.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите во вкладку Все сервисы → Yandex Cloud Organization → Федерации.
- Если в списке есть хотя бы одна настроенная федерация удостоверений, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Посмотрите информацию о настроенных федерациях:
yc organization-manager federation saml list \ --organization-id=<ID_организации>
-
Если в списке есть хотя бы одна настроенная федерация удостоверений, то рекомендация выполнена. Если нет, перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
- Инструкция по настройке SAML федерации удостоверений.
- Инструкция по настройке SAML федерации с KeyCloak
.
1.1.1 Настроено сопоставление групп пользователей в федерации удостоверений
Для организаций, в которых много участников, одинаковые права доступа к ресурсам Yandex Cloud могут потребоваться сразу нескольким пользователям. В этом случае роли и доступы эффективнее выдавать не персонально, а для группы.
Если вы используете группы пользователей в вашем поставщике удостоверений или собираетесь это сделать, настройте сопоставление групп пользователей между поставщиком удостоверений и Cloud Organization. Пользователи в группах поставщика удостоверений будут иметь права доступа к ресурсам Yandex Cloud из сопоставленных групп в Cloud Organization.
1.2 Учетные записи Яндекс ID используются только в исключительных случаях
Наиболее правильный с точки зрения безопасности подход к управлению учетными записями — это использование федерации удостоверений (подробнее в рекомендации № 1.1). В связи с этим необходимо стремиться к тому, чтобы в списке пользователей вашей организации находились только федеративные пользователи (пользователи c атрибутом FEDERATION ID
) и минимум учетных записей с Яндекс ID. Список допустимых исключений:
- Учетная запись с правами
billing.accounts.owner
(технически на текущий момент данную роль может иметь только учетная запись Яндекс ID). - Учетная запись с правами
organization-manager.organizations.owner
иresource-manager.clouds.owner
, если вы используете ее только для аварийного применения, например, когда сломалась настройка федерации. При необходимости можно удалить привилегированный аккаунт на Яндексе с рольюorganization-manager.organizations.owner
из организации. - Внешние учетные записи, например, контрагентов или подрядчиков, которые по каким-либо причинам вы не можете завести в вашей IdP.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите во вкладку Все сервисы → Yandex Cloud Organization → Пользователи.
- Если у всех учетных записей в колонке Федерация выставлено значение federation (кроме записей, указанных в списке допустимых исключений выше), то рекомендация выполняется. Если нет, перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска нефедеративных учетных записей в вашей организации, за исключением ID учетной записи, которая входит в список валидных исключений:
yc organization-manager user list --organization-id=<ID_организации> \ --format=json | jq -r '.[] | select(.subject_claims.sub!="<ID учетной записи, которая входит в список валидных исключений>")' | jq -r 'select(.subject_claims.federation | not)'
-
Если в списке нет учетных записей, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Удалите из вашей организации все учетные записи с Яндекс ID, кроме случаев из списка допустимых исключений.
1.3 Таймаут жизни cookie в федерации меньше 6 часов
В настройках федерации удостоверений необходимо убедиться, что значение параметра Время жизни cookie меньше либо равно 6 часов. Это необходимо, чтобы минимизировать риск компрометации рабочих станций пользователей облака.
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите во вкладку Organizations.
- Далее перейдите во вкладку Федерации и выберите вашу федерацию.
- Найдите параметр Время жизни cookie.
- Если значение этого параметра меньше либо равно 6 часам, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска учетных записей с назначенными примитивными ролями на уровне организации:
export ORG_ID=<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 bpfdshe1skaqcjp6uc50 --format=json | jq -r '. | select(.cookie_max_age>"21600s")' done
-
Если выдается пустая строка, то рекомендация выполняется. Если выдается результат с настройкой текущей федерации, где параметр
cookie_max_age
> 21600s, то перейдите к п.Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Задайте значение параметра Время жизни cookie равным 6 часам (21600 секундам) или меньше.
Особенности управления доступом
1.4 Только необходимые администраторы управляют членством в IAM-группах
Для управления доступом к ресурсам удобно использовать группы пользователей. Необходимо контролировать права доступа к самой группе как к ресурсу. Пользователь с правами доступа к группе может управлять членством других пользователей. Случаи, в которых пользователь получает такие права:
- Пользователю назначена роль
organization-manager.groups.memberAdmin
на организацию. - Пользователю назначена роль
organization-manager.groups.memberAdmin
на конкретную группу как на ресурс. - Пользователю назначена роль
organization-manager.organizations.owner
илиadmin
или другая привилегированная роль на всю организацию. - Пользователю назначена роль
admin
илиeditor
на конкретную группу как на ресурс (нерекомендованный сценарий).
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите во вкладку Все сервисы → Yandex Cloud Organization → Группы → Выберите нужную группу → Права доступа к группе.
- Нажмите тумблер Наследуемые роли.
- Если в списке отсутствуют учетные записи, которые не должны иметь прав управления членством в группе, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Удалите права на доступ к группе у учетных записей, которым это не требуется.
1.5 Используются сервисные роли вместо примитивных: admin, editor, viewer, auditor
Принцип минимальных привилегий требует назначать минимально необходимые для работы роли. Не рекомендуется использовать примитивные роли admin
, editor
, viewer
и auditor
, действующие во всех сервисах, так как это противоречит принципу минимальных привилегий. Для более избирательного управления доступом и реализации принципа минимальных привилегий используйте сервисные роли, которые содержат разрешения только для определенного типа ресурсов в указанном сервисе. Со списком всех сервисных ролей можно ознакомиться в справочнике ролей Yandex Cloud.
Используйте роль auditor без возможности доступа к данным везде, где это возможно.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите во вкладку Все сервисы → Yandex Cloud Organization → Пользователи.
- Если у всех учетных записей в колонке Права доступа отсутствуют примитивные роли
admin
,editor
иviewer
, то рекомендация выполняется. Если нет, то перейдите к п.Инструкции и решения по выполнению
. - Далее перейдите в общее меню облака (нажать на облако в исходном меню облака). Выберите вкладку Права доступа.
- Если у всех учетных записей в колонке Роли отсутствуют примитивные роли
admin
,editor
иviewer
, то рекомендация выполняется. Если нет, то перейдите к п.Инструкции и решения по выполнению
. - Далее перейдите в каждый каталог каждого облака и по аналогии перейдите во вкладку Права доступа.
- Если у всех учетных записей в колонке роли отсутствуют примитивные роли
admin
,editor
иviewer
, то рекомендация выполняется. Если нет, то перейдите к п.Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска учетных записей с назначенными примитивными ролями на уровне организации:
Bash
export ORG_ID=<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")'
PowerShell
$ORG_ID = "<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
-
Если в списке отсутствуют учетные записи, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
. -
Выполните команду для поиска учетных записей с назначенными примитивными ролями на уровне облаков:
Bash
export ORG_ID=<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
PowerShell
Install-Module -Name Join-Object $ORG_ID = "<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
-
Если в списке отсутствуют учетные записи, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
. -
Выполните команду для поиска учетных записей с назначенными примитивными ролями на уровне всех каталогов в ваших облаках:
Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Если в списке отсутствуют учетные записи, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Проанализируйте найденные учетные записи с назначенными примитивными ролями admin
, editor
и viewer
и замените их на сервисные гранулярные роли в соответствии с вашей матрицей ролей.
Чтобы просмотреть полный список доступов субъекта, воспользуйтесь инструкцией.
1.6 Используется роль auditor для исключения доступа к данным пользователей
Для пользователей, которые не нуждаются в доступе к данным (таких как внешние подрядчики или аудиторы), необходимо назначить роль auditor
.
Роль auditor
это роль с минимальными привилегиями и без доступа к данным сервисов. Она дает разрешение на чтение конфигурации и метаданных сервисов.
Роль auditor
позволяет выполнять следующие операции:
- Просмотр информации о ресурсе.
- Просмотр метаданных ресурса.
- Просмотр списка операций с ресурсом.
Использование роли auditor
по умолчанию позволяет более избирательно управлять доступом и реализовывать принцип минимальных привилегий.
- В консоли управления
перейдите в нужный каталог. - Перейдите на вкладку Права доступа.
- Нажмите кнопку Назначить роли.
- В окне Настройка прав доступа нажмите кнопку Выбрать пользователя.
- Выберите пользователя из списка или воспользуйтесь поиском по пользователям.
- Нажмите кнопку Добавить роль.
- Выберите роль
auditor
в каталоге. - Нажмите кнопку Сохранить.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска учетных записей с ролью
auditor
на уровне организации:export ORG_ID=<ID_организации> yc organization-manager organization list-access-bindings \ --id=${ORG_ID} \ --format=json | jq -r '.[] | select(.role_id=="auditor")'
Если в списке отсутствуют учетные записи, то перейдите к п.
Инструкции и решения по выполнению
. -
Выполните команду для поиска учетных записей с ролью
auditor
на уровне облаков:export ORG_ID=<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
Если в списке отсутствуют учетные записи, то перейдите к п.
Инструкции и решения по выполнению
. -
Выполните команду для поиска учетных записей с ролью
auditor
на уровне всех каталогов в ваших облаках:export ORG_ID=<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
Если в списке отсутствуют учетные записи, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
- Назначьте роль
auditor
пользователям, которые не нуждаются в доступе к данным. - Удалите избыточные права аккаунта с помощью сервиса IAM.
Сервисные аккаунты
1.7 Облачные сущности с сервисными аккаунтами учтены и ограничены
Сервисный аккаунт — аккаунт, от имени которого программы могут управлять ресурсами в Yandex Cloud. Сервисный аккаунт служит для выполнения запросов от имени приложения.
- Не используйте вместо сервисных аккаунтов аккаунты сотрудников. Например, если сотрудник уволится или сменит подразделение, его аккаунт потеряет права, что может привести к сбою приложения.
- Не записывайте ключи сервисных аккаунтов напрямую в код приложения, конфигурационные файлы или переменные окружения.
При использовании сервисных аккаунтов:
-
Применяйте механизм назначения сервисного аккаунта виртуальной машине и получения токена через сервис метаданных.
-
Дополнительно: настройте локальный файрвол на ВМ так, чтобы только необходимые процессы и пользователи системы имели доступ к сервису метаданных (IP-адрес:
169.254.169.254
).Пример блокирования доступа от всех пользователей, кроме указанного (в данном случае
root
):sudo iptables --append OUTPUT --proto tcp \ --destination 169.254.169.254 --match owner ! --uid-owner root \ --jump REJECT
Облачные сущности, на которые назначены сервисные аккаунты, должны быть учтены и ограничены, т.к., например, если сервисный аккаунт назначен на ВМ, то злоумышленник может получить токен сервисного аккаунта из сервиса метаданных изнутри ВМ.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите в нужный каталог и откройте настройки нужной ВМ.
- Нажмите Изменить.
- На экране появится информация о сервисном аккаунте.
- Повторите действия для всех ВМ во всех каталогах.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска ВМ, на которые назначены сервисные аккаунты в вашей организации:
export ORG_ID=<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.8 Сервисным аккаунтам назначены минимальные привилегии
Следуйте принципу минимальных привилегий и назначайте сервисному аккаунту только те роли, которые необходимы для функционирования приложения.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите в нужный каталог.
- В списке сервисов выберите Identity and Access Management.
- На панели слева выберите
Сервисные аккаунты. - Проверьте список сервисных аккаунтов.
- Повторите действия для других каталогов.
- Перейдите во вкладку Права доступа на уровнях облаков и каталогов.
Права доступа на уровне организации можно посмотреть только в YC CLI.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для отображения всех сервисных аккаунтов организации в формате
<id_сервисного_аккаунта>:<имя_сервисного_аккаунта>
:export ORG_ID=<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
-
Выполните команду для отображения всех прав доступа конкретного сервисного аккаунта на организацию:
export ORG_ID=<ID_организации> yc organization-manager organization list-access-bindings \ --id=${ORG_ID} \ --format=json | jq -r '.[] | select(.subject.type=="serviceAccount")'
-
Просмотрите права доступа сервисного аккаунта на всех облаках:
export ORG_ID=<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;
-
Просмотрите права доступа сервисного аккаунта на всех каталогах:
export ORG_ID=<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
-
Если в списках отсутствуют избыточные права, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
- Посмотрите полный список доступов сервисного аккаунта с помощью сервиса Yandex Security Deck.
- Отзовите избыточные доступы у сервисного аккаунта с помощью сервиса Security Deck.
- Удалите избыточные права у сервисного аккаунта с помощью сервиса IAM.
1.9 Только доверенные администраторы имеют доступ к сервисным аккаунтам
Существует возможность назначать права на использование сервисного аккаунта от имени другого пользователя или сервисного аккаунта.
Следуйте принципу минимальных привилегий при выдаче доступа к сервисному аккаунту как к ресурсу: при наличии у пользователя прав на сервисный аккаунт, у него также появляется доступ и ко всем его правам. Назначайте роли на использование и управление сервисными аккаунтами минимальному кругу пользователей.
Каждый сервисный аккаунт с расширенными правами нужно размещать как ресурс в отдельном каталоге. Это необходимо для того, чтобы случайно не выдать пользователю права на такой сервисный аккаунт вместе с правами на каталог с компонентом сервиса.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите в нужный каталог.
- В списке сервисов выберите Identity and Access Management.
- На панели слева выберите
Сервисные аккаунты. - Нажмите на сервисный аккаунт и перейдите во вкладку Права доступа.
- Проверьте права, назначенные на сервисный аккаунт.
- Если в списке находятся только валидные администраторы, рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для отображения всех сервисных аккаунтов в облаках:
export ORG_ID=<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;
-
Выполните команду для отображения всех прав доступа на конкретный сервисный аккаунт как на ресурс:
yc iam service-account list-access-bindings \ --id <ID_сервисного_аккаунта>
-
Если в списке находятся только валидные администраторы, рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Удалите избыточные права сервисного аккаунта с помощью сервиса IAM.
1.10 Выполняется периодическая ротация ключей сервисных аккаунтов
В Yandex Cloud поддерживаются следующие ключи доступа, которые могут быть созданы для сервисных аккаунтов:
- IAM-токены — действуют 12 часов.
- API-ключи — можно выбрать любой срок действия.
- Авторизованные ключи — не имеют срока действия.
- Статические ключи доступа, совместимые с AWS API — не имеют срока действия.
Ключи без срока действия требуется ротировать самостоятельно — удалять и создавать новые. Дату создания можно проверить в свойствах ключа. Рекомендуется ротировать ключи как минимум раз в 90 дней, в соответствии со стандартами информационной безопасности, например, PCI DSS.
- Откройте консоль Yandex Cloud в вашем браузере.
- Перейдите в нужный каталог.
- В списке сервисов выберите Identity and Access Management.
- На панели слева выберите
Сервисные аккаунты. - Нажмите на нужный сервисный аккаунт и в разделе Свойства ключей доступа проверьте дату создания каждого ключа.
- Повторите действия в каждом из своих каталогов.
- Если даты создания ключей не старше 90 дней, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Проверьте дату создания ключей:
Bash
export ORG_ID=<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
export ORG_ID=<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
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
Данный скрипт возвращает три массива объектов — со статическими, авторизованными и API-ключами, а также с автоматическим определением истекших ключей (более 90 дней).
-
Если в списке любого типа ключей отсутствуют ключи, у которых дата в поле
created_at
старше 90 дней, то рекомендация выполняется. Если нет, то перейдите к п.Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Для ротации ключей в зависимости от их типа воспользуйтесь инструкцией.
1.11 Для API-ключей сервисных аккаунтов заданы минимально необходимые области действия
Область действия — совокупность разрешенных сервисному аккаунту действий с ресурсами сервиса. В сервисе может быть больше одной области действия. API-ключ с заданными областями действия нельзя использовать в других сервисах или областях действия.
Области действия ограничивают применение API-ключей в дополнение к собственным правам доступа сервисного аккаунта. Настройка ограничений области и срока действия позволяет снизить риск несанкционированного использования ключей. Задавайте для API-ключей только те области действия, которые действительно необходимы.
- В консоли управления
перейдите в каталог, которому принадлежит сервисный аккаунт. - В списке сервисов выберите Identity and Access Management.
- На панели слева выберите
Сервисные аккаунты и выберите нужный сервисный аккаунт. - В блоке API-ключи обратите внимание на поле Область действия в таблице с информацией о ваших API-ключах.
- Если для всех API-ключей заданы минимально необходимые области действия, рекомендация выполняется. В противном случае перейдите к п. «Инструкции и решения по выполнению».
Выполните команду, указав имя сервисного аккаунта, которому принадлежат ваши API-ключи:
yc iam api-key list --service-account-name <имя_сервисного_аккаунта>
Если в выводе команды в поле SCOPES
для всех API-ключей заданы минимально необходимые области действия, рекомендация выполняется. В противном случае перейдите к п. «Инструкции и решения по выполнению».
Инструкции и решения по выполнению:
Создайте API-ключ с заданной областью действия.
1.12 Токен для облачных функций и ВМ выдается через сервисный аккаунт
Для получения IAM-токена в ходе выполнения функции необходимо назначить функции сервисный аккаунт. В этом случае функция получит IAM-токен с помощью встроенных механизмов Yandex Cloud, без необходимости передачи каких-либо секретов в функцию извне. Аналогично и для ВМ. Дополнительную информацию о получении IAM-токена в функции см. в разделе Получение IAM-токена сервисного аккаунта с помощью функции.
Проанализируйте все ваши ВМ и облачные функции на предмет созданных вручную токенов сервисных аккаунтов. Правильно использовать токены путем назначения сервисного аккаунта на сущность и использовать токен аккаунта изнутри, через сервис метаданных.
1.13 Используется имперсонация, где это возможно
Имперсонация позволяет пользователю выполнять действия от имени сервисного аккаунта и предоставляет возможность временно расширить права, не прибегая к генерации статических учетных данных. Может быть полезна в следующих сценариях: дежурства, локальная разработка, проверка прав доступа.
- В консоли управления
на панели слева нажмите на имя нужного облака. - Перейдите на вкладку Права доступа и проверьте наличие роли
iam.serviceAccounts.tokenCreator
.
Инструкции и решения по выполнению:
Если роль iam.serviceAccounts.tokenCreator
отсутствует, то настройте имперсонацию для сервисных аккаунтов для обеспечения временного доступа к критичным данным по данной инструкции.
Метаданные ВМ
1.14 В сервисе метаданных ВМ отсутствуют облачные ключи в открытом виде
Не записывайте ключи сервисных аккаунтов и другие ключи в метаданные виртуальной машины напрямую. Используйте механизм назначения сервисного аккаунта виртуальной машине и получения токена через сервис метаданных. Чувствительные данные могут находиться в любом поле метаданных, но самое распространенное — user-data
(за счет использования в утилите cloud-init).
Чтобы получить метаданные виртуальной машины снаружи ВМ, выполните команду:
Bash
yc compute instance get \
--id <идентификатор_виртуальной_машины> \
--full \
--format=json | jq -r '. | select(.metadata."user-data") | .metadata."user-data"'
PowerShell
yc compute instance get `
--id <идентификатор_виртуальной_машины> `
--full `
--format=json | ConvertFrom-Json
Ознакомьтесь со списком всех регулярных выражений для поиска секретов учетных данных облачных аккаунтов:
- 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
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
В Yandex Cloud используются секреты разных типов, которые могут оказаться в метаданных или переменных окружения ВМ в явном виде. Для поиска кандидатов ВМ с секретами облака в метаданных, выполните следующий скрипт:
Bash
export ORG_ID=<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
PowerShell
$ORG_ID=<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
Скрипт выполняет поиск всех секретов по всем ВМ в организации и возвращает вхождения строк с секретом в
user-data
, номер строки и тип секрета (IAM Token
,Static Key
,API Key
илиPrivate Key
).Пример вывода
$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
-
Если в списке отсутствуют строки, содержащие секреты, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Удалите ключи из метаданных ВМ, у которых были найдены отклонения:
- В консоли управления
выберите каталог, которому принадлежит ВМ. - В списке сервисов выберите Compute Cloud.
- На панели слева выберите
Виртуальные машины. - В строке с нужной ВМ нажмите значок
и выберите Редактировать. - Раскройте секцию Метаданные и удалите ключи, нажав
. - Нажмите Сохранить изменения.
Если у вас еще нет интерфейса командной строки Yandex Cloud, установите и инициализируйте его.
По умолчанию используется каталог, указанный при создании профиля CLI. Чтобы изменить каталог по умолчанию, используйте команду yc config set folder-id <идентификатор_каталога>
. Также для любой команды вы можете указать другой каталог с помощью параметров --folder-name
или --folder-id
.
-
Посмотрите описание команды CLI для удаления метаданных:
yc compute instance remove-metadata --help
-
Удалите ключи:
yc compute instance remove-metadata <идентификатор_ВМ> --keys <имя_SSH-ключа>
Чтобы удалить SSH-ключи из метаданных ВМ, воспользуйтесь методом REST API updateMetadata для ресурса Instance или вызовом gRPC API InstanceService/UpdateMetadata.
В запросе передайте параметр delete
с SSH-ключом.
Пример запроса для REST API
curl \
--request POST \
--header "Authorization: Bearer <IAM-токен>" \
--data '{"delete":["<имя_SSH-ключа>"]}' \
https://compute.api.cloud.yandex.net/compute/v1/instances/<идентификатор_ВМ>/updateMetadata
1.15 На ВМ отключено получение токена через AWS IMDSv1
В облаке есть сервис метаданных, предоставляющий сведения о работе виртуальных машин.
Изнутри виртуальной машины метаданные доступны в следующих форматах:
- Google Compute Engine (поддерживаются не все поля).
- Amazon EC2 (поддерживаются не все поля).
Формат Amazon EC2 Instance Metadata Service version 1 (IMDSv1) имеет ряд недостатков. Наиболее критичный из них — это риск компрометации токена сервисного аккаунта через сервис метаданных с помощью SSRF-атаки. Подробности в официальном блоге AWS
В Yandex Cloud пока нет поддержки второй версии, поэтому строго рекомендуется технически отключать возможность получения токена сервисного аккаунта через Amazon EC2 сервис метаданных.
Сервис метаданных Google Compute Engine использует дополнительный заголовок для защиты от SSRF и повышения безопасности.
Отключить получение токена сервисного аккаунта через Amazon EC2 сервис метаданных можно с помощью параметра ВМ aws_v1_http_token:DISABLED.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска ВМ, у которых включено использование IMDSv1 для получения токена:
export ORG_ID=<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
-
Если в списке отсутствуют строки, то рекомендация выполнена. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
В блоке metadata_options задайте параметру aws_v1_http_token значение DISABLED
у найденных ВМ:
yc compute instance update <ID_виртуальной_машины> \
--metadata-options aws-v1-http-token=DISABLED
Привилегированные аккаунты
1.16 Настроена двухфакторная аутентификация для привилегированных аккаунтов
Рекомендуется использовать двухфакторную аутентификацию (2FA) для доступа к облачной инфраструктуре, чтобы избежать рисков, связанных с компрометацией пользовательских учетных записей. Доступ в консоль Yandex Cloud может быть организован с помощью 2FA.
Чтобы подключить двухфакторную аутентификацию, обратитесь к поставщику удостоверений (identity provider) с поддержкой 2FA и настройте SAML-совместимую федерацию удостоверений. В Yandex Cloud нет своего IdP и задача идентификации пользователей решается с помощью внешних сервисов — Яндекс ID или корпоративных систем, интегрированных с помощью федерации удостоверений. Например, если вы используете IdP системы Active Directory или Keycloak, то настройте 2FA в данных системах. Необходимо настроить 2FA как минимум для привилегированных учетных записей облака.
Для аккаунта Яндекс ID настройте 2FA согласно инструкции
- Откройте UI Яндекс ID в вашем браузере.
- Перейдите на вкладку Безопасность
. - Проверьте, что указан способ входа с помощью дополнительного ключа.
- Если способ входа с помощью ключа настроен, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
. - Если вы используете сторонние IdP, проверьте настройки по инструкциям.
Инструкции и решения по выполнению:
- Двухфакторная аутентификация — Яндекс ID
. - KeyCloak — Creating other credentials
. - Configure Additional Authentication Methods for AD FS
.
1.17 Привилегированные роли назначены только доверенным администраторам
К привилегированным пользователям Yandex Cloud относятся аккаунты со следующими ролями:
billing.accounts.owner
;admin
, назначенная на платежный аккаунт;organization-manager.organizations.owner
;organization-manager.admin
;resource-manager.clouds.owner
;admin
,editor
, назначенные на организацию;admin
,editor
, назначенные на облако;admin
,editor
, назначенные на каталог.
Роль billing.accounts.owner
автоматически выдается при создании платежного аккаунта и не может быть переназначена другому пользователю. Роль позволяет выполнять любые действия с платежным аккаунтом.
Роль billing.accounts.owner
может быть назначена только аккаунту Яндекс ID. Аккаунт с ролью billing.accounts.owner
используется при настройке способов оплаты и подключении облаков.
Безопасности этого аккаунта следует уделять повышенное внимание, поскольку он обладает значительными полномочиями и не может быть объединен с корпоративным аккаунтом.
Наиболее правильным подходом можно считать отказ от регулярного использования данного аккаунта:
- Используйте его только при первоначальной настройке и внесении изменений.
- На время активного использования данного аккаунта включите двухфакторную аутентификацию (2FA) в Яндекс ID.
- Затем, если вы не используете способ оплаты банковской картой (доступный только для данной роли), назначьте данному аккаунту сложный пароль (сгенерированный с помощью специализированного ПО), отключите 2FA и не используйте этот аккаунт без необходимости.
- После каждого использования меняйте пароль на сгенерированный заново.
Отключить 2FA рекомендуется только для этого аккаунта и в случае, если аккаунт не закреплен
за конкретным сотрудником. Эта мера нужна, чтобы избежать привязки критически важного аккаунта к личному устройству.
Для управления платежным аккаунтом назначьте роль admin
или editor
на платежный аккаунт выделенному сотруднику организации с федеративным аккаунтом.
Для просмотра платежных данных назначьте роль viewer
на платежный аккаунт выделенному сотруднику организации с федеративным аккаунтом.
Роль organization-manager.organizations.owner
по умолчанию получает владелец организации — пользователь, который ее создал. Роль дает возможность назначать владельцев организации, а также пользоваться всеми полномочиями администратора.
Роль resource-manager.clouds.owner
автоматически выдается при создании первого облака в организации. Пользователь с этой ролью может выполнять любые операции с облаком и ресурсами в нем, а также выдавать доступ к облаку другим пользователям: назначать роли и отзывать их.
Назначайте роль resource-manager.clouds.owner
и organization-manager.organizations.owner
одному или нескольким сотрудникам организации с федеративным аккаунтом. Аккаунту Яндекс ID, с которым создано облако, назначьте сложный пароль и используйте только в случае крайней необходимости, например, при поломке федерации.
Федеративный аккаунт с одной из привилегированных ролей, указанных выше, необходимо всесторонне защитить:
- Включите двухфакторную аутентификацию.
- Запретите аутентификацию с устройств, не управляемых организацией.
- Настройте мониторинг попыток входа и задайте пороги предупреждений.
Назначайте роли admin
на облака, каталоги и платежные аккаунты федеративным аккаунтам. Минимизируйте количество аккаунтов с этими ролями и регулярно перепроверяйте потребность в этих ролях для тех аккаунтов, которым они назначены.
Проверка ролей на сервис Yandex Cloud Billing:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите в сервис Yandex Cloud Billing
. - Проверьте кому назначены роли:
billing.accounts.owner
,admin
.
Проверка ролей на организацию:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите во вкладку Все сервисы → Yandex Cloud Organization → Пользователи.
- Проверьте кому назначены роли:
admin
,organization-manager.organizations.owner
,organization-manager.admin
,resource-manager.clouds.owner
.
Проверка ролей на облако:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите в общее меню облака: нажмите на облако в исходном меню облака. Выберите вкладку Права доступа.
- Проверьте кому назначены роли:
admin
,editor
,resource-manager.clouds.owner
.
Проверка ролей на каталоге:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Далее перейдите в каждый каталог каждого облака и по аналогии перейдите во вкладку Права доступа.
- Проверьте кому назначена роль
admin
. - Если все привилегированные роли назначены доверенным администраторам, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Найдите привилегированные права на уровне организации:
Bash
export ORG_ID=<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")'
PowerShell
$ORG_ID = "<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
-
Найдите привилегированные права на уровне облаков:
Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Выполните команду для поиска привилегированных прав на уровне всех каталогов в ваших облаках:
Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Если все привилегированные роли назначены доверенным администраторам, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Если обнаружены роли, которые назначены недоверенным администраторам, необходимо провести расследование и удалить лишние права.
Локальные пользователи управляемых БД
1.18 Для локальных пользователей управляемых БД задан стойкий пароль
Для работы с БД на прикладном уровне помимо сервисных IAM ролей создается отдельный локальный пользователь — владелец БД. В отношении него действует следующая парольная политика:
- пароль должен содержать цифры, буквы в верхнем регистре, буквы в нижнем регистре, специальные символы;
- длина пароля — не менее 8 символов.
Также рекомендуется использовать сгенерированные пароли. В этом случае в сервисе Yandex Lockbox будет создан сгенерированный секрет, значение которого будет являться паролем пользователя СУБД.
Убедитесь, что пароль периодически ротируется в ручном режиме и соответствует парольным политикам вашей компании. Данный пароль хранится на стороне клиента и недоступен для просмотра в консоли управления, CLI и API.
Доступ третьих лиц
1.19 Доступ для подрядных организаций и третьих лиц контролируется
Если вы предоставляете доступ к облакам внешним подрядным организациям, соблюдайте следующие меры безопасности:
- Назначайте права сотрудникам подрядных организаций с учетом принципа минимальных привилегий.
- По возможности создавайте отдельный аккаунт для сотрудников внешних организаций в вашем корпоративном IdP и назначайте ему необходимые политики.
- Предъявляйте требование по бережному обращению с секретами аккаунта.
- Перепроверяйте актуальность необходимости доступа внешних пользователей к вашей облачной инфраструктуре.
- Используйте роль auditor без возможности доступа к данным везде, где это возможно.
Проверьте все учетные записи в вашей организации и убедитесь, что вы знаете обо всех учетных записях подрядных организаций и третьих лиц и выполняете рекомендации выше.
Ресурсная модель
1.20 Используется корректная ресурсная модель
При разработке модели доступа для вашей инфраструктуры рекомендуется пользоваться принципом минимальных привилегий и принципом разделения ресурсов. Схематически ресурсную модель облака можно представить в виде вложенных друг в друга контейнеров: организация, облако, каталог.
Организация — корневой контейнер, содержащий информацию о пользователях, их ролях, а также некоторые сервисы (Yandex DataLens, Yandex DataSphere и т.д.) Роли уровня организации автоматически наследуется всеми низлежащими контейнерами. Поэтому рекомендуется выдавать роли на уровне организации только администраторам и пользователям сервисов уровня организации.
Облако — контейнер под организацией, который содержит каталоги с сервисами. Облако логически объединяет несколько взаимосвязанных сред в его каталогах. Однако прямой связности между двумя облаками не предусмотрено. Роли, назначенные на уровне облака, наследуется всеми каталогами внутри него. Рекомендуется не выдавать слишком широкие привилегии на этом уровне.
Каталог — контейнер с ресурсами и сервисами. В рамках одного облака возможно организовывать сетевую связность между каталогами. Поэтому рекомендуется связанные сервисы и среды внутри инфраструктуры располагать в соседних каталогах.
При разработке модели доступа для вашей инфраструктуры рекомендуется использовать следующие подходы:
- Как минимум одна организация для компании (корневой контейнер, от которого роли пользователей наследуются на облака, каталоги и сервисы).
- Хорошей практикой является группировка ресурсов по проектам. Рекомендуется группировать ресурсы сервисов по назначению и помещать их в отдельные облака. Для наиболее строгой изоляции — в отдельные каталоги.
- Если над сервисами работают разные команды, имеет смысл разделить ресурсы этих команд в разные облака.
- Все критичные ресурсы помещайте в отдельные каталоги или облака. К критичным относятся в том числе ресурсы, которые связаны с обработкой платежных данных, персональных данных и данных, содержащих коммерческую тайну.
- Хорошая практика — не выдавать пользователям роли
.admin
на каталог с продуктовой средой. В этом случае рекомендуется использовать подходGitOps
и управлять инфраструктурой каталога с помощью Terraform и GitLab. - Группы ресурсов, которые требуют различного административного доступа например, DMZ, CDE, security, backoffice и т.д., поместите в разные каталоги или облака.
- При разработке приложений необходимо разделять тестовые и промышленные среды.
- Общие ресурсы (например, сеть и группы безопасности) поместите в отдельный каталог для разделяемых ресурсов (в случае разделения компонентов по каталогам).
Проанализируйте вашу ресурсную модель и убедитесь, что рекомендации, указанные выше, выполняются.
публичный доступ
1.21 На ресурсах в организации отсутствует В Yandex Cloud существует возможность предоставлять публичный доступ на ресурсы. Публичный доступ предоставляется путем назначения прав доступа для публичных групп (All authenticated users
, All users
).
Описание публичных групп:
All authenticated users
— все пользователи, прошедшие аутентификацию. Это все зарегистрированные пользователи или сервисные аккаунты Yandex Cloud: как из ваших облаков, так и из облаков других пользователей.All users
— любой пользователь, аутентификация не требуется.
Важно
Сейчас All users
поддерживается только в сервисах: Object Storage при управлении доступом с помощью ACL, Container Registry, Cloud Functions. В остальных сервисах назначение роли для группы All users
эквивалентно назначению роли для All authenticated users
.
Убедитесь, что на ваши ресурсы — облака, каталоги, бакеты и т.д., не предоставлен публичный доступ для этих групп.
Проверка ролей в облаке:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Далее перейдите в общее меню облака (нажать на облако в исходном меню облака). Выберите вкладку Права доступа.
- Проверьте, есть ли среди пользователей
All users
иAll authenticated users
.
Проверка ролей в каталоге:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите в нужный каталог нужного облака и перейдите во вкладку Права доступа.
- Проверьте, есть ли среди пользователей
All users
иAll authenticated users
. - Повторите действия для всех каталогов всех ваших облаков.
Проверка ролей в Object Storage:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите в нужное облако и найдите сервис Object Storage.
- Нажмите на три точки напротив бакета и проверьте ACL бакета на наличие
allUsers
,allAuthenticatedUsers
. - Зайдите внутрь бакета и проверьте ACL на каждый объект бакета на наличие
allUsers
,allAuthenticatedUsers
. - Зайдите в глобальные настройки бакета и в разделе Доступ на чтение объектов проверьте, что параметр Публичный выключен.
- Повторите действия для всех бакетов и объектов во всех ваших облаках.
Проверка ролей в Container Registry:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Далее перейдите в каждое облако и найдите сервис Container Registry.
- Перейдите в необходимый реестр и слева нажмите Права доступа.
- Проверьте, есть ли среди пользователей
All users
иAll authenticated users
. - Повторите действия для всех ваших облаков.
Проверка ролей в Cloud Functions:
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Далее перейдите в каждое облако и найдите сервис Cloud Functions.
- Перейдите во все облачные функции и проверьте, что параметр Публичный доступ выключен.
- Если в каждом указанном ресурсе нет субъектов
All users
иAll authenticated users
, то рекомендация выполняется. Если есть, то перейдите к п.Инструкции и решения по выполнению
.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для поиска учетных записей с назначенными примитивными ролями на уровне организации:
Bash
export ORG_ID=<ID_организации> yc organization-manager organization list-access-bindings \ --id=${ORG_ID} \ --format=json | jq -r '.[] | select(.subject.id=="allAuthenticatedUsers" or .subject.id=="allUsers")'
PowerShell
$ORG_ID = "<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
-
Выполните команду для поиска прав доступа
allUsers
,allAuthenticatedUsers
на уровне облаков:Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Выполните команду для поиска прав доступа
allUsers
,allAuthenticatedUsers
на уровне каталогов:Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Выполните команду для поиска прав доступа
allUsers
,allAuthenticatedUsers
на уровне Container Registry во всех каталогах:Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Выполните команду для поиска прав доступа
allUsers
,allAuthenticatedUsers
на уровне Cloud Functions во всех каталогах:Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
-
Если в каждом указанном ресурсе отсутствуют субъекты:
allUsers
,allAuthenticatedUsers
то рекомендация выполняется. Если нет, то перейдите к п.Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Если обнаружено наличие прав доступа у All users
, All authenticated users
, необходимо удалить данные права.
1.22 Контактные данные ответственного за организацию актуальны
В Yandex Cloud при регистрации облака клиент указывает контактные данные. Например, электронная почта используется для оповещений, связанных с инцидентами, плановыми работами и т.д.
Например, если со стороны облака были обнаружены аномальные активности в организации клиента или облачные ключи IAM становятся доступными во внешних репозиториях GitHub, клиенту будет направлено оповещение. Эта возможность реализована с помощью участия Yandex Cloud в программе Github Secret scanning partner program
Убедитесь, что контактные данные актуальны и указанный почтовый ящик рассылает сообщения нескольким ответственным.
- Откройте консоль управления Yandex Cloud в вашем браузере.
- Перейдите в сервис Yandex Cloud Billing
. - Перейдите во вкладку Данные аккаунта.
- В самом низу будет кнопка Редактировать данные в Яндекс Балансе.
- Проверьте указанные контактные данные.
- Если указанные данные актуальны, то рекомендация выполняется. Если нет, то перейдите к п.
Инструкции и решения по выполнению
.
Инструкции и решения по выполнению:
Укажите актуальные контактные данные по инструкции.
1.23 На ресурсах используются метки
Для отслеживания потоков данных и обозначения критичности ресурсов для управления привилегиями необходимо использование меток.
Например, для тегирования ресурсов, которые обрабатывают персональные данные в рамках Федерального закона Российской Федерации «О персональных данных» № 152-ФЗ нужно выбрать метку 152-fz:true
для:
В примере ниже показана проверка наличия метки к облачной сети Yandex Virtual Private Cloud. Аналогично вы можете проверить наличие метки у другого ресурса.
- В консоли управления
выберите каталог. - Выберите сервис Virtual Private Cloud.
- Проверьте наличие меток.
Инструкции и решения по выполнению:
Инструкция по управлению метками.
Уведомления и аудит
1.24 Уведомления безопасности Yandex Cloud включены
Для получения уведомлений о событиях в области безопасности, например, обнаруженных уязвимостях и их устранении, рекомендуется выбрать уведомления безопасности в настройках консоли управления.
- В консоли управления
нажмите Настройки . - Выберите раздел Уведомления.
- В настройках уведомлений включите опцию Безопасность.
Инструкции и решения по выполнению:
- Убедитесь, что уведомления настроены.
- Включите опцию Безопасность в настройках уведомлений консоли управления.
1.25 Отслеживается дата последней аутентификации сервисного аккаунта и последнего использования ключей доступа в Yandex Identity and Access Management
В консоли управления
Чтобы обеспечивать безопасность и контроль над доступом к ресурсам, отслеживать случаи несанкционированного использования ключей, а также удалять неиспользуемые ключи без риска нарушить работу сервисов Yandex Cloud, вы можете отслеживать даты последнего использования ключей доступа сервисных аккаунтов. Информация доступна на странице сервисного аккаунта в консоли управленияlast_used_at
при вызове методов управления ключами доступа через API.
Подробнее см. в разделе Ключи сервисного аккаунта.
- В консоли управления
перейдите в каталог, которому принадлежит сервисный аккаунт с ключами доступа. - В списке сервисов выберите Identity and Access Management.
- На панели слева выберите
Сервисные аккаунты. - В открывшемся списке выберите нужный сервисный аккаунт.
- Данные о времени последнего использования ключа доступны в таблице с информацией о ключах в поле Дата последнего использования.
-
Посмотрите доступные вам организации и зафиксируйте необходимый ID:
yc organization-manager organization list
-
Выполните команду для отображения дат последней аутентификации сервисных аккаунтов и последнего использования ключей доступа:
Bash
export ORG_ID=<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
PowerShell
$ORG_ID = "<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
1.26 Регулярно проводится аудит прав доступа пользователей и сервисных аккаунтов с использованием Yandex Security Deck CIEM
В целях обеспечения безопасности данных и облачной инфраструктуры необходимо регулярно проводить аудит прав доступа, имеющихся у пользователей и сервисных аккаунтов.
Модуль диагностики доступов
Подробнее см. в разделе Модуль диагностики доступов (CIEM).
Инструкции и решения по выполнению:
Просмотреть список доступов субъекта.
Отозвать доступ у субъекта.