
repokid v0.19.8
Mínimo privilegio en AWS para despliegue distribuido y de alta velocidad
Repokid
Repokid utiliza Access Advisor proporcionado por Aardvark para eliminar permisos que otorgan acceso a servicios no utilizados de las políticas inline de roles IAM en una cuenta de AWS.
Comenzando
Instalar
mkvirtualenv repokid
git clone [email protected]:Netflix/repokid.git
cd repokid
pip install -e .
repokid config config.json
DynamoDB
Necesitarás una tabla DynamoDB llamada repokid_roles (especifica la cuenta y el endpoint en dynamo_db del archivo de configuración).
La tabla debe tener las siguientes propiedades:
RoleId(string) como clave de partición primaria, sin clave de ordenación primaria- Un índice secundario global llamado
Accountcon una clave de partición primaria deAccountyRoleIdyAccountcomo atributos proyectados - Un índice secundario global llamado
RoleNamecon una clave de partición primaria deRoleNameyRoleIdyRoleNamecomo atributos proyectados
Para desarrollo, puedes ejecutar dynamo localmente.
Para ejecutar localmente:
docker-compose up
El endpoint de DynamoDB será http://localhost:8000. Se puede encontrar un panel de administración de DynamoDB en http://localhost:8001.
Si ejecutas la versión de desarrollo, la tabla y el índice se crearán automáticamente.
Permisos IAM
Repokid necesita un rol IAM en cada cuenta que se consultará. Además, Repokid debe ejecutarse con un rol o usuario que pueda sts:AssumeRole hacia los diferentes roles de las cuentas.
RepokidInstanceProfile:
- Solo crear uno.
- Necesita la capacidad de llamar a
sts:AssumeRolehacia todos los RepokidRoles. - Permisos DynamoDB para la tabla
repokid_rolesy todos los índices (especificados en la subsecciónassume_rolededynamo_dben la configuración) y la capacidad de ejecutardynamodb:ListTables
RepokidRole:
- Debe existir en cada cuenta a ser gestionada por repokid.
- Debe tener una política de confianza que permita a
RepokidInstanceProfile. - El nombre debe especificarse en
connection_iamen el archivo de configuración. - Tiene estos permisos:
{
"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": "*"
}
]
}
Por lo tanto, si estás monitoreando n cuentas, siempre necesitarás n+1 roles. (n RepokidRoles y 1 RepokidInstanceProfile).
Editando config.json
Ejecutar repokid config config.json crea un archivo que necesitarás editar. Busca y actualiza estos campos:
dynamodb: Si usas dynamo localmente, establece el endpoint enhttp://localhost:8010. Si usas dynamo alojado en AWS, estableceregion,assume_roleyaccount_number.aardvark_api_location: La ubicación de tu API REST de Aardvark. Algo comohttps://aardvark.yourcompany.net/api/1/advisorsconnection_iam: Estableceassume_roleaRepokidRole, o como lo hayas llamado.
Configuración Opcional
Repokid utiliza filtros para decidir qué roles son candidatos a ser repoed. Los filtros pueden configurarse para adaptarse a tu entorno como se describe a continuación.
Filtro de Lista Negra
Los roles pueden excluirse añadiéndolos al filtro Blocklist. Una razón común para excluir un rol es si la carga de trabajo correspondiente realiza acciones ocasionales que pueden no haber sido observadas pero se sabe que son necesarias. Hay dos formas de excluir un rol:
- Excluir nombre de rol para todas las cuentas: añadirlo a una lista en la configuración
filter_config.BlocklistFilter.all - Excluir nombre de rol para una cuenta específica: añadirlo a una lista en la configuración
filter_config.BlocklistFilter.<ACCOUNT_NUMBER>
Las listas negras también pueden mantenerse en un archivo S3 blocklist. Deben tener la siguiente forma:
{
"arns": ["arn1", "arn2"],
"names": {"role_name_1": ["all", "account_number_1"], "role_name_2": ["account_number_2", "account_number_3"]}
}
Filtro Exclusivo
Si prefieres repo solo ciertos roles puedes usar el filtro Exclusive. Quizás quieras considerar solo roles utilizados en producción o por ciertos equipos. Para seleccionar roles para repo puedes listar sus nombres en los archivos de configuración. También se admiten patrones glob estilo shell. La selección de roles puede especificarse por cuenta individual o globalmente. Para activar este filtro pon "repokid.filters.exclusive:ExclusiveFilter" en la sección active_filters del archivo de configuración. Para configurarlo puedes comenzar con el archivo de configuración autogenerado, que tiene un ejemplo de configuración en la sección "filter_config":
"ExclusiveFilter": {
"all": [
"<GLOB_PATTERN>"
],
"<ACCOUNT_NUMBER>": [
"<GLOB_PATTERN>"
]
}
Filtro de Antigüedad
Por defecto el filtro de edad excluye roles que tienen menos de 90 días. Para cambiar esto edita la configuración: filter_config.AgeFilter.minimum_age.
Filtros Activos
Se pueden crear nuevos filtros para soportar lógica interna. En Netflix tenemos varios que son específicos de nuestros casos de uso. Para activarlos, asegúrate de que estén en el path de Python y agrégalos en la configuración a la lista en la sección active_filters.
Extendiendo Repokid
Hooks
Repokid es extensible mediante hooks que se llaman antes, durante y después de varias operaciones, como se lista a continuación.
| Nombre del hook | Contexto |
|---|---|
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 |
Los hooks deben adherirse a la siguiente interfaz:
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:
"""Las funciones hook son llamadas con un dict que contiene las claves listadas arriba según el hook objetivo.
Cualquier mutación realizada en la entrada y devuelta en la salida será pasada a las siguientes funciones hook.
"""
...
Ejemplos de implementaciones de hooks se pueden encontrar en repokid.hooks.loggers.
Filtros
Se pueden escribir filtros personalizados para excluir roles de ser repoed. Los filtros deben adherirse a la siguiente interfaz:
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:
"""Los filtros se inicializan con un dict que contiene el contenido de `filter_config.FilterName`
del archivo de configuración. Este ejemplo se inicializaría con `filter_config.CustomFilterName`.
La configuración se puede acceder via `self.config`
Si no necesitas lógica de inicialización personalizada, puedes omitir esta función en tu
clase de filtro.
"""
super().__init__(config=config)
# la lógica de inicialización personalizada va aquí
...
def apply(self, input_list: RoleList) -> RoleList:
"""Determina los roles a ser excluidos y los devuelve como un RoleList"""
...
Una implementación simple de filtro se puede encontrar en repokid.filters.age. Un ejemplo más complejo está en repokid.blocklist.age.
Cómo Usar
Una vez configurado Repokid, úsalo de la siguiente manera:
Flujo estándar
- Actualizar caché de roles:
repokid update_role_cache <ACCOUNT_NUMBER> - Mostrar caché de roles:
repokid display_role_cache <ACCOUNT_NUMBER> - Mostrar información sobre un rol específico:
repokid display_role <ACCOUNT_NUMBER> <ROLE_NAME> - Repo un rol específico:
repokid repo_role <ACCOUNT_NUMBER> <ROLE_NAME> - Repo todos los roles en una cuenta:
repokid repo_all_roles <ACCOUNT_NUMBER> -c
Programación
En lugar de ejecutar un repo ahora mismo, puedes programar uno (comando schedule_repo). La duración entre la programación y la elegibilidad es configurable, pero por defecto los roles pueden ser repoed 7 días después de la programación. Luego puedes ejecutar un comando repo_scheduled_roles para repo solo roles que ya han sido programados.
Apuntando a un permiso específico
Supón que encuentras un permiso dado especialmente peligroso en tu entorno. Aquí usaré s3:PutObjectACL como ejemplo. Puedes usar Repokid para encontrar todos los roles que tienen este permiso (incluso aquellos ocultos en un comodín), y luego eliminar solo ese permiso único.
Buscar y Eliminar:
- Asegúrate de que la caché de roles esté actualizada antes de comenzar.
- Encontrar roles con un permiso dado:
repokid find_roles_with_permissions <permission>... [--output=ROLE_FILE] - Eliminar permiso de los roles:
repokid remove_permissions_from_roles --role-file=ROLE_FILE <permission>... [-c]
Ejemplo:
$ 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
Revertir
Repokid almacena una copia de cada versión de las políticas inline que conoce. Estas se agregan cuando se encuentra una versión diferente de una política durante update_role_cache y cada vez que ocurre una acción de repo. Para restaurar una versión anterior ejecuta:
Ver todas las versiones de roles: repokid rollback_role <ACCOUNT_NUMBER> <ROLE_NAME>
Restaurar una versión específica: repokid rollback_role <ACCOUNT_NUMBER> <ROLE_NAME> --selection=<NUMBER> -c
Estadísticas
Repokid mantiene conteos de los permisos totales para cada rol. Las estadísticas se agregan cada vez que ocurre una acción update_role_cache o repo_role. Para exportar todas las estadísticas a un archivo CSV ejecuta: repokid repo_stats <OUTPUT_FILENAME>. Se puede especificar un número de cuenta opcional para exportar estadísticas solo para una cuenta específica.
Biblioteca
Nuevo en
v0.14.2
Repokid puede ser llamado como biblioteca usando el módulo 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)
Dispatcher
Repokid Dispatcher está diseñado para escuchar mensajes en una cola y realizar acciones. Hasta ahora las acciones son:
- Listar servicios repoables desde un rol
- Establecer o eliminar una exclusión voluntaria (opt-out)
- Listar y realizar reversiones para un rol
Repokid responderá en un tema SNS configurable con información sobre cualquier éxito o fallo. El componente Dispatcher existe para ayudar con la operacionalización del ciclo de vida de repo en toda tu organización. Puedes optar por exponer la cola directamente a los desarrolladores, pero es más probable que esto deba protegerse porque revertir puede ser una acción destructiva si no se hace con cuidado.
Desarrollo
Publicación
El versionado es manejado por setupmeta. Para crear una nueva versión:
python setup.py version --bump patch --push
# Inspecciona la salida y asegúrate de que es lo que esperas
# Si todo está bien, haz commit y push del nuevo tag:
python setup.py version --bump patch --push --commit