AlpinaShop té una infraestructura sòlida i absolutament ningú no la pot fer servir. La botiga se serveix per una adreça IP numèrica, sense nom i sense certificat: escriure https://34.120.x.x en un navegador produeix un advertiment vermell de seguretat, i cap client no introdueix les dades de la seva targeta després de veure això. Tota la feina dels sis apartats anteriors del mòdul depèn de la peça que falta: un nom i un certificat.

Aquesta lliçó tanca el mòdul 3 posant en marxa el que el client veu realment. Crearàs la zona DNS pública d'alpinashop.example, apuntaràs el domini a la IP global alpinashop-lb-ip, delegaràs des del registrador i ho verificaràs; aprovisionaràs un certificat gestionat per Google i entendràs per què es queda a PROVISIONING quan alguna cosa falla; enduriràs la connexió amb una política SSL; afegiràs les capçaleres de seguretat que ha d'emetre l'aplicació Flask; i verificaràs el resultat d'extrem a extrem amb curl i openssl. Acabarem amb una llista de comprovació que recorre tot el que s'ha construït al mòdul, de la VPC al certificat.

Avís. La configuració de TLS i de capçaleres de seguretat té efectes permanents difícils de revertir —HSTS és l'exemple canònic— i implicacions de compliment normatiu si es processen pagaments. Abans d'aplicar aquesta configuració a un domini real de producció, revisa-la amb un professional de seguretat. I una nota pràctica: alpinashop.example fa servir el domini .example, reservat per a documentació; en un cas real treballaries amb un domini registrat de veritat.

Contingut

  1. Repàs funcional del DNS: el just per operar
  2. Cloud DNS: zones gestionades
  3. La zona pública d'AlpinaShop, registre a registre
  4. Delegació des del registrador i verificació amb dig
  5. Zones privades per a resolució interna
  6. DNSSEC: què protegeix i què no
  7. Certificats gestionats per Google
  8. Per què un certificat es queda a PROVISIONING
  9. Certificate Manager: molts dominis i comodins
  10. Certificats propis i quan tenen sentit
  11. Polítiques SSL: versió mínima i conjunts de xifratge
  12. Capçaleres de seguretat que emet l'aplicació
  13. Verificació d'extrem a extrem
  14. Llista de comprovació de publicació segura del mòdul 3

  1. Repàs funcional del DNS: el just per operar

El DNS tradueix noms a adreces. El seu model és un arbre invertit en què cada nivell delega en el següent: l'arrel delega en .example, que delega en alpinashop.example, els servidors autoritatius del qual responen per tot el que hi ha a sota.

Aquest és el recorregut complet del que passa quan un client escriu el domini al navegador, i convé tenir-lo al davant perquè hi apareixen totes les peces de la lliçó:

sequenceDiagram
    participant N as Navegador
    participant R as Resolutor (8.8.8.8)
    participant RT as Servidors arrel
    participant TLD as Servidors de .example
    participant CD as Cloud DNS<br/>alpinashop-publica
    participant LB as Balancejador<br/>alpinashop-lb-ip

    N->>R: A d'alpinashop.example?
    R->>RT: qui sap de .example?
    RT-->>R: els servidors de .example
    R->>TLD: qui sap d'alpinashop.example?
    TLD-->>R: NS → ns-cloud-b1.googledomains.com (delegació)
    R->>CD: A d'alpinashop.example?
    CD-->>R: 34.120.10.5 (+ signatura DNSSEC)
    R-->>N: 34.120.10.5, desada durant el TTL
    N->>LB: TLS ClientHello (SNI: alpinashop.example)
    LB-->>N: certificat alpinashop-cert + política SSL
    N->>LB: GET / sobre HTTPS
    LB-->>N: 200 + HSTS, CSP, X-Content-Type-Options

Fixa't en dos punts que es corresponen amb dos apartats d'aquesta lliçó: la delegació que retornen els servidors de .example (apartat 4) i el SNI que envia el navegador, que és el que permet que un mateix balancejador serveixi diversos dominis amb diversos certificats (apartats 7 i 9).

Els tipus de registre que necessites conèixer:

Tipus Per a què Exemple
A Nom → adreça IPv4 alpinashop.example → 34.120.10.5
AAAA Nom → adreça IPv6 alpinashop.example → 2600:1901::…
CNAME Àlies d'un altre nom www → alpinashop.example
MX Servidors de correu, amb prioritat 10 aspmx.l.google.com.
TXT Text lliure: verificació de domini, SPF, DKIM, DMARC "v=spf1 include:_spf.google.com ~all"
NS Delegació: qui mana en aquesta zona Els quatre servidors de Cloud DNS
CAA Quines autoritats poden emetre certificats del domini 0 issue "pki.goog"
SOA Metadades de la zona Es genera sol

Tres regles que causen la majoria dels problemes i que convé tenir presents:

  1. No hi pot haver un CNAME al vèrtex de la zona. alpinashop.example no pot ser un CNAME; ha de ser un registre A o AAAA. És una restricció del mateix protocol, perquè el vèrtex ja té registres SOA i NS i un CNAME no pot coexistir amb altres registres. Per això vam reservar una IP global estàtica a 03-01: és exactament el que es necessita al vèrtex.
  2. El TTL mana sobre la propagació. Quan un resolutor desa una resposta a la memòria cau, la conserva el temps que indiqui el TTL. Si el TTL és de 24 hores i canvies la IP, hi ha clients que continuaran anant a la vella durant 24 hores. Abans d'una migració, baixa el TTL a 60-300 segons amb dies d'antelació, i torna'l a apujar quan tot estigui estable. És el consell més rendible de tot l'apartat.
  3. Els noms absoluts acaben en punt. alpinashop.example. amb punt final és un nom absolut; sense ell, algunes eines hi afegeixen el domini de cerca local. Cloud DNS és estricte: exigeix el punt.

  1. Cloud DNS: zones gestionades

Cloud DNS és el servei de DNS autoritatiu de Google, amb anycast global, latència molt baixa i un acord de nivell de servei del 100 % de disponibilitat. Les seves unitats són les zones gestionades:

Tipus Visible des de Ús a AlpinaShop
Pública Tot internet alpinashop.example: la botiga
Privada Només les VPC que autoritzis interna.alpinashop.example: serveis interns
De reenviament Delega consultes a servidors propis Connectivitat híbrida (07-03)
Peering Comparteix resolució entre VPC VPC compartida (07-03)

Compte amb la distinció entre registrar un domini i allotjar-ne el DNS: són coses diferents. El registrador és on compres el domini (Cloud Domains, o qualsevol altre); Cloud DNS és on s'allotgen els seus registres. Pots tenir el domini en un registrador i el DNS a Google sense problema, i de fet és el cas més habitual.

  1. La zona pública d'AlpinaShop, registre a registre

gcloud config set project alpinashop-prod
gcloud services enable dns.googleapis.com

gcloud dns managed-zones create alpinashop-publica \
  --dns-name="alpinashop.example." \
  --description="Zona publica de la botiga AlpinaShop" \
  --visibility=public \
  --dnssec-state=on

# Els servidors de noms que cal declarar al registrador
gcloud dns managed-zones describe alpinashop-publica \
  --format="value(nameServers)"

Aquesta última comanda retorna una cosa com ara ns-cloud-b1.googledomains.com. i tres més. Apunta'ls: són la peça que va al registrador.

Ara els registres. Recorda la IP global reservada a 03-01:

IP_LB=$(gcloud compute addresses describe alpinashop-lb-ip --global --format="value(address)")
echo "$IP_LB"

# Vertex de la zona: registre A obligatori (no pot ser CNAME)
gcloud dns record-sets create alpinashop.example. \
  --zone=alpinashop-publica --type=A --ttl=300 --rrdatas="$IP_LB"

# www: CNAME al vertex. Un sol lloc per canviar si canvia la IP.
gcloud dns record-sets create www.alpinashop.example. \
  --zone=alpinashop-publica --type=CNAME --ttl=300 --rrdatas="alpinashop.example."

# imagenes: MATEIXA IP. El mapa d'URL de 03-02 ja encamina per Host i ruta.
gcloud dns record-sets create imagenes.alpinashop.example. \
  --zone=alpinashop-publica --type=A --ttl=3600 --rrdatas="$IP_LB"

# Correu corporatiu
gcloud dns record-sets create alpinashop.example. \
  --zone=alpinashop-publica --type=MX --ttl=3600 \
  --rrdatas="1 aspmx.l.google.com.,5 alt1.aspmx.l.google.com.,10 alt2.aspmx.l.google.com."

# SPF, perque el correu de la botiga no acabi a la safata de brossa
gcloud dns record-sets create alpinashop.example. \
  --zone=alpinashop-publica --type=TXT --ttl=3600 \
  --rrdatas='"v=spf1 include:_spf.google.com ~all"'

# CAA: nomes Google pot emetre certificats d'aquest domini
gcloud dns record-sets create alpinashop.example. \
  --zone=alpinashop-publica --type=CAA --ttl=3600 \
  --rrdatas='0 issue "pki.goog"'

Decisions de disseny que mereixen explicació:

  • imagenes.alpinashop.example apunta a la mateixa IP. No cal un altre balancejador: el mapa d'URL encamina per Host i per ruta. Un sol balancejador, un sol certificat, un sol punt on aplicar Cloud Armor. Un subdomini no implica infraestructura nova.
  • www és un CNAME al vèrtex, de manera que un canvi de IP es fa en un únic registre.
  • TTL de 300 segons en el que pot canviar (el vèrtex, www) i de 3600 en l'estable (MX, TXT). Abans d'una migració, baixa'l a 60.
  • El registre CAA és un cadenat barat: impedeix que una altra autoritat de certificació emeti un certificat per al teu domini, encara que aconsegueixi enganyar algú. Si més endavant fas servir Let's Encrypt, hauràs d'afegir 0 issue "letsencrypt.org".

Per a diversos canvis atòmics, Cloud DNS ofereix transaccions:

gcloud dns record-sets transaction start --zone=alpinashop-publica
gcloud dns record-sets transaction add "$IP_LB" \
  --name=api.alpinashop.example. --ttl=300 --type=A --zone=alpinashop-publica
gcloud dns record-sets transaction add "$IP_LB" \
  --name=blog.alpinashop.example. --ttl=300 --type=A --zone=alpinashop-publica
gcloud dns record-sets transaction execute --zone=alpinashop-publica

gcloud dns record-sets list --zone=alpinashop-publica \
  --format="table(name, type, ttl, rrdatas.list())"

  1. Delegació des del registrador i verificació amb dig

Crear la zona a Cloud DNS no fa res per si sol. Internet continua preguntant als servidors que digui el registrador. La delegació consisteix a anar al panell del registrador i substituir els servidors de noms pels quatre de Cloud DNS.

I aquí hi ha l'error més freqüent: el canvi de servidors de noms triga. La delegació al nivell superior té el seu propi TTL, típicament de 24 a 48 hores. Durant aquest temps, uns resolutors del món veuran la configuració nova i altres la vella, amb la qual cosa la botiga funcionarà "de vegades". Això no és una fallada: és com funciona el DNS.

Verificació, en aquest ordre:

# 1) Quins servidors diu el nivell superior que son autoritatius?
dig NS alpinashop.example +short

# 2) Preguntar DIRECTAMENT a Cloud DNS: descarta la propagacio de l'equacio
dig @ns-cloud-b1.googledomains.com A alpinashop.example +short

# 3) El que veu un resolutor public qualsevol
dig @8.8.8.8 A alpinashop.example +short
dig @1.1.1.1 A alpinashop.example +short

# 4) La cadena completa, des de l'arrel
dig +trace alpinashop.example

# 5) El CNAME de www
dig CNAME www.alpinashop.example +short

La lectura d'aquestes comandes és el que converteix una hora de frustració en un diagnòstic d'un minut:

  • Si (2) funciona i (3) no, la configuració és correcta i només falta propagació. Espera.
  • Si (2) no funciona, el registre està malament a Cloud DNS. Revisa'l tu.
  • Si (1) retorna els servidors antics, la delegació no s'ha fet o encara no ha propagat.

  1. Zones privades per a resolució interna

Dins d'alpinashop-vpc, Google ja resol automàticament els noms interns de les VM. Però és molt millor que l'aplicació es connecti a pedidos.interna.alpinashop.example que a 10.10.1.5: el dia que la IP canviï —una rèplica que es promou, una migració— no cal tocar el codi.

gcloud dns managed-zones create alpinashop-interna \
  --dns-name="interna.alpinashop.example." \
  --description="Resolucio interna d'AlpinaShop" \
  --visibility=private \
  --networks=alpinashop-vpc

IP_SQL=$(gcloud sql instances describe alpinashop-pedidos \
  --format="value(ipAddresses[0].ipAddress)")

gcloud dns record-sets create pedidos.interna.alpinashop.example. \
  --zone=alpinashop-interna --type=A --ttl=60 --rrdatas="$IP_SQL"

gcloud dns record-sets create cache.interna.alpinashop.example. \
  --zone=alpinashop-interna --type=A --ttl=60 --rrdatas="10.10.1.20"

Propietats de les zones privades:

  • Només resolen des de les VPC autoritzades. Des d'internet, pedidos.interna.alpinashop.example no existeix. No filtres res sobre la teva topologia interna.
  • TTL baix (60 s) a propòsit: són noms pensats precisament per canviar sense drama.
  • La mateixa zona es pot definir en diverses VPC. Compartir-la entre projectes entra al terreny de VPC compartida i peering, que es tracta a 07-03.

  1. DNSSEC: què protegeix i què no

DNSSEC signa criptogràficament les respostes DNS, de manera que un resolutor pot verificar que la resposta és autèntica i no l'ha fabricada un atacant. Protegeix de l'enverinament de memòria cau DNS: que algú aconsegueixi que el teu resolutor cregui que alpinashop.example és a la IP de l'atacant.

# Ja el vam activar en crear la zona; si no, s'actualitza
gcloud dns managed-zones update alpinashop-publica --dnssec-state=on

# Obtenir el registre DS que cal declarar AL REGISTRADOR
gcloud dns dns-keys list --zone=alpinashop-publica \
  --format="table(keyTag, type, algorithm, digests[0].digest)"

# Verificar que la cadena de confianca esta completa
dig +dnssec alpinashop.example | grep -E "RRSIG|ad;"

El pas que gairebé tothom oblida és el segon: activar DNSSEC a Cloud DNS no n'hi ha prou. Cal portar el registre DS al registrador perquè el nivell superior signi la delegació. Sense aquest pas, has signat la teva zona però ningú no pot verificar la signatura, i no serveix de res.

Què no protegeix DNSSEC, per no confondre capes:

  • No xifra res: les consultes DNS continuen sent visibles. Això ho resolen DoH i DoT, que són cosa del client.
  • No protegeix el contingut del web: això és TLS.
  • No impedeix que algú registri alpinashop-tienda.example per fer pesca de credencials.

I un advertiment operatiu seriós: DNSSEC mal configurat deixa el domini invisible, no simplement insegur. Si el registre DS del registrador no concorda amb les claus de la zona, els resolutors validadors rebutgen la resposta i el teu domini desapareix per a una part d'internet. Canvia'l amb cura i verifica sempre després.

  1. Certificats gestionats per Google

Un certificat TLS acredita que el servidor que respon per alpinashop.example és realment qui diu ser, i permet xifrar la connexió. Google els emet i els renova gratis i automàticament.

gcloud compute ssl-certificates create alpinashop-cert \
  --domains="alpinashop.example,www.alpinashop.example,imagenes.alpinashop.example" \
  --global

# Associar-lo al proxy HTTPS creat a 03-02
gcloud compute target-https-proxies update alpinashop-https-proxy \
  --ssl-certificates=alpinashop-cert --global

# Seguir l'aprovisionament
gcloud compute ssl-certificates describe alpinashop-cert --global \
  --format="yaml(name, managed.status, managed.domainStatus)"

El camp managed.domainStatus dona l'estat per domini, que és el que necessites per depurar:

Estat Significat Què fer
PROVISIONING En curs Esperar, fins a uns 60 minuts en el cas normal
FAILED_NOT_VISIBLE El domini no resol a la IP del balancejador El cas habitual. Revisar el registre A
FAILED_CAA_CHECKING Hi ha un registre CAA que no permet a Google emetre Afegir 0 issue "pki.goog"
FAILED_RATE_LIMITED Massa intents Esperar; no esborrar i recrear en bucle
ACTIVE Llest Res

Com valida Google el domini, que és la clau per entendre les fallades: comprova que el nom resol a la IP del balancejador on està associat el certificat. És a dir, l'ordre correcte és DNS primer, certificat després. Si crees el certificat abans que el registre A propagui, es quedarà esperant.

Avantatges i límits dels certificats gestionats:

Avantatges Límits
Gratis Fins a 100 dominis per certificat
Renovació automàtica, sense ensurts No admet comodins (*.alpinashop.example)
Sense fitxers de clau privada per custodiar Requereix que el domini ja apunti al balancejador
Se n'associen diversos a un mateix proxy Només per a balancejadors de Google

  1. Per què un certificat es queda a PROVISIONING

Mereix un apartat propi perquè és, amb diferència, el problema més freqüent en publicar a Google Cloud. La llista de causes, ordenada per probabilitat:

  1. El registre A no existeix o apunta a una altra IP. L'error més comú amb molta diferència.
  2. El DNS encara no ha propagat. Correcte però recent; cal esperar.
  3. El balancejador no té regla de reenviament al 443. Google valida a través del mateix balancejador; si el 443 no està publicat, no pot.
  4. Un registre CAA bloqueja Google. Si tenies un CAA d'una altra autoritat, cal afegir pki.goog.
  5. El certificat no està associat al proxy HTTPS. Sense associació, la validació no es dispara.
  6. S'ha esborrat i recreat moltes vegades, activant un límit de taxa. La paciència és la solució.

Diagnòstic en l'ordre correcte:

# 1) A on resol realment el domini?
dig A alpinashop.example +short

# 2) Quina es la IP del balancejador?
gcloud compute addresses describe alpinashop-lb-ip --global --format="value(address)"
#    Els dos valors HAN de coincidir.

# 3) Esta el 443 publicat?
gcloud compute forwarding-rules list --global \
  --format="table(name, IPAddress, portRange, target)"

# 4) Esta el certificat associat al proxy?
gcloud compute target-https-proxies describe alpinashop-https-proxy --global \
  --format="value(sslCertificates)"

# 5) Hi ha un CAA que fa nosa?
dig CAA alpinashop.example +short

I el consell que estalvia mig dia: quan canviïs el DNS per arreglar-ho, no esborris el certificat. Google reintenta la validació periòdicament pel seu compte. Esborrar i recrear reinicia el rellotge i acosta el límit de taxa.

  1. Certificate Manager: molts dominis i comodins

Quan els certificats clàssics es queden curts —comodins, centenars de dominis, desplegament en diverses regions— l'eina és Certificate Manager. El seu mecanisme de validació és diferent: no requereix que el domini apunti ja al balancejador, sinó que valida mitjançant un registre DNS d'autorització. Això permet emetre el certificat abans de migrar el trànsit, cosa que és exactament el que vols en una migració real.

gcloud services enable certificatemanager.googleapis.com

# 1) Autoritzacio DNS: genera un registre CNAME que cal crear
gcloud certificate-manager dns-authorizations create auth-alpinashop \
  --domain="alpinashop.example"

gcloud certificate-manager dns-authorizations describe auth-alpinashop \
  --format="value(dnsResourceRecord.name, dnsResourceRecord.data)"

# 2) Crear aquest CNAME a la zona
gcloud dns record-sets create "_acme-challenge.alpinashop.example." \
  --zone=alpinashop-publica --type=CNAME --ttl=300 \
  --rrdatas="<valor retornat per la comanda anterior>"

# 3) Certificat amb COMODI: cobreix qualsevol subdomini
gcloud certificate-manager certificates create cert-alpinashop-comodin \
  --domains="alpinashop.example,*.alpinashop.example" \
  --dns-authorizations=auth-alpinashop

# 4) Mapa de certificats i la seva entrada
gcloud certificate-manager maps create mapa-alpinashop

gcloud certificate-manager maps entries create entrada-principal \
  --map=mapa-alpinashop \
  --certificates=cert-alpinashop-comodin \
  --hostname="alpinashop.example"

gcloud certificate-manager maps entries create entrada-comodin \
  --map=mapa-alpinashop \
  --certificates=cert-alpinashop-comodin \
  --hostname="*.alpinashop.example"

# 5) Associar el mapa al proxy (substitueix --ssl-certificates)
gcloud compute target-https-proxies update alpinashop-https-proxy \
  --certificate-map=mapa-alpinashop --global
Certificat clàssic gestionat Certificate Manager
Comodins No
Validació El domini ha d'apuntar ja al balancejador Registre DNS d'autorització, abans de migrar
Escala Fins a 100 dominis Milers
Complexitat Una comanda Autorització + certificat + mapa + entrada
Recomanació AlpinaShop avui Quan calgui un comodí o una migració sense tall

Per a AlpinaShop, el certificat clàssic amb tres noms és suficient. Si demà cada marca associada tingués el seu subdomini, el comodí de Certificate Manager seria la resposta.

  1. Certificats propis i quan tenen sentit

També pots pujar un certificat emès per una altra autoritat:

gcloud compute ssl-certificates create alpinashop-cert-propio \
  --certificate=cadena-completa.pem \
  --private-key=clave-privada.pem \
  --global

Casos legítims: certificats de validació estesa (EV), certificats emesos per l'autoritat corporativa, o requisits contractuals concrets. A canvi assumeixes tres coses: custodiar la clau privada (Secret Manager, 03-06), renovar abans que caduqui —l'incident clàssic de les 3 de la matinada— i avisar abans del venciment. Si no hi ha un motiu específic, el certificat gestionat és millor decisió, precisament perquè elimina aquestes tres responsabilitats.

  1. Polítiques SSL: versió mínima i conjunts de xifratge

Per defecte, el balancejador accepta versions antigues de TLS per no deixar ningú fora. Per a una botiga que processa pagaments, això no és acceptable: PCI DSS exigeix TLS 1.2 com a mínim.

gcloud compute ssl-policies create pol-ssl-alpinashop \
  --profile=MODERN \
  --min-tls-version=1.2 \
  --description="TLS 1.2 minim, perfil modern"

gcloud compute target-https-proxies update alpinashop-https-proxy \
  --ssl-policy=pol-ssl-alpinashop --global

Els perfils disponibles:

Perfil Conjunts de xifratge Compatibilitat Quan
COMPATIBLE Tots, inclosos els antics Màxima Només si tens clients molt vells
MODERN Els recomanats actualment Molt bona L'elecció d'AlpinaShop
RESTRICTED Només els exigits per normatives estrictes Menor Requisits de compliment normatiu explícits
CUSTOM Els que enumeris tu La que decideixis Casos molt concrets
# Veure quins conjunts habilita cada perfil abans de decidir
gcloud compute ssl-policies list-available-features

Com decidir sense trencar res: MODERN amb TLS 1.2 mínim deixa fora navegadors realment antics (Internet Explorer en Windows anterior a 7, Android 4.x). Per a una botiga de material de muntanya el 2026, aquest trànsit és residual i probablement ni tan sols humà. Si et preocupa, mesura abans: el registre del balancejador enregistra la versió de TLS negociada, així que pots saber exactament a quants clients reals afectaria.

Dos ajustos més del proxy, ja que hi som:

# HTTP/3 (QUIC): menys latencia d'establiment, sobretot en mobil
gcloud compute target-https-proxies update alpinashop-https-proxy \
  --quic-override=ENABLE --global

I recorda que la redirecció d'HTTP a HTTPS ja està feta a 03-02, amb un mapa d'URL a part al port 80 que retorna un 301 permanent. Sense aquesta redirecció, la capçalera HSTS de l'apartat següent no arribaria mai als clients que escriuen el domini sense protocol.

  1. Capçaleres de seguretat que emet l'aplicació

El balancejador xifra la connexió, però hi ha proteccions que només pot activar l'aplicació, perquè són instruccions per al navegador.

# seguridad.py — capceleres de seguretat d'AlpinaShop
from flask import request

CSP = "; ".join([
    "default-src 'self'",
    "img-src 'self' https://imagenes.alpinashop.example data:",
    "script-src 'self' https://www.google.com/recaptcha/",
    "style-src 'self' 'unsafe-inline'",
    "frame-ancestors 'none'",          # equival a X-Frame-Options: DENY
    "form-action 'self'",
    "base-uri 'self'",
    "upgrade-insecure-requests",
])


def registrar_capceleres_seguretat(app):
    @app.after_request
    def capceleres(resposta):
        # HSTS: obliga el navegador a fer servir HTTPS durant un any.
        # 'preload' sol·licita la inclusio a la llista precarregada dels
        # navegadors. COMPTE: es practicament irreversible.
        resposta.headers["Strict-Transport-Security"] = \
            "max-age=31536000; includeSubDomains"

        # Impedeix que el navegador "endevini" el tipus de contingut,
        # cosa que evita que un .txt pujat per un usuari s'executi com a script.
        resposta.headers["X-Content-Type-Options"] = "nosniff"

        # No filtrar la URL completa (que pot portar un SKU o un id de comanda)
        # a dominis externs.
        resposta.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"

        # Denegar d'entrada APIs del navegador que la botiga no fa servir.
        resposta.headers["Permissions-Policy"] = \
            "geolocation=(), microphone=(), camera=(), payment=(self)"

        # Politica de seguretat de contingut: la defensa mes forta davant d'XSS.
        # Es desplega PRIMER en mode nomes-informe durant setmanes.
        if request.path.startswith("/admin"):
            resposta.headers["Content-Security-Policy"] = CSP
        else:
            resposta.headers["Content-Security-Policy-Report-Only"] = CSP

        return resposta
Capçalera Què evita Parany
Strict-Transport-Security Degradació a HTTP i atacs d'intermediari Gairebé irreversible: durant max-age, els navegadors es neguen a fer servir HTTP al teu domini
Content-Security-Policy XSS, injecció d'scripts de tercers Trenca el lloc si es desplega sense mesurar. Fes servir Report-Only primer
X-Content-Type-Options Execució de contingut pujat per usuaris Cap. Posa-la sempre
Referrer-Policy Fuita d'URL internes a tercers Cap
Permissions-Policy Ús d'APIs del navegador per scripts de tercers Enumera només el que facis servir

HSTS mereix un paràgraf a part. Comença amb max-age=300 durant uns dies, apuja'l a un dia, després a un any, i només aleshores considera preload. La raó: un cop que un navegador ha vist la capçalera, es negarà a connectar per HTTP al teu domini durant tot el max-age, encara que tu ho vulguis. I preload va encara més lluny: incorpora el teu domini a una llista compilada dins dels mateixos navegadors, de la qual sortir triga mesos. Si actives includeSubDomains i després resulta que un subdomini intern no té certificat, aquest subdomini deixa de ser accessible.

De la mateixa manera, CSP es desplega en Content-Security-Policy-Report-Only primer, es recullen els informes de violació durant setmanes i s'ajusta la política fins que no quedin falsos positius. És exactament la mateixa disciplina que el mode de vista prèvia de Cloud Armor a 03-05: mesurar abans d'aplicar.

  1. Verificació d'extrem a extrem

# 1) Handshake complet, cadena de certificats i versio de TLS
curl -vI https://alpinashop.example/ 2>&1 | \
  grep -E "SSL connection|subject:|issuer:|expire|HTTP/"

# 2) Detall del certificat: noms coberts i dates
echo | openssl s_client -connect alpinashop.example:443 \
  -servername alpinashop.example 2>/dev/null | \
  openssl x509 -noout -subject -issuer -dates -ext subjectAltName

# 3) Es rebutgen de veritat les versions antigues de TLS?
openssl s_client -connect alpinashop.example:443 -tls1_1 2>&1 | grep -i "alert\|failure"
#    Ha de FALLAR. Si connecta, la politica SSL no esta aplicada.

# 4) Redirigeix HTTP a HTTPS?
curl -sI http://alpinashop.example/ | grep -E "HTTP/|location"

# 5) Hi son les capceleres de seguretat?
curl -sI https://alpinashop.example/ | \
  grep -iE "strict-transport|content-security|x-content-type|referrer-policy"

# 6) El subdomini d'imatges va al bucket i amb memoria cau? (03-03)
curl -sI https://imagenes.alpinashop.example/productos/MOCH-2210/web/frontal-800.a3f9c1.webp | \
  grep -iE "HTTP/|age:|cache-control|via:"

# 7) Bloqueja Cloud Armor el que ha de bloquejar? (03-05, des de fora de l'oficina)
curl -s -o /dev/null -w "%{http_code}\n" \
  "https://alpinashop.example/buscar?q=%27%20OR%201%3D1--"

Què ha de sortir de cadascun:

Comprovació Resultat esperat
1 TLSv1.3, emissor Google Trust Services, HTTP/2 200
2 subjectAltName amb els tres noms; caducitat a mesos vista
3 Fallada de connexió. Si connecta, revisa la política SSL
4 301 amb location: https://alpinashop.example/
5 Les quatre capçaleres presents
6 200, age més gran que zero a la segona petició, via: 1.1 google
7 403

Eines externes complementàries, útils per a l'informe a direcció: SSL Labs per a una nota global de la configuració TLS, i Security Headers per a les capçaleres. Cap no substitueix comprovar-ho tu, però produeixen un document presentable.

  1. Llista de comprovació de publicació segura del mòdul 3

Aquest és el resum operatiu de tot el que s'ha construït. Fes-lo servir abans de cada publicació d'un servei nou.

Xarxa (03-01)

  • [ ] VPC en mode personalitzat, amb subxarxes planificades i sense encavalcaments de CIDR.
  • [ ] Cap VM amb IP pública tret de justificació explícita; sortida per Cloud NAT.
  • [ ] SSH només des del rang d'IAP 35.235.240.0/20; mai 0.0.0.0/0 al 22.
  • [ ] Regla que permet 130.211.0.0/22 i 35.191.0.0/16 cap al port de l'aplicació.
  • [ ] Denegació explícita al final, amb registre activat.
  • [ ] Cloud SQL en IP privada, mitjançant accés privat a serveis.
  • [ ] Accés privat de Google activat a les subxarxes sense sortida a internet.

Balanceig (03-02)

  • [ ] IP global estàtica reservada.
  • [ ] Comprovació d'estat superficial, que no consulta la base de dades.
  • [ ] Port amb nom declarat al grup d'instàncies.
  • [ ] Drenatge de connexions configurat.
  • [ ] max-rate-per-instance mesurat amb una prova de càrrega, no triat a ull.
  • [ ] Registre del balancejador activat.
  • [ ] Redirecció d'HTTP a HTTPS.

Memòria cau (03-03)

  • [ ] CDN activat al backend de bucket i al servei de backend.
  • [ ] Mode de memòria cau adequat; mai FORCE_CACHE_ALL sobre contingut d'usuari.
  • [ ] Paràmetres utm_*, gclid i fbclid exclosos de la clau de memòria cau.
  • [ ] Noms d'objecte immutables amb TTL llarg; HTML amb TTL curt.
  • [ ] Memòria cau negativa amb els 5xx a 0.
  • [ ] serve-while-stale activat.

Identitat (03-04)

  • [ ] Cap rol bàsic (Owner, Editor) en producció.
  • [ ] Permisos concedits a grups, no a persones.
  • [ ] Un compte de servei per càrrega de treball; mai el de Compute per defecte.
  • [ ] Zero claus JSON descarregades.
  • [ ] Accessos excepcionals amb condició de caducitat.
  • [ ] IAP amb tunnelResourceAccessor per a SSH i httpsResourceAccessor per a l'intern.

WAF (03-05)

  • [ ] Política de seguretat adjunta al servei de backend.
  • [ ] Exempció de la IP de l'oficina a la prioritat més baixa.
  • [ ] Regles OWASP amb sensibilitat 1, després d'almenys una setmana en vista prèvia.
  • [ ] Limitació de taxa al formulari d'accés i al cercador.
  • [ ] Registre VERBOSE i alerta sobre el volum de peticions denegades.

Secrets i xifratge (03-06)

  • [ ] Cap secret a metadades, a Git, a imatges de contenidor ni a registres.
  • [ ] Secrets a Secret Manager, amb permís a nivell de secret.
  • [ ] Procediment de rotació escrit; deshabilitar abans de destruir.
  • [ ] CMEK on ho exigeixi el compliment normatiu, amb permís a l'agent de servei.

DNS i TLS (03-07)

  • [ ] Zona pública a Cloud DNS, amb delegació verificada amb dig.
  • [ ] Registre A del vèrtex apuntant a la IP del balancejador.
  • [ ] DNSSEC activat i registre DS declarat al registrador.
  • [ ] Registre CAA restringint qui pot emetre certificats.
  • [ ] Certificat gestionat en estat ACTIVE, associat al proxy HTTPS.
  • [ ] Política SSL amb TLS 1.2 mínim i perfil MODERN.
  • [ ] HSTS, CSP, X-Content-Type-Options i Referrer-Policy a les respostes.
  • [ ] Verificació d'extrem a extrem amb curl i openssl superada.

Aquesta llista és un punt de partida sòlid, no un certificat de conformitat. Abans de publicar un servei que tracti dades personals o pagaments, la revisió final la fa un professional de seguretat i compliment normatiu. Les millors pràctiques de seguretat es reprenen de forma transversal a 07-04 i el govern a escala a 07-07.

Errors habituals i consells

  • Intentar un CNAME al vèrtex de la zona. El protocol no ho permet. Registre A a la IP global estàtica.
  • No baixar el TTL abans d'una migració. Amb TTL de 24 hores, el canvi triga un dia a veure's. Baixa'l a 60 amb antelació.
  • Oblidar el punt final als noms de Cloud DNS.
  • Crear el certificat abans que el registre DNS. Es queda a PROVISIONING. Primer el DNS, després el certificat.
  • Esborrar i recrear el certificat per impaciència. Reinicia el rellotge i acosta el límit de taxa. Google reintenta sol.
  • Activar DNSSEC sense declarar el registre DS al registrador. No serveix de res; i si el DS no concorda, el domini desapareix.
  • Posar un CAA sense incloure pki.goog. El certificat gestionat no s'emetrà mai.
  • Esperar un comodí d'un certificat gestionat clàssic. No els admet: això és Certificate Manager.
  • Activar HSTS amb preload des del primer dia. És pràcticament irreversible. Apuja el max-age per fases.
  • Desplegar CSP sense Report-Only. Trenca el lloc. Mateixa disciplina que el mode de vista prèvia de Cloud Armor.
  • Provar només des del navegador. Desa DNS i certificats a la memòria cau de forma agressiva. Fes servir dig i openssl s_client.
  • Pujar un certificat propi i oblidar la renovació. És l'incident clàssic de matinada. Si no hi ha un motiu real, fes servir el gestionat.
  • Consell: fes servir un subdomini de proves (pre.alpinashop.example) apuntant a un balancejador de preproducció. Assajar la publicació completa allà costa poc i evita sorpreses.
  • Consell: alerta de caducitat de certificat a Cloud Monitoring (06-04), encara que siguin gestionats. Una renovació pot fallar si el DNS ha canviat.
  • Consell: gestiona la zona DNS com a codi amb Terraform (06-07). Un registre afegit a mà i no documentat és un misteri garantit.

Exercicis

Exercici 1 — Publicar un subdomini nou d'extrem a extrem

AlpinaShop llança un blog a blog.alpinashop.example, servit per un servei de backend nou bs-blog que ja existeix. Escriu tots els passos necessaris, en ordre, des del DNS fins a la verificació, incloent-hi què cal tocar de les lliçons anteriors del mòdul.

Exercici 2 — Migrar el domini des d'un proveïdor antic

alpinashop.example és avui en un allotjament tradicional, amb el DNS al registrador i TTL de 86 400 segons. Cal migrar-lo a Google Cloud sense que la botiga deixi de funcionar ni un minut i sense que el correu es perdi. Escriu el pla amb la seva cronologia.

Exercici 3 — Diagnosticar una publicació trencada

La Marta ha seguit la lliçó i https://alpinashop.example dona ERR_SSL_PROTOCOL_ERROR al navegador. Recull aquestes dades:

  • dig A alpinashop.example +short34.120.10.5.
  • gcloud compute addresses describe alpinashop-lb-ip --global34.120.10.5.
  • gcloud compute ssl-certificates describe alpinashop-cert --globalmanaged.status: ACTIVE.
  • curl -I http://alpinashop.example/301 correcte cap a HTTPS.
  • gcloud compute forwarding-rules list --global mostra una sola regla, al port 80.

Identifica la causa i escriu les comandes que la corregeixen.


Solucions

Solució 1

# 1) DNS: registre A del subdomini a la MATEIXA IP global
IP_LB=$(gcloud compute addresses describe alpinashop-lb-ip --global --format="value(address)")
gcloud dns record-sets create blog.alpinashop.example. \
  --zone=alpinashop-publica --type=A --ttl=300 --rrdatas="$IP_LB"

# 2) Verificar que resol ABANS de tocar el certificat
dig @8.8.8.8 A blog.alpinashop.example +short

# 3) Certificat NOU que inclogui el subdomini (no s'edita l'existent)
gcloud compute ssl-certificates create alpinashop-cert-v2 \
  --domains="alpinashop.example,www.alpinashop.example,imagenes.alpinashop.example,blog.alpinashop.example" \
  --global

# 4) Associar TOTS DOS al proxy: el vell continua servint mentre el nou s'aprovisiona
gcloud compute target-https-proxies update alpinashop-https-proxy \
  --ssl-certificates=alpinashop-cert,alpinashop-cert-v2 --global

# 5) Esperar a ACTIVE
watch -n 60 'gcloud compute ssl-certificates describe alpinashop-cert-v2 \
  --global --format="value(managed.status)"'

# 6) Mapa d'URL: encaminar el nou Host (03-02)
gcloud compute url-maps add-path-matcher alpinashop-url-map \
  --path-matcher-name=matcher-blog \
  --default-service=bs-blog \
  --new-hosts=blog.alpinashop.example

# 7) Treure el certificat antic quan el nou estigui actiu
gcloud compute target-https-proxies update alpinashop-https-proxy \
  --ssl-certificates=alpinashop-cert-v2 --global
gcloud compute ssl-certificates delete alpinashop-cert --global --quiet

Què més cal tocar de les lliçons anteriors:

  • 03-05: la regla 2300 rebutja peticions amb un Host que no sigui a la llista. Cal afegir blog.alpinashop.example a aquesta expressió, o el blog retornarà 404 des del WAF i ningú no sabrà per què.
  • 03-03: decidir la política de memòria cau de bs-blog. Un blog és contingut gairebé estàtic: CACHE_ALL_STATIC amb s-maxage de diversos minuts és una gran millora.
  • 03-01: si bs-blog apunta a instàncies noves, necessiten l'etiqueta de xarxa que permet les comprovacions d'estat.
  • 03-04: qui publica al blog necessita permisos, i aquests permisos van a un grup.

El pas clau és el 4: associar tots dos certificats al proxy simultàniament. El balancejador n'admet diversos i tria per SNI, així que el lloc continua funcionant mentre el nou es valida. Substituir directament el certificat deixaria la botiga sense certificat vàlid durant l'aprovisionament.

Solució 2

T-7 dies — Preparar i baixar el TTL.

# Al proveidor ACTUAL: baixar el TTL de tots els registres a 300 s.
# Aquest pas triga fins a 86 400 s a fer efecte: per aixo va una setmana abans.

S'inventarien tots els registres existents: A, MX, TXT (SPF, DKIM, DMARC, verificacions de serveis de tercers), CNAME. Perdre un TXT de verificació trenca serveis de forma silenciosa; perdre els MX perd correu, que és irrecuperable.

T-3 dies — Construir la zona a Cloud DNS.

gcloud dns managed-zones create alpinashop-publica \
  --dns-name="alpinashop.example." --visibility=public
# Replicar TOTS els registres de l'inventari, amb TTL de 300.

# Verificar contra Cloud DNS directament, sense delegar encara
NS=$(gcloud dns managed-zones describe alpinashop-publica --format="value(nameServers[0])")
dig @"$NS" A alpinashop.example +short
dig @"$NS" MX alpinashop.example +short
dig @"$NS" TXT alpinashop.example +short

En aquest punt la zona nova és una còpia fidel, però encara no la fa servir ningú. El registre A continua apuntant a l'allotjament antic: això és deliberat.

T-1 dia — Certificat per endavant. Amb Certificate Manager i autorització DNS es pot emetre el certificat abans que el domini apunti a Google. És exactament l'escenari per al qual existeix aquesta validació, i evita la finestra en què el domini ja apunta al balancejador però encara no hi ha certificat.

T-0 — Delegar. Canviar els servidors de noms al registrador pels de Cloud DNS. Durant 24-48 hores conviuran les dues configuracions; com que són idèntiques tret del que es canviï després, l'usuari no nota res. Mantenir l'allotjament antic encès tot aquest temps.

T+2 dies — Canviar la destinació. Amb la delegació ja propagada i el TTL a 300 segons, s'actualitza el registre A a la IP del balancejador. El canvi real de trànsit passa ara, amb una finestra de cinc minuts i amb possibilitat de desfer-ho en cinc minuts.

gcloud dns record-sets update alpinashop.example. \
  --zone=alpinashop-publica --type=A --ttl=300 --rrdatas="$IP_LB"

T+3 dies — Estabilitzar. Verificar que no queda trànsit arribant a l'allotjament antic (els seus registres ho diuen), apujar els TTL a valors normals, activar DNSSEC amb el seu registre DS, i només aleshores donar de baixa l'allotjament.

La idea que cal retenir: se separa el canvi de qui resol (T-0) del canvi de cap a on apunta (T+2). Si es fan alhora i alguna cosa falla, no se sap quin dels dos ho ha causat i desfer-ho triga 48 hores.

Solució 3

La causa és a l'última dada: només hi ha una regla de reenviament, al port 80. Falta la regla del 443. El certificat està ACTIVE (Google va validar per HTTP), el DNS és correcte i la redirecció funciona —d'aquí el 301—, però quan el navegador segueix aquesta redirecció a https://, no hi ha res escoltant al 443. L'error ERR_SSL_PROTOCOL_ERROR és exactament això: no hi ha diàleg TLS a l'altre costat.

# 1) Confirmar que el proxy HTTPS existeix
gcloud compute target-https-proxies list --global \
  --format="table(name, urlMap, sslCertificates.list())"

# 2) Crear la regla de reenviament que falta
gcloud compute forwarding-rules create alpinashop-fr-https \
  --global \
  --address=alpinashop-lb-ip \
  --target-https-proxy=alpinashop-https-proxy \
  --ports=443 \
  --load-balancing-scheme=EXTERNAL_MANAGED

# 3) Esperar 5-10 minuts a la propagacio i verificar
curl -vI https://alpinashop.example/ 2>&1 | grep -E "SSL connection|HTTP/"

Si el pas 1 revelés que tampoc no existeix el proxy HTTPS, caldria crear-lo abans:

gcloud compute target-https-proxies create alpinashop-https-proxy \
  --url-map=alpinashop-url-map \
  --ssl-certificates=alpinashop-cert \
  --ssl-policy=pol-ssl-alpinashop \
  --global

La lliçó de diagnòstic: un certificat en ACTIVE demostra que Google va poder validar el domini, no que el lloc serveixi HTTPS. Són dues coses diferents i és fàcil confondre-les. Davant d'una fallada de publicació, recorre la cadena completa de 03-02 de fora cap a dins: regla de reenviament → proxy → certificat → mapa d'URL → servei de backend → backend → comprovació d'estat. L'anella trencada apareix sempre.

Conclusió

AlpinaShop està publicada. Els clients escriuen alpinashop.example al navegador, veuen el cadenat i compren. Darrere d'aquest gest trivial hi ha set lliçons de feina.

En aquesta última has repassat el DNS amb la profunditat justa per operar-lo: els tipus de registre, la impossibilitat d'un CNAME al vèrtex —que és la raó de ser de la IP global estàtica—, el paper del TTL en qualsevol migració i el costum de baixar-lo amb antelació. Has creat la zona pública alpinashop-publica amb el registre A del vèrtex apuntant a alpinashop-lb-ip, el CNAME de www, el registre d'imagenes a la mateixa IP —perquè un subdomini no implica infraestructura nova quan el mapa d'URL encamina per Host—, els MX, l'SPF i un registre CAA que restringeix qui pot emetre certificats. Has delegat des del registrador i saps diagnosticar amb dig si el problema és teu o és propagació. Has creat la zona privada alpinashop-interna perquè l'aplicació deixi de conèixer adreces IP de memòria, i has activat DNSSEC sense oblidar el pas que gairebé tothom oblida: el registre DS al registrador.

Has aprovisionat un certificat gestionat per Google i, sobretot, saps per què es queda a PROVISIONING i en quin ordre mirar les sis causes possibles, començant per l'única que n'explica la majoria: el registre A. Coneixes els límits dels certificats gestionats i saps que els comodins i les migracions sense tall són territori de Certificate Manager, amb la seva validació per autorització DNS que permet emetre abans de moure el trànsit. Has endurit la connexió amb la política pol-ssl-alpinashop (perfil MODERN, TLS 1.2 mínim) i has afegit les capçaleres que només pot emetre l'aplicació —HSTS, CSP, X-Content-Type-Options, Referrer-Policy, Permissions-Policy—, amb la mateixa disciplina que ja vas aplicar al WAF: Report-Only primer, mesurar, i només després aplicar. I has verificat el resultat d'extrem a extrem amb curl i openssl s_client, comprovant no només que HTTPS funciona, sinó que TLS 1.1 falla, que el subdomini d'imatges retorna Age i que Cloud Armor continua bloquejant el que ha de bloquejar.

Amb la llista de comprovació final, el mòdul 3 queda tancat com una unitat: xarxa segmentada sense IP públiques, balancejador global amb comprovacions d'estat sanes, memòria cau a la vora amb la clau ben calculada, permisos mínims per grups i sense claus descarregades, WAF calibrat amb vista prèvia, secrets fora del codi i claus gestionades on cal, i per fi nom i certificat. AlpinaShop és a internet i està protegida.

I ara comença una altra història. Aquesta botiga que funciona genera dades cada segon: comandes que entren a alpinashop-pedidos, visites que queden als registres del balancejador, clics en fitxes de producte, cerques que no troben res, imatges que se serveixen des del CDN, cistelles que s'abandonen a Firestore. Ara mateix, tot això s'acumula sense que ningú ho miri. La Marta sap quantes instàncies hi ha aixecades, però ningú no sap quina motxilla es ven més a Catalunya, ni si la campanya de tardor ha funcionat, ni per què el 30 % de les cistelles es queden a mitges al pas d'enviament. La Lucía, que fins ara només ha aparegut per demanar permisos, passa a ser la protagonista.

Al mòdul 4, Dades i anàlisi, construirem la plataforma que respon a aquestes preguntes. Començarem per 04-01, BigQuery, creant el dataset alpinashop_analitica a alpinashop-datos i carregant-hi l'històric de comandes, per descobrir per què un magatzem analític no és una base de dades més gran, com es paga pel que es consulta i per què una consulta mal escrita pot costar més que una instància sencera. Després arribaran Pub/Sub per capturar els esdeveniments en el moment en què passen, Dataflow per transformar-los, i la resta de les peces fins a arribar a quadres de comandament que la Lucía pugui fer servir sense demanar res a ningú.

Curs de Google Cloud Platform (GCP)

Mòdul 1: Introducció a Google Cloud Platform

Mòdul 2: Serveis principals de GCP

Mòdul 3: Xarxes i seguretat

Mòdul 4: Dades i anàlisi

Mòdul 5: Aprenentatge automàtic i IA

Mòdul 6: DevOps i monitoratge

Mòdul 7: Temes avançats de GCP

Mòdul 8: Projecte final

© Copyright 2026. Tots els drets reservats