Repokid 使用 Aardvark 提供的 Access Advisor,从 AWS 账户中 IAM 角色的内联策略中移除对未使用服务的访问权限。
mkvirtualenv repokid
git clone [email protected]:Netflix/repokid.git
cd repokid
pip install -e .
repokid config config.json
您需要一个名为 repokid_roles 的 DynamoDB 表(在配置文件的 dynamo_db 中指定账户和端点)。
该表应具有以下属性:
RoleId(字符串)作为主分区键,无主排序键Account 的全局二级索引,主分区键为 Account,投影属性为 RoleId 和 AccountRoleName 的全局二级索引,主分区键为 RoleName,投影属性为 RoleId 和 RoleName在开发环境中,您可以在 本地 运行 DynamoDB。
本地运行方式:
docker-compose up
DynamoDB 的端点为 http://localhost:8000。DynamoDB 管理面板可在 http://localhost:8001 访问。
如果您运行开发版本,表和索引将自动为您创建。
Repokid 需要在每个将要查询的账户中有一个 IAM 角色。此外,Repokid 需要使用一个可以 sts:AssumeRole 到不同账户角色的角色或用户来启动。
RepokidInstanceProfile:
sts:AssumeRole。repokid_roles 表及其所有索引具有 DynamoDB 权限(在配置中 dynamo_db 的 assume_role 子部分指定),并且能够运行 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:如果使用本地 dynamo,将端点设置为 http://localhost:8010。如果使用 AWS 托管的 dynamo,请设置 region、assume_role 和 account_number。aardvark_api_location:您的 Aardvark REST API 的位置。类似 https://aardvark.yourcompany.net/api/1/advisors。connection_iam:将 assume_role 设置为 RepokidRole 或您自定义的名称。Repokid 使用过滤器来决定哪些角色适合被 repo。过滤器可以根据您的环境进行配置,如下所述。
角色可以通过添加到黑名单过滤器来排除。一个常见的排除原因是,相应的工作负载可能会执行一些偶尔的操作,这些操作可能尚未被观察到,但已知是必需的。排除角色有两种方式:
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"]}
}
如果您只希望对某些角色进行 repo,可以使用独占过滤器。也许您只想考虑用于生产环境或特定团队的角色。要选择要 repo 的角色,您可以在配置文件中列出它们的名称。支持 Shell 风格的 glob 模式。角色选择可以针对单个账户或全局进行指定。
要激活此过滤器,请在配置文件的 active_filters 部分添加 "repokid.filters.exclusive:ExclusiveFilter"。要配置它,可以从自动生成的配置文件开始,该文件在 "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 中找到。
可以编写自定义过滤器来排除角色,使其不被 repo。过滤器必须遵循以下接口:
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您可以调度一个 repo 操作(schedule_repo 命令),而不是立即执行。调度与实际可执行之间的持续时间是可配置的,但默认情况下,角色在调度后 7 天才能进行 repo。然后您可以运行 repo_scheduled_roles 命令,仅对已调度的角色进行 repo。
假设您发现某个特定权限在您的环境中特别危险。这里以 s3:PutObjectACL 为例。您可以使用 Repokid 查找所有具有此权限的角色(甚至包括隐藏在通配符中的角色),然后仅移除该单个权限。
查找与移除:
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 会存储其知道的每个内联策略版本的副本。这些副本会在 update_role_cache 期间发现策略的不同版本时以及每次 repo 操作发生时添加。要恢复以前版本,运行:
查看角色的所有版本: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.lib 模块将 Repokid 作为库调用:
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 组件旨在帮助您在整个组织中操作化 repo 生命周期。您可以选择直接向开发者公开队列,但更可能的是应该加以保护,因为如果操作不当,回滚可能是一种破坏性操作。
版本管理由 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 |