Aller au contenu principal
Page traduite

Cette page a été traduite de l'anglais avec l'aide de l'IA. En cas de divergence, la version anglaise fait référence.

Inventaire global AWS

Dans ce guide, nous montrons comment utiliser StackQL - un outil de développement puissant qui permet d'interroger et de déployer l'infrastructure et les ressources cloud à l'aide de la syntaxe SQL - pour générer un inventaire complet de toutes les ressources, dans tous les services, dans toutes les régions d'un compte AWS donné.

Testé avec backend SQL embarqué backend SQL postgres macos linux powershell

Fonctionnement​

StackQL implémente un moteur SQL capable de traiter plusieurs requêtes de manière asynchrone, par exemple :

SELECT region, COUNT(*) as num_functions
FROM aws.lambda.functions
WHERE region IN (
'us-east-1','us-east-2','us-west-1','us-west-2',
'ap-south-1','ap-northeast-3','ap-northeast-2',
'ap-southeast-1','ap-southeast-2','ap-northeast-1',
'ca-central-1','eu-central-1','eu-west-1',
'eu-west-2','eu-west-3','eu-north-1','sa-east-1')
GROUP BY region;

La requête ci-dessus correspond en réalité à 17 requêtes exécutées en parallèle (une requête par région) ; les résultats sont agrégés et présentés sous forme de rapport. À l'aide de pystackql - un wrapper Python pour StackQL - nous pouvons parcourir toutes les ressources de tous les services pour toutes les régions prises en charge par le service concerné. Le résultat est un rapport indiquant combien d'instances de chaque ressource sont déployées dans chaque région, comme le montre l'exemple ci-dessous :

Exemple d'inventaire AWS

Prérequis​

  • pystackql, qui s'installe avec pip install pystackql
  • Un utilisateur AWS ou un rôle (qui peut être assumé avec sts assume-role) auquel est attachée la politique ReadOnlyAccess ou une politique plus étendue
  • Les variables d'environnement AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY définies (ce qui peut se faire automatiquement avec AWS Cloud Shell)

Le code​

Le code suivant effectue les actions suivantes :

  1. Définit une liste de toutes les régions AWS (regions) et une liste des régions prises en charge pour chaque service (supported_regions) ; pour plus d'informations sur la façon d'obtenir supported_regions, consultez AWS Service Support by Region at a Glance
  2. Télécharge les providers StackQL aws et aws s'ils ne sont pas déjà installés.
  3. Parcourt chaque service (avec SHOW SERVICES), puis, pour chaque service, parcourt chaque ressource (avec SHOW RESOURCES)
  4. Sélectionne avec SELECT toutes les instances de chaque ressource dans toutes les régions de manière asynchrone, regroupe les données par région et compte les instances de chaque ressource pour chaque région

Le voici...

from regions import supported_regions, regions
from resources import excluded_resources, resource_filters
import time
from pystackql import StackQL
import pandas as pd

stackql = StackQL(output='pandas', page_limit=-1, execution_concurrency_limit=-1)

def pull_stackql_providers():
providers_df = stackql.execute("SHOW PROVIDERS")
installed = providers_df['name'].values if not providers_df.empty else []
for provider in ('aws', 'awscc'):
if provider not in installed:
print(f"{provider} not installed. Installing {provider}")
res = stackql.executeStmt(f"REGISTRY PULL {provider}")
print(res['message'])

def get_s3_buckets():
# special case for s3 buckets - use the awscc provider's list view, which
# returns each bucket alongside its region in a single query across all regions
regions_in = ", ".join([f"'{region}'" for region in regions])
buckets_df = stackql.execute(f"""
SELECT region, bucket_name
FROM awscc.s3.buckets_list_only
WHERE region IN ({regions_in});
""")
# Group by region and count the total resources (buckets) in each region
grouped = buckets_df.groupby('region').size().reset_index(name='total_resources')
grouped['svc'] = 's3'
grouped['res'] = 'buckets'
output_df = grouped[['svc', 'res', 'region', 'total_resources']]
return output_df

def main():
start_time = time.time()
pull_stackql_providers()
results_df = pd.DataFrame(columns=['svc', 'res', 'region', 'total_resources'])
# get all enumerable aws services
services_df = stackql.execute("SHOW SERVICES IN aws")
for svcIx, svcRow in services_df.iterrows():
service = svcRow['name']
if service in supported_regions:
# check all enumerable aws resources in the service against supported regions
resources_df = stackql.execute(f"SHOW RESOURCES IN aws.{service}")
plural_resources = [resource for resource in resources_df['name'].tolist() if resource.endswith('s')]
if plural_resources:
for resource in plural_resources:
print(f"Checking {resource} in {service}...")
if service == 's3' and resource == 'buckets':
print(f"Checking location for s3 buckets...")
resource_df = get_s3_buckets()
else:
# should we skip this service?
if service in excluded_resources and resource in excluded_resources[service]:
continue
# check if the resource is global or regional
if 'global' in supported_regions[service]:
regions_in = ", ".join([f"'{region}'" for region in regions])
else:
regions_in = ", ".join([f"'{region}'" for region in supported_regions[service]])

# check if there are additional where clauses for this resource
where_clause = resource_filters.get(service, {}).get(resource, '')

resource_df = stackql.execute(f"""
SELECT '{service}' as svc, '{resource}' as res, region, COUNT(*) as total_resources
FROM aws.{service}.{resource}
WHERE region IN ({regions_in}){where_clause}
GROUP BY svc, res, region
""")

if not resource_df.empty:
# Append resource_df to the results_df
if not 'error' in resource_df.columns:
results_df = pd.concat([results_df, resource_df], ignore_index=True)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time:.2f} seconds")
results_df.to_csv('all_aws_resources.csv', index=False)

if __name__ == "__main__":
main()