Saltar al contenido principal
Página traducida

Esta página se tradujo del inglés con ayuda de IA. Si hay diferencias entre ambas, la versión en inglés es la referencia.

Inventario global de AWS

En esta guía mostraremos cómo usar StackQL - una potente herramienta de desarrollo que permite consultar y desplegar infraestructura y recursos en la nube con sintaxis SQL - para generar un inventario completo de todos los recursos, en todos los servicios, en todas las regiones de una cuenta de AWS determinada.

Probado con backend SQL integrado backend SQL postgres macos linux powershell

Funcionamiento​

StackQL implementa un motor SQL que puede procesar varias consultas de forma asíncrona, por ejemplo:

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 consulta anterior es en realidad 17 consultas ejecutadas en paralelo (una consulta por región); los resultados se agregan y se presentan como un informe. Con pystackql - un wrapper de Python para StackQL - podemos recorrer todos los recursos de todos los servicios en todas las regiones que admite el servicio en cuestión. El resultado es un informe de cuántas instancias de cada recurso hay desplegadas en cada región, como se ve en el ejemplo siguiente:

Ejemplo de inventario de AWS

Requisitos previos​

  • pystackql, que se puede instalar con pip install pystackql
  • Un usuario de AWS o un rol (se puede asumir con sts assume-role) que tenga asociada la política ReadOnlyAccess o una superior
  • Las variables de entorno AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY definidas (esto se puede hacer automáticamente con AWS Cloud Shell)

El código​

El siguiente código realiza estas acciones:

  1. Define una lista de todas las regiones de AWS (regions) y una lista de las regiones admitidas por cada servicio (supported_regions); encontrará más información sobre cómo obtener supported_regions en AWS Service Support by Region at a Glance
  2. Descarga los providers de StackQL aws y aws si aún no están instalados.
  3. Recorre cada servicio (con SHOW SERVICES) y, para cada servicio, recorre cada recurso (con SHOW RESOURCES)
  4. Selecciona con SELECT todas las instancias de cada recurso en todas las regiones de forma asíncrona, agrupa los datos por región y cuenta las instancias de cada recurso en cada región

Aquí está...

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()