En tancar la lliçó anterior va quedar una frase incòmoda: la xarxa de vpc-mercadofresco està ben
dissenyada, però no filtra res. La ruta local que AWS posa a totes les taules fa que
qualsevol instància de la VPC pugui intentar obrir una connexió al port 5432 de
mercadofresco-pedidos, i la subxarxa pública accepta el que arribi per l'Internet Gateway. L'
adreçament decideix per on pot anar un paquet; falta decidir si se li permet passar.
AWS ofereix dos tallafocs per a això, i són diferents en gairebé tot: els grups de seguretat, que protegeixen la interfície de xarxa de cada recurs, i les llistes de control d'accés de xarxa (NACL), que protegeixen el perímetre de cada subxarxa. No competeixen: es complementen, i un paquet que entra a la VPC els travessa tots dos, en un ordre concret que convé tenir gravat.
En aquesta lliçó la Marta configura el filtratge complet de MercadoFresco aplicant el patró que distingeix una xarxa ben feta d'una xarxa plena de rangs IP copiats a mà: referenciar grups de seguretat entre capes. En acabar, la base de dades de comandes només acceptarà connexions del grup de seguretat de la botiga, i ni tan sols la Marta des del seu portàtil hi podrà arribar directament.
Contingut
- Les dues capes de filtratge d'una VPC
- Grups de seguretat: amb estat i només amb regles de permís
- Anatomia d'una regla: protocol, port i origen
- El patró clau: referenciar grups de seguretat entre capes
- Les tres capes de MercadoFresco amb els seus grups de seguretat
- Límits i quotes dels grups de seguretat
- NACL: sense estat, numerades i amb regles de denegació
- El parany dels ports efímers
- Taula comparativa: grups de seguretat davant de NACL
- El camí complet d'un paquet
- Cas pràctic: obrir el port 22 només a l'oficina (i per què no fer-ho)
- Cas pràctic: bloquejar una IP abusiva amb una NACL
- Depuració: quin error veus quan falla cada cosa
- Confirmar-ho amb VPC Flow Logs
- Creació i auditoria per CLI
- Una altra capa diferent: les polítiques d'identitat
Les dues capes de filtratge d'una VPC
Abans de res, el mapa mental. Quan un paquet entra a la VPC des d'internet, travessa això:
flowchart LR
NET["Internet"]
NACL{{"NACL de la subxarxa<br/>(sense estat, perimetre)"}}
SG{{"Grup de seguretat<br/>(amb estat, a la ENI)"}}
ENI["Instancia<br/>(la seva ENI)"]
NET --> NACL --> SG --> ENI
- La NACL actua a la frontera de la subxarxa. Un paquet que va d'una instància a una altra dins de la mateixa subxarxa no la travessa.
- El grup de seguretat actua a la ENI, és a dir, enganxat al recurs. Tot el trànsit dirigit a una instància el travessa, vingui d'on vingui.
La conseqüència pràctica és que el 95 % de la feina diària es fa amb grups de seguretat, i les NACL es reserven per a regles gruixudes de subxarxa, sobretot denegacions, que és l'única cosa que els grups de seguretat no saben fer.
Grups de seguretat: amb estat i només amb regles de permís
Un grup de seguretat és un tallafocs virtual que s'assigna a una ENI. Té tres propietats que cal entendre bé perquè expliquen gairebé tot el seu comportament:
1. Només admet regles de permís (allow). No existeix la regla «denegar». Tot allò que no està explícitament permès queda denegat per defecte. Això simplifica moltíssim el raonament —no cal pensar en l'ordre de les regles— però significa que amb un grup de seguretat no pots bloquejar una IP concreta: per a això hi ha les NACL.
2. Té estat (stateful). Si permets una connexió d'entrada, la resposta surt automàticament, encara que no hi hagi cap regla de sortida que la contempli. I a l'inrevés: si una instància inicia una connexió de sortida, la resposta entra encara que no hi hagi regla d'entrada. El grup de seguretat recorda les connexions establertes.
Això és el que fa que una instància amb aquestes regles funcioni perfectament:
| Direcció | Protocol | Port | Origen/Destinació |
|---|---|---|---|
| Entrada | TCP | 443 | 0.0.0.0/0 |
| Sortida | (cap regla especial, la de per defecte) |
Un navegador es connecta des del port efímer 51234 al 443 de la instància; la resposta surt del 443 al 51234 sense necessitar cap regla, perquè el grup de seguretat sap que aquella conversa ja estava oberta.
3. Totes les regles s'avaluen en conjunt, sense ordre. Si una ENI té tres grups de seguretat assignats, s'avalua la unió de totes les seves regles. N'hi ha prou que una regla de qualsevol d'ells permeti el trànsit. No hi ha prioritats ni «la primera que coincideixi».
Per defecte, un grup de seguretat acabat de crear té:
- Entrada: cap regla (no entra res).
- Sortida:
0.0.0.0/0en tots els protocols i ports (surt tot).
Anatomia d'una regla: protocol, port i origen
Cada regla té quatre camps:
| Camp | Valors | Notes |
|---|---|---|
| Tipus/Protocol | TCP, UDP, ICMP, o -1 (tots) |
A la consola s'ofereixen dreceres: «HTTPS», «PostgreSQL» |
| Rang de ports | Un port (443) o un rang (1024-65535) |
ICMP no fa servir ports sinó tipus i codi |
| Origen (entrada) / Destinació (sortida) | CIDR, un altre grup de seguretat, o prefix list | El camp més important |
| Descripció | Text lliure | Opcional però decisiu per al manteniment |
Els tres tipus d'origen possibles:
| Tipus d'origen | Exemple | Quan fer-lo servir |
|---|---|---|
| CIDR IPv4/IPv6 | 0.0.0.0/0, 81.45.20.7/32 |
Trànsit d'internet o d'una IP externa concreta |
| Un altre grup de seguretat | sg-mercadofresco-alb |
Sempre que l'origen sigui un altre recurs de la VPC |
| Prefix list | pl-6da54004 (S3), o una de pròpia |
Conjunts de rangs gestionats o reutilitzables |
Sobre la descripció: és opcional, però una regla sense descripció és una regla que d'aquí a un any ningú no esborrarà per por. La Marta imposa la norma que tota regla en porti una que expliqui per què existeix, no què fa: «accés del proveïdor de pagaments», no «port 443 obert».
Un detall sobre /32: és la màscara que designa una única adreça IP. 81.45.20.7/32
significa exactament aquella IP i cap més. És la manera correcta d'expressar «només aquesta màquina».
El patró clau: referenciar grups de seguretat entre capes
Aquí hi ha la idea més important de la lliçó. Compara dues maneres d'escriure la mateixa intenció, «la base de dades només accepta connexions de les instàncies de la botiga»:
Forma ingènua, amb rangs d'IP:
Entrada TCP 5432 des de 10.0.32.0/20 # subxarxa d'app A Entrada TCP 5432 des de 10.0.48.0/20 # subxarxa d'app B
Forma correcta, amb referència a grup de seguretat:
Les diferències són de fons, no d'estil:
| Amb rangs d'IP | Amb referència a grup de seguretat | |
|---|---|---|
| Abast real | Tota la subxarxa, inclosa qualsevol màquina futura | Només els recursos que porten aquell grup |
| En afegir una AZ o subxarxa | Cal editar totes les regles | No cal tocar res |
| En escalar l'ASG | Funciona, però per accident | Funciona per disseny |
| En llançar una instància aliena a la subxarxa | Pot arribar a la base de dades | No pot |
| Llegibilitat | «10.0.32.0/20» no diu res | «des del grup de la botiga» es llegeix sol |
El cas que ho deixa clar: si el Luis llança una instància de proves a snet-mercadofresco-app-a amb
un grup de seguretat diferent, amb la forma ingènua aquella instància pot connectar-se a la base de
dades de producció, perquè és dins del rang permès. Amb la referència entre grups, no pot,
perquè no porta sg-mercadofresco-tienda.
Com funciona per dins: quan una regla referencia sg-mercadofresco-tienda, AWS resol
dinàmicament el conjunt d'IP privades de totes les ENI que tinguin aquell grup assignat, i el
manté actualitzat en temps real. Quan l'ASG llança la instància número 3 i la número 4 el
divendres a les 17:00, queden autoritzades en el mateix instant en què reben la seva IP.
Dos matisos que sorprenen:
- La referència resol a IP privades. Si el trànsit arribés per la IP pública, la regla no coincidiria. Dins de la VPC això no passa, però explica per què cal fer servir sempre noms DNS interns.
- Es pot referenciar el mateix grup (
sg-xpermet entrada des desg-x). És el patró per a clústers els nodes dels quals parlen entre ells, com el que necessitarà ElastiCache a 06-05.
Les tres capes de MercadoFresco amb els seus grups de seguretat
flowchart TB
USER["Usuaris d'internet"]
subgraph VPC["vpc-mercadofresco"]
subgraph PUB["Subxarxes publiques (10.0.0.0/20, 10.0.16.0/20)"]
ALB["Balancejador de la botiga<br/><b>sg-mercadofresco-alb</b><br/>entrada 80 i 443 des de 0.0.0.0/0"]
end
subgraph APP["Subxarxes d'aplicacio (10.0.32.0/20, 10.0.48.0/20)"]
EC2["Instancies de l'ASG<br/><b>sg-mercadofresco-tienda</b><br/>entrada 443 des de sg-mercadofresco-alb"]
end
subgraph DAT["Subxarxes de dades (10.0.64.0/20, 10.0.80.0/20)"]
RDS[("mercadofresco-pedidos<br/><b>sg-mercadofresco-basedatos</b><br/>entrada 5432 des de sg-mercadofresco-tienda")]
EFS["efs-mercadofresco-fotos<br/><b>sg-efs-mercadofresco</b><br/>entrada 2049 des de sg-mercadofresco-tienda"]
end
end
USER -->|"443"| ALB
ALB -->|"443"| EC2
EC2 -->|"5432"| RDS
EC2 -->|"2049 NFS"| EFS
La cadena de referències és la part elegant: ningú no escriu ni un sol rang IP privat. Només el
grup del balancejador, que és la porta d'entrada, esmenta 0.0.0.0/0.
Les regles completes, grup per grup:
sg-mercadofresco-alb — la porta d'entrada
| Dir. | Protocol | Port | Origen/Destinació | Descripció |
|---|---|---|---|---|
| Entrada | TCP | 443 | 0.0.0.0/0 |
Trànsit HTTPS públic de la botiga |
| Entrada | TCP | 80 | 0.0.0.0/0 |
Només per redirigir a HTTPS (vegeu 03-03) |
| Sortida | TCP | 443 | sg-mercadofresco-tienda |
Reenviament a les instàncies de l'ASG |
sg-mercadofresco-tienda — la capa d'aplicació
| Dir. | Protocol | Port | Origen/Destinació | Descripció |
|---|---|---|---|---|
| Entrada | TCP | 443 | sg-mercadofresco-alb |
Només des del balancejador |
| Sortida | TCP | 5432 | sg-mercadofresco-basedatos |
Consultes a la base de comandes |
| Sortida | TCP | 2049 | sg-efs-mercadofresco |
Muntatge NFS del sistema de fitxers |
| Sortida | TCP | 443 | 0.0.0.0/0 |
API d'AWS, passarel·la de pagament, actualitzacions |
Fixa't que no hi ha regla d'entrada per al port 22. Ni una IP d'oficina, ni res. Hi tornem al cas pràctic.
sg-mercadofresco-basedatos — la capa de dades
| Dir. | Protocol | Port | Origen/Destinació | Descripció |
|---|---|---|---|---|
| Entrada | TCP | 5432 | sg-mercadofresco-tienda |
Consultes de l'aplicació |
| Entrada | TCP | 5432 | sg-lambda-mercadofresco |
Funció mercadofresco-estado-pedido |
| Sortida | (cap) | Una base de dades no necessita sortir |
Aquell «cap sortida» és deliberat: cal esborrar explícitament la regla de sortida per defecte
0.0.0.0/0. Com que el grup té estat, les respostes a les consultes surten igualment.
sg-efs-mercadofresco — el sistema de fitxers compartit
| Dir. | Protocol | Port | Origen/Destinació | Descripció |
|---|---|---|---|---|
| Entrada | TCP | 2049 | sg-mercadofresco-tienda |
NFS des de les instàncies de la botiga |
Límits i quotes dels grups de seguretat
Xifres que convé tenir presents perquè s'assoleixen abans del que sembla:
| Límit | Valor per defecte | Ampliable |
|---|---|---|
| Grups de seguretat per VPC | 2.500 | Sí |
| Regles d'entrada per grup | 60 | Sí, fins a 1.000 |
| Regles de sortida per grup | 60 | Sí |
| Grups de seguretat per ENI | 5 | Sí, fins a 16 |
| Regles × grups per ENI | 1.000 | Sí |
La regla real és l'última: regles per grup × grups per ENI no pot passar de 1.000. I un
detall comptable: una regla amb un rang de ports compta com una, però una regla amb diversos
CIDR compta com una per CIDR. Un grup amb «443 des d'aquestes 40 IP» consumeix 40 regles. És
exactament l'escenari per al qual existeixen les prefix lists gestionades pel client: es
defineix una llista amb les 40 IP i es referencia amb una sola regla.
NACL: sense estat, numerades i amb regles de denegació
Una NACL (Network Access Control List) és un tallafocs a nivell de subxarxa. Cada subxarxa està associada a exactament una NACL; si no l'associes, fa servir la NACL per defecte de la VPC, que permet absolutament tot en els dos sentits.
Les seves propietats són gairebé les oposades a les d'un grup de seguretat:
1. Permet i denega. Cada regla és allow o deny. Això és l'única cosa que les fa
imprescindibles.
2. No té estat (stateless). No recorda res. Si una petició entra per una regla d' entrada, la resposta necessita la seva pròpia regla de sortida. Aquest és l'origen del 90 % dels problemes amb NACL.
3. S'avaluen en ordre numèric, i la primera coincidència guanya. Les regles es numeren d'1 a 32.766. AWS les recorre de menor a major i s'atura en la primera que coincideix, ignorant totes les següents.
4. Existeix la regla *. Al final de tota NACL hi ha una regla no editable, numerada *, que
denega tot allò que no hagi coincidit abans. És la xarxa de seguretat final.
La NACL per defecte d'una VPC nova:
| Regla | Tipus | Protocol | Port | Origen | Acció |
|---|---|---|---|---|---|
| 100 | Tot | Tots | Tots | 0.0.0.0/0 |
ALLOW |
* |
Tot | Tots | Tots | 0.0.0.0/0 |
DENY |
(i el mateix en sortida). És a dir: per defecte, una NACL no filtra res. Això és intencionat, i és la raó per la qual moltes arquitectures correctes deixen les NACL tal qual i confien tot el filtratge als grups de seguretat.
Consell de numeració: fes servir salts de 100 (100, 200, 300…). Quan necessitis inserir una regla entre dues, tindràs lloc. Renumerar una NACL en producció és una operació desagradable.
El parany dels ports efímers
Aquest apartat es mereix la seva pròpia secció perquè és on tothom s'estavella.
Quan un navegador es connecta a la botiga, obre la connexió des d'un port aleatori alt —un port efímer— cap al 443 del servidor. El servidor respon des del 443 cap a aquell port efímer. Com que la NACL no té estat, aquella resposta s'avalua contra les regles de sortida, i el seu port de destinació no és el 443: és el 51234, o el 62890, o el que sigui.
Per això una NACL restrictiva necessita sempre una regla de sortida que obri el rang de ports efímers. I el rang depèn del client:
| Sistema del client | Rang de ports efímers |
|---|---|
| Linux modern | 32768–60999 |
| Windows (des de Vista/2008) | 49152–65535 |
| Balancejadors d'AWS (ELB/NLB) | 1024–65535 |
| Lambda, contenidors | 1024–65535 |
La recomanació pràctica d'AWS: obrir 1024–65535 en sortida, perquè no saps quin client tindràs. Sí, és un rang enorme, i és la raó per la qual les NACL són un instrument tosc: filtrar finament el trànsit de tornada és pràcticament impossible.
Una NACL funcional per a una subxarxa pública queda així:
| Regla | Dir. | Protocol | Port | Origen/Destinació | Acció | Per què |
|---|---|---|---|---|---|---|
| 100 | Entrada | TCP | 443 | 0.0.0.0/0 |
ALLOW | Peticions HTTPS |
| 110 | Entrada | TCP | 80 | 0.0.0.0/0 |
ALLOW | Peticions HTTP a redirigir |
| 120 | Entrada | TCP | 1024-65535 | 0.0.0.0/0 |
ALLOW | Respostes a connexions sortints |
* |
Entrada | Tots | Tots | 0.0.0.0/0 |
DENY | Regla implícita |
| 100 | Sortida | TCP | 443 | 0.0.0.0/0 |
ALLOW | Connexions sortints HTTPS |
| 110 | Sortida | TCP | 1024-65535 | 0.0.0.0/0 |
ALLOW | Respostes a les peticions entrants |
* |
Sortida | Tots | Tots | 0.0.0.0/0 |
DENY | Regla implícita |
Quatre de les sis regles existeixen només per la manca d'estat. Compara-ho amb el grup de seguretat equivalent, que en necessitava una.
Taula comparativa: grups de seguretat davant de NACL
| Criteri | Grup de seguretat | NACL |
|---|---|---|
| Nivell | ENI (instància, RDS, ALB, punt d'enllaç…) | Subxarxa completa |
| Estat | Amb estat: la resposta es permet sola | Sense estat: la resposta necessita regla pròpia |
| Tipus de regla | Només permetre | Permetre i denegar |
| Avaluació | Totes les regles alhora, sense ordre | Per número, la primera que coincideix guanya |
| Quantes se n'apliquen | Diversos per ENI (fins a 5), se sumen | Una per subxarxa |
| Per defecte | No entra res, surt tot | Entra tot i surt tot |
| Origen per grup de seguretat | Sí, la característica clau | No, només CIDR |
| Trànsit dins de la mateixa subxarxa | Sí que el filtra | No el veu |
| Quan fer-lo servir | Sempre; és l'eina principal | Bloquejos gruixuts per subxarxa i denegacions |
| Cas d'ús típic | «La base de dades només parla amb la botiga» | «Aquesta IP no entra a la subxarxa pública» |
Regla pràctica que resumeix el repartiment: els grups de seguretat defineixen l'arquitectura permesa; les NACL bloquegen el que cal bloquejar.
El camí complet d'un paquet
Aquest diagrama és el que cal memoritzar. Segueix una petició HTTPS d'un client fins a la instància i la seva resposta de tornada:
sequenceDiagram
participant C as Client<br/>(203.0.113.50:51234)
participant NE as NACL entrada<br/>subxarxa app
participant SE as SG entrada<br/>sg-mercadofresco-tienda
participant I as Instancia<br/>(10.0.32.15:443)
participant SS as SG sortida<br/>(amb estat)
participant NS as NACL sortida<br/>subxarxa app
C->>NE: Peticio → port desti 443
Note over NE: Regla 100: ALLOW TCP 443 ✔
NE->>SE: Peticio
Note over SE: Entrada 443 des de sg-alb ✔
SE->>I: Arriba a l'aplicacio
I->>SS: Resposta → port desti 51234
Note over SS: Connexio ja establerta:<br/>NO s'avalua cap regla ✔
SS->>NS: Resposta
Note over NS: Regla 110: ALLOW TCP 1024-65535<br/>SENSE aquesta regla, la resposta MOR AQUI ✘
NS->>C: Resposta lliurada
Quatre punts de control en total, i l'asimètric és el tercer: el grup de seguretat no avalua res a la sortida perquè recorda la connexió, mentre que la NACL la torna a examinar com si fos trànsit nou. El símptoma quan falta la regla 110 és especialment cruel: la connexió s' estableix, la petició arriba, l'aplicació la processa correctament… i el client es queda esperant fins que expira el temps d'espera.
Cas pràctic: obrir el port 22 només a l'oficina (i per què no fer-ho)
El Luis demana accés SSH a les instàncies per depurar. La resposta «correcta segons el manual» seria obrir el 22 només a la IP fixa de l'oficina:
aws ec2 authorize-security-group-ingress \
--profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_TIENDA" \
--ip-permissions 'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=81.45.20.7/32,Description="SSH des de la oficina de Barcelona"}]'Mai 0.0.0.0/0. Un port 22 obert a internet rep intents d'accés automatitzats en
qüestió de minuts.
Però per a MercadoFresco ni tan sols això és la solució correcta, per quatre raons:
- La IP de l'oficina canvia. El dia que l'operador la renovi, no hi entra ningú, i algú
«arreglarà» el problema posant
0.0.0.0/0a les onze de la nit. - No serveix per al teletreball. La Marta des de casa té una altra IP.
- No queda registre de qui va entrar. SSH amb clau compartida no identifica la persona.
- Les instàncies de l'ASG són efímeres. Entrar per SSH a una màquina que es destruirà d'aquí a dues hores per «arreglar-la» a mà és exactament el que l'ASG intenta evitar.
L'alternativa, que ja fem servir a 02-01, és el Session Manager: l'agent de SSM instal·lat a la instància inicia una connexió sortint cap al servei d'AWS, i la sessió viatja per aquell túnel.
| SSH amb port 22 obert | Session Manager | |
|---|---|---|
| Ports d'entrada necessaris | 22 des d'algun origen | Cap |
| Necessita IP pública o bastió | Sí | No |
| Gestió de claus | Fitxers .pem que es comparteixen |
Cap: fa servir credencials d'AWS |
| Qui va entrar i què va fer | Sense registre fiable | Registrat a CloudTrail i CloudWatch Logs |
| Control de permisos | Tot o res | Polítiques d'IAM per persona (04-01) |
| Funciona en subxarxa privada | Només amb bastió | Sí, amb NAT o amb punts d'enllaç d'interfície |
Per això sg-mercadofresco-tienda no té cap regla d'entrada per al 22, i aquella absència és
una decisió de disseny, no un oblit.
Cas pràctic: bloquejar una IP abusiva amb una NACL
Un dimarts, la Sara detecta als registres que la IP 198.51.100.77 està recorrent el catàleg
sencer a raó de 40 peticions per segon. No és un atac distribuït, és una sola IP raspant
preus. Els grups de seguretat no serveixen: no saben denegar.
# Localitzar la NACL associada a les subxarxes publiques
NACL_PUB=$(aws ec2 describe-network-acls \
--profile mercadofresco-dev --region eu-west-1 \
--filters "Name=association.subnet-id,Values=$PUB_A" \
--query 'NetworkAcls[0].NetworkAclId' --output text)
# Regla 50: numero BAIX perque s'avalui ABANS que l'ALLOW general de la 100
aws ec2 create-network-acl-entry \
--profile mercadofresco-dev --region eu-west-1 \
--network-acl-id "$NACL_PUB" \
--rule-number 50 \
--protocol -1 \
--rule-action deny \
--ingress \
--cidr-block 198.51.100.77/32El número 50 és tota la lliçó: si haguéssim fet servir el 150, la regla 100 (ALLOW general) s'
avaluaria primer, coincidiria, i la 150 no es llegiria mai. La primera coincidència guanya.
Per retirar-la quan l'abús cessi:
aws ec2 delete-network-acl-entry --profile mercadofresco-dev --region eu-west-1 \
--network-acl-id "$NACL_PUB" --rule-number 50 --ingressDos advertiments honestos:
- Bloquejar IP a mà no escala. Si demà en són 300, això és inviable i caldrà l' eina adequada: AWS WAF, que s'estudia a 04-05, amb les seves regles de límit de taxa. La NACL és la resposta d'urgència, no la solució.
- La NACL bloqueja en entrar a la subxarxa. Si el trànsit arriba a través de CloudFront (lliçó 03-04) o d'un balancejador, la IP que veu la NACL és la de l'intermediari, no la de l'atacant, i bloquejar-la deixaria fora tothom.
Depuració: quin error veus quan falla cada cosa
Els símptomes són diferents i saber llegir-los estalvia hores:
| Símptoma | Causa més probable | Com confirmar-ho |
|---|---|---|
| Temps d'espera esgotat (connection timed out, la petició es queda penjada) | Grup de seguretat o NACL: el paquet es descarta en silenci | Flow Logs amb REJECT, o cap entrada en absolut |
| Connexió rebutjada (connection refused, resposta immediata) | La xarxa funciona: no hi ha res escoltant en aquell port | ss -lntp a la instància; el servei està caigut |
| Es connecta i es penja a mitges | NACL sense regla de ports efímers a la sortida | Flow Logs: ACCEPT d'entrada i REJECT de sortida |
| Es resol a una IP pública des de dins | enableDnsHostnames o PubliclyAccessible |
dig des de la instància (vist a 03-01) |
| Funciona des d'una instància i no des d'una altra | La segona no porta el grup de seguretat referenciat | describe-instances i comparar SecurityGroups |
Accés denegat (AccessDenied) de l'API d'AWS |
No és la xarxa: és una política d'IAM | CloudTrail; s'estudia a 04-01 |
La distinció entre les dues primeres files és la més útil de tota la taula: un tallafocs
descarta el paquet en silenci i el client espera; un servei caigut respon immediatament
rebutjant. Si telnet mercadofresco-pedidos... 5432 retorna «connection refused» a l'instant,
el problema no és al grup de seguretat.
Confirmar-ho amb VPC Flow Logs
Els Flow Logs que vam activar a 03-01 són l'única manera de tenir-ne certesa. Recordant el format:
2 111122223333 eni-0a1b2c3d 10.0.32.15 10.0.64.30 44321 5432 6 12 3800 1738500000 1738500060 REJECT OK
Aquí 10.0.32.15 (instància de la botiga) va intentar arribar a 10.0.64.30 (la base de dades) al
port 5432, i el resultat va ser REJECT. Això confirma que el bloqueig passa a la capa de xarxa.
Com distingir quina de les dues capes ha bloquejat:
| Què veus als Flow Logs | Interpretació |
|---|---|
Només un REJECT d'entrada, cap resposta |
Grup de seguretat de destinació: va descartar la petició |
ACCEPT d'entrada i REJECT de sortida a la resposta |
NACL: falta la regla de ports efímers |
| Cap entrada en absolut | El paquet ni hi va arribar: problema de rutes (03-01) o de DNS |
ACCEPT en tots dos sentits però l'aplicació falla |
La xarxa està bé: mira l'aplicació |
Aquella tercera fila és especialment valuosa: l'absència de registres és informació. L'anàlisi amb CloudWatch Logs Insights i les consultes sobre aquestes dades s'estudien a 05-01.
Creació i auditoria per CLI
Crear els grups amb referències creuades
Hi ha un problema d'ou i gallina: sg-mercadofresco-tienda referencia sg-mercadofresco-alb i
a l'inrevés. La solució és crear primer els grups buits i després les regles.
crear_sg() {
local nom=$1 desc=$2 component=$3
aws ec2 create-security-group \
--profile mercadofresco-dev --region eu-west-1 \
--group-name "$nom" --description "$desc" --vpc-id "$VPC_ID" \
--tag-specifications "ResourceType=security-group,Tags=[
{Key=Name,Value=$nom},{Key=Proyecto,Value=mercadofresco},
{Key=Entorno,Value=produccion},{Key=Componente,Value=$component},
{Key=Propietario,Value=marta},{Key=CentroCoste,Value=operaciones}]" \
--query 'GroupId' --output text
}
SG_ALB=$(crear_sg sg-mercadofresco-alb "Balancejador public de la botiga" tienda)
SG_TIENDA=$(crear_sg sg-mercadofresco-tienda "Instancies EC2 de la botiga" tienda)
SG_BD=$(crear_sg sg-mercadofresco-basedatos "RDS PostgreSQL de comandes" pedidos)
SG_EFS=$(crear_sg sg-efs-mercadofresco "Sistema de fitxers de fotos" catalogo)Ara les regles. --ip-permissions en format llarg permet incloure la descripció, cosa que la
forma curta --port / --cidr no admet:
# ALB: entrada des d'internet
aws ec2 authorize-security-group-ingress --profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_ALB" --ip-permissions \
'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=0.0.0.0/0,Description="HTTPS public de la botiga"}]' \
'IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges=[{CidrIp=0.0.0.0/0,Description="HTTP per redirigir a HTTPS"}]'
# Botiga: entrada NOMES des del grup del balancejador (UserIdGroupPairs, no IpRanges)
aws ec2 authorize-security-group-ingress --profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_TIENDA" --ip-permissions \
"IpProtocol=tcp,FromPort=443,ToPort=443,UserIdGroupPairs=[{GroupId=$SG_ALB,Description=\"Transit del balancejador\"}]"
# Base de dades: entrada NOMES des del grup de la botiga
aws ec2 authorize-security-group-ingress --profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_BD" --ip-permissions \
"IpProtocol=tcp,FromPort=5432,ToPort=5432,UserIdGroupPairs=[{GroupId=$SG_TIENDA,Description=\"Consultes de la botiga\"}]"
# EFS: NFS des de la botiga
aws ec2 authorize-security-group-ingress --profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_EFS" --ip-permissions \
"IpProtocol=tcp,FromPort=2049,ToPort=2049,UserIdGroupPairs=[{GroupId=$SG_TIENDA,Description=\"Muntatge NFS de la botiga\"}]"
# Treure la sortida total de la base de dades: no necessita iniciar res
aws ec2 revoke-security-group-egress --profile mercadofresco-dev --region eu-west-1 \
--group-id "$SG_BD" --ip-permissions 'IpProtocol=-1,IpRanges=[{CidrIp=0.0.0.0/0}]'UserIdGroupPairs és la clau del patró: és el camp que expressa «des d'aquest altre grup de
seguretat» en lloc d'un rang d'IP.
Auditoria: trobar regles perilloses
Aquesta comanda és la que la Marta executa cada dilluns. Busca qualsevol grup de seguretat del compte amb un port d'administració o de base de dades obert a tot internet:
aws ec2 describe-security-groups --profile mercadofresco-dev --region eu-west-1 \
--query 'SecurityGroups[?IpPermissions[?
(FromPort==`22` || FromPort==`3389` || FromPort==`3306` || FromPort==`5432` || FromPort==`6379`)
&& IpRanges[?CidrIp==`0.0.0.0/0`]]].{
Grup:GroupName, Id:GroupId, VPC:VpcId,
Ports:IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]].FromPort}' \
--output tableDesglossament de l'expressió JMESPath, que és densa però val la pena entendre:
SecurityGroups[? ... ]filtra la llista de grups.IpPermissions[? ... ]mira dins de les regles d'entrada de cada grup.- La condició combina dues coses amb
&&: que el port sigui un dels sensibles (22 SSH, 3389 RDP, 3306 MySQL, 5432 PostgreSQL, 6379 Redis) i que entre els seus rangs hi hagi un0.0.0.0/0. - Els accents greus (
`) marquen literals numèrics i de cadena a JMESPath, com vam veure a 01-05.
Si això retorna alguna cosa, hi ha un problema per arreglar avui. I un complement útil, buscar grups orfes que ningú no fa servir:
# Grups que no estan assignats a cap interficie de xarxa
comm -23 \
<(aws ec2 describe-security-groups --profile mercadofresco-dev --region eu-west-1 \
--query 'SecurityGroups[].GroupId' --output text | tr '\t' '\n' | sort) \
<(aws ec2 describe-network-interfaces --profile mercadofresco-dev --region eu-west-1 \
--query 'NetworkInterfaces[].Groups[].GroupId' --output text | tr '\t' '\n' | sort -u)I la comprovació des de Python, útil per integrar-la en un pipeline (mòdul 8):
import boto3
ec2 = boto3.client("ec2", region_name="eu-west-1")
PORTS_SENSIBLES = {22, 3389, 3306, 5432, 6379, 27017}
troballes = []
paginador = ec2.get_paginator("describe_security_groups")
for pagina in paginador.paginate():
for grup in pagina["SecurityGroups"]:
for regla in grup.get("IpPermissions", []):
# Una regla amb IpProtocol == "-1" no porta FromPort: són TOTS els ports
inici = regla.get("FromPort", 0)
fi = regla.get("ToPort", 65535)
obert_a_internet = any(
r["CidrIp"] == "0.0.0.0/0" for r in regla.get("IpRanges", [])
)
if not obert_a_internet:
continue
afectats = {p for p in PORTS_SENSIBLES if inici <= p <= fi}
if afectats:
troballes.append({
"grup": grup["GroupName"],
"id": grup["GroupId"],
"ports": sorted(afectats),
})
for t in troballes:
print(f"PERILL {t['grup']:35} {t['id']:22} ports {t['ports']}")
print(f"\n{len(troballes)} regles perilloses trobades")Detall important del codi: es comprova el rang complet (inici <= p <= fi), no només
el port inicial. Una regla «TCP 1-65535 des de 0.0.0.0/0» no té FromPort == 22, però inclou
el 22 i és igual de perillosa. La comanda CLI anterior, més simple, se li escaparia.
Una altra capa diferent: les polítiques d'identitat
Convé tancar desfent una confusió freqüent. Els grups de seguretat i les NACL controlen paquets de xarxa: qui pot obrir una connexió TCP a quin port. No tenen cap opinió sobre qui és el que fa la petició ni sobre quina acció sol·licita.
Quan la instància de la botiga demana un objecte de mercadofresco-catalogo-fotos, hi ha dues preguntes
independents:
- Hi ha camí i està permès el paquet? → rutes (03-01), grup de seguretat, NACL, punt d'enllaç de VPC.
- Té permís aquella identitat per fer
s3:GetObjectsobre aquell objecte? → polítiques d' IAM, el rolrol-mercadofresco-tienda, i les polítiques de bucket. Això és matèria de la lliçó 04-01, i unAccessDeniedd'allà no s'arregla mai tocant un grup de seguretat.
Distingir aquestes dues capes estalvia sessions senceres de depuració en la direcció equivocada. I la protecció davant d'atacs a nivell d'aplicació —injeccions, bots, denegació de servei— és una tercera capa diferent encara, la de Shield (04-04) i WAF (04-05).
Errors Habituals i Consells
Fer servir rangs d'IP on hi hauria d'haver referències entre grups. Funciona, i per això es propaga.
Però obre la porta a qualsevol recurs futur d'aquelles subxarxes i obliga a editar regles cada vegada que
canvia la xarxa. Si l'origen és un recurs de la VPC, la resposta és sempre UserIdGroupPairs.
Obrir el 22 o el 3389 a 0.0.0.0/0 «un moment, per provar». Els escàners automàtics
troben el port en minuts. Si de debò cal, /32 d'una IP concreta; millor, Session
Manager.
Oblidar els ports efímers a la NACL de sortida. El símptoma —la connexió s'estableix i després es penja— no apunta gens a la NACL. Si toques una NACL, obre 1024-65535 en sortida.
Numerar malament les regles de NACL. Un DENY amb número més alt que un ALLOW que ja coincideix és una
regla morta. Les denegacions van amb números baixos. I numera de 100 en 100 per poder inserir.
Creure que una NACL filtra el trànsit entre dues instàncies de la mateixa subxarxa. No ho fa: la NACL només actua a la frontera de la subxarxa. Aquell trànsit només el veuen els grups de seguretat.
Deixar la sortida 0.0.0.0/0 al grup de la base de dades. No és un risc immediat, però si
la base de dades es veu compromesa, aquella regla és la seva via per treure dades. Treu-la: l'estat del
grup de seguretat fa que les respostes surtin igual.
Confondre «temps d'espera esgotat» amb «connexió rebutjada». El primer és un tallafocs, el segon és un servei caigut. Diagnosticar en la direcció equivocada costa hores.
No posar descripció a les regles. Una regla sense explicació és permanent per por. Exigeix una descripció a cada regla i revisa la llista cada trimestre.
Consell d'or: dibuixa el diagrama de les capes amb les fletxes dels grups de seguretat abans d'escriure ni una sola regla. Si la fletxa no és al dibuix, la regla no hauria d'existir.
Exercicis
Exercici 1: dissenyar els grups de seguretat d'un tauler intern
MercadoFresco necessita un tauler d'administració intern en instàncies pròpies, que la Sara farà servir
des de l'oficina. El tauler ha de: rebre trànsit del balancejador al 443, consultar la rèplica de
lectura mercadofresco-pedidos-lectura al 5432, i escriure informes a
mercadofresco-informes-analitica. No ha de poder arribar a la base de dades primària.
Dissenya el grup sg-mercadofresco-panel i els canvis necessaris als grups existents,
respectant el patró de referències.
Exercici 2: corregir una NACL trencada
Un company ha configurat aquesta NACL a la subxarxa d'aplicació i la botiga ha deixat de respondre:
| Regla | Dir. | Protocol | Port | Origen | Acció |
|---|---|---|---|---|---|
| 100 | Entrada | TCP | 443 | 10.0.0.0/16 |
ALLOW |
* |
Entrada | Tots | Tots | 0.0.0.0/0 |
DENY |
| 100 | Sortida | TCP | 5432 | 10.0.64.0/20 |
ALLOW |
| 200 | Sortida | TCP | 443 | 0.0.0.0/0 |
ALLOW |
* |
Sortida | Tots | Tots | 0.0.0.0/0 |
DENY |
Identifica tots els problemes, explica el símptoma exacte de cadascun i escriu la NACL corregida.
Exercici 3: auditar i corregir un grup de seguretat heretat
Escriu un script de shell que, per a un grup de seguretat donat, imprimeixi un informe llegible de totes
les seves regles d'entrada distingint el tipus d'origen, marqui les perilloses, i generi les comandes
revoke-security-group-ingress necessàries per eliminar-les sense executar-les.
Solucions
Solució 1
Grup nou sg-mercadofresco-panel:
| Dir. | Protocol | Port | Origen/Destinació | Descripció |
|---|---|---|---|---|
| Entrada | TCP | 443 | sg-mercadofresco-alb |
Tauler servit a través del balancejador |
| Sortida | TCP | 5432 | sg-mercadofresco-lectura |
Consultes a la rèplica de lectura |
| Sortida | TCP | 443 | 0.0.0.0/0 |
S3 i API d'AWS |
Canvis als grups existents: cal un grup nou per a la rèplica,
sg-mercadofresco-lectura, separat de sg-mercadofresco-basedatos. Aquest és el nucli de l'exercici:
si la rèplica compartís grup amb la primària, autoritzar el tauler a la rèplica l'autoritzaria
també a la primària, incomplint el requisit.
sg-mercadofresco-lectura |
Protocol | Port | Origen |
|---|---|---|---|
| Entrada | TCP | 5432 | sg-mercadofresco-panel |
| Entrada | TCP | 5432 | sg-mercadofresco-tienda |
I sg-mercadofresco-basedatos no es toca: continua acceptant només des de sg-mercadofresco-tienda
i la Lambda, per la qual cosa el tauler no pot arribar a la primària.
Sobre l'accés de la Sara des de l'oficina: no s'obre cap port per a ella. Entra pel mateix
balancejador que els clients, i la restricció a l'oficina es fa per autenticació de l'
aplicació, o amb WAF filtrant per IP a /admin (04-05). Afegir una regla amb la IP de l'oficina
al grup del tauler seria tornar al problema de les IP canviants.
Sobre l'accés a mercadofresco-informes-analitica: no requereix cap regla nova més enllà
del 443 de sortida, i si existeix el punt d'enllaç de passarel·la de S3 (03-01), ni tan sols passa pel
NAT. El permís per escriure al bucket és cosa del rol d'IAM (04-01), no del tallafocs.
Solució 2
Hi ha tres problemes:
Problema 1 — falta el rang de ports efímers a la sortida. Les peticions HTTPS entren per la
regla 100 i arriben a l'aplicació, però la resposta va dirigida al port efímer del client
(per exemple, 51234). En sortida, la 100 només cobreix el 5432 i la 200 només el 443, així que la resposta
cau al * DENY. Símptoma: la connexió s'estableix, el servidor processa la petició i el
client es queda penjat fins que expira el temps d'espera. Als Flow Logs: ACCEPT d'entrada
i REJECT de sortida.
Problema 2 — falta el rang de ports efímers a l'entrada. Quan la instància consulta RDS (sortint pel 5432, permès per la regla 100 de sortida), la resposta de RDS arriba a un port efímer de la instància. En entrada només està permès el 443, així que la resposta es denega. Símptoma: les consultes a la base de dades es pengen i acaben en temps d'espera esgotat. El mateix passa amb les crides HTTPS sortints a S3 o a la passarel·la de pagament.
Problema 3 — l'origen de l'entrada és massa restrictiu en un sentit i poc precís en un
altre. 10.0.0.0/16 cobreix la VPC sencera, cosa que és correcta si el trànsit només ve del
balancejador, però a més permet que qualsevol subxarxa de la VPC entri pel 443, cosa que la
NACL no hauria de decidir. No trenca res, però és una regla mal plantejada: el filtratge fi d'origen
és feina del grup de seguretat.
NACL corregida:
| Regla | Dir. | Protocol | Port | Origen/Destinació | Acció | Per què |
|---|---|---|---|---|---|---|
| 100 | Entrada | TCP | 443 | 10.0.0.0/16 |
ALLOW | Peticions del balancejador |
| 200 | Entrada | TCP | 1024-65535 | 0.0.0.0/0 |
ALLOW | Respostes a consultes sortints |
* |
Entrada | Tots | Tots | 0.0.0.0/0 |
DENY | Implícita |
| 100 | Sortida | TCP | 5432 | 10.0.64.0/20 |
ALLOW | Consultes a RDS |
| 200 | Sortida | TCP | 443 | 0.0.0.0/0 |
ALLOW | S3, API d'AWS, pagaments |
| 300 | Sortida | TCP | 1024-65535 | 0.0.0.0/0 |
ALLOW | Respostes al balancejador |
* |
Sortida | Tots | Tots | 0.0.0.0/0 |
DENY | Implícita |
Moralitat de l'exercici: si el filtratge fi ja el fan els grups de seguretat, aquesta NACL podria
perfectament deixar-se en l'ALLOW total per defecte sense perdre seguretat real, i s'hauria evitat
la incidència.
Solució 3
#!/usr/bin/env bash
# auditar-sg.sh — informe de regles d'entrada d'un grup de seguretat
set -euo pipefail
GRUP="${1:?Us: $0 <sg-id>}"
PERFIL="mercadofresco-dev"
REGIO="eu-west-1"
PERILLOSOS="22 3389 3306 5432 6379 27017"
echo "=== Regles d'entrada de $GRUP ==="
REGLES=$(aws ec2 describe-security-groups --profile "$PERFIL" --region "$REGIO" \
--group-ids "$GRUP" --query 'SecurityGroups[0].IpPermissions' --output json)
# Recorrem les regles amb jq, generant una linia per combinacio regla-origen
echo "$REGLES" | jq -r '
.[] |
. as $r |
(($r.IpRanges // [])[] | "CIDR|\($r.IpProtocol)|\($r.FromPort // 0)|\($r.ToPort // 65535)|\(.CidrIp)|\(.Description // "-")"),
(($r.UserIdGroupPairs // [])[] | "SG |\($r.IpProtocol)|\($r.FromPort // 0)|\($r.ToPort // 65535)|\(.GroupId)|\(.Description // "-")"),
(($r.PrefixListIds // [])[] | "PL |\($r.IpProtocol)|\($r.FromPort // 0)|\($r.ToPort // 65535)|\(.PrefixListId)|\(.Description // "-")")
' | while IFS='|' read -r tipus proto inici fi origen desc; do
marca=" "
if [[ "$origen" == "0.0.0.0/0" ]]; then
for p in $PERILLOSOS; do
if (( inici <= p && p <= fi )); then marca="!!"; break; fi
done
fi
printf "%s %-4s %-5s %6s-%-6s %-22s %s\n" \
"$marca" "$tipus" "$proto" "$inici" "$fi" "$origen" "$desc"
if [[ "$marca" == "!!" ]]; then
echo " → aws ec2 revoke-security-group-ingress --profile $PERFIL --region $REGIO \\"
echo " --group-id $GRUP --protocol $proto --port $inici-$fi --cidr $origen"
fi
done
echo
echo "Les línies marcades amb !! exposen un port sensible a tot internet."
echo "Revisa les comandes suggerides abans d'executar-les."Punts de disseny de l'script: distingeix els tres tipus d'origen (CIDR, SG, PL) perquè una
referència a un altre grup mai no és perillosa per si mateixa; comprova el rang complet de ports
en lloc de només l'inicial; fa servir // 0 i // 65535 a jq per al cas IpProtocol: "-1", on
FromPort i ToPort no existeixen; i no executa res, només imprimeix les comandes, perquè revocar
regles a cegues en producció és pitjor que la vulnerabilitat.
Conclusió
MercadoFresco ja té tallafocs. Saps que els grups de seguretat actuen a la ENI, tenen
estat —la resposta a una connexió permesa surt sola, sense regla—, només permeten i s'avaluen
en conjunt sense ordre, i que per defecte no deixen entrar res i ho deixen sortir tot. Coneixes l'
anatomia d'una regla i, sobretot, domines el patró que defineix una xarxa ben construïda:
referenciar uns grups de seguretat des d'uns altres amb UserIdGroupPairs en lloc d'escriure rangs
d'IP. Gràcies a això, sg-mercadofresco-basedatos accepta el 5432 només des de
sg-mercadofresco-tienda, i les instàncies que l'ASG llança el divendres a les 17:00 queden
autoritzades en el mateix instant en què arrenquen, sense editar res.
Saps que les NACL són el contrari en gairebé tot: actuen a la frontera de la subxarxa, no
tenen estat, s'avaluen per número aturant-se en la primera coincidència, acaben sempre en
la regla * de denegació, i són l'única de les dues capes capaç de denegar. Has entès per
què això les obliga a obrir el rang de ports efímers 1024-65535 en el sentit de tornada, i
per què el símptoma d'oblidar-ho —la connexió s'estableix i es penja— és tan difícil d'atribuir.
Has recorregut el camí complet d'un paquet pels quatre punts de control i saps quin d'
ells és asimètric i per què.
A la pràctica has decidit no obrir el port 22 ni tan sols a la IP de l'oficina, amb quatre
raons concretes i el Session Manager com a alternativa; has bloquejat una IP abusiva amb una regla
DENY numerada 50, entenent que el número baix és el que la fa efectiva, i sabent que
aquesta és una resposta d'urgència i no una solució que escali —per a això hi ha WAF, a 04-05. Saps
distingir un temps d'espera esgotat (tallafocs) d'una connexió rebutjada (servei
caigut), i confirmar quina de les dues capes ha bloquejat un paquet llegint l'ACCEPT/REJECT dels
VPC Flow Logs. I has automatitzat l'auditoria setmanal que busca ports sensibles oberts a
0.0.0.0/0, tant en JMESPath com en boto3 comprovant el rang complet de ports. Finalment,
tens clar que les polítiques d'identitat són una capa diferent: un AccessDenied d'IAM
no s'arregla mai tocant un grup de seguretat, i això és matèria del mòdul 4.
Amb la xarxa dissenyada i filtrada, ja podem posar la peça que MercadoFresco porta esperant des de la
primera lliçó. El grup d'Auto Scaling asg-mercadofresco-tienda sap llançar quatre instàncies
el divendres a la tarda, però res no reparteix el trànsit entre elles: avui encara pengen d'una
única IP. A la lliçó 03-03, «Elastic Load Balancing», muntarem el balancejador d'aplicació
a les subxarxes públiques amb el grup sg-mercadofresco-alb que acabem de crear, el connectarem
a l'ASG perquè registri i doni de baixa les instàncies automàticament, configurarem comprovacions
d'estat que no tombin l'aplicació en lloc de salvar-la, i acabarem de resoldre el
problema 1: les caigudes dels divendres.
Curs d'AWS
Mòdul 1: Introducció a AWS
- Què és AWS?
- Configuració del teu compte d'AWS
- Infraestructura global d'AWS
- Consola d'administració d'AWS
- AWS CLI i SDK
Mòdul 2: Serveis principals d'AWS
Mòdul 3: Xarxes i lliurament de contingut
- Amazon VPC
- Grups de seguretat i llistes de control d'accés
- Elastic Load Balancing
- Amazon CloudFront
- Route 53
Mòdul 4: Seguretat i identitat
- AWS Identity and Access Management (IAM)
- AWS Key Management Service (KMS)
- Secrets Manager i Parameter Store
- AWS Shield
- AWS WAF
Mòdul 5: Monitoratge i gestió
- Amazon CloudWatch
- AWS X-Ray i traçabilitat distribuïda
- AWS CloudTrail
- AWS Config
- AWS Trusted Advisor
Mòdul 6: Bases de dades
- Com triar la base de dades adequada
- Amazon DynamoDB
- Amazon Aurora
- Amazon Redshift
- Amazon ElastiCache
Mòdul 7: Integració d'aplicacions
- Amazon SQS
- Amazon SNS
- Amazon EventBridge
- AWS Step Functions
- Patrons d'integració: idempotència, reintents i cues de missatges fallits
