A la lliçó anterior vam recórrer la consola i vam crear el nostre primer bucket amb el ratolí. Va funcionar, però vam deixar una pregunta oberta: com repeteixes això mateix cent vegades, o com demostres d'aquí a sis mesos què vas fer exactament? La resposta és deixar de fer clic i començar a escriure comandes i codi.

Aquesta lliçó és la porta d'entrada a tota la feina seriosa a AWS. L'AWS CLI és l' eina que faràs servir cada dia per consultar, crear i diagnosticar; els SDK són les biblioteques amb les quals la teva aplicació parla amb AWS des de dins. Tots dos fan servir les mateixes APIs que la consola, així que tot el que aprenguis aquí et serveix per a qualsevol servei de la resta del curs.

Contingut

  1. Per què automatitzar: el problema de la consola
  2. Instal·lar AWS CLI v2 a Linux, macOS i Windows
  3. Anatomia d'una comanda
  4. Configurar credencials: aws configure, fitxers i perfils
  5. Ordre de precedència de les credencials
  6. Seguretat de les claus d'accés
  7. Formats de sortida i filtratge amb --query
  8. Paginació, --dry-run i altres opcions útils
  9. Comandes d'exploració imprescindibles
  10. SDK: què són i quins llenguatges hi ha
  11. boto3: l'SDK de Python pas a pas
  12. Una ullada equivalent en JavaScript
  13. CloudShell com a alternativa sense instal·lació

Per què automatitzar: el problema de la consola

La Marta va crear el bucket de proves a la consola. Ara en Luis necessita crear tres buckets iguals (un per entorn) amb les mateixes etiquetes i la mateixa configuració. Amb la consola hauria de repetir uns quinze clics tres vegades, i qualsevol descuit produiria una diferència silenciosa entre entorns.

Els quatre problemes estructurals de la consola:

Problema Conseqüència real a MercadoFresco
No és reproduïble L'entorn de desenvolupament mai no acaba sent idèntic al de producció, i els errors "només passen en producció"
No és documentable Ningú no pot revisar a Git el que es va fer amb el ratolí, ni saber per què
No és componible No pots encadenar "llista totes les instàncies aturades i etiqueta-les"
No escala Etiquetar 200 recursos a mà és inviable

La CLI resol els quatre: una comanda és text, i el text es desa, es versiona, es revisa, es repeteix i s'encadena. I és el pas previ natural cap a la infraestructura com a codi del mòdul 9, on ja ni tan sols escriurem comandes sinó declaracions de l'estat desitjat.

Instal·lar AWS CLI v2 a Linux, macOS i Windows

Fes servir sempre la versió 2. La v1 està en manteniment, s'instal·lava amb pip (cosa que causava conflictes de dependències) i li falten funcions importants com l'inici de sessió amb IAM Identity Center.

Linux (x86_64)

# 1. Descarrega l'instal·lador oficial en un fitxer zip
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# 2. Descomprimeix el paquet al directori actual
unzip awscliv2.zip

# 3. Executa l'instal·lador amb permisos d'administrador
sudo ./aws/install

# 4. Neteja els fitxers temporals
rm -rf awscliv2.zip aws/

Què fa cada línia:

  • curl ... -o "awscliv2.zip": descarrega el paquet i el desa amb aquest nom. L'URL és l'oficial d'AWS; desconfia dels instal·ladors de tercers.
  • unzip: extreu una carpeta aws/ amb l'instal·lador.
  • sudo ./aws/install: copia els binaris a /usr/local/aws-cli i crea l'enllaç /usr/local/bin/aws. Necessita sudo perquè escriu fora del teu directori personal.
  • rm -rf: esborra el que s'ha descarregat, que ja no fa falta.

Si la teva màquina és ARM (per exemple, una instància Graviton), canvia x86_64 per aarch64.

Per actualitzar una instal·lació existent, afegeix els paràmetres d'actualització:

sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

macOS

# Descarrega el paquet .pkg oficial
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"

# Instal·la per a tots els usuaris de l'equip
sudo installer -pkg AWSCLIV2.pkg -target /

Alternativa amb Homebrew, si ja el fas servir: brew install awscli.

Windows

Descarrega i executa l'instal·lador MSI oficial:

https://awscli.amazonaws.com/AWSCLIV2.msi

O des de PowerShell com a administrador:

msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi

Després tanca i torna a obrir el terminal perquè es recarregui la variable PATH.

Verificació

En qualsevol sistema:

aws --version

Sortida esperada (els números variaran):

aws-cli/2.15.40 Python/3.11.8 Linux/6.5.0 exe/x86_64.ubuntu.22

Es llegeix així: versió de la CLI, versió de Python incrustada (no fa servir el teu Python, va inclosa), sistema operatiu i tipus de compilació. Si veus aws-cli/1.x, tens la v1 i l'hauries de desinstal·lar abans de continuar.

Anatomia d'una comanda

Totes les comandes segueixen la mateixa estructura:

aws <servei> <operació> [--paràmetre valor] [--opcions-globals]

Un exemple real, línia a línia:

aws ec2 describe-instances \
  --filters "Name=instance-state-name,Values=running" \
  --region eu-west-1 \
  --output table
Part Què és Detall
aws El programa
ec2 Servei Sol coincidir amb el nom del servei: s3, iam, lambda, rds
describe-instances Operació L'API s'anomena DescribeInstances; la CLI fa servir minúscules i guions
--filters "..." Paràmetre específic Filtra al servidor: només instàncies en execució
--region Opció global Sobreescriu la regió del perfil per a aquesta comanda
--output table Opció global Format de sortida

Els verbs segueixen convencions molt previsibles, i reconèixer-les accelera molt l'aprenentatge:

Prefix Què fa Exemples
describe- Retorna informació detallada describe-instances, describe-vpcs
list- Retorna una llista d'identificadors list-buckets, list-functions
get- Obté un element concret get-caller-identity, get-bucket-tagging
create- Crea un recurs create-bucket, create-tags
delete- / terminate- Elimina delete-bucket, terminate-instances
put- Escriu o sobreescriu una configuració put-bucket-tagging, put-metric-alarm

L'ajuda integrada

És la millor documentació que tens i funciona sense connexió:

aws help                        # llista tots els serveis disponibles
aws s3api help                  # llista totes les operacions de s3api
aws s3api create-bucket help    # tots els paràmetres d'aquesta operació, amb exemples

S'obre en un paginador: navega amb les fletxes i surt amb q.

Configurar credencials: aws configure, fitxers i perfils

La CLI necessita saber qui ets. Crearem unes claus d'accés per a l'usuari mercadofresco-admin que vam crear a la lliçó 01-02.

Pas 1: crear les claus d'accés

A la consola: IAM → Users → mercadofresco-admin → Security credentials → Create access key. Tria el cas d'ús Command Line Interface (CLI), confirma l'avís i crea-la.

N'obtindràs dos valors:

  • Access key ID: una cosa com AKIAIOSFODNN7EXAMPLE. És més aviat públic, identifica la clau.
  • Secret access key: una cosa com wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY. Només es mostra una vegada. Si la perds, cal crear una clau nova.

Advertiment: no creïs mai claus d'accés per a l'usuari root (lliçó 01-02). I si no vols manejar claus permanents en absolut, l'alternativa moderna és aws configure sso amb IAM Identity Center, que emet credencials temporals.

Pas 2: aws configure

aws configure

Et farà quatre preguntes:

AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: eu-west-1
Default output format [None]: json
  • Regió per defecte: eu-west-1, la que vam decidir a la lliçó 01-03. T'evita escriure --region a cada comanda.
  • Format de sortida: json és un bon valor per defecte perquè és el que consumeixen altres eines.

Els fitxers de configuració

aws configure no fa màgia: escriu dos fitxers de text al teu directori personal (~/.aws/ a Linux i macOS, %USERPROFILE%\.aws\ a Windows).

~/.aws/credentials — conté els secrets:

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

~/.aws/config — conté els ajustos no secrets:

[default]
region = eu-west-1
output = json

Els pots editar a mà perfectament. Comprova a més que els permisos siguin restrictius:

chmod 600 ~/.aws/credentials

Això deixa el fitxer llegible i escrivible només pel teu usuari. En un equip compartit és imprescindible.

Perfils amb nom

Gairebé mai treballaràs amb una sola identitat. MercadoFresco tindrà aviat un entorn de desenvolupament i un altre de producció, i convé que no es puguin confondre.

Crea un perfil nou:

aws configure --profile mercadofresco-dev

Els fitxers queden així:

# ~/.aws/credentials
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[mercadofresco-dev]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCoEXAMPLEKEY
# ~/.aws/config
[default]
region = eu-west-1
output = json

[profile mercadofresco-dev]
region = eu-west-1
output = json

Atenció al detall: a credentials la secció és [mercadofresco-dev], però a config és [profile mercadofresco-dev], amb la paraula profile al davant. És una inconsistència històrica que provoca errors constants. Si un perfil "no es troba", revisa això primer.

Per fer servir un perfil:

# Opció 1: per paràmetre, en una comanda concreta
aws s3 ls --profile mercadofresco-dev

# Opció 2: per variable d'entorn, per a tota la sessió de terminal
export AWS_PROFILE=mercadofresco-dev
aws s3 ls

I per saber sempre amb qui estàs actuant:

aws sts get-caller-identity --profile mercadofresco-dev

Adquireix l'hàbit d'executar aquesta comanda abans de qualsevol operació destructiva. És la diferència entre esborrar la base de dades de desenvolupament i esborrar la de producció.

Ordre de precedència de les credencials

Quan executes una comanda, la CLI busca credencials en un ordre fix i es queda amb la primera font que trobi. Conèixer aquest ordre explica el 90 % dels "però si jo vaig configurar això":

# Font Com s'indica Quan es fa servir
1 Opcions de línia de comandes --profile, --region Sobreescriu tota la resta
2 Variables d'entorn AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE, AWS_DEFAULT_REGION CI/CD, contenidors, sessions temporals
3 Fitxer ~/.aws/credentials Perfil [default] o l'indicat Feina diària al teu portàtil
4 Fitxer ~/.aws/config Secció [profile ...] Configuració i rols
5 Credencials de contenidor Variable injectada per ECS/EKS Contenidors a AWS (mòdul 10)
6 Rol d'instància (IMDS) Metadades de la mateixa EC2 La manera correcta dins d'AWS

Els dos últims són els importants conceptualment. Quan el teu codi s'executa dins d'AWS —en una instància EC2, en una funció Lambda, en un contenidor— no necessita claus en absolut: se li assigna un rol IAM i l'SDK obté automàticament credencials temporals que es roten soles cada poques hores.

flowchart TB
    A["Comanda o SDK necessita credencials"] --> B{"--profile a la linia?"}
    B -->|si| USA1["Fes servir aquest perfil"]
    B -->|no| C{"Variables d'entorn?"}
    C -->|si| USA2["Fes servir les variables"]
    C -->|no| D{"Fitxer ~/.aws/credentials?"}
    D -->|si| USA3["Fes servir el perfil default"]
    D -->|no| E{"S'executa dins d'AWS?"}
    E -->|si| USA4["Rol de la instancia - credencials temporals - L'IDEAL"]
    E -->|no| F["Error: Unable to locate credentials"]

Els rols IAM s'estudien a fons a la lliçó 04-01. Queda't amb la idea: claus permanents només al teu portàtil; dins d'AWS, sempre rols.

Seguretat de les claus d'accés

Una clau d'accés de mercadofresco-admin és, literalment, el control total del compte. Aquestes regles no són opcionals.

Mai al codi ni a Git

Aquest és l'error que arruïna comptes cada dia. Hi ha bots que escanegen GitHub de manera contínua buscant cadenes que comencin per AKIA; una clau publicada s'explota en minuts, típicament llançant desenes d'instàncies grans per minar criptomonedes. La factura resultant pot ser de milers d'euros.

Protecció mínima en qualsevol repositori:

# .gitignore
.env
.aws/
*.pem
credentials

I una barrera automàtica, molt recomanable:

# git-secrets escaneja cada commit buscant patrons de credencials d'AWS
git secrets --install
git secrets --register-aws

Si alguna vegada publiques una clau per error: desactiva-la i esborra-la immediatament a IAM, revisa CloudTrail (lliçó 05-03) per veure què s'hi va fer, i crea'n una de nova. Esborrar el commit no serveix de res: ja està indexat.

Altres regles

Regla Per què
Rotar cada 90 dies Redueix la finestra d'explotació d'una clau filtrada
Una clau per persona i ús Permet revocar-ne una sense afectar les altres
Eliminar les claus inactives IAM mostra la data d'últim ús; el que no es fa servir, s'esborra
Mai claus al root Ja vist a 01-02
Dins d'AWS, rols en lloc de claus Credencials temporals, rotades automàticament
MFA per a operacions sensibles Es pot exigir a les polítiques IAM (lliçó 04-01)

El procediment de rotació sense talls és senzill: crea una segona clau, actualitza on es faci servir, comprova que tot funciona, desactiva l'antiga, espera uns dies i esborra-la. IAM permet dues claus actives per usuari precisament per això.

Formats de sortida i filtratge amb --query

Les comandes d'AWS retornen molta informació. Aprendre a retallar-la és el que converteix la CLI en una eina còmoda.

Formats de sortida

Format Quan fer-lo servir
json Per defecte. Ideal per encadenar amb jq o per processar en scripts
table Per llegir amb els ulls: vores ASCII i columnes
text Per processar amb grep, awk o cut; separat per tabuladors
yaml Més llegible que JSON per a configuracions llargues
aws ec2 describe-regions --output table

--query amb JMESPath

--query aplica una expressió JMESPath sobre la resposta, al client. Anem de menys a més.

Nivell 1 — extreure una llista:

# Retorna només l'array Regions complet
aws ec2 describe-regions --query 'Regions'

Nivell 2 — un camp de cada element:

# De cada regió, només el seu nom. Els claudàtors [] recorren la llista
aws ec2 describe-regions --query 'Regions[].RegionName' --output text

Sortida:

eu-west-1	eu-west-2	eu-west-3	us-east-1	...

Nivell 3 — reanomenar camps en un objecte:

aws ec2 describe-regions \
  --query 'Regions[].{Region:RegionName, Endpoint:Endpoint}' \
  --output table

Les claus {...} construeixen un objecte nou; a l'esquerra dels : va el nom que vols veure, a la dreta el camp original.

Nivell 4 — filtrar amb una condició:

# Només les regions europees: ? introdueix el filtre, contains() és una funció JMESPath
aws ec2 describe-regions \
  --query 'Regions[?contains(RegionName, `eu-`)].RegionName' \
  --output table

Fixa't en les cometes invertides al voltant d'eu-: a JMESPath, els literals van entre backticks, no entre cometes normals. És una font freqüent d'errors.

Nivell 5 — un cas real de MercadoFresco:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{
      Id:InstanceId,
      Tipus:InstanceType,
      Estat:State.Name,
      IP:PrivateIpAddress,
      Zona:Placement.AvailabilityZone,
      Nom:Tags[?Key==`Name`]|[0].Value
    }' \
  --output table

Desglossament:

  • Reservations[].Instances[]: aplana l'estructura imbricada d'EC2 (les instàncies vénen agrupades per reserva) en una sola llista.
  • State.Name: navega dins d'un objecte imbricat amb el punt.
  • Tags[?Key==\Name`]|[0].Value: filtra les etiquetes quedant-se amb la de clau Name, i el |[0]` pren el primer resultat d'aquella llista per extreure'n el valor.

--query enfront de --filters

--filters --query
On s'aplica Al servidor d'AWS Al teu equip, després de rebre la resposta
Efecte Redueix el que es transfereix Només redueix el que es mostra
Disponibilitat Només en alguns serveis i camps En qualsevol comanda
Recomanació Fes-lo servir sempre que existeixi Per donar forma al resultat

L'ideal és combinar-los: --filters per portar poc, --query per presentar-ho bé.

Paginació, --dry-run i altres opcions útils

Paginació

Quan hi ha molts resultats, la CLI v2 els pagina automàticament i obre un paginador. Opcions per controlar-ho:

# Retorna com a màxim 5 elements
aws s3api list-buckets --max-items 5

# Desactiva el paginador interactiu (útil en scripts)
aws ec2 describe-instances --no-cli-pager

# Desactivar-lo de manera permanent
export AWS_PAGER=""

Si limites amb --max-items i hi ha més resultats, la resposta inclou un NextToken que pots passar amb --starting-token per demanar la pàgina següent.

--dry-run

Moltes operacions d'EC2 accepten --dry-run: comproven si tindries permisos per fer l' operació, però no l'executen.

aws ec2 run-instances \
  --image-id ami-0abcdef1234567890 \
  --instance-type t3.micro \
  --dry-run

Si tens permís, veuràs:

An error occurred (DryRunOperation) when calling the RunInstances operation:
Request would have succeeded, but DryRun flag is set

Aquest missatge, encara que digui "error", és la confirmació d'èxit. Si no en tinguessis permís, l'error seria UnauthorizedOperation. És una manera segura de verificar permisos sense crear res ni gastar res.

Altres opcions que es fan servir molt

Opció Per a què
--no-cli-pager Sortida directa sense paginador
--debug Traça completa de la petició HTTP; imprescindible per diagnosticar
--cli-input-json file://params.json Passar tots els paràmetres des d'un fitxer
--generate-cli-skeleton Generar la plantilla JSON de paràmetres d'una operació
--endpoint-url Apuntar a un endpoint alternatiu (p. ex. un emulador local)

Comandes d'exploració imprescindibles

Aquestes són les comandes que executaràs centenars de vegades. Desa-les.

# 1. Qui sóc? Retorna compte, ID d'usuari i ARN
aws sts get-caller-identity
# 2. Quines regions existeixen i estan habilitades al meu compte?
aws ec2 describe-regions --query 'Regions[].RegionName' --output text
# 3. Quines zones de disponibilitat té la meva regió, amb el seu ID físic?
aws ec2 describe-availability-zones \
  --query 'AvailabilityZones[].{AZ:ZoneName, Id:ZoneId, Estat:State}' \
  --output table
# 4. Quins buckets tinc?
aws s3 ls
# 5. Quines instàncies EC2 tinc i en quin estat?
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{Id:InstanceId, Estat:State.Name}' \
  --output table
# 6. Quina configuració té la CLI i d'on surt cada valor?
aws configure list

La sortida de l'última és especialment útil perquè indica l'origen de cada valor:

      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile     mercadofresco-dev           env    AWS_PROFILE
access_key     ****************MPLE   shared-credentials-file
    region                eu-west-1      config-file    ~/.aws/config

Quan alguna cosa no funcioni com esperes, aquesta comanda et dirà exactament quina credencial i quina regió està fent servir la CLI i per què.

SDK: què són i quins llenguatges hi ha

Un SDK (Software Development Kit) és una biblioteca que permet a la teva aplicació cridar les APIs d'AWS des del llenguatge en què està escrita, sense construir peticions HTTP signades a mà.

La diferència amb la CLI:

CLI SDK
Qui el fa servir Una persona en un terminal, o un script La teva aplicació, en temps d'execució
Cas típic "Llista els buckets", "atura aquesta instància" "Quan el client puja una foto, desa-la a S3"
Format Comandes de text Codi en el teu llenguatge

Llenguatges amb SDK oficial:

Llenguatge Nom de l'SDK Nota
Python boto3 El més usat en scripting i automatització
JavaScript / TypeScript AWS SDK for JavaScript v3 Modular: instal·les només el client que fas servir
Java AWS SDK for Java 2.x Molt comú a l'empresa
.NET (C#) AWS SDK for .NET
Go AWS SDK for Go v2 Habitual en eines d'infraestructura
PHP AWS SDK for PHP Rellevant per al monòlit actual de MercadoFresco
Rust, Ruby, C++, Kotlin, Swift Disponibles

Tots comparteixen la mateixa lògica: cadena de proveïdors de credencials (el mateix ordre de precedència que hem vist), reintents automàtics amb retrocés exponencial, i noms d'operació equivalents als de l'API.

boto3: l'SDK de Python pas a pas

En Luis farà servir Python per als scripts de MercadoFresco, així que vegem boto3 en detall.

Instal·lació

# Crear un entorn virtual aïllat (bona pràctica: no instal·lar al Python del sistema)
python3 -m venv venv

# Activar-lo (a Windows: venv\Scripts\activate)
source venv/bin/activate

# Instal·lar boto3
pip install boto3

Client enfront de recurs

boto3 ofereix dues interfícies diferents per al mateix:

Client Resource
Nivell Baix: reflecteix l'API 1:1 Alt: orientat a objectes
Cobertura Tots els serveis i operacions Només alguns serveis; en manteniment
Estil s3.list_buckets() retorna un diccionari for b in s3.buckets.all()
Recomanació Fes-lo servir per defecte Només si te'l trobes en codi heretat

Exemple del mateix objectiu amb totes dues:

import boto3

# --- Interfície Client (recomanada) ---
s3_client = boto3.client("s3")
resposta = s3_client.list_buckets()           # retorna un diccionari tal com el dona l'API
for bucket in resposta["Buckets"]:
    print(bucket["Name"], bucket["CreationDate"])

# --- Interfície Resource (més antiga) ---
s3_recurs = boto3.resource("s3")
for bucket in s3_recurs.buckets.all():        # objectes amb atributs
    print(bucket.name, bucket.creation_date)

Credencials i sessions

boto3 fa servir exactament el mateix ordre de precedència que la CLI, així que si aws s3 ls funciona, el teu codi Python funcionarà sense configurar res.

Per triar perfil o regió explícitament es fa servir una sessió:

import boto3

# Una sessió encapsula credencials + regió
sessio = boto3.Session(profile_name="mercadofresco-dev", region_name="eu-west-1")
s3 = sessio.client("s3")

print(sessio.client("sts").get_caller_identity()["Arn"])

Gestió d'errors amb ClientError

Tot error retornat per un servei d'AWS arriba com a botocore.exceptions.ClientError. Ignorar-lo és l'error més comú dels scripts de principiant.

import boto3
from botocore.exceptions import ClientError

s3 = boto3.client("s3", region_name="eu-west-1")

def existeix_bucket(nom: str) -> bool:
    """Comprova si un bucket existeix i és accessible per a les nostres credencials."""
    try:
        s3.head_bucket(Bucket=nom)             # petició lleugera: només capçaleres
        return True
    except ClientError as error:
        # El codi concret és sempre a error.response["Error"]["Code"]
        codi = error.response["Error"]["Code"]
        if codi == "404":
            print(f"El bucket '{nom}' no existeix.")
        elif codi == "403":
            print(f"El bucket '{nom}' existeix però no tens permís per veure'l.")
        else:
            raise                              # qualsevol altre error, que es propagui
        return False

print(existeix_bucket("mercadofresco-fotos-producto"))

Punts clau del fragment:

  • head_bucket és la manera barata de comprovar l'existència: no descarrega contingut.
  • error.response["Error"]["Code"] és la ruta estàndard per llegir el codi d'error. Memoritza-la.
  • Distingir 404 de 403 importa: "no existeix" i "existeix però no el pots veure" exigeixen accions diferents.
  • El raise final evita l'antipatró d'empassar-se errors desconeguts, que amaga problemes reals.

Paginació a boto3

Les APIs retornen com a molt uns centenars d'elements per crida. Si itères només la primera resposta, perdràs dades en silenci. Els paginadors ho resolen:

import boto3

s3 = boto3.client("s3", region_name="eu-west-1")

paginador = s3.get_paginator("list_objects_v2")
pagines = paginador.paginate(Bucket="mercadofresco-fotos-producto", Prefix="2026/")

total = 0
for pagina in pagines:                     # cada iteració és una crida a l'API
    for objecte in pagina.get("Contents", []):  # .get() evita KeyError si la pàgina ve buida
        total += 1
print(f"Objectes trobats: {total}")

Una ullada equivalent en JavaScript

Perquè vegis que els conceptes es traslladen, el mateix llistat de buckets amb l'AWS SDK for JavaScript v3:

# L'SDK v3 és modular: només s'instal·la el client del servei que necessites
npm install @aws-sdk/client-s3
// Importa només el client de S3 i la comanda concreta que farem servir
import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";

// El client llegeix credencials amb el mateix ordre de precedència que la CLI
const client = new S3Client({ region: "eu-west-1" });

async function llistarBuckets() {
  try {
    // Al v3, cada operació és un objecte Command que s'envia amb send()
    const resposta = await client.send(new ListBucketsCommand({}));
    resposta.Buckets.forEach((b) => console.log(b.Name, b.CreationDate));
  } catch (error) {
    // L'equivalent a ClientError: el codi és a error.name
    console.error("Error d'AWS:", error.name, "-", error.message);
  }
}

llistarBuckets();

Diferències respecte a boto3: el v3 és modular (menys pes a Lambda) i fa servir el patró comanda: crees un objecte XxxCommand i l'envies amb send(). La lògica de credencials, reintents i errors és equivalent.

CloudShell com a alternativa sense instal·lació

Com vam veure a la lliçó 01-04, AWS CloudShell et dona un terminal al navegador amb la CLI v2, Python i boto3 ja instal·lats, i autenticada automàticament amb l'usuari de la consola.

CLI local CloudShell
Instal·lació No
Credencials Configures claus Heretades, temporals
Rendiment i fitxers locals Total Limitat (1 GB persistent)
Sessió Permanent Caduca per inactivitat
Ideal per a Feina diària, scripts, CI Proves ràpides, emergències, formació

CloudShell és especialment útil per a l'escenari "sóc en un ordinador que no és el meu i necessito diagnosticar alguna cosa ja". No substitueix la CLI local per a la feina diària, però és una xarxa de seguretat excel·lent.

Errors Habituals i Consells

  • Unable to locate credentials. No has configurat el perfil, o has fet servir un nom de perfil inexistent. Diagnostica-ho amb aws configure list.
  • ProfileNotFound amb el perfil ben escrit. Gairebé sempre és la secció de ~/.aws/config sense el prefix profile : ha de ser [profile mercadofresco-dev], no [mercadofresco-dev].
  • You must specify a region. Ni el perfil ni la variable d'entorn ni la comanda indiquen regió. Afegeix --region o configura-la al perfil.
  • AccessDenied inesperat. Comprova primer amb quina identitat estàs actuant amb aws sts get-caller-identity; molt sovint és el perfil equivocat, no un problema de permisos.
  • Pujar claus a Git. El desastre més car i més freqüent. .gitignore, git secrets i, millor encara, credencials temporals.
  • Fer servir claus permanents dins d'una instància EC2. Mai. Es fa servir un rol d'instància (lliçó 04-01), que a més rota les credencials sol.
  • Oblidar la paginació. El teu script diu "hi ha 1.000 objectes" quan n'hi ha 50.000. Fes servir paginadors a boto3 i --max-items/NextToken a la CLI.
  • Confondre aws s3 amb aws s3api. El primer és d'alt nivell (ls, cp, sync); el segon exposa l'API completa (get-bucket-tagging, put-bucket-policy). Si una opció no existeix a s3, busca-la a s3api.
  • Ignorar ClientError. Un script que falla en silenci és pitjor que un que es trenca.
  • Consell: defineix àlies al teu terminal per al que repeteixis molt, per exemple alias qui='aws sts get-caller-identity'.
  • Consell: quan una comanda no funcioni i no entenguis per què, afegeix-hi --debug. Veuràs la petició signada completa i la resposta del servei.

Exercicis

Exercici 1: instal·lació i exploració

  1. Instal·la AWS CLI v2 al teu sistema i verifica'n la versió.
  2. Configura un perfil anomenat mercadofresco-admin amb regió eu-west-1 i sortida json.
  3. Executa aws sts get-caller-identity i anota el teu ARN complet.
  4. Escriu una sola comanda que mostri, en format taula, totes les regions el nom de les quals comenci per eu-, amb una única columna anomenada Region.

Exercici 2: script bash d'inventari

Escriu un script inventario-mercadofresco.sh que:

  1. Comprovi amb quina identitat i en quin compte s'està executant, i ho mostri.
  2. Llisti tots els buckets de S3 del compte.
  3. Llisti les zones de disponibilitat d'eu-west-1 amb el seu ID físic.
  4. Llisti les instàncies EC2 amb el seu ID, tipus, estat i zona (si no n'hi ha cap, ho ha d'indicar sense fallar).
  5. Tot amb sortida en taula i sense obrir el paginador interactiu.

Exercici 3: script boto3 que crea i etiqueta un bucket

Escriu un script Python crear_bucket_mercadofresco.py que:

  1. Rebi el nom del bucket com a argument de línia de comandes.
  2. Comprovi si ja existeix (distingint "no existeix" de "sense permisos").
  3. Si no existeix, el creï a eu-west-1 amb el bloqueig d'accés públic activat.
  4. Li apliqui les etiquetes Proyecto=mercadofresco, Entorno=pruebas, Componente=formacion.
  5. Mostri les etiquetes resultants.
  6. Gestioni els errors amb ClientError i retorni un codi de sortida diferent de zero si falla.

Cost: un bucket buit no genera cost apreciable i la capa gratuïta cobreix 5 GB. Tot i així, esborra'l en acabar amb aws s3 rb s3://<nom-del-bucket>.

Solucions

Solució 1

# 1. Instal·lació a Linux i verificació
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install
aws --version

# 2. Perfil
aws configure --profile mercadofresco-admin
# Regió: eu-west-1 ; Sortida: json

# 3. Identitat
aws sts get-caller-identity --profile mercadofresco-admin

# 4. Regions europees en taula, columna única anomenada Region
aws ec2 describe-regions \
  --query 'Regions[?starts_with(RegionName, `eu-`)].{Region:RegionName}' \
  --output table

Es pot fer servir starts_with() o contains(); starts_with és més precís perquè contains també acceptaria un nom que portés eu- al mig.

Solució 2

#!/usr/bin/env bash
# inventario-mercadofresco.sh - inventari ràpid del compte d'AWS

set -euo pipefail            # avorta davant d'error, variable no definida o fallada en una canonada

PERFIL="${1:-mercadofresco-admin}"   # primer argument o valor per defecte
REGIO="eu-west-1"
export AWS_PAGER=""                  # desactiva el paginador interactiu

echo "===== IDENTITAT ====="
aws sts get-caller-identity \
  --profile "$PERFIL" \
  --query '{Compte:Account, Identitat:Arn}' \
  --output table

echo "===== BUCKETS S3 ====="
aws s3api list-buckets \
  --profile "$PERFIL" \
  --query 'Buckets[].{Nom:Name, Creat:CreationDate}' \
  --output table

echo "===== ZONES DE DISPONIBILITAT DE $REGIO ====="
aws ec2 describe-availability-zones \
  --profile "$PERFIL" --region "$REGIO" \
  --query 'AvailabilityZones[].{AZ:ZoneName, IdFisic:ZoneId, Estat:State}' \
  --output table

echo "===== INSTÀNCIES EC2 ====="
INSTANCIES=$(aws ec2 describe-instances \
  --profile "$PERFIL" --region "$REGIO" \
  --query 'Reservations[].Instances[].{Id:InstanceId, Tipus:InstanceType, Estat:State.Name, Zona:Placement.AvailabilityZone}' \
  --output table)

if [ -z "$INSTANCIES" ]; then
  echo "(no hi ha instàncies EC2 a $REGIO)"
else
  echo "$INSTANCIES"
fi

echo "===== FI DE L'INVENTARI ====="

Detalls importants:

  • set -euo pipefail evita que l'script continuï alegrement després d'una fallada.
  • export AWS_PAGER="" és imprescindible en scripts: sense això, la CLI obriria un paginador i l' script es quedaria bloquejat esperant que algú premés q.
  • Desar la sortida en una variable permet comprovar si és buida i donar un missatge clar en lloc d'imprimir una taula buida.

S'executa amb:

chmod +x inventario-mercadofresco.sh
./inventario-mercadofresco.sh mercadofresco-admin

Solució 3

#!/usr/bin/env python3
"""crear_bucket_mercadofresco.py - crea i etiqueta un bucket de S3 per a MercadoFresco."""

import sys
import boto3
from botocore.exceptions import ClientError

REGIO = "eu-west-1"
ETIQUETES = [
    {"Key": "Proyecto",   "Value": "mercadofresco"},
    {"Key": "Entorno",    "Value": "pruebas"},
    {"Key": "Componente", "Value": "formacion"},
]


def existeix_bucket(s3, nom: str) -> bool:
    """True si el bucket existeix i és accessible; False si no existeix."""
    try:
        s3.head_bucket(Bucket=nom)
        return True
    except ClientError as error:
        codi = error.response["Error"]["Code"]
        if codi in ("404", "NoSuchBucket"):
            return False
        if codi == "403":
            print(f"El bucket '{nom}' existeix però pertany a un altre compte.")
            sys.exit(1)
        raise


def crear_bucket(s3, nom: str) -> None:
    """Crea el bucket a REGIO amb l'accés públic bloquejat."""
    # Fora d'us-east-1 cal indicar LocationConstraint explícitament
    s3.create_bucket(
        Bucket=nom,
        CreateBucketConfiguration={"LocationConstraint": REGIO},
    )
    print(f"Bucket '{nom}' creat a {REGIO}.")

    # Bloqueig total d'accés públic: les quatre opcions a True
    s3.put_public_access_block(
        Bucket=nom,
        PublicAccessBlockConfiguration={
            "BlockPublicAcls": True,
            "IgnorePublicAcls": True,
            "BlockPublicPolicy": True,
            "RestrictPublicBuckets": True,
        },
    )
    print("Accés públic bloquejat.")


def etiquetar(s3, nom: str) -> None:
    """Aplica el conjunt d'etiquetes (sobreescriu les existents)."""
    s3.put_bucket_tagging(Bucket=nom, Tagging={"TagSet": ETIQUETES})
    print("Etiquetes aplicades.")


def main() -> int:
    if len(sys.argv) != 2:
        print("Ús: python crear_bucket_mercadofresco.py <nom-del-bucket>")
        return 1

    nom = sys.argv[1]
    s3 = boto3.client("s3", region_name=REGIO)

    try:
        if existeix_bucket(s3, nom):
            print(f"El bucket '{nom}' ja existeix al teu compte; no es torna a crear.")
        else:
            crear_bucket(s3, nom)

        etiquetar(s3, nom)

        actuals = s3.get_bucket_tagging(Bucket=nom)["TagSet"]
        print("\nEtiquetes actuals del bucket:")
        for etiqueta in actuals:
            print(f"  {etiqueta['Key']} = {etiqueta['Value']}")

    except ClientError as error:
        print(f"Error d'AWS: {error.response['Error']['Code']} - "
              f"{error.response['Error']['Message']}", file=sys.stderr)
        return 1

    return 0


if __name__ == "__main__":
    sys.exit(main())

Claus de la solució:

  • LocationConstraint: si crees un bucket en qualsevol regió que no sigui us-east-1 i omets aquest paràmetre, S3 el crea a us-east-1. És una de les raresses històriques de l'API.
  • put_public_access_block amb les quatre opcions a True és la protecció que evita la fuita de dades més habitual a AWS.
  • put_bucket_tagging sobreescriu el conjunt complet d'etiquetes: si en volguessis afegir una sense esborrar les altres, hauries de llegir-les primer amb get_bucket_tagging i fusionar-les.
  • Codis de sortida: 0 si tot va bé, 1 si falla, per poder encadenar l'script en un pipeline.

Execució i neteja:

python crear_bucket_mercadofresco.py mercadofresco-pruebas-cli-jc-2741

# Neteja obligatòria en acabar (rb = remove bucket; ha d'estar buit)
aws s3 rb s3://mercadofresco-pruebas-cli-jc-2741

Conclusió

Amb aquesta lliçó tanques el mòdul d'introducció i, sobretot, fas el salt d'"usuari d'AWS" a "operador d'AWS". Has instal·lat l'AWS CLI v2, has entès l'anatomia d'una comanda (aws <servei> <operació> --paràmetres) i les convencions de noms que et permeten endevinar comandes que encara no coneixes. Has configurat credencials amb aws configure, has vist què hi ha realment dins de ~/.aws/credentials i ~/.aws/config, i saps treballar amb perfils amb nom per no confondre mai desenvolupament amb producció. Coneixes l'ordre de precedència de les credencials, que explica gairebé tots els comportaments estranys, i les regles de seguretat innegociables: mai claus a Git, rotació periòdica i, dins d'AWS, rols en lloc de claus.

Has après a domar la sortida de les comandes amb --output i amb --query i JMESPath, a evitar el parany silenciós de la paginació, a verificar permisos sense gastar res amb --dry-run, i tens a la mà el grapat de comandes d'exploració que faràs servir cada dia. I has fet els teus primers passos amb els SDK: boto3 en Python, amb la distinció entre client i resource, la gestió correcta d'errors mitjançant ClientError i els paginadors, més l'equivalent en JavaScript per veure que els conceptes són universals.

MercadoFresco ja té tot el que necessita per començar de debò: un compte segur i vigilat, una regió triada amb criteri, una consola que saps manejar i unes eines de línia de comandes i programació que fan la feina repetible.

Al mòdul 2, «Serveis principals d'AWS», començant per la lliçó 02-01 «Amazon EC2», aixecarem el primer servidor real de MercadoFresco al núvol i començarem la migració que resoldrà, un a un, els quatre problemes que vam descobrir a la primera lliçó.

Curs d'AWS

Mòdul 1: Introducció a AWS

Mòdul 2: Serveis principals d'AWS

Mòdul 3: Xarxes i lliurament de contingut

Mòdul 4: Seguretat i identitat

Mòdul 5: Monitoratge i gestió

Mòdul 6: Bases de dades

Mòdul 7: Integració d'aplicacions

Mòdul 8: Eines per a desenvolupadors

Mòdul 9: Infraestructura com a codi i govern de comptes

Mòdul 10: Contenidors a AWS

Mòdul 11: Millors pràctiques i gestió de costos

© Copyright 2026. Tots els drets reservats