
Privilegio minimo AWS per distribuzione distribuita e ad alta velocità
Repokid ======= []() [](https://travis-ci.com/Netflix/repokid) [](https://badge.fury.io/py/repokid) [](https://coveralls.io/github/Netflix/repokid?branch=master) [](https://discord.gg/9kwMWa6) <img align="center" alt="Repokid Logo" src="https://raw.githubusercontent.com/Netflix/repokid/master/docs/images/Repokid.png?raw=true" width="25%" display="block"> Repokid utilizza Access Advisor fornito da [Aardvark](https://github.com/Netflix-Skunkworks/aardvark) per rimuovere dalle policy inline dei ruoli IAM in un account AWS i permessi che concedono accesso a servizi non utilizzati. ## Per Iniziare ### Installazione ```bash mkvirtualenv repokid git clone [email protected]:Netflix/repokid.git cd repokid pip install -e . repokid config config.json ``` #### DynamoDB Avrai bisogno di una tabella [DynamoDB](https://aws.amazon.com/dynamodb/) chiamata `repokid_roles` (specifica l'account e l'endpoint in `dynamo_db` nel file di configurazione). La tabella deve avere le seguenti proprietà: - `RoleId` (stringa) come chiave primaria di partizione, nessuna chiave primaria di ordinamento - Un indice secondario globale chiamato `Account` con una chiave primaria di partizione `Account` e `RoleId` e `Account` come attributi proiettati - Un indice secondario globale chiamato `RoleName` con una chiave primaria di partizione `RoleName` e `RoleId` e `RoleName` come attributi proiettati Per lo sviluppo, puoi eseguire Dynamo [in locale](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html). Per eseguire in locale: ```bash docker-compose up ``` L'endpoint per DynamoDB sarà `http://localhost:8000`. Un pannello di amministrazione di DynamoDB si trova a `http://localhost:8001`. Se esegui la versione di sviluppo, la tabella e l'indice verranno creati automaticamente per te. #### Permessi IAM Repokid necessita di un ruolo IAM in ogni account che verrà interrogato. Inoltre, Repokid deve essere avviato con un ruolo o un utente che possa eseguire `sts:AssumeRole` nei diversi ruoli dell'account. RepokidInstanceProfile: - Creane solo uno. - Deve avere la capacità di chiamare `sts:AssumeRole` in tutti i RepokidRole. - Permessi DynamoDB per la tabella `repokid_roles` e tutti gli indici (specificati nella sottosezione `assume_role` di `dynamo_db` nella configurazione) e la capacità di eseguire `dynamodb:ListTables` RepokidRole: - Deve esistere in ogni account da gestire con repokid. - Deve avere una politica di trust che permetta `RepokidInstanceProfile`. - Il nome deve essere specificato in `connection_iam` nel file di configurazione. - Ha questi permessi: ```json { "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": "*" } ] } ``` Quindi, se stai monitorando `n` account, avrai sempre bisogno di `n+1` ruoli. (`n` RepokidRole e `1` RepokidInstanceProfile). #### Modifica di config.json Eseguendo `repokid config config.json` viene creato un file che dovrai modificare. Trova e aggiorna questi campi: - `dynamodb`: Se usi Dynamo in locale, imposta l'endpoint su `http://localhost:8010`. Se usi Dynamo ospitato su AWS, imposta `region`, `assume_role` e `account_number`. - `aardvark_api_location`: La posizione della tua API REST Aardvark. Qualcosa come `https://aardvark.yourcompany.net/api/1/advisors` - `connection_iam`: Imposta `assume_role` su `RepokidRole`, o come l'hai chiamato. ## Configurazione Opzionale Repokid utilizza filtri per decidere quali ruoli sono candidati per essere ripuliti. I filtri possono essere configurati per adattarsi al tuo ambiente come descritto di seguito. ### Filtro Blocca elenco (Blocklist Filter) I ruoli possono essere esclusi aggiungendoli al filtro Blocklist. Un motivo comune per escludere un ruolo è se il carico di lavoro corrispondente esegue azioni occasionali che potrebbero non essere state osservate ma sono note come necessarie. Ci sono due modi per escludere un ruolo: - Escludere il nome del ruolo per tutti gli account: aggiungilo a un elenco nella configurazione `filter_config.BlocklistFilter.all` - Escludere il nome del ruolo per un account specifico: aggiungilo a un elenco nella configurazione `filter_config.BlocklistFilter.<ACCOUNT_NUMBER>` I blocca elenco possono anche essere mantenuti in un file S3 blocklist. Devono essere nella forma seguente: ```json { "arns": ["arn1", "arn2"], "names": {"role_name_1": ["all", "account_number_1"], "role_name_2": ["account_number_2", "account_number_3"]} } ``` ### Filtro Esclusivo (Exclusive Filter) Se preferisci ripulire solo determinati ruoli, puoi usare il Filtro Esclusivo. Forse vuoi considerare solo i ruoli utilizzati in produzione o da certi team. Per selezionare i ruoli da ripulire, puoi elencare i loro nomi nei file di configurazione. Sono supportati anche i pattern glob in stile shell. La selezione dei ruoli può essere specificata per singolo account o globalmente. Per attivare questo filtro inserisci `"repokid.filters.exclusive:ExclusiveFilter"` nella sezione `active_filters` del file di configurazione. Per configurarlo, puoi iniziare con il file di configurazione generato automaticamente, che ha un esempio di configurazione nella sezione `"filter_config"`: ``` "ExclusiveFilter": { "all": [ "<GLOB_PATTERN>" ], "<ACCOUNT_NUMBER>": [ "<GLOB_PATTERN>" ] } ``` ### Filtro Età (Age Filter) Per impostazione predefinita, il filtro età esclude i ruoli più giovani di 90 giorni. Per modificarlo, modifica l'impostazione di configurazione: `filter_config.AgeFilter.minimum_age`. ### Filtri Attivi (Active Filters) È possibile creare nuovi filtri per supportare logiche interne. Da Netflix ne abbiamo diversi specifici per i nostri casi d'uso. Per renderli attivi, assicurati che siano nel percorso Python e aggiungili nella configurazione all'elenco nella sezione `active_filters`. ## Estendere Repokid ### Hook Repokid è estendibile tramite hook che vengono chiamati prima, durante e dopo varie operazioni come elencato di seguito. | Nome Hook | Contesto | |-----------|---------| | `AFTER_REPO` | ruolo, errori | | `AFTER_REPO_ROLES` | ruoli, errori | | `BEFORE_REPO_ROLES` | numero_account, ruoli | | `AFTER_SCHEDULE_REPO` | ruoli | | `DURING_REPOABLE_CALCULATION` | role_id, arn, account_number, role_name, permessi_potenzialmente_ripulibili, eta_minima | | `DURING_REPOABLE_CALCULATION_BATCH` | lotto_ruoli, permessi_potenzialmente_ripulibili, eta_minima | Gli hook devono aderire alla seguente interfaccia: ```python 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: """Le funzioni hook vengono chiamate con un dict contenente le chiavi elencate sopra in base all'hook di destinazione. Qualsiasi modifica apportata all'input e restituita nell'output verrà passata alle successive funzioni hook. """ ... ``` Esempi di implementazioni di hook possono essere trovati in [`repokid.hooks.loggers`](https://github.com/netflix/repokid/blob/master/repokid/hooks/loggers/__init__.py). ### Filtri Possono essere scritti filtri personalizzati per escludere i ruoli dall'essere ripuliti. I filtri devono aderire alla seguente interfaccia: ```python 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: """I filtri vengono inizializzati con un dict contenente il contenuto di `filter_config.FilterName` dal file di configurazione. Questo esempio verrebbe inizializzato con `filter_config.CustomFilterName`. La configurazione può essere accessita tramite `self.config` Se non hai bisogno di alcuna logica di inizializzazione personalizzata, puoi omettere questa funzione dalla tua classe filtro. """ super().__init__(config=config) # la logica di inizializzazione personalizzata va qui ... def apply(self, input_list: RoleList) -> RoleList: """Determina i ruoli da escludere e restituiscili come RoleList""" ... ``` Un'implementazione semplice di filtro si trova in [`repokid.filters.age`](https://github.com/netflix/repokid/blob/master/repokid/filters/age/__init__.py). Un esempio più complesso è in [`repokid.blocklist.age`](https://github.com/netflix/repokid/blob/master/repokid/filters/blocklist/__init__.py). ## Come Usarlo Una volta configurato Repokid, usalo come segue: ### Flusso Standard - Aggiornare la cache dei ruoli: `repokid update_role_cache <NUMERO_ACCOUNT>` - Visualizzare la cache dei ruoli: `repokid display_role_cache <NUMERO_ACCOUNT>` - Visualizzare informazioni su un ruolo specifico: `repokid display_role <NUMERO_ACCOUNT> <NOME_RUOLO>` - Ripulire un ruolo specifico: `repokid repo_role <NUMERO_ACCOUNT> <NOME_RUOLO>` - Ripulire tutti i ruoli in un account: `repokid repo_all_roles <NUMERO_ACCOUNT> -c` ### Pianificazione Invece di eseguire una pulizia immediata, puoi pianificarne una (comando `schedule_repo`). La durata tra la pianificazione e l'idoneità è configurabile, ma per impostazione predefinita i ruoli possono essere ripuliti 7 giorni dopo la pianificazione. Puoi quindi eseguire un comando `repo_scheduled_roles` per ripulire solo i ruoli che sono già stati pianificati. ### Mirare a un permesso specifico Supponiamo che trovi un determinato permesso particolarmente pericoloso nel tuo ambiente. Qui userò `s3:PutObjectACL` come esempio. Puoi usare Repokid per trovare tutti i ruoli che hanno questo permesso (anche quelli nascosti in un wildcard), e poi rimuovere solo quel singolo permesso. Trova e Rimuovi: - Assicurati che la cache dei ruoli sia aggiornata prima di iniziare. - Trova i ruoli con un dato permesso: `repokid find_roles_with_permissions <permesso>... [--output=FILE_RUOLI]` - Rimuovi il permesso dai ruoli: `repokid remove_permissions_from_roles --role-file=FILE_RUOLI <permesso>... [-c]` Esempio: ``` $ 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 ``` ### Rollback Repokid memorizza una copia di ogni versione delle policy inline di cui è a conoscenza. Queste vengono aggiunte quando una versione diversa di una policy viene trovata durante `update_role_cache` e ogni volta che si verifica un'azione di pulizia. Per ripristinare una versione precedente esegui: Visualizza tutte le versioni dei ruoli: `repokid rollback_role <NUMERO_ACCOUNT> <NOME_RUOLO>` Ripristina una versione specifica: `repokid rollback_role <NUMERO_ACCOUNT> <NOME_RUOLO> --selection=<NUMERO> -c` ### Statistiche Repokid tiene traccia dei conteggi dei permessi totali per ogni ruolo. Le statistiche vengono aggiunte ogni volta che si verifica un'azione `update_role_cache` o `repo_role`. Per esportare tutte le statistiche in un file CSV esegui: `repokid repo_stats <NOME_FILE_OUTPUT>`. Può essere specificato un numero di account opzionale per esportare le statistiche solo per un account specifico. ### Libreria > Nuovo in `v0.14.2` Repokid può essere chiamato come libreria utilizzando il modulo `repokid.lib`: ```python 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 è progettato per ascoltare i messaggi su una coda ed eseguire azioni. Finora le azioni sono: - Elencare i servizi ripulibili da un ruolo - Impostare o rimuovere un opt-out - Elencare ed eseguire rollback per un ruolo Repokid risponderà su un argomento SNS configurabile con informazioni su eventuali successi o fallimenti. Il componente Dispatcher esiste per aiutare con l'operatività del ciclo di vita della pulizia nella tua organizzazione. Potresti scegliere di esporre la coda direttamente agli sviluppatori, ma più probabilmente dovrebbe essere protetta perché il rollback può essere un'azione distruttiva se non eseguita con attenzione. ## Sviluppo ### Rilascio Il versionamento è gestito da [setupmeta](https://github.com/zsimic/setupmeta). Per creare una nuova release: ```bash python setup.py version --bump patch --push # Ispeziona l'output e assicurati che sia quello che ti aspetti # Se tutto è a posto, fai commit e push del nuovo tag: python setup.py version --bump patch --push --commit ```