
Moindre privilège AWS pour un déploiement distribué et à haute vélocité
Repokid utilise Access Advisor fourni par Aardvark pour supprimer les autorisations donnant accès à des services inutilisés des politiques inline des rôles IAM dans un compte AWS.
mkvirtualenv repokid
git clone [email protected]:Netflix/repokid.git
cd repokid
pip install -e .
repokid config config.json
Vous aurez besoin d'une table DynamoDB appelée repokid_roles (spécifiez le compte et le point de terminaison dans dynamo_db du fichier de configuration).
La table doit avoir les propriétés suivantes :
RoleId (string) comme clé de partition primaire, pas de clé de tri primaireAccount avec une clé de partition primaire Account et les attributs projetés RoleId et AccountRoleName avec une clé de partition primaire RoleName et les attributs projetés RoleId et RoleNamePour le développement, vous pouvez exécuter Dynamo localement.
Pour exécuter localement :
docker-compose up
Le point de terminaison pour DynamoDB sera http://localhost:8000. Un panneau d'administration DynamoDB se trouve à http://localhost:8001.
Si vous exécutez la version de développement, la table et l'index seront créés automatiquement pour vous.
Repokid a besoin d'un rôle IAM dans chaque compte qui sera interrogé. De plus, Repokid doit être lancé avec un rôle ou un utilisateur capable d'utiliser sts:AssumeRole pour accéder aux différents rôles des comptes.
RepokidInstanceProfile :
sts:AssumeRole sur tous les RepokidRoles.repokid_roles et tous les index (spécifiés dans la sous-section assume_role de dynamo_db dans la configuration) et la capacité d'exécuter dynamodb:ListTablesRepokidRole :
RepokidInstanceProfile.connection_iam du fichier de configuration.{
"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": "*"
}
]
}
Donc si vous surveillez n comptes, vous aurez toujours besoin de n+1 rôles. (n RepokidRoles et 1 RepokidInstanceProfile).
L'exécution de repokid config config.json crée un fichier que vous devrez modifier. Trouvez et mettez à jour ces champs :
dynamodb : Si vous utilisez Dynamo localement, définissez le point de terminaison sur http://localhost:8010. Si vous utilisez Dynamo hébergé par AWS, définissez region, assume_role et account_number.aardvark_api_location : L'emplacement de votre API REST Aardvark. Quelque chose comme https://aardvark.yourcompany.net/api/1/advisorsconnection_iam : Définissez assume_role sur RepokidRole, ou le nom que vous lui avez donné.Repokid utilise des filtres pour décider quels rôles sont candidats à être repoés. Les filtres peuvent être configurés pour s'adapter à votre environnement comme décrit ci-dessous.
Les rôles peuvent être exclus en les ajoutant au filtre de blocage. Une raison courante d'exclure un rôle est si la charge de travail correspondante effectue des actions occasionnelles qui n'ont peut-être pas été observées mais qui sont connues comme étant nécessaires. Il y a deux façons d'exclure un rôle :
filter_config.BlocklistFilter.allfilter_config.BlocklistFilter.<NUMERO_COMPTE>Les listes de blocage peuvent également être maintenues dans un fichier de blocage S3. Elles doivent être sous la forme suivante :
{
"arns": ["arn1", "arn2"],
"names": {"role_name_1": ["all", "account_number_1"], "role_name_2": ["account_number_2", "account_number_3"]}
}
Si vous préférez ne repoer que certains rôles, vous pouvez utiliser le filtre exclusif. Vous voudrez peut-être ne considérer que les rôles utilisés en production ou par certaines équipes. Pour sélectionner les rôles à repoer, vous pouvez lister leurs noms dans les fichiers de configuration. Les motifs glob de type shell sont également pris en charge. La sélection des rôles peut être spécifiée par compte individuel ou globalement. Pour activer ce filtre, mettez "repokid.filters.exclusive:ExclusiveFilter" dans la section active_filters du fichier de configuration. Pour le configurer, vous pouvez commencer par le fichier de configuration autogénéré, qui contient un exemple de configuration dans la section "filter_config" :
"ExclusiveFilter": {
"all": [
"<GLOB_PATTERN>"
],
"<ACCOUNT_NUMBER>": [
"<GLOB_PATTERN>"
]
}
Par défaut, le filtre d'âge exclut les rôles de moins de 90 jours. Pour modifier cela, modifiez le paramètre de configuration : filter_config.AgeFilter.minimum_age.
De nouveaux filtres peuvent être créés pour prendre en charge la logique interne. Chez Netflix, nous en avons plusieurs qui sont spécifiques à nos cas d'utilisation. Pour les rendre actifs, assurez-vous qu'ils sont dans le chemin Python et ajoutez-les dans la configuration à la liste de la section active_filters.
Repokid est extensible via des hooks qui sont appelés avant, pendant et après diverses opérations comme listé ci-dessous.
Les hooks doivent adhérer à l'interface suivante :
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:
"""Hook functions are called with a dict containing the keys listed above based on the target hook.
Any mutations made to the input and returned in the output will be passed on to subsequent hook funtions.
"""
...
Des exemples d'implémentations de hooks peuvent être trouvés dans repokid.hooks.loggers.
Des filtres personnalisés peuvent être écrits pour exclure des rôles du repo. Les filtres doivent adhérer à l'interface suivante :
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:
"""Filters are initialized with a dict containing the contents of `filter_config.FilterName`
from the config file. This example would be initialized with `filter_config.CustomFilterName`.
The configuration can be accessed via `self.config`
If you don't need any custom initialization logic, you can leave this function out of your
filter class.
"""
super().__init__(config=config)
# custom initialization logic goes here
...
def apply(self, input_list: RoleList) -> RoleList:
"""Determine roles to be excluded and return them as a RoleList"""
...
Une implémentation simple de filtre peut être trouvée dans repokid.filters.age. Un exemple plus complexe se trouve dans repokid.blocklist.age.
Une fois Repokid configuré, utilisez-le comme suit :
repokid update_role_cache <NUMERO_COMPTE>repokid display_role_cache <NUMERO_COMPTE>repokid display_role <NUMERO_COMPTE> <NOM_ROLE>repokid repo_role <NUMERO_COMPTE> <NOM_ROLE>repokid repo_all_roles <NUMERO_COMPTE> -cPlutôt que d'exécuter un repo immédiatement, vous pouvez en planifier un (commande schedule_repo). La durée entre la planification et l'éligibilité est configurable, mais par défaut, les rôles peuvent être repoés 7 jours après la planification. Vous pouvez ensuite exécuter une commande repo_scheduled_roles pour ne repoer que les rôles déjà planifiés.
Supposons que vous trouviez une autorisation particulièrement dangereuse dans votre environnement. Ici, je vais utiliser s3:PutObjectACL comme exemple. Vous pouvez utiliser Repokid pour trouver tous les rôles qui ont cette autorisation (même ceux cachés dans un caractère générique), puis supprimer cette seule autorisation.
Rechercher et supprimer :
repokid find_roles_with_permissions <permission>... [--output=FICHIER_ROLES]repokid remove_permissions_from_roles --role-file=FICHIER_ROLES <permission>... [-c]Exemple :
$ 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 stocke une copie de chaque version des politiques inline qu'il connaît. Elles sont ajoutées lorsqu'une version différente d'une politique est trouvée lors de update_role_cache et à chaque fois qu'une action de repo a lieu. Pour restaurer une version précédente, exécutez :
Voir toutes les versions des rôles : repokid rollback_role <NUMERO_COMPTE> <NOM_ROLE>
Restaurer une version spécifique : repokid rollback_role <NUMERO_COMPTE> <NOM_ROLE> --selection=<NUMERO> -c
Repokid conserve le nombre total d'autorisations pour chaque rôle. Les statistiques sont ajoutées à chaque fois qu'une action update_role_cache ou repo_role a lieu. Pour exporter toutes les statistiques vers un fichier CSV, exécutez : repokid repo_stats <NOM_FICHIER_SORTIE>. Un numéro de compte optionnel peut être spécifié pour n'exporter que les statistiques d'un compte spécifique.
Nouveau dans
v0.14.2
Repokid peut être appelé comme une bibliothèque en utilisant le module 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)
Le Dispatcher Repokid est conçu pour écouter les messages sur une file d'attente et effectuer des actions. Jusqu'à présent, les actions sont :
Repokid répondra sur un sujet SNS configurable avec des informations sur les succès ou échecs. Le composant Dispatcher existe pour aider à l'opérationnalisation du cycle de vie du repo dans votre organisation. Vous pouvez choisir d'exposer la file d'attente directement aux développeurs, mais il est plus probable qu'elle devrait être protégée car le rollback peut être une action destructive si elle n'est pas faite avec précaution.
La gestion des versions est assurée par setupmeta. Pour créer une nouvelle version :
python setup.py version --bump patch --push
# Inspect output and make sure it's what you expect
# If all is well, commit and push the new tag:
python setup.py version --bump patch --push --commit
| Nom du hook | Contexte |
|---|
AFTER_REPO | rôle, erreurs |
AFTER_REPO_ROLES | rôles, erreurs |
BEFORE_REPO_ROLES | numéro_compte, rôles |
AFTER_SCHEDULE_REPO | rôles |
DURING_REPOABLE_CALCULATION | role_id, arn, numéro_compte, nom_rôle, permissions_potentiellement_repoables, âge_minimum |
DURING_REPOABLE_CALCULATION_BATCH | lot_rôles, permissions_potentiellement_repoables, âge_minimum |