
AWS Least Privilege для распределенного высокоскоростного развертывания
Repokid использует Access Advisor, предоставляемый Aardvark, для удаления разрешений, предоставляющих доступ к неиспользуемым сервисам, из inline-политик IAM-ролей в учётной записи AWS.
mkvirtualenv repokid
git clone [email protected]:Netflix/repokid.git
cd repokid
pip install -e .
repokid config config.json
Вам понадобится таблица DynamoDB с именем repokid_roles (укажите учётную запись и endpoint в разделе dynamo_db файла конфигурации).
Таблица должна иметь следующие свойства:
RoleId (строка) в качестве первичного ключа раздела, без первичного ключа сортировки.Account, где первичный ключ раздела — Account, а проецируемые атрибуты — RoleId и Account.RoleName, где первичный ключ раздела — RoleName, а проецируемые атрибуты — RoleId и RoleName.Для разработки вы можете запустить DynamoDB локально.
Для локального запуска:
docker-compose up
Endpoint для DynamoDB будет http://localhost:8000. Панель администрирования DynamoDB доступна по адресу http://localhost:8001.
Если вы используете версию для разработки, таблица и индексы будут созданы автоматически.
Repokid требует IAM-роль в каждой учётной записи, которая будет опрашиваться. Кроме того, Repokid должен запускаться с ролью или пользователем, который может выполнять sts:AssumeRole для ролей разных учётных записей.
RepokidInstanceProfile:
sts:AssumeRole для всех RepokidRole.repokid_roles и всех индексов (указываются в подразделе assume_role раздела dynamo_db конфигурации) и возможность выполнять dynamodb:ListTables.RepokidRole:
RepokidInstanceProfile.connection_iam файла конфигурации.{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:DeleteInstanceProfile",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:GetAccountAuthorizationDetails",
"iam:GetInstanceProfile",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:ListInstanceProfiles",
"iam:ListInstanceProfilesForRole",
"iam:ListRolePolicies",
"iam:PutRolePolicy",
"iam:UpdateRoleDescription"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
Таким образом, если вы отслеживаете n учётных записей, вам всегда понадобится n+1 ролей (n RepokidRole и 1 RepokidInstanceProfile).
Запуск repokid config config.json создаёт файл, который необходимо отредактировать. Найдите и обновите следующие поля:
dynamodb: При использовании локального DynamoDB укажите endpoint http://localhost:8010. При использовании DynamoDB, размещённого в AWS, укажите region, assume_role и account_number.aardvark_api_location: Адрес вашего REST API Aardvark. Например, https://aardvark.yourcompany.net/api/1/advisors.connection_iam: Установите assume_role в RepokidRole (или любое другое имя, которое вы выбрали).Repokid использует фильтры для определения того, какие роли являются кандидатами на репо. Фильтры могут быть настроены под вашу среду, как описано ниже.
Роли могут быть исключены путём добавления в фильтр блокировки. Одна из распространённых причин исключения роли — если соответствующая рабочая нагрузка изредка выполняет действия, которые не были замечены, но, как известно, являются обязательными. Есть два способа исключить роль:
filter_config.BlocklistFilter.all.filter_config.BlocklistFilter.<ACCOUNT_NUMBER>.Чёрные списки также можно поддерживать в S3-файле блокировки. Они должны быть в следующем формате:
{
"arns": ["arn1", "arn2"],
"names": {"role_name_1": ["all", "account_number_1"], "role_name_2": ["account_number_2", "account_number_3"]}
}
Если вы предпочитаете репозировать только определённые роли, можете использовать фильтр исключительности. Например, вы хотите учитывать только роли, используемые в production или определёнными командами. Чтобы выбрать роли для репо, перечислите их имена в файлах конфигурации. Также поддерживаются шаблоны в стиле glob. Выбор ролей может быть задан для каждой учётной записи отдельно или глобально. Чтобы активировать этот фильтр, добавьте "repokid.filters.exclusive:ExclusiveFilter" в раздел active_filters файла конфигурации. Для настройки вы можете начать с автоматически сгенерированного файла конфигурации, в котором есть пример конфигурации в разделе "filter_config":
"ExclusiveFilter": {
"all": [
"<GLOB_PATTERN>"
],
"<ACCOUNT_NUMBER>": [
"<GLOB_PATTERN>"
]
}
По умолчанию фильтр возраста исключает роли, возраст которых меньше 90 дней. Чтобы изменить это, отредактируйте настройку конфигурации: filter_config.AgeFilter.minimum_age.
Могут быть созданы новые фильтры для поддержки внутренней логики. В Netflix у нас есть несколько, специфичных для наших случаев использования. Чтобы сделать их активными, убедитесь, что они находятся в пути Python, и добавьте их в конфигурацию в список в разделе active_filters.
Repokid расширяется с помощью хуков, которые вызываются до, во время и после различных операций, как указано ниже.
Хуки должны соответствовать следующему интерфейсу:
from repokid.hooks import implements_hook
from repokid.types import RepokidHookInput, RepokidHookOutput
@implements_hook("TARGET_HOOK_NAME", 1)
def custom_hook(input_dict: RepokidHookInput) -> RepokidHookOutput:
"""Функции хуков вызываются со словарём, содержащим ключи, перечисленные выше, в зависимости от целевого хука.
Любые изменения, внесённые во входные данные и возвращённые в выходных, будут переданы последующим функциям хуков.
"""
...
Примеры реализаций хуков можно найти в repokid.hooks.loggers.
Можно написать собственные фильтры, чтобы исключить роли из репо. Фильтры должны соответствовать следующему интерфейсу:
from repokid.filters import Filter
from repokid.types import RepokidFilterConfig
from repokid.role import RoleList
class CustomFilterName(Filter):
def __init__(self, config: RepokidFilterConfig = None) -> None:
"""Фильтры инициализируются словарём, содержащим содержимое `filter_config.FilterName`
из файла конфигурации. В этом примере инициализация будет с `filter_config.CustomFilterName`.
Конфигурация доступна через `self.config`.
Если вам не нужна какая-либо пользовательская логика инициализации, вы можете опустить эту функцию
в своём классе фильтра.
"""
super().__init__(config=config)
# пользовательская логика инициализации здесь
...
def apply(self, input_list: RoleList) -> RoleList:
"""Определить роли, которые нужно исключить, и вернуть их как RoleList"""
...
Простая реализация фильтра находится в repokid.filters.age. Более сложный пример — в repokid.blocklist.age.
После настройки Repokid используйте его следующим образом:
repokid update_role_cache <ACCOUNT_NUMBER>repokid display_role_cache <ACCOUNT_NUMBER>repokid display_role <ACCOUNT_NUMBER> <ROLE_NAME>repokid repo_role <ACCOUNT_NUMBER> <ROLE_NAME>repokid repo_all_roles <ACCOUNT_NUMBER> -cВместо немедленного выполнения репо вы можете запланировать его (команда schedule_repo). Время между планированием и возможностью выполнения настраивается, но по умолчанию роли могут быть репозированы через 7 дней после планирования. Затем вы можете выполнить команду repo_scheduled_roles, чтобы репозировать только те роли, которые уже были запланированы.
Допустим, вы считаете определённое разрешение особенно опасным в вашей среде. Здесь я использую s3:PutObjectACL в качестве примера. Вы можете использовать Repokid, чтобы найти все роли, имеющие это разрешение (даже скрытые в wildcard), и затем удалить только это одно разрешение.
Поиск и удаление:
repokid find_roles_with_permissions <permission>... [--output=ROLE_FILE]repokid remove_permissions_from_roles --role-file=ROLE_FILE <permission>... [-c]Пример:
$ repokid find_roles_with_permissions "s3:putobjectacl" "sts:assumerole" --output=myroles.json
...
$ repokid remove_permissions_from_roles --role-file=myroles.json "s3:putobjectacl" "sts:assumerole" -c
Repokid сохраняет копию каждой версии inline-политик, о которых ему известно. Они добавляются, когда во время update_role_cache обнаруживается другая версия политики, а также при каждом действии репо. Чтобы восстановить предыдущую версию, выполните:
Просмотреть все версии ролей: repokid rollback_role <ACCOUNT_NUMBER> <ROLE_NAME>
Восстановить конкретную версию: repokid rollback_role <ACCOUNT_NUMBER> <ROLE_NAME> --selection=<NUMBER> -c
Repokid ведёт подсчёт общего количества разрешений для каждой роли. Статистика добавляется при каждом выполнении update_role_cache или repo_role. Чтобы вывести всю статистику в CSV-файл, выполните: repokid repo_stats <OUTPUT_FILENAME>. Можно указать номер учётной записи, чтобы вывести статистику только для неё.
Новое в
v0.14.2
Repokid можно вызывать как библиотеку с помощью модуля repokid.lib:
from repokid.lib import display_role, repo_role, update_role_cache
account_number = "123456789012"
display_role(account_number, "superCoolRoleName")
update_role_cache(account_number)
repo_role(account_number, "superCoolRoleName", commit=True)
Repokid Dispatcher предназначен для прослушивания сообщений в очереди и выполнения действий. На данный момент доступны следующие действия:
Repokid будет отвечать через настраиваемый SNS-топик с информацией об успехах или ошибках. Компонент Dispatcher помогает организовать жизненный цикл репо в вашей организации. Вы можете предоставить очередь напрямую разработчикам, но, скорее всего, её следует защитить, поскольку откат может быть опасным действием, если выполнять его без осторожности.
Версионирование осуществляется с помощью setupmeta. Чтобы создать новый релиз:
python setup.py version --bump patch --push
# Проверьте вывод и убедитесь, что он соответствует ожиданиям
# Если всё в порядке, сделайте коммит и отправьте новый тег:
python setup.py version --bump patch --push --commit
| Имя хука | Контекст |
|---|
AFTER_REPO | role, errors |
AFTER_REPO_ROLES | roles, errors |
BEFORE_REPO_ROLES | account_number, roles |
AFTER_SCHEDULE_REPO | roles |
DURING_REPOABLE_CALCULATION | role_id, arn, account_number, role_name, potentially_repoable_permissions, minimum_age |
DURING_REPOABLE_CALCULATION_BATCH | role_batch, potentially_repoable_permissions, minimum_age |