CloudTrail va tancar la lliçó anterior amb una limitació concreta i honesta: detecta esdeveniments, no estats. Sap que algú va cridar DeleteBucketEncryption aquest matí. No sap que mercadofresco-registros-web fa cinc mesos que no té xifratge perquè no es va configurar mai. No sap que hi ha un grup de seguretat amb 0.0.0.0/0 al port 22 des d'una prova de març que ningú no va desfer. No pot dir quants recursos del compte incompleixen l'etiquetatge obligatori de MercadoFresco. I, per descomptat, no pot arreglar res.

Aquesta és la cinquena i última pregunta que va deixar oberta el mòdul 4: res no avisa si algú desactiva el xifratge d'un bucket o obre un grup de seguretat al món.

AWS Config és la resposta. La seva idea és diferent de tot el que hem vist en aquest mòdul: en lloc de registrar el que passa, fotografia contínuament com està configurat cada recurs, desa l'historial d'aquestes fotografies i avalua cadascuna contra un conjunt de regles. Quan una configuració es desvia del que hauria de ser, Config ho marca com a no conforme, avisa i —si l'hi permets— ho corregeix sol.

És la diferència entre una càmera de seguretat que grava qui entra i un inventari que, cada nit, comprova que totes les portes estan tancades.

Avís de cost. AWS Config és, juntament amb la ingesta de registres de CloudWatch, el servei d'aquest mòdul que es dispara amb més facilitat. Cobra per cada element de configuració enregistrat i per cada avaluació de regla. Un compte amb un grup d'autoescalat que rota instàncies tot el dia pot generar desenes de milers d'elements al mes. Hi ha una secció sencera amb el càlcul i les cinc maneres de controlar-lo.

Avís de compliment. Aquest material és didàctic. Els paquets de conformitat que s'hi esmenten (CIS, PCI DSS) són ajudes, no certificacions: activar un conformance pack no et fa conforme amb PCI DSS. Qualsevol ús de Config amb finalitat de compliment normatiu real l'ha de validar un professional de compliment.

Contingut

  1. Què és la configuració d'un recurs
  2. L'element de configuració i la línia temporal
  3. Config enfront de CloudTrail
  4. El flux complet: enregistrador, regles i remediació
  5. Activar l'enregistrador de configuració
  6. El canal de lliurament: S3 i SNS
  7. Triar quins tipus de recurs s'enregistren
  8. Regles: el cor del servei
  9. Les regles gestionades que activa MercadoFresco
  10. Activació per canvi enfront d'activació periòdica
  11. L'etiquetatge obligatori amb required-tags
  12. Regles personalitzades amb Lambda
  13. Regles personalitzades amb Guard
  14. Remediació automàtica amb Systems Manager
  15. Els dos casos reals: xifratge de bucket i SG obert
  16. L'advertència de provar primer en mode manual
  17. Paquets de conformitat
  18. El quadre de compliment de MercadoFresco
  19. Consultes avançades per inventariar
  20. Agregadors multicompte
  21. Security Hub i GuardDuty: on encaixa cadascun
  22. Cost real i com no disparar-lo
  23. Neteja

Què és la configuració d'un recurs

La configuració d'un recurs és el conjunt de propietats que el defineixen en un moment donat. No les seves dades, no el seu trànsit: els seus ajustos.

Recurs La seva configuració inclou…
mercadofresco-catalogo-fotos (S3) Xifratge, versionatge, política, bloqueig públic, cicle de vida, etiquetes
sg-mercadofresco-basedatos Regles d'entrada i sortida, VPC, descripció, etiquetes
mercadofresco-pedidos (RDS) Classe, Multi-AZ, xifratge, retenció de còpies, versió del motor, finestra
rol-mercadofresco-tienda (IAM) Polítiques adjuntes, política de confiança, límit de permisos
mercadofresco-tienda-01 (EC2) Tipus, AMI, subxarxa, SG, rol d'instància, volums, etiquetes
alb-mercadofresco-tienda Oients, certificats, esquema, grups de destinació

Config és capaç d'enregistrar la configuració de més de 250 tipus de recurs de desenes de serveis, i de mantenir l'historial complet dels seus canvis.

L'element de configuració i la línia temporal

Un element de configuració (CI, configuration item) és una fotografia completa d'un recurs en un instant concret. Config en crea un cada vegada que detecta un canvi.

{
  "configurationItemVersion": "1.3",
  "configurationItemCaptureTime": "2026-07-28T09:14:33.412Z",
  "configurationItemStatus": "OK",
  "configurationStateId": "1785142473412",
  "awsAccountId": "111122223333",
  "resourceType": "AWS::S3::Bucket",
  "resourceId": "mercadofresco-registros-web",
  "resourceName": "mercadofresco-registros-web",
  "ARN": "arn:aws:s3:::mercadofresco-registros-web",
  "awsRegion": "eu-west-1",
  "resourceCreationTime": "2026-03-02T11:20:01.000Z",

  "tags": {
    "Proyecto": "mercadofresco",
    "Entorno": "produccion",
    "Componente": "registros",
    "Propietario": "marta",
    "CentroCoste": "plataforma"
  },

  "relationships": [
    { "resourceType": "AWS::KMS::Key",
      "resourceId": "8f2c1a9b-4d3e-4f6a-9c1b-2e5d7a8f3c04",
      "relationshipName": "Is encrypted with" }
  ],

  "configuration": {
    "name": "mercadofresco-registros-web",
    "bucketVersioningConfiguration": { "status": "Enabled" },
    "publicAccessBlockConfiguration": {
      "blockPublicAcls": true, "ignorePublicAcls": true,
      "blockPublicPolicy": true, "restrictPublicBuckets": true
    },
    "serverSideEncryptionConfiguration": {
      "rules": [{
        "applyServerSideEncryptionByDefault": {
          "sseAlgorithm": "aws:kms",
          "kmsMasterKeyID": "arn:aws:kms:eu-west-1:111122223333:alias/mercadofresco-datos"
        }
      }]
    }
  },

  "supplementaryConfiguration": {
    "BucketPolicy": { "policyText": "{...}" },
    "IsRequesterPaysEnabled": false
  }
}

Tres camps mereixen una atenció especial:

  • relationships: Config no desa recursos aïllats, desa el graf. Sap que aquest bucket està xifrat amb aquella clau KMS, que aquella instància és en aquella subxarxa, que aquell SG està associat a aquell ALB. Quan vulguis saber què es trenca si esborres una clau, això és el que respon.
  • supplementaryConfiguration: propietats que no arriben a la crida Describe principal i que Config recull a part. La política del bucket, per exemple.
  • configurationItemStatus: OK, ResourceDiscovered, ResourceDeleted. Sí: Config també enregistra l'esborrament, així que pots veure com estava configurat un recurs que ja no existeix.

La línia temporal (configuration timeline) és la seqüència de tots els CI d'un recurs. És la vista més potent de la consola de Config i respon a la pregunta que a operacions es fa cada setmana: «això funcionava divendres; què ha canviat?»

timeline
    title Linia temporal de sg-mercadofresco-basedatos
    2026-03-02 : Creat amb regla 5432 des de sg-mercadofresco-tienda : CONFORME
    2026-05-14 : Afegida regla 22 des de 0.0.0.0-0 : NO CONFORME
    2026-05-14 : Remediacio automatica revoca la regla : CONFORME
    2026-07-09 : Afegida regla 5432 des de sg-mercadofresco-admin : CONFORME

I la consulta:

aws configservice get-resource-config-history \
  --resource-type AWS::EC2::SecurityGroup \
  --resource-id sg-0a1b2c3d4e5f6a7b8 \
  --limit 10 \
  --query 'configurationItems[].[configurationItemCaptureTime,configurationItemStatus]' \
  --output table \
  --profile mercadofresco-dev --region eu-west-1

Config enfront de CloudTrail

Són complementaris i es confonen constantment. La taula:

CloudTrail (05-03) AWS Config
Enregistra La crida a l'API L'estat del recurs
Pregunta Qui ha fet què, quan i des d'on? Com està configurat ara? Compleix?
Unitat Esdeveniment Element de configuració
Veu l'estat previ No Sí: abans i després
Detecta desviacions existents No
Avalua contra regles No
Corregeix No Sí (remediació)
Veu canvis fets fora de l'API No Sí, en l'avaluació periòdica
Cost Gairebé zero Per CI i per avaluació
Primera còpia gratuïta No

L'exemple que ho fixa. Algú afegeix una regla SSH oberta a sg-mercadofresco-basedatos:

  • CloudTrail: un esdeveniment AuthorizeSecurityGroupIngress, amb la identitat, l'hora i la IP de qui ho va fer. No diu com va quedar el grup de seguretat, només què es va demanar.
  • Config: un CI nou amb la configuració completa del grup després del canvi, la comparació amb el CI anterior (el diff), l'avaluació de la regla restricted-ssh marcant-lo com a NON_COMPLIANT, i —si està configurada— la remediació que revoca la regla.

S'usen junts, i de fet Config depèn de CloudTrail: fa servir els seus esdeveniments per saber que alguna cosa ha canviat i disparar l'enregistrament d'un CI nou.

El flux complet: enregistrador, regles i remediació

flowchart TD
    R["Recurs d'AWS<br/>bucket, SG, RDS, rol..."] -->|"canvi"| CT["CloudTrail<br/>detecta la crida"]
    CT --> G["ENREGISTRADOR DE CONFIGURACIO<br/>crea un element de configuracio"]
    G --> H["Historial a S3<br/>mercadofresco-config-historial"]
    G --> E["Motor de REGLES"]
    E -->|"COMPLIANT"| OK["Res a fer"]
    E -->|"NON_COMPLIANT"| N["Marcat com a no conforme"]
    N --> SNS["Notificacio SNS<br/>alertas-mercadofresco"]
    N --> EB["Esdeveniment d'EventBridge<br/>07-03"]
    N --> REM["REMEDIACIO<br/>document de SSM Automation"]
    REM -->|"corregeix"| R
    G --> SH["Security Hub<br/>agregacio de troballes"]

Cinc peces i el seu ordre:

  1. Enregistrador de configuració (configuration recorder): el procés que crea els CI. Només pot haver-hi un per compte i regió.
  2. Canal de lliurament (delivery channel): on es dipositen els CI (un bucket de S3) i on es notifiquen els canvis (un tema d'SNS). També un per compte i regió.
  3. Regles: les condicions que s'avaluen.
  4. Remediació: l'acció correctiva, executada per Systems Manager Automation.
  5. Agregador: la vista consolidada de diversos comptes i regions (09-04).

Activar l'enregistrador de configuració

Pas 1: el bucket de l'historial.

aws s3api create-bucket \
  --bucket mercadofresco-config-historial \
  --region eu-west-1 \
  --create-bucket-configuration LocationConstraint=eu-west-1 \
  --profile mercadofresco-dev

aws s3api put-public-access-block \
  --bucket mercadofresco-config-historial \
  --public-access-block-configuration \
    "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" \
  --profile mercadofresco-dev

aws s3api put-bucket-encryption \
  --bucket mercadofresco-config-historial \
  --server-side-encryption-configuration '{
    "Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"},
              "BucketKeyEnabled":true}]}' \
  --profile mercadofresco-dev

Amb la seva política:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ConfigComprobarAcl",
      "Effect": "Allow",
      "Principal": { "Service": "config.amazonaws.com" },
      "Action": ["s3:GetBucketAcl", "s3:ListBucket"],
      "Resource": "arn:aws:s3:::mercadofresco-config-historial",
      "Condition": {
        "StringEquals": { "AWS:SourceAccount": "111122223333" }
      }
    },
    {
      "Sid": "ConfigEscribir",
      "Effect": "Allow",
      "Principal": { "Service": "config.amazonaws.com" },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::mercadofresco-config-historial/AWSLogs/111122223333/Config/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control",
          "AWS:SourceAccount": "111122223333"
        }
      }
    }
  ]
}

Pas 2: el rol de servei. Config necessita permís per llegir la configuració de tot:

aws iam create-role \
  --role-name rol-aws-config-mercadofresco \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": { "Service": "config.amazonaws.com" },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": { "AWS:SourceAccount": "111122223333" }
      }
    }]
  }' \
  --profile mercadofresco-dev

aws iam attach-role-policy \
  --role-name rol-aws-config-mercadofresco \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWS_ConfigRole \
  --profile mercadofresco-dev

La política gestionada AWS_ConfigRole concedeix només lectura sobre desenes de serveis. Config no necessita escriure res: la remediació l'executa Systems Manager amb un altre rol diferent, que és on hi haurà els permisos perillosos. Aquesta separació és deliberada i bona.

Pas 3: l'enregistrador.

aws configservice put-configuration-recorder \
  --configuration-recorder '{
    "name": "grabador-mercadofresco",
    "roleARN": "arn:aws:iam::111122223333:role/rol-aws-config-mercadofresco",
    "recordingGroup": {
      "allSupported": false,
      "includeGlobalResourceTypes": false,
      "resourceTypes": [
        "AWS::S3::Bucket",
        "AWS::EC2::SecurityGroup",
        "AWS::EC2::Instance",
        "AWS::EC2::Volume",
        "AWS::EC2::NetworkAcl",
        "AWS::EC2::VPC",
        "AWS::EC2::Subnet",
        "AWS::RDS::DBInstance",
        "AWS::RDS::DBSnapshot",
        "AWS::Lambda::Function",
        "AWS::IAM::Role",
        "AWS::IAM::Policy",
        "AWS::IAM::User",
        "AWS::KMS::Key",
        "AWS::SecretsManager::Secret",
        "AWS::ElasticLoadBalancingV2::LoadBalancer",
        "AWS::CloudFront::Distribution",
        "AWS::CloudTrail::Trail",
        "AWS::Logs::LogGroup",
        "AWS::WAFv2::WebACL"
      ]
    },
    "recordingMode": {
      "recordingFrequency": "CONTINUOUS",
      "recordingModeOverrides": [
        {
          "description": "Les instancies del grup ASG roten molt: diari ja es suficient",
          "resourceTypes": ["AWS::EC2::Instance", "AWS::EC2::Volume"],
          "recordingFrequency": "DAILY"
        }
      ]
    }
  }' \
  --profile mercadofresco-dev --region eu-west-1

Dues decisions que aquí valen diners:

  • allSupported: false amb llista explícita. Enregistrar els 250+ tipus admesos en un compte viu genera un volum de CI enorme, i molts no aporten res.
  • recordingModeOverrides amb DAILY per a instàncies i volums. Aquesta és l'optimització més important de tota la lliçó. L'ASG asg-mercadofresco-tienda llança i acaba instàncies a cada pic dels divendres; cada llançament genera CI de la instància, dels seus volums, de les seves interfícies de xarxa. En mode continu són milers de CI al mes per un recurs efímer amb una configuració sempre idèntica —ve de lt-mercadofresco-tienda—. En mode diari, un.

Pas 4: el canal de lliurament.

aws configservice put-delivery-channel \
  --delivery-channel '{
    "name": "canal-mercadofresco",
    "s3BucketName": "mercadofresco-config-historial",
    "s3KeyPrefix": "config",
    "snsTopicARN": "arn:aws:sns:eu-west-1:111122223333:alertas-mercadofresco",
    "configSnapshotDeliveryProperties": {
      "deliveryFrequency": "TwentyFour_Hours"
    }
  }' \
  --profile mercadofresco-dev --region eu-west-1

Pas 5: engegar-lo. Igual que amb CloudTrail, crear no és engegar:

aws configservice start-configuration-recorder \
  --configuration-recorder-name grabador-mercadofresco \
  --profile mercadofresco-dev --region eu-west-1

# Comprovar
aws configservice describe-configuration-recorder-status \
  --query 'ConfigurationRecordersStatus[].[name,recording,lastStatus]' \
  --output table \
  --profile mercadofresco-dev --region eu-west-1

I una advertència sobre el tema d'SNS: si connectes totes les notificacions de Config a alertas-mercadofresco, rebràs un missatge per cada canvi de configuració del compte. Amb l'ASG rotant, això és soroll pur que farà que la gent deixi de llegir els avisos. La manera correcta és enviar per SNS només les notificacions de no conformitat, i això es fa amb EventBridge (07-03) filtrant el tipus d'esdeveniment, o amb un tema separat per al soroll. MercadoFresco fa servir el tema aquí únicament perquè el canal ho exigeix, i filtra a EventBridge el que arriba a les persones.

Triar quins tipus de recurs s'enregistren

La taula de decisió de MercadoFresco, que és el patró que cal copiar:

Tipus de recurs Enregistrar? Freqüència Motiu
AWS::S3::Bucket Contínua Xifratge, accés públic: crític
AWS::EC2::SecurityGroup Contínua La porta d'entrada
AWS::RDS::DBInstance Contínua Xifratge, Multi-AZ, còpies
AWS::IAM::Role / Policy / User Contínua És global: només en una regió
AWS::KMS::Key Contínua Rotació, política
AWS::CloudTrail::Trail Contínua Que ningú no el desactivi
AWS::Logs::LogGroup Contínua Retenció (el problema de 05-01)
AWS::EC2::Instance Diària Roten constantment
AWS::EC2::Volume Diària Ídem
AWS::EC2::NetworkInterface No Pur soroll de l'ASG
AWS::SSM::ManagedInstanceInventory No Volum enorme, valor baix
AWS::Config::ResourceCompliance No Config enregistrant Config

Les tres últimes files són les que més diners estalvien en comptes reals. NetworkInterface i ManagedInstanceInventory són, de bon tros, els dos tipus que més CI generen per accident.

Recursos globals: IAM i CloudFront són globals. Si actives includeGlobalResourceTypes en diverses regions, pagaràs el mateix CI diverses vegades. S'activa en una sola regió —MercadoFresco fa servir eu-west-1— i s'enregistren explícitament els tipus d'IAM tal com hem fet més amunt.

Regles: el cor del servei

Una regla de Config avalua recursos i els assigna un estat:

Estat Significa
COMPLIANT Compleix
NON_COMPLIANT No compleix
NOT_APPLICABLE La regla no s'aplica a aquell recurs
INSUFFICIENT_DATA No s'ha pogut avaluar

Hi ha tres classes de regla:

Classe Qui l'escriu Cost d'avaluació
Gestionada per AWS AWS. N'hi ha més de 300 0,001 USD
Personalitzada amb Lambda Tu, en codi 0,001 USD + cost de Lambda
Personalitzada amb Guard Tu, en llenguatge declaratiu 0,001 USD

Comença sempre per les gestionades: cobreixen el 90 % del que necessites i no cal mantenir-les.

Les regles gestionades que activa MercadoFresco

Regla Què comprova Per què la necessita MercadoFresco Activació
s3-bucket-server-side-encryption-enabled Xifratge per defecte als buckets La pregunta del mòdul 4 Canvi
s3-bucket-public-read-prohibited Que no es pugui llegir públicament mercadofresco-copias-basedatos públic seria catastròfic Canvi
s3-bucket-public-write-prohibited Que no s'hi pugui escriure Ídem Canvi
s3-bucket-versioning-enabled Versionatge actiu Recuperació davant esborraments Canvi
s3-bucket-ssl-requests-only Política que exigeix TLS Dades en trànsit Canvi
rds-storage-encrypted Xifratge d'RDS mercadofresco-pedidos amb alias/mercadofresco-datos (04-02) Canvi
rds-instance-public-access-check RDS no accessible des d'internet Ha de ser a subxarxes de dades (03-01) Canvi
rds-multi-az-support Multi-AZ actiu El vam muntar a 02-04; que ningú no el tregui Canvi
db-instance-backup-enabled Còpies automàtiques actives PITR de 02-04 Canvi
restricted-ssh Port 22 no obert a 0.0.0.0/0 L'altra pregunta del mòdul 4 Canvi
restricted-common-ports 3389, 5432, 3306, 6379… tancats Que ningú no exposi PostgreSQL Canvi
vpc-default-security-group-closed El SG per defecte sense regles L'oblit clàssic de 03-02 Canvi
vpc-flow-logs-enabled Flow logs actius a la VPC flowlogs-mercadofresco (03-01) Periòdica
iam-user-mfa-enabled MFA a tots els usuaris IAM 04-01 Periòdica (24 h)
iam-root-access-key-check L'arrel sense claus d'accés 04-01 Periòdica (24 h)
iam-password-policy Política de contrasenyes robusta 04-01 Periòdica
access-keys-rotated Claus rotades cada 90 dies Exercici 2 de 05-03 Periòdica
iam-policy-no-statements-with-admin-access Sense "Action": "*" Mínim privilegi (04-01) Canvi
cloudtrail-enabled Existeix un trail actiu trail-mercadofresco (05-03) Periòdica
cloud-trail-log-file-validation-enabled Validació d'integritat 05-03 Periòdica
cloud-trail-encryption-enabled Trail xifrat amb KMS 05-03 Periòdica
cw-loggroup-retention-period-check Retenció configurada L'error de 610 USD de 05-01 Canvi
encrypted-volumes Volums EBS xifrats 04-02 Canvi
ec2-imdsv2-check IMDSv2 obligatori a EC2 Protegeix el rol d'instància Canvi
elb-tls-https-listeners-only ALB només amb HTTPS 03-03 Canvi
kms-cmk-not-scheduled-for-deletion Cap clau marcada per esborrar L'esdeveniment més destructiu (05-03) Periòdica
required-tags Etiquetatge obligatori La política de MercadoFresco Canvi
lambda-function-public-access-prohibited Lambdes no invocables per qualsevol 02-05 Canvi
secretsmanager-rotation-enabled-check Rotació activa als secrets 04-03 Periòdica

Són 29 regles. Activar-les:

# La que respon a la pregunta del modul 4
aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-s3-cifrado",
  "Description": "Tots els buckets han de tenir xifratge per defecte",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"
  },
  "Scope": { "ComplianceResourceTypes": ["AWS::S3::Bucket"] }
}' --profile mercadofresco-dev --region eu-west-1

# L'altra: SSH obert al mon
aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-ssh-restringido",
  "Description": "Cap SG amb el port 22 obert a 0.0.0.0/0",
  "Source": { "Owner": "AWS", "SourceIdentifier": "INCOMING_SSH_DISABLED" },
  "Scope": { "ComplianceResourceTypes": ["AWS::EC2::SecurityGroup"] }
}' --profile mercadofresco-dev --region eu-west-1

# Ports comuns, amb parametres
aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-puertos-restringidos",
  "Source": { "Owner": "AWS", "SourceIdentifier": "RESTRICTED_INCOMING_TRAFFIC" },
  "Scope": { "ComplianceResourceTypes": ["AWS::EC2::SecurityGroup"] },
  "InputParameters": "{\"blockedPort1\":\"22\",\"blockedPort2\":\"3389\",\"blockedPort3\":\"5432\",\"blockedPort4\":\"3306\",\"blockedPort5\":\"6379\"}"
}' --profile mercadofresco-dev --region eu-west-1

# Retencio dels grups de registres: l'error de 05-01
aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-retencion-registros",
  "Description": "Tot grup de registres ha de tenir retencio configurada",
  "Source": { "Owner": "AWS", "SourceIdentifier": "CW_LOGGROUP_RETENTION_PERIOD_CHECK" },
  "InputParameters": "{\"MinRetentionTime\":\"7\"}"
}' --profile mercadofresco-dev --region eu-west-1

I la consulta de l'estat general:

aws configservice describe-compliance-by-config-rule \
  --query 'ComplianceByConfigRules[?Compliance.ComplianceType==`NON_COMPLIANT`].[ConfigRuleName,Compliance.ComplianceContributorCount.CappedCount]' \
  --output table \
  --profile mercadofresco-dev --region eu-west-1

# I el detall d'una regla concreta
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name mercadofresco-s3-cifrado \
  --compliance-types NON_COMPLIANT \
  --query 'EvaluationResults[].EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId' \
  --output table \
  --profile mercadofresco-dev --region eu-west-1

Activació per canvi enfront d'activació periòdica

Per canvi de configuració Periòdica
Quan avalua En detectar un CI nou Cada 1, 3, 6, 12 o 24 hores
Latència de detecció Minuts Fins a 24 hores
Cost Una avaluació per canvi Una avaluació per període
Per a què Recursos concrets Comprovacions de compte
Exemple restricted-ssh iam-user-mfa-enabled, cloudtrail-enabled

La distinció no és arbitrària. Una regla per canvi necessita un recurs a què associar-se. Regles com cloudtrail-enabled o iam-password-policy avaluen una propietat del compte, no d'un recurs concret, així que només poden ser periòdiques.

I hi ha un matís de cost important: una regla per canvi sobre un tipus de recurs que canvia molt —instàncies EC2 amb l'ASG rotant— s'avalua moltíssimes vegades. Una regla periòdica cada 24 hores s'avalua 30 vegades al mes i prou. Quan una comprovació no necessiti detecció immediata, posa-la periòdica.

Es pot combinar:

{
  "ConfigRuleName": "mercadofresco-volumenes-cifrados",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "ENCRYPTED_VOLUMES",
    "SourceDetails": [
      { "EventSource": "aws.config",
        "MessageType": "ConfigurationItemChangeNotification" },
      { "EventSource": "aws.config",
        "MessageType": "ScheduledNotification",
        "MaximumExecutionFrequency": "TwentyFour_Hours" }
    ]
  }
}

Avalua en canviar i un cop al dia, que és la xarxa de seguretat per si s'ha perdut algun CI.

L'etiquetatge obligatori amb required-tags

L'etiquetatge de MercadoFresco és Proyecto, Entorno, Componente, Propietario, CentroCoste. Fins ara era una norma escrita que ningú no comprovava. Config la converteix en una regla:

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-etiquetado-obligatorio",
  "Description": "Els recursos han de portar les cinc etiquetes de MercadoFresco",
  "Source": { "Owner": "AWS", "SourceIdentifier": "REQUIRED_TAGS" },
  "InputParameters": "{\"tag1Key\":\"Proyecto\",\"tag1Value\":\"mercadofresco\",\"tag2Key\":\"Entorno\",\"tag2Value\":\"produccion,preproduccion,desarrollo\",\"tag3Key\":\"Componente\",\"tag4Key\":\"Propietario\",\"tag5Key\":\"CentroCoste\"}",
  "Scope": {
    "ComplianceResourceTypes": [
      "AWS::EC2::Instance",
      "AWS::EC2::Volume",
      "AWS::S3::Bucket",
      "AWS::RDS::DBInstance",
      "AWS::Lambda::Function",
      "AWS::ElasticLoadBalancingV2::LoadBalancer"
    ]
  },
  "MaximumExecutionFrequency": "TwentyFour_Hours"
}' --profile mercadofresco-dev --region eu-west-1

Detalls de la sintaxi que no són evidents:

  • tagNKey sense tagNValue exigeix que l'etiqueta existeixi, amb qualsevol valor. Així estan Componente, Propietario i CentroCoste: els seus valors són lliures.
  • tagNValue amb una llista separada per comes exigeix que el valor sigui un d'aquests. Entorno només pot ser produccion, preproduccion o desarrollo.
  • Màxim 6 etiquetes per regla. Si en necessites més, dues regles.

I el resultat la primera vegada que s'executa, que és el moment més instructiu:

Tipus Total Conformes No conformes Què falta
Buckets S3 6 4 2 mercadofresco-registros-web sense CentroCoste
Instàncies EC2 2 2 0
Volums EBS 4 1 3 Els creats per l'ASG no hereten etiquetes
Lambdes 2 2 0
RDS 2 2 0
ALB 1 1 0

La fila dels volums és la troballa real, i és un problema que gairebé tothom té sense saber-ho: els volums EBS creats automàticament per un ASG no hereten les etiquetes de la instància llevat que es configuri explícitament a la plantilla de llançament:

{
  "TagSpecifications": [
    {
      "ResourceType": "instance",
      "Tags": [
        { "Key": "Proyecto", "Value": "mercadofresco" },
        { "Key": "Entorno", "Value": "produccion" },
        { "Key": "Componente", "Value": "tienda" },
        { "Key": "Propietario", "Value": "marta" },
        { "Key": "CentroCoste", "Value": "tienda-online" }
      ]
    },
    {
      "ResourceType": "volume",
      "Tags": [
        { "Key": "Proyecto", "Value": "mercadofresco" },
        { "Key": "Entorno", "Value": "produccion" },
        { "Key": "Componente", "Value": "tienda" },
        { "Key": "Propietario", "Value": "marta" },
        { "Key": "CentroCoste", "Value": "tienda-online" }
      ]
    }
  ]
}

Conseqüència directa i mesurable: al mòdul 11, quan la Sara reparteixi el cost per CentroCoste, els volums de la botiga apareixerien com a «sense assignar». Una regla de Config ha trobat un forat a la comptabilitat de costos que ningú no havia vist en mesos. És el millor argument per activar required-tags des del primer dia.

Regles personalitzades amb Lambda

Quan cap regla gestionada no serveix. El cas de MercadoFresco: cap bucket de dades de negoci pot tenir una regla de cicle de vida que esborri objectes abans de 30 dies, perquè la Sara necessita poder recalcular informes del mes.

"""Regla de Config personalitzada: cicle de vida segur als buckets de negoci.

L'esdeveniment que rep la funcio conte l'element de configuracio
complet del recurs avaluat.
"""
import json
import boto3

config = boto3.client("config")
s3 = boto3.client("s3")

BUCKETS_DE_NEGOCI = (
    "mercadofresco-informes-analitica",
    "mercadofresco-copias-basedatos",
)
DIES_MINIMS = 30


def avaluar(element):
    """Retorna (estat, motiu) per a un element de configuracio."""
    nom = element["resourceName"]

    if not nom.startswith(BUCKETS_DE_NEGOCI):
        return "NOT_APPLICABLE", "No es un bucket de dades de negoci"

    try:
        cicle = s3.get_bucket_lifecycle_configuration(Bucket=nom)
    except s3.exceptions.ClientError as e:
        if "NoSuchLifecycleConfiguration" in str(e):
            return "COMPLIANT", "Sense regles de cicle de vida: no s'esborra res"
        raise

    for regla in cicle.get("Rules", []):
        if regla.get("Status") != "Enabled":
            continue
        expiracio = regla.get("Expiration", {})
        dies = expiracio.get("Days")
        if dies is not None and dies < DIES_MINIMS:
            return ("NON_COMPLIANT",
                    f"La regla '{regla.get('ID')}' expira objectes als {dies} dies "
                    f"(minim exigit: {DIES_MINIMS})")

    return "COMPLIANT", f"Cap regla no expira abans de {DIES_MINIMS} dies"


def handler(esdeveniment, context):
    invocacio = json.loads(esdeveniment["invokingEvent"])
    element = invocacio["configurationItem"]
    token = esdeveniment["resultToken"]

    # Un recurs esborrat no s'avalua.
    if element["configurationItemStatus"] in ("ResourceDeleted",
                                              "ResourceDeletedNotRecorded"):
        estat, motiu = "NOT_APPLICABLE", "Recurs esborrat"
    else:
        estat, motiu = avaluar(element)

    config.put_evaluations(
        Evaluations=[{
            "ComplianceResourceType": element["resourceType"],
            "ComplianceResourceId": element["resourceId"],
            "ComplianceType": estat,
            "Annotation": motiu[:256],           # limit de 256 caracters
            "OrderingTimestamp": element["configurationItemCaptureTime"],
        }],
        ResultToken=token,
    )
    return {"estat": estat, "motiu": motiu}

Quatre coses que cal fer bé i que s'obliden:

  • Retornar NOT_APPLICABLE per al que no aplica, no COMPLIANT. Si retornes COMPLIANT per a tots els buckets del món, el quadre de compliment menteix: semblarà que 40 buckets compleixen una regla que només s'aplica a dos.
  • Tractar ResourceDeleted. Avaluar un recurs que ja no existeix deixa registres orfes marcats com a no conformes per sempre.
  • Annotation és el text que es veu a la consola al costat del recurs no conforme. Un bon missatge aquí estalvia mitja hora d'investigació. Màxim 256 caràcters.
  • ResultToken cal retornar-lo tal qual. És el que associa la resposta amb l'avaluació.

I el registre de la regla:

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-ciclo-vida-seguro",
  "Description": "Els buckets de negoci no poden expirar objectes abans de 30 dies",
  "Source": {
    "Owner": "CUSTOM_LAMBDA",
    "SourceIdentifier": "arn:aws:lambda:eu-west-1:111122223333:function:mercadofresco-regla-ciclo-vida",
    "SourceDetails": [{
      "EventSource": "aws.config",
      "MessageType": "ConfigurationItemChangeNotification"
    }]
  },
  "Scope": { "ComplianceResourceTypes": ["AWS::S3::Bucket"] }
}' --profile mercadofresco-dev --region eu-west-1

Cost: 0,001 USD per avaluació més el cost de la invocació de Lambda. Amb pocs buckets és menyspreable; amb una regla personalitzada sobre instàncies EC2 en un compte amb molt moviment, pot sorprendre.

Regles personalitzades amb Guard

AWS CloudFormation Guard és un llenguatge declaratiu de regles, molt més curt que una Lambda per a comprovacions sobre la configuració. Les regles de Config escrites en Guard s'anomenen Custom Policy rules i no requereixen cap funció: no hi ha codi a mantenir, ni rol, ni cost de Lambda.

La mateixa idea d'abans, en Guard, comprovant que els buckets de negoci estan xifrats amb la clau de MercadoFresco i no amb la d'AWS:

# Regla: els buckets de negoci han de fer servir alias/mercadofresco-datos
rule buckets_negoci_amb_clau_propia when
    resourceType == "AWS::S3::Bucket"
{
    let nom = resourceName

    when %nom == /^mercadofresco-(informes-analitica|copias-basedatos)/ {
        configuration.serverSideEncryptionConfiguration.rules[*]
            .applyServerSideEncryptionByDefault.sseAlgorithm == "aws:kms"
            <<
              Els buckets de dades de negoci s'han de xifrar amb KMS,
              no amb AES256 gestionat per S3.
            >>

        configuration.serverSideEncryptionConfiguration.rules[*]
            .applyServerSideEncryptionByDefault.kmsMasterKeyID
            == /mercadofresco-datos/
            <<
              Cal fer servir la clau alias/mercadofresco-datos (04-02).
            >>
    }
}

# Regla: cap grup de registres sense retencio
rule grups_registres_amb_retencio when
    resourceType == "AWS::Logs::LogGroup"
{
    configuration.retentionInDays EXISTS
        << Tot grup de registres ha de tenir retencio (05-01). >>
    configuration.retentionInDays <= 400
        << Les retencions superiors a 400 dies s'han de justificar. >>
}

El bloc entre << i >> és el missatge d'error, que apareix com a anotació a la consola.

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "mercadofresco-cifrado-buckets-negocio",
  "Source": {
    "Owner": "CUSTOM_POLICY",
    "SourceDetails": [{
      "EventSource": "aws.config",
      "MessageType": "ConfigurationItemChangeNotification"
    }],
    "CustomPolicyDetails": {
      "PolicyRuntime": "guard-2.x.x",
      "PolicyText": "<contingut del fitxer .guard>",
      "EnableDebugLogDelivery": true
    }
  },
  "Scope": { "ComplianceResourceTypes": ["AWS::S3::Bucket"] }
}' --profile mercadofresco-dev --region eu-west-1
Lambda Guard
Escrius Codi Python/Node Regles declaratives
Pots cridar altres API No
Cost extra Invocacions de Lambda Cap
Manteniment Runtime, dependències, rol Cap
Complexitat admesa Qualsevol El que hi hagi al CI
Recomanació Només si necessites lògica externa Per defecte

La diferència pràctica: Guard només pot mirar el que hi ha a l'element de configuració. Si la teva comprovació necessita cridar una altra API —com l'exemple de Lambda, que consultava get_bucket_lifecycle_configuration—, necessites Lambda. Per a tota la resta, Guard.

Remediació automàtica amb Systems Manager

Detectar és bo. Corregir sol és millor, i és el que converteix Config en una eina operativa i no en un informe més que ningú no llegeix.

La remediació s'executa amb un document de Systems Manager Automation: un procediment predefinit amb passos i paràmetres. AWS proporciona dotzenes de documents AWS-* a punt per fer servir.

El rol de remediació. Aquí és on hi ha els permisos perillosos, i per això és un rol a part del de Config, amb el mínim estricte:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CifrarBuckets",
      "Effect": "Allow",
      "Action": [
        "s3:PutEncryptionConfiguration",
        "s3:GetEncryptionConfiguration"
      ],
      "Resource": "arn:aws:s3:::mercadofresco-*"
    },
    {
      "Sid": "CerrarGruposDeSeguridad",
      "Effect": "Allow",
      "Action": [
        "ec2:RevokeSecurityGroupIngress",
        "ec2:DescribeSecurityGroups"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": { "aws:ResourceTag/Proyecto": "mercadofresco" }
      }
    },
    {
      "Sid": "PonerRetencionEnRegistros",
      "Effect": "Allow",
      "Action": ["logs:PutRetentionPolicy", "logs:DescribeLogGroups"],
      "Resource": "arn:aws:logs:eu-west-1:111122223333:log-group:*"
    }
  ]
}

Fixa't en tres decisions de mínim privilegi, totes del manual de 04-01:

  • s3:PutEncryptionConfiguration només sobre mercadofresco-*. El rol no pot tocar buckets aliens.
  • Condició d'etiqueta a les accions sobre SG: només actua sobre recursos del projecte.
  • No hi ha ec2:AuthorizeSecurityGroupIngress. El rol pot treure regles, mai afegir-ne. Si algú comprometés aquest rol, el pitjor que podria fer és tancar coses. Aquesta asimetria és deliberada i és el tipus de detall que separa una configuració segura d'una de perillosa.

Els dos casos reals: xifratge de bucket i SG obert

Cas 1: reactivar el xifratge d'un bucket.

aws configservice put-remediation-configurations \
  --remediation-configurations '[{
    "ConfigRuleName": "mercadofresco-s3-cifrado",
    "TargetType": "SSM_DOCUMENT",
    "TargetId": "AWS-EnableS3BucketEncryption",
    "TargetVersion": "1",
    "Automatic": true,
    "MaximumAutomaticAttempts": 3,
    "RetryAttemptSeconds": 300,
    "Parameters": {
      "AutomationAssumeRole": {
        "StaticValue": {
          "Values": ["arn:aws:iam::111122223333:role/rol-remediacion-mercadofresco"]
        }
      },
      "BucketName": {
        "ResourceValue": { "Value": "RESOURCE_ID" }
      },
      "SSEAlgorithm": {
        "StaticValue": { "Values": ["AES256"] }
      }
    }
  }]' \
  --profile mercadofresco-dev --region eu-west-1

El ResourceValue: RESOURCE_ID és la peça clau: li diu a la remediació que el nom del bucket sigui el del recurs que ha fallat l'avaluació. Sense això, la remediació no sabria sobre què actuar.

Cronologia completa del que passa ara si algú desactiva el xifratge:

Moment Què passa
T+0 s Algú executa DeleteBucketEncryption
T+2 s CloudTrail registra l'esdeveniment (05-03)
T+3 min Config crea un CI nou del bucket
T+3 min La regla mercadofresco-s3-cifrado avalua: NON_COMPLIANT
T+3 min S'emet un esdeveniment d'EventBridge i una notificació a SNS
T+4 min La remediació executa AWS-EnableS3BucketEncryption
T+5 min El xifratge està restaurat
T+8 min Nova avaluació: COMPLIANT
T+8 min La Marta rep l'avís amb tot el cicle al registre

Vuit minuts, sense intervenció humana. I amb el rastre complet: CloudTrail sap qui el va desactivar, Config sap com va quedar, la remediació ho va arreglar, i la línia temporal ho explica sencer. Aquesta és la resposta a l'última pregunta del mòdul 4.

Cas 2: revocar una regla de grup de seguretat oberta al món.

aws configservice put-remediation-configurations \
  --remediation-configurations '[{
    "ConfigRuleName": "mercadofresco-ssh-restringido",
    "TargetType": "SSM_DOCUMENT",
    "TargetId": "AWSConfigRemediation-RemoveUnrestrictedSourceIngressRules",
    "TargetVersion": "1",
    "Automatic": true,
    "MaximumAutomaticAttempts": 5,
    "RetryAttemptSeconds": 60,
    "Parameters": {
      "AutomationAssumeRole": {
        "StaticValue": {
          "Values": ["arn:aws:iam::111122223333:role/rol-remediacion-mercadofresco"]
        }
      },
      "GroupId": { "ResourceValue": { "Value": "RESOURCE_ID" } }
    }
  }]' \
  --profile mercadofresco-dev --region eu-west-1

Aquest document revoca totes les regles d'entrada amb origen 0.0.0.0/0 o ::/0 del grup, no només la del 22. És agressiu, i cal saber-ho: si el teu ALB públic és en un grup de seguretat que legítimament permet 0.0.0.0/0 al 443, aquesta remediació el tombaria.

Per això MercadoFresco acota l'abast de la regla, no el de la remediació:

{
  "ConfigRuleName": "mercadofresco-ssh-restringido",
  "Source": { "Owner": "AWS", "SourceIdentifier": "INCOMING_SSH_DISABLED" },
  "Scope": {
    "ComplianceResourceTypes": ["AWS::EC2::SecurityGroup"],
    "TagKey": "Componente",
    "TagValue": "basedatos"
  }
}

Amb TagKey/TagValue, la regla —i per tant la remediació— només s'aplica als grups de seguretat etiquetats com a Componente=basedatos. sg-mercadofresco-alb, que ha d'estar obert al món al 443, en queda fora. És el mateix raonament de l'abast mínim que apliquem a les exclusions de WAF a 04-05.

Cas 3, el més rendible: posar retenció als grups de registres.

aws configservice put-remediation-configurations \
  --remediation-configurations '[{
    "ConfigRuleName": "mercadofresco-retencion-registros",
    "TargetType": "SSM_DOCUMENT",
    "TargetId": "AWSConfigRemediation-SetCloudWatchLogGroupRetention",
    "Automatic": true,
    "MaximumAutomaticAttempts": 3,
    "RetryAttemptSeconds": 300,
    "Parameters": {
      "AutomationAssumeRole": { "StaticValue": { "Values": [
        "arn:aws:iam::111122223333:role/rol-remediacion-mercadofresco"] } },
      "LogGroupName": { "ResourceValue": { "Value": "RESOURCE_ID" } },
      "RetentionInDays": { "StaticValue": { "Values": ["30"] } }
    }
  }]' \
  --profile mercadofresco-dev --region eu-west-1

Aquesta és la que hauria evitat l'incident dels 610 USD de l'exercici 3 de 05-01. Qualsevol grup de registres nou —creat per una Lambda, per l'agent, per un servei— rep 30 dies de retenció automàticament en qüestió de minuts. És la remediació amb millor relació cost-benefici de tot el mòdul.

L'advertència de provar primer en mode manual

No activis mai Automatic: true en una remediació que no hagis provat. Una remediació és codi amb permisos que modifica la teva producció sense que ningú no ho aprovi. Si està malament, ho fa molt ràpid i arreu.

El procediment de MercadoFresco, i és innegociable:

Fase 1 — Només detecció, 1 setmana. La regla, sense remediació. S'observa quins recursos marca. Aquí surten els falsos positius: recursos que incompleixen la lletra de la regla per bones raons.

Fase 2 — Remediació manual, 2 setmanes. Automatic: false. La remediació existeix però cal llançar-la a mà des de la consola, recurs a recurs:

aws configservice start-remediation-execution \
  --config-rule-name mercadofresco-s3-cifrado \
  --resource-keys resourceType=AWS::S3::Bucket,resourceId=mercadofresco-registros-web \
  --profile mercadofresco-dev --region eu-west-1

S'executa sobre un recurs poc crític, es comprova que fa exactament el que s'espera i res més, i es revisa el registre de l'execució a Systems Manager.

Fase 3 — Automàtica, amb abast acotat. Automatic: true, però primer només sobre els recursos etiquetats Entorno=desarrollo. Una setmana. Després, producció.

Fase 4 — Amb límits. MaximumAutomaticAttempts i RetryAttemptSeconds són un fre important: si la remediació falla 3 vegades, Config deixa d'intentar-ho en lloc d'entrar en bucle. Un bucle de remediació pot generar milers de crides a l'API i una factura considerable.

I tres tipus de remediació que MercadoFresco NO automatitza mai:

Remediació Per què no
Esborrar recursos no conformes Irreversible. Una regla mal escrita esborra producció
Aturar instàncies EC2 Talla el servei. La regla pot estar malament
Modificar polítiques d'IAM Pot deixar tothom sense accés, inclosa la mateixa remediació

La regla mental: automatitza el que afegeix seguretat i és reversible (activar xifratge, posar retenció, treure accés públic). No automatitzis mai el que treu disponibilitat o és irreversible.

Paquets de conformitat

Un conformance pack és una plantilla que desplega un conjunt de regles i remediacions de cop, com una unitat, i que es pot aplicar a tota una organització.

AWS publica plantilles alineades amb marcs coneguts:

Paquet Regles aprox. Per a què
Operational Best Practices for CIS AWS Foundations Benchmark v1.4 ~50 L'estàndard de partida més habitual
Operational Best Practices for PCI DSS 3.2.1 ~90 Comerços que processen targetes
Operational Best Practices for NIST 800-53 ~200 Sector públic nord-americà
Operational Best Practices for GDPR ~60 Ajuda per al RGPD
Operational Best Practices for Amazon S3 ~15 Només S3
Security Best Practices ~120 Generalista d'AWS
# paquete-mercadofresco.yaml
Parameters:
  RetencionMinimaRegistros:
    Type: String
    Default: '7'

Resources:
  S3CifradoActivado:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: paq-mercadofresco-s3-cifrado
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
      Scope:
        ComplianceResourceTypes: [ 'AWS::S3::Bucket' ]

  S3SinLecturaPublica:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: paq-mercadofresco-s3-sin-lectura-publica
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED
      Scope:
        ComplianceResourceTypes: [ 'AWS::S3::Bucket' ]

  RdsCifrado:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: paq-mercadofresco-rds-cifrado
      Source:
        Owner: AWS
        SourceIdentifier: RDS_STORAGE_ENCRYPTED

  RetencionRegistros:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: paq-mercadofresco-retencion-registros
      InputParameters:
        MinRetentionTime: !Ref RetencionMinimaRegistros
      Source:
        Owner: AWS
        SourceIdentifier: CW_LOGGROUP_RETENTION_PERIOD_CHECK
aws configservice put-conformance-pack \
  --conformance-pack-name paquete-mercadofresco-base \
  --template-body file://paquete-mercadofresco.yaml \
  --delivery-s3-bucket mercadofresco-config-historial \
  --delivery-s3-key-prefix conformance \
  --profile mercadofresco-dev --region eu-west-1

aws configservice describe-conformance-pack-compliance \
  --conformance-pack-name paquete-mercadofresco-base \
  --profile mercadofresco-dev --region eu-west-1

L'advertència que cal repetir. Desplegar el paquet de PCI DSS no et fa conforme amb PCI DSS. És una ajuda: comprova automàticament un subconjunt de controls tècnics. La conformitat real inclou processos, formació, contractes, avaluacions i una auditoria formal per un avaluador qualificat. Presentar un quadre verd de Config com a prova de conformitat és un error greu. Aquestes decisions les valida un professional de compliment, no un curs.

Cost: un paquet no costa res per si mateix; costen les regles que conté. Un paquet de PCI DSS amb 90 regles avaluant-se sobre centenars de recursos és la manera més ràpida de multiplicar la factura de Config per deu. Llegeix-lo abans de desplegar-lo.

El quadre de compliment de MercadoFresco

El primer resultat, tres dies després d'activar-ho tot. Aquest és el moment realment valuós, perquè treu a la llum el que feia mesos que era allà:

Regla Estat Recursos no conformes Comentari
mercadofresco-s3-cifrado NO CONFORME 1 mercadofresco-registros-web sense xifratge des del març
mercadofresco-ssh-restringido NO CONFORME 1 Un SG de proves amb el 22 obert des del maig
mercadofresco-etiquetado-obligatorio NO CONFORME 5 3 volums EBS + 2 buckets
mercadofresco-retencion-registros NO CONFORME 4 4 grups «no expira mai»
mercadofresco-puertos-restringidos CONFORME 0 La feina de 03-02 aguanta
mercadofresco-rds-cifrado CONFORME 0 04-02
mercadofresco-rds-multi-az CONFORME 0 02-04
mercadofresco-iam-mfa NO CONFORME 1 Un usuari de servei sense MFA
mercadofresco-cloudtrail-activo CONFORME 0 05-03
mercadofresco-claves-rotadas NO CONFORME 1 Clau de 412 dies
mercadofresco-vpc-flow-logs CONFORME 0 03-01
mercadofresco-sg-defecto-cerrado NO CONFORME 1 El SG per defecte de la VPC, amb regles

Sis regles no conformes, 14 recursos. I cap d'aquests catorze no havia disparat mai una alarma de CloudWatch ni havia aparegut en una investigació de CloudTrail, perquè cap no era un esdeveniment: eren estats. Feia mesos que eren allà.

Les tres troballes que la Marta no esperava:

  1. mercadofresco-registros-web sense xifratge des del març. Es va crear a mà a 03-03 per als registres de l'ALB, abans que existís la política de xifratge de 04-02, i ningú no hi va tornar.
  2. El SG amb el 22 obert des d'una prova de maig. La regla es va afegir «un moment» per depurar i s'hi va quedar tres mesos.
  3. El grup de seguretat per defecte de vpc-mercadofresco amb regles. És el clàssic de 03-02: ningú no el fa servir, però hi és, permissiu, esperant que algú llanci una instància sense especificar grup.

El pla de correcció, ordenat per risc:

Prioritat Recurs Acció Com
1 SG amb el 22 obert Revocar la regla Remediació automàtica
2 SG per defecte Buidar-ne les regles Manual, amb revisió
3 mercadofresco-registros-web Activar xifratge Remediació automàtica
4 4 grups de registres Posar retenció de 30 dies Remediació automàtica
5 Clau de 412 dies Rotar i desactivar l'antiga Manual, coordinat
6 Usuari sense MFA Substituir per rol (04-01) Manual, canvi de disseny
7 Etiquetes de volums Corregir lt-mercadofresco-tienda Manual, canvi de plantilla

Fixa't en el patró: les quatre primeres s'automatitzen perquè afegeixen seguretat i són reversibles. Les tres últimes requereixen criteri humà, i per això no s'automatitzen.

Consultes avançades per inventariar

Config inclou un motor de consultes SQL sobre l'inventari actual de tots els recursos enregistrats. És una de les seves funcions més infravalorades.

# Tots els buckets sense xifratge
aws configservice select-resource-config \
  --expression "
    SELECT resourceId, resourceName, awsRegion
    WHERE resourceType = 'AWS::S3::Bucket'
      AND supplementaryConfiguration.ServerSideEncryptionConfiguration NOT LIKE '%aws:kms%'
  " \
  --profile mercadofresco-dev --region eu-west-1

# Instancies EC2 per tipus, per a l'analisi de cost del modul 11
aws configservice select-resource-config \
  --expression "
    SELECT configuration.instanceType, COUNT(*)
    WHERE resourceType = 'AWS::EC2::Instance'
    GROUP BY configuration.instanceType
  " \
  --profile mercadofresco-dev --region eu-west-1

# Recursos SENSE l'etiqueta CentroCoste: el forat de la comptabilitat
aws configservice select-resource-config \
  --expression "
    SELECT resourceType, resourceId, resourceName, tags
    WHERE tags.key != 'CentroCoste'
  " \
  --profile mercadofresco-dev --region eu-west-1

# Volums EBS sense xifrar
aws configservice select-resource-config \
  --expression "
    SELECT resourceId, configuration.size, configuration.volumeType
    WHERE resourceType = 'AWS::EC2::Volume'
      AND configuration.encrypted = false
  " \
  --profile mercadofresco-dev --region eu-west-1

# Grups de seguretat amb regles obertes al mon
aws configservice select-resource-config \
  --expression "
    SELECT resourceId, resourceName, configuration.ipPermissions
    WHERE resourceType = 'AWS::EC2::SecurityGroup'
      AND configuration.ipPermissions.ipRanges = '0.0.0.0/0'
  " \
  --profile mercadofresco-dev --region eu-west-1

Aquest motor respon en segons a preguntes que altrament requeririen recórrer desenes de crides Describe paginades. I a diferència d'Athena sobre CloudTrail (05-03), no costa res per consulta: forma part del servei.

Una consulta que la Marta executa cada mes i que ja ha justificat el cost de Config diverses vegades:

# Volums EBS sense associar a cap instancia: diners llencats
aws configservice select-resource-config \
  --expression "
    SELECT resourceId, configuration.size, configuration.createTime, tags
    WHERE resourceType = 'AWS::EC2::Volume'
      AND configuration.state.value = 'available'
  " \
  --profile mercadofresco-dev --region eu-west-1

Un volum available és un volum que existeix, que es paga cada mes, i que no està connectat a res. Solen quedar d'instàncies acabades. És exactament una de les troballes que també reporta Trusted Advisor, que és la lliçó següent.

Agregadors multicompte

Un agregador consolida les dades de Config de diversos comptes i regions en una sola vista.

aws configservice put-configuration-aggregator \
  --configuration-aggregator-name agregador-mercadofresco \
  --account-aggregation-sources '[{
    "AccountIds": ["111122223333"],
    "AllAwsRegions": true
  }]' \
  --profile mercadofresco-dev --region eu-west-1

Amb AWS Organizations es fa servir --organization-aggregation-source i l'agregador recull automàticament tots els comptes de l'organització, inclosos els que es creïn en el futur. Aquesta és la configuració correcta per a qualsevol empresa amb diversos comptes, i és la lliçó 09-04.

MercadoFresco té un compte avui, així que l'agregador només aporta la vista multiregió —útil per detectar recursos oblidats en regions on no s'hauria de tenir res, el cas de l'exercici 3 de 05-03—.

Security Hub i GuardDuty: on encaixa cadascun

És fàcil confondre aquestes tres eines. La taula que les separa:

AWS Config Amazon GuardDuty AWS Security Hub
Què fa Avalua configuracions Detecta amenaces Agrega troballes
Font de dades Elements de configuració CloudTrail, DNS, flow logs, S3, EKS Config, GuardDuty, Inspector, Macie…
Detecta Un bucket sense xifrar Una IP maliciosa parlant amb la teva instància Totes dues coses, en un tauler
Basat en Les teves regles Aprenentatge i intel·ligència d'amenaces Estàndards (CIS, PCI, AWS FSBP)
Corregeix (remediació) No Via accions personalitzades
Cost Per CI i avaluació Per GB analitzat i esdeveniments Per comprovació i troballa
Pregunta Està ben configurat? Hi ha algú a dins? Quina és la meva postura global?

Exemples concrets que aclareixen la divisió del treball:

  • Config: «mercadofresco-registros-web no té xifratge.» És un problema de configuració.
  • GuardDuty: «Una instància d'asg-mercadofresco-tienda està resolent dominis associats a mineria de criptomonedes» o «credencials del rol d'instància usades des d'una IP externa a AWS». És un problema d'intrusió, i cap regla de configuració no ho detectaria.
  • Security Hub: «El teu compte compleix el 82 % del CIS Benchmark; aquestes 14 troballes són crítiques», amb les troballes de Config i de GuardDuty a la mateixa llista prioritzada.

Recomanació pràctica: si vas a activar els tres, activa'ls en aquest ordre —Config primer, perquè és la base i perquè Security Hub consumeix les seves regles; GuardDuty després, perquè és el que detecta el que Config no pot veure; Security Hub al final, com a capa d'agregació—. I tingues present que els tres costen diners i els tres generen troballes que algú ha de llegir. Activar els tres i no mirar-los és pitjor que activar només Config i revisar-lo mensualment.

Cost real i com no disparar-lo

Concepte Preu a eu-west-1
Element de configuració enregistrat 0,003 USD cadascun
Avaluació de regla (primeres 100.000/mes) 0,001 USD cadascuna
Avaluacions 100.001-500.000 0,0008 USD
Consultes avançades Gratuïtes
Paquets de conformitat Només les regles que contenen
Execució de remediació (SSM Automation) Gratuïta al nivell estàndard
Emmagatzematge a S3 0,023 USD/GB/mes
Agregador Gratuït

Càlcul per a MercadoFresco:

Concepte Quantitat/mes Cost
CI de recursos estables (S3, RDS, IAM, KMS, SG, ALB…) ~450 1,35 USD
CI d'instàncies i volums (mode diari) ~180 0,54 USD
Avaluacions de regles per canvi (29 regles) ~4.200 4,20 USD
Avaluacions periòdiques (10 regles × 30 dies) 300 0,30 USD
Emmagatzematge a S3 ~0,3 GB 0,01 USD
Total ~6,40 USD/mes

I ara el mateix càlcul sense les optimitzacions, que és el que li passa a la majoria dels comptes:

Concepte Quantitat/mes Cost
allSupported: true amb instàncies en mode continu ~28.000 CI 84,00 USD
Avaluacions sobre tots aquests recursos ~140.000 132,00 USD
Total ~216,00 USD/mes

Trenta-quatre vegades més car, i amb exactament la mateixa capacitat de detecció dels problemes que importen. La diferència és tota en tres decisions de configuració.

Les cinc maneres de disparar la factura de Config, per freqüència real:

  1. allSupported: true en un compte amb autoescalat. Cada llançament d'instància genera CI de la instància, els seus volums, les seves interfícies de xarxa i les seves associacions. Milers al mes.
  2. No fer servir recordingFrequency: DAILY per a recursos efímers. L'optimització més rendible i la menys coneguda.
  3. Enregistrar recursos globals (IAM) en diverses regions. Es paga el mateix CI tantes vegades com regions tinguin l'enregistrador amb includeGlobalResourceTypes.
  4. Desplegar un conformance pack de 200 regles sense llegir-lo. Cada regla s'avalua contra cada recurs aplicable, a cada canvi.
  5. Regles personalitzades amb Lambda sobre tipus de recurs molt canviants. Es paga l'avaluació i la invocació.

Les cinc defenses:

  1. Llista explícita de resourceTypes, mai allSupported.
  2. recordingFrequency: DAILY per a AWS::EC2::Instance, AWS::EC2::Volume i tot el que sigui efímer.
  3. Recursos globals en una sola regió.
  4. Regles periòdiques cada 24 h en lloc de per canvi sempre que no necessitis detecció immediata.
  5. Un pressupost d'AWS Budgets filtrat per servei = Config (mòdul 11), amb avís al 80 %.

Neteja

# 1. Treure les remediacions ABANS que les regles
aws configservice delete-remediation-configuration \
  --config-rule-name mercadofresco-s3-cifrado \
  --profile mercadofresco-dev --region eu-west-1

# 2. Esborrar les regles
for R in mercadofresco-s3-cifrado mercadofresco-ssh-restringido \
         mercadofresco-puertos-restringidos mercadofresco-retencion-registros \
         mercadofresco-etiquetado-obligatorio mercadofresco-ciclo-vida-seguro \
         mercadofresco-cifrado-buckets-negocio; do
  aws configservice delete-config-rule --config-rule-name "$R" \
    --profile mercadofresco-dev --region eu-west-1
done

# 3. El paquet de conformitat
aws configservice delete-conformance-pack \
  --conformance-pack-name paquete-mercadofresco-base \
  --profile mercadofresco-dev --region eu-west-1

# 4. ATURAR L'ENREGISTRADOR: aixo es el que talla la despesa
aws configservice stop-configuration-recorder \
  --configuration-recorder-name grabador-mercadofresco \
  --profile mercadofresco-dev --region eu-west-1

# 5. Canal i enregistrador
aws configservice delete-delivery-channel --delivery-channel-name canal-mercadofresco \
  --profile mercadofresco-dev --region eu-west-1
aws configservice delete-configuration-recorder \
  --configuration-recorder-name grabador-mercadofresco \
  --profile mercadofresco-dev --region eu-west-1

# 6. El bucket de l'historial (revisa abans si hi ha obligacio de conservar-lo)
aws s3 rm s3://mercadofresco-config-historial --recursive --profile mercadofresco-dev
aws s3api delete-bucket --bucket mercadofresco-config-historial --profile mercadofresco-dev

El pas 4 és l'important. Esborrar regles no atura la despesa: els CI es continuen enregistrant mentre l'enregistrador estigui actiu. Aturar l'enregistrador és el que talla la facturació. I si en algun moment veus un càrrec de Config que no esperes, comença sempre per describe-configuration-recorder-status a totes les regions: un enregistrador oblidat en una regió que no fas servir és un clàssic.

Errors Comuns i Consells

1. Activar allSupported: true sense pensar-hi. És l'error de cost número u del servei. Llista explícita, sempre.

2. No fer servir recordingFrequency: DAILY per a instàncies i volums. Amb un ASG actiu, és la diferència entre 6 i 216 USD al mes.

3. Enregistrar recursos globals en diverses regions. Es paga el mateix CI diverses vegades. IAM i CloudFront en una sola regió.

4. Activar Automatic: true en una remediació sense provar-la. Detecció una setmana, remediació manual dues setmanes, automàtica en desenvolupament una setmana, i després producció. Sense dreceres.

5. Automatitzar remediacions destructives. Esborrar recursos, aturar instàncies o modificar IAM automàticament pot convertir una regla mal escrita en una caiguda. Automatitza només el que afegeix seguretat i és reversible.

6. Confondre Config amb CloudTrail. «Qui ho ha canviat?» → CloudTrail. «Com està i compleix?» → Config. Es fan servir junts.

7. Retornar COMPLIANT en lloc de NOT_APPLICABLE en una regla personalitzada. El quadre de compliment queda inflat i deixa de ser útil.

8. Connectar totes les notificacions de Config a SNS. Un missatge per cada canvi de configuració és soroll garantit, i el soroll fa que la gent deixi de llegir els avisos importants. Filtra amb EventBridge (07-03) i envia a les persones només les no conformitats.

9. Creure que un conformance pack et certifica. No. Comprova controls tècnics; la conformitat real inclou processos, contractes i una auditoria formal. Que ho validi un professional de compliment.

10. Aplicar una remediació de SG sense acotar l'abast de la regla. RemoveUnrestrictedSourceIngressRules sobre sg-mercadofresco-alb tombaria la botiga. Acota amb TagKey/TagValue.

11. Esborrar regles creient que s'atura la despesa. El que factura són els CI de l'enregistrador. stop-configuration-recorder.

12. Oblidar start-configuration-recorder. Com amb CloudTrail, crear no és engegar.

13. Escriure una regla amb Lambda quan n'hi havia prou amb Guard. Si la comprovació només mira l'element de configuració, Guard és més curt, més barat i no cal mantenir cap runtime.

Consell final: activa Config amb poques regles i ben triades abans que amb un paquet de conformitat complet. Deu regles que algú revisa cada mes valen infinitament més que dues-centes que generen un quadre vermell permanent al qual tothom s'acostuma. L'objectiu no és tenir moltes regles: és arribar a zero no conformitats i que qualsevol de nova sigui un senyal real.

Exercicis

Exercici 1: dissenyar la configuració de Config amb pressupost

MercadoFresco vol activar Config amb un pressupost màxim de 12 USD al mes. Inventari real del compte:

Tipus de recurs Quantitat Canvis/mes estimats
AWS::S3::Bucket 7 4
AWS::EC2::SecurityGroup 6 8
AWS::EC2::Instance 2-4 (ASG) 620 (rotació)
AWS::EC2::Volume 4-8 640
AWS::EC2::NetworkInterface 4-8 1.280
AWS::RDS::DBInstance 2 3
AWS::IAM::Role 9 6
AWS::IAM::Policy 12 5
AWS::Lambda::Function 2 20 (desplegaments)
AWS::Logs::LogGroup 9 12
AWS::KMS::Key 1 1

Requisits: cal detectar en menys de 15 minuts que un bucket perd el xifratge o que un SG s'obre al món; cal comprovar l'etiquetatge obligatori; cal vigilar la retenció dels grups de registres.

Dissenya: la llista de resourceTypes amb la seva recordingFrequency, el conjunt de regles amb el seu tipus d'activació, i calcula el cost total. Justifica cada exclusió. Si et passes del pressupost, explica què retallaries i quina capacitat de detecció perdries.

Exercici 2: la regla personalitzada i la seva remediació

MercadoFresco té una política interna: tota instantània d'RDS de més de 90 dies ha d'estar xifrada i no ha de ser pública, i les de més de 365 dies s'han d'esborrar llevat que portin l'etiqueta Retencion=legal.

  • a) Explica per què aquesta comprovació no es pot fer amb una sola regla gestionada, i quines regles gestionades cobreixen part del problema.
  • b) Escriu la regla personalitzada (Lambda o Guard, justificant l'elecció) que avalua les instantànies.
  • c) Dissenya la remediació. Decideix quina part s'automatitza i quina no, i justifica-ho amb el criteri de la lliçó.
  • d) Calcula el cost afegit si MercadoFresco té 120 instantànies i la regla és periòdica cada 24 hores, enfront de per canvi de configuració.

Exercici 3: la investigació combinada

Un dilluns, la regla mercadofresco-s3-cifrado marca mercadofresco-informes-analitica com a NO CONFORME. La remediació automàtica encara és en mode manual. Dades:

  • La línia temporal mostra que el CI no conforme es va crear el diumenge a les 04:17.
  • El CI anterior, del dijous, era conforme.
  • La regla mercadofresco-etiquetado-obligatorio marca el mateix bucket com a no conforme des del diumenge a les 04:17: li falta l'etiqueta Propietario.
  • Hi ha tres buckets nous al compte, creats el diumenge entre les 04:10 i les 04:25, cap amb xifratge ni etiquetes.
  • CloudTrail mostra 46 crides d'escriptura aquell diumenge entre les 04:05 i les 04:30, totes amb userIdentity.type = "AssumedRole" i sessionIssuer.userName = "rol-despliegue-infra".

Explica: què ha passat amb tota probabilitat; com ho confirmaries combinant Config i CloudTrail (amb comandes i consultes concretes); per què Config va detectar una cosa que CloudTrail tot sol no hauria fet saltar; quina remediació aplicaries i en quin ordre; i quin arranjament de fons proposaries perquè no torni a passar, indicant en quin mòdul del curs s'estudia.

Solucions

Solució 1

Anàlisi de l'inventari. El problema està concentrat en tres files: instàncies (620), volums (640) i interfícies de xarxa (1.280). Són 2.540 dels 2.679 canvis mensuals: el 95 %. Tots generats per la rotació de l'ASG i tots de configuració idèntica, perquè vénen de lt-mercadofresco-tienda.

Configuració proposada de l'enregistrador:

Tipus Enregistrar? Freqüència Justificació
AWS::S3::Bucket Contínua Requisit: detecció en 15 min
AWS::EC2::SecurityGroup Contínua Requisit: detecció en 15 min
AWS::RDS::DBInstance Contínua Pocs canvis, alt valor
AWS::IAM::Role / Policy Contínua Pocs canvis, alt valor
AWS::KMS::Key Contínua 1 canvi/mes
AWS::Logs::LogGroup Contínua Requisit de retenció
AWS::Lambda::Function Contínua 20 canvis/mes, assumible
AWS::EC2::Instance DIÀRIA 620 → ~30 CI/mes
AWS::EC2::Volume DIÀRIA 640 → ~30 CI/mes
AWS::EC2::NetworkInterface NO 1.280 CI de valor gairebé nul

Càlcul d'elements de configuració:

Tipus CI/mes Cost
Buckets 4 0,012 USD
SG 8 0,024 USD
Instàncies (diària) 30 0,090 USD
Volums (diària) 30 0,090 USD
RDS 3 0,009 USD
Rols + polítiques 11 0,033 USD
Lambdes 20 0,060 USD
Grups de registres 12 0,036 USD
KMS 1 0,003 USD
Descobriment inicial (un cop) ~55 0,165 USD
Total CI ~174 ~0,52 USD

Regles proposades:

Regla Activació Avaluacions/mes Cost
s3-bucket-server-side-encryption-enabled Canvi 4 + 7 inicials = 11 0,011 USD
s3-bucket-public-read-prohibited Canvi 11 0,011 USD
restricted-ssh Canvi 8 + 6 = 14 0,014 USD
restricted-common-ports Canvi 14 0,014 USD
vpc-default-security-group-closed Canvi 14 0,014 USD
rds-storage-encrypted Canvi 3 + 2 = 5 0,005 USD
rds-multi-az-support Canvi 5 0,005 USD
cw-loggroup-retention-period-check Canvi 12 + 9 = 21 0,021 USD
encrypted-volumes Canvi (diària) 30 0,030 USD
required-tags Periòdica 24 h 30 × 25 recursos = 750 0,750 USD
iam-user-mfa-enabled Periòdica 24 h 30 0,030 USD
iam-root-access-key-check Periòdica 24 h 30 0,030 USD
cloudtrail-enabled Periòdica 24 h 30 0,030 USD
access-keys-rotated Periòdica 24 h 30 0,030 USD
kms-cmk-not-scheduled-for-deletion Periòdica 24 h 30 0,030 USD
Total avaluacions ~1.062 ~1,03 USD

Cost total: 0,52 + 1,03 + ~0,02 de S3 = ~1,57 USD/mes. Molt per sota dels 12 USD.

Amb el marge sobrant es pot: afegir el paquet de conformitat CIS complet (~50 regles, uns 3-4 USD més), passar required-tags a activació per canvi per a una detecció més ràpida, o incloure AWS::EC2::NetworkInterface si alguna vegada calgués per a una investigació de xarxa.

Justificació de les exclusions:

  • NetworkInterface: 1.280 CI (3,84 USD) per interfícies efímeres que l'ASG crea i destrueix. La seva configuració és sempre la mateixa i ve de la plantilla de llançament. Si calgués investigar la xarxa, hi ha els VPC Flow Logs (03-01) i CloudTrail (05-03).
  • Instàncies i volums en mode diari: es perd la detecció immediata d'un canvi en una instància concreta. Importa? Les instàncies són bestiar, no mascotes: si una es degrada, l'ASG la reemplaça. Els canvis que importen són a la plantilla de llançament, no a la instància. El compromís és correcte.

El que es perdria retallant més: si calgués baixar d'1,57 USD, la retallada següent seria required-tags (0,75 USD, gairebé la meitat del total). Es perdria la detecció del forat de CentroCoste als volums, que al mòdul 11 val molt més de 0,75 USD. No es retalla.

Solució 2

a) Per què no n'hi ha prou amb una regla gestionada.

Hi ha regles gestionades que cobreixen parts:

Regla gestionada Què cobreix Què li falta
rds-snapshot-encrypted Instantànies xifrades No mira l'antiguitat
rds-snapshots-public-prohibited Que no siguin públiques No mira l'antiguitat
required-tags L'etiqueta Retencion No la relaciona amb l'edat

El que cap no cobreix és la lògica combinada: «més de 90 dies i sense xifrar», «més de 365 dies i sense l'etiqueta Retencion=legal». Config no permet compondre regles gestionades amb condicions entre elles. Això exigeix una regla pròpia.

b) La regla. Elecció: Lambda, no Guard.

Guard només pot mirar el que hi ha a l'element de configuració. Aquí necessitem calcular l'antiguitat respecte a la data actual, i Guard no té aritmètica de dates contra «ara». A més, convé una activació periòdica que avaluï totes les instantànies, no només les que canvien —una instantània no canvia: simplement envelleix—. Aquest és l'argument decisiu: l'incompliment apareix amb el pas del temps, no amb un canvi de configuració.

"""Regla de Config: instantanies d'RDS segons antiguitat.

Activacio PERIODICA cada 24 h: una instantania no canvia,
pero envelleix, i l'incompliment apareix pel pas del temps.
"""
import json
from datetime import datetime, timezone
import boto3

config = boto3.client("config")
rds = boto3.client("rds")

DIES_XIFRATGE = 90
DIES_ESBORRAT = 365


def edat_en_dies(data):
    return (datetime.now(timezone.utc) - data).days


def avaluar_instantania(snap, etiquetes):
    identificador = snap["DBSnapshotIdentifier"]
    edat = edat_en_dies(snap["SnapshotCreateTime"])

    if edat > DIES_ESBORRAT and etiquetes.get("Retencion") != "legal":
        return ("NON_COMPLIANT",
                f"{edat} dies d'antiguitat i sense Retencion=legal: s'ha d'esborrar")

    if edat > DIES_XIFRATGE and not snap.get("Encrypted", False):
        return ("NON_COMPLIANT",
                f"{edat} dies d'antiguitat i SENSE XIFRAR")

    # La comprovacio de publicitat requereix una altra crida.
    atributs = rds.describe_db_snapshot_attributes(
        DBSnapshotIdentifier=identificador
    )["DBSnapshotAttributesResult"]["DBSnapshotAttributes"]
    for atribut in atributs:
        if atribut["AttributeName"] == "restore" and "all" in atribut["AttributeValues"]:
            return "NON_COMPLIANT", f"La instantania es PUBLICA"

    return "COMPLIANT", f"{edat} dies, xifrada i privada"


def handler(esdeveniment, context):
    token = esdeveniment["resultToken"]
    avaluacions = []
    ara = datetime.now(timezone.utc)

    paginador = rds.get_paginator("describe_db_snapshots")
    for pagina in paginador.paginate(SnapshotType="manual"):
        for snap in pagina["DBSnapshots"]:
            etiquetes = {t["Key"]: t["Value"] for t in snap.get("TagList", [])}
            estat, motiu = avaluar_instantania(snap, etiquetes)
            avaluacions.append({
                "ComplianceResourceType": "AWS::RDS::DBSnapshot",
                "ComplianceResourceId": snap["DBSnapshotIdentifier"],
                "ComplianceType": estat,
                "Annotation": motiu[:256],
                "OrderingTimestamp": ara,
            })

    # put_evaluations accepta com a maxim 100 per crida.
    for i in range(0, len(avaluacions), 100):
        config.put_evaluations(
            Evaluations=avaluacions[i:i + 100],
            ResultToken=token,
        )

    return {"avaluades": len(avaluacions)}

Quatre detalls que fan que aquesta funció funcioni en producció i no només a l'exemple:

  • SnapshotType="manual": les automàtiques les gestiona RDS amb la seva pròpia retenció (02-04) i s'esborren soles. Avaluar-les generaria no conformitats impossibles de remeiar.
  • put_evaluations en lots de 100: és el límit de l'API. Amb 120 instantànies, una sola crida fallaria.
  • Annotation amb l'edat concreta: qui miri la consola sabrà immediatament de què es tracta.
  • La comprovació de publicitat fa una crida extra per instantània. Amb 120 instantànies són 120 crides cada 24 hores: acceptable. Amb 10.000, caldria paral·lelitzar o separar en una altra regla.

c) La remediació, i aquí hi ha el criteri.

Incompliment Automatitzar? Per què
Instantània pública SÍ, immediat Afegeix seguretat, és reversible, i una còpia de base de dades pública és una bretxa de dades en curs. AWSConfigRemediation-RevokeRDSDBSnapshotPublicAccess
Instantània sense xifrar de més de 90 dies NO automàtic «Xifrar» una instantània existent no és possible: cal copiar-la xifrada i esborrar l'original. És una operació amb cost, durada i risc. Es genera un tiquet
Instantània de més de 365 dies sense etiqueta MAI automàtic És un esborrament. Irreversible. Si la regla o l'etiqueta estan malament, es destrueix l'única còpia d'alguna cosa important

Aquesta taula és exactament la regla de la lliçó: automatitza el que afegeix seguretat i és reversible; mai el que és destructiu. La instantània pública es tanca sola en minuts; l'esborrament l'aprova una persona.

Per a les dues que no s'automatitzen, la resposta correcta és notificar bé: una regla d'EventBridge (07-03) que capturi el canvi a no conformitat i enviï a alertas-mercadofresco un missatge que inclogui l'Annotation de l'avaluació, que és on hi ha l'explicació concreta («412 dies d'antiguitat i sense xifrar»). Un avís que només diu «hi ha un recurs no conforme» obliga a entrar a la consola; un que diu quina instantània i per què es resol des del mòbil.

I una revisió trimestral al calendari de la Marta per decidir què s'esborra, amb la llista al davant.

d) Cost.

Opció periòdica cada 24 hores:

  • 120 instantànies × 30 dies = 3.600 avaluacions/mes = 3,60 USD
  • Invocacions de Lambda: 30/mes (una per avaluació de la regla, no per instantània) ≈ 0,00 USD
  • Crides a l'API d'RDS: gratuïtes
  • Total: ~3,60 USD/mes

Opció per canvi de configuració:

  • Les instantànies manuals canvien poquíssim: potser 10 CI/mes.
  • 10 avaluacions = 0,01 USD
  • Total: ~0,01 USD/mes

Però l'opció per canvi NO SERVEIX, i aquesta és la conclusió de l'apartat. L'incompliment aquí apareix amb el pas del temps, no amb un canvi: una instantània creada avui sense xifrar és conforme, i d'aquí a 91 dies deixa de ser-ho sense que hagi canviat res en ella. Una regla per canvi no la tornaria a avaluar mai i la no conformitat no es detectaria mai.

3,60 USD al mes és el preu de detectar incompliments que depenen del temps, i TwentyFour_Hours ja és la freqüència periòdica més espaiada que admet Config: no hi ha marge per aquí. L'única palanca real d'estalvi seria emetre una sola avaluació agregada per regla en lloc d'una per instantània, però llavors la consola diria «la regla no es compleix» sense dir quina de les 120 instantànies en té la culpa, que és justament la dada que cal per actuar. Es paga el detall, i val la pena.

Solució 3

Què ha passat, amb tota probabilitat.

Les dades apunten de manera inequívoca a un desplegament automatitzat d'infraestructura el diumenge de matinada que va crear recursos sense les propietats obligatòries, i que a més va modificar un bucket existent.

Les pistes, en ordre:

  1. Diumenge a les 04:17, hora sense activitat humana: és un procés automàtic.
  2. rol-despliegue-infra amb 46 crides d'escriptura en 25 minuts: és un pipeline o una execució d'infraestructura com a codi.
  3. Tres buckets nous sense xifratge ni etiquetes, creats a la mateixa finestra.
  4. Un bucket existent que va passar de conforme a no conforme exactament a la mateixa hora.

El punt 4 és el més greu i el més revelador: la plantilla no només va crear recursos nous mal configurats, sinó que va redefinir un bucket que ja existia, sobreescrivint-ne el xifratge i les etiquetes amb una definició incompleta. És el patró clàssic d'una plantilla de CloudFormation o Terraform que declara un recurs que ja existia i l'«alinea» amb una especificació pobra.

Confirmació, pas a pas.

1. Veure exactament què va canviar al bucket (això és el que només Config pot donar):

aws configservice get-resource-config-history \
  --resource-type AWS::S3::Bucket \
  --resource-id mercadofresco-informes-analitica \
  --later-time 2026-08-03T00:00:00Z \
  --earlier-time 2026-07-30T00:00:00Z \
  --profile mercadofresco-dev --region eu-west-1

Comparant el CI del dijous amb el del diumenge es veu el diff: serverSideEncryptionConfiguration va desaparèixer i les etiquetes es van reduir. Això és informació que CloudTrail no té: CloudTrail registra la crida PutBucketEncryption o la seva absència, però no l'estat resultant complet del bucket.

2. Veure qui va fer la crida concreta (això és el que només CloudTrail pot donar):

SELECT eventtime, eventname,
       split_part(userIdentity.arn, '/', 3) AS sessio,
       sourceipaddress, useragent,
       json_extract_scalar(requestParameters, '$.bucketName') AS bucket
FROM auditoria_mercadofresco.cloudtrail_mercadofresco
WHERE anio='2026' AND mes='08' AND dia='02'
  AND userIdentity.sessionContext.sessionIssuer.userName = 'rol-despliegue-infra'
ORDER BY eventtime;

Es busca: el userAgent (cloudformation.amazonaws.com? Terraform/1.7?), el nom de sessió, i si hi ha un DeleteBucketEncryption explícit o simplement un CreateBucket sobre un bucket existent.

3. Veure tots els recursos afectats alhora, amb la consulta avançada de Config:

aws configservice select-resource-config \
  --expression "
    SELECT resourceId, resourceName, resourceCreationTime, tags
    WHERE resourceType = 'AWS::S3::Bucket'
      AND resourceCreationTime > '2026-08-02T00:00:00Z'
  " \
  --profile mercadofresco-dev --region eu-west-1

4. Quadre de compliment complet, per veure si hi ha més danys dels que se sabien:

aws configservice get-compliance-details-by-config-rule \
  --config-rule-name mercadofresco-etiquetado-obligatorio \
  --compliance-types NON_COMPLIANT \
  --profile mercadofresco-dev --region eu-west-1

Per què CloudTrail tot sol no hauria fet saltar res.

Aquesta és la pregunta central de l'exercici, i hi ha tres raons:

  1. CloudTrail no avalua. Registra 46 crides d'un rol de desplegament un diumenge. Això és completament normal per a un pipeline programat. No hi ha res anòmal en l'esdeveniment en si.
  2. L'alarma de 05-03 no hauria saltat. Els filtres de mètriques que vam muntar vigilaven DeleteBucketEncryption i PutBucketPolicy, però des d'un rol de desplegament legítim, i probablement sense DeleteBucketEncryption explícit: si la plantilla simplement no declara xifratge en crear el bucket, no hi ha cap crida a registrar. L'absència d'una crida no genera un esdeveniment.
  3. CloudTrail no coneix la política de MercadoFresco. No sap que tots els buckets han d'estar xifrats ni que calen cinc etiquetes. Config sí, perquè l'hi hem dit amb regles.

Config detecta l'estat resultant; CloudTrail detecta l'acte. Aquí l'acte era legítim i l' estat resultant no ho era. Aquest és exactament el buit que aquesta lliçó ve a cobrir.

Remediació, en ordre de risc:

# Acció Mode
1 Aturar el pipeline o desactivar-ne l'execució programada Manual, immediat
2 Restaurar el xifratge de mercadofresco-informes-analitica Remediació manual, verificant
3 Comprovar si es van pujar objectes sense xifrar entre el diumenge i el dilluns Manual
4 Xifrar els tres buckets nous Remediació manual
5 Restaurar les etiquetes del bucket afectat Manual
6 Decidir què fer amb els tres buckets nous: havien d'existir? Manual, amb el Luis
7 Només llavors, reactivar el pipeline amb la plantilla corregida Manual

El pas 3 mereix un comentari: els objectes escrits mentre el xifratge per defecte estava desactivat es van desar sense xifrar, i activar-lo ara no els xifra retroactivament. Cal reescriure'ls:

aws s3 cp s3://mercadofresco-informes-analitica/ s3://mercadofresco-informes-analitica/ \
  --recursive --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:eu-west-1:111122223333:alias/mercadofresco-datos \
  --metadata-directive REPLACE \
  --profile mercadofresco-dev

Aquest detall es passa per alt constantment i és el que converteix un incident de configuració en un incident de dades.

Els arranjaments de fons, que són la part important:

Arranjament Mòdul Per què
Corregir la plantilla perquè declari xifratge i etiquetes obligatòries 09-01 (CloudFormation) / 09-02 (CDK) La causa arrel. En CDK es poden imposar valors per defecte per a tota l'organització
Validar la plantilla abans de desplegar amb cfn-guard al pipeline 08-02 (CodeBuild) Detectar el problema abans que arribi a producció és sempre millor que remeiar-lo després
Activar la remediació automàtica de mercadofresco-s3-cifrado Aquesta lliçó Hauria corregit el xifratge en 8 minuts, un diumenge de matinada, sense que ningú no se n'assabentés fins al dilluns
Política de control de serveis que denegui s3:PutObject sense xifratge 09-04 (Organizations) Prevenció dura: ni tan sols es pot escriure sense xifrar
Revisió obligatòria de canvis d'infraestructura 08-04 (CodePipeline) Un pas d'aprovació manual per a canvis sobre recursos existents

La lliçó de fons, i mereix subratllar-se perquè és l'argument més fort a favor d'aquest servei: la mateixa regla de Guard que escrius per a Config es pot executar al pipeline amb cfn-guard abans del desplegament. Config és la xarxa de seguretat que atrapa el que se't va escapar; la validació al pipeline és la que evita que s'escapi. Totes dues, amb la mateixa regla escrita un cop. Aquest és el patró que MercadoFresco adopta, i que es tanca al mòdul 8.

Conclusió

MercadoFresco ja té l'última peça que li faltava. Saps què és la configuració d'un recurs —els seus ajustos, no les seves dades— i què és un element de configuració: una fotografia completa amb els seus relationships, la seva supplementaryConfiguration i el seu estat, que Config crea a cada canvi i que fins i tot enregistra quan el recurs s'esborra. Coneixes la línia temporal, que respon a la pregunta que es fa cada setmana a operacions: «això funcionava divendres; què ha canviat?».

Tens clara la diferència essencial amb la lliçó anterior: CloudTrail enregistra la crida, Config enregistra l'estat. CloudTrail diu qui va cridar AuthorizeSecurityGroupIngress; Config diu com va quedar el grup de seguretat, si compleix, i ho arregla. I saps que Config depèn de CloudTrail per assabentar-se dels canvis: no competeixen, es donen suport.

Has activat l'enregistrador grabador-mercadofresco amb el seu rol de només lectura, el seu canal cap a mercadofresco-config-historial i el seu tema d'SNS, amb les dues decisions que valen diners: allSupported: false amb llista explícita, i recordingFrequency: DAILY per a instàncies i volums, que és l'optimització més rendible i menys coneguda del servei. I saps que crear no és engegar: start-configuration-recorder.

Coneixes les 29 regles gestionades que MercadoFresco activa, cadascuna lligada a alguna cosa que vam construir en un mòdul anterior —s3-bucket-server-side-encryption-enabled per 04-02, restricted-ssh per 03-02, cloudtrail-enabled per 05-03, cw-loggroup-retention-period-check per l'incident de 610 USD de 05-01— i la diferència entre activació per canvi (minuts, però s'avalua a cada canvi) i periòdica (fins a 24 hores, però cost fix i única opció per a comprovacions de compte). required-tags t'ha trobat el forat que ningú no veia: els volums EBS creats per l'ASG no hereten etiquetes, i al mòdul 11 haurien aparegut com a cost sense assignar.

Saps escriure regles pròpies: amb Lambda quan necessites cridar altres API o calcular amb dates —retornant NOT_APPLICABLE en lloc de COMPLIANT, tractant ResourceDeleted i escrivint una Annotation útil— i amb Guard, declaratiu, sense runtime, sense cost extra i sense manteniment, que és el que cal fer servir per defecte quan n'hi ha prou amb mirar l'element de configuració.

I has muntat la remediació automàtica amb documents de Systems Manager, que és el que converteix Config en una eina operativa: AWS-EnableS3BucketEncryption restaura el xifratge d'un bucket en vuit minuts sense intervenció humana, RemoveUnrestrictedSourceIngressRules tanca un grup de seguretat obert, i SetCloudWatchLogGroupRetention posa 30 dies a qualsevol grup de registres nou. Amb el rol de remediació separat del de Config, amb permisos acotats per prefix i per etiqueta, i sense AuthorizeSecurityGroupIngress: el rol pot tancar, mai obrir. I amb el procediment innegociable de quatre fases —detecció, remediació manual, automàtica en desenvolupament, automàtica en producció— i la regla que ho resumeix tot: automatitza el que afegeix seguretat i és reversible; mai el que és destructiu ni el que treu disponibilitat.

Coneixes els paquets de conformitat alineats amb CIS, PCI DSS, NIST i RGPD, amb l'advertència que cal repetir sempre: desplegar el paquet de PCI DSS no et fa conforme amb PCI DSS. I el quadre de compliment t'ha donat el resultat que justifica el servei sencer: sis regles no conformes i catorze recursos, entre ells un bucket sense xifrar des del març, un port 22 obert des del maig i el grup de seguretat per defecte amb regles. Catorze problemes que feia mesos que eren allà i que no haurien disparat mai una alarma de CloudWatch ni haurien aparegut en una investigació de CloudTrail, perquè no eren esdeveniments: eren estats.

I tens les consultes avançades, gratuïtes, que inventarien el compte en segons: buckets sense xifrar, volums sense associar que es paguen cada mes sense servir per a res, recursos sense CentroCoste. Amb l'agregador per a la vista multicompte que arribarà a 09-04, i el repartiment clar de feina amb GuardDuty —que detecta intrusions, no configuracions— i Security Hub, que agrega les troballes de tots.

Tot per uns 6,40 USD al mes, enfront dels 216 USD que costaria exactament la mateixa capacitat de detecció sense les tres decisions de configuració correctes. Aquest factor de trenta- quatre és el resum de per què aquesta lliçó dedica una secció sencera al cost.

Amb això queden respostes les cinc preguntes del mòdul 4. L'avís arriba de debò, els registres estan correlacionats, la comanda de vuit segons té culpable i arranjament, sabem qui va desxifrar la còpia, i ara res no pot desactivar el xifratge d'un bucket sense que salti un avís —i es corregeixi sol en vuit minuts—.

Queda una última peça, i és diferent de tot l'anterior. Config comprova les regles que tu li has dit. És potent i és exacte, però té un límit evident: no et pot avisar del que no se t'ha acudit. No sap que tens tres volums EBS orfes costant diners, ni que hi ha una IP elàstica sense associar que es factura per no fer-se servir, ni que l'asg-mercadofresco-tienda és a punt de xocar amb una quota de servei que ningú no ha mirat mai, ni que una de les teves instàncies fa dos mesos que està al 4 % de CPU. Ningú no ha escrit regles per a això, i ningú no les escriurà, perquè per escriure-les caldria sospitar primer que el problema existeix.

Hi ha un servei que fa precisament aquest repàs: comparar el teu compte amb les bones pràctiques que AWS ha destil·lat de milions de clients, i dir-te el que no havies pensat a preguntar. A la lliçó 05-05, «AWS Trusted Advisor», veurem les seves cinc categories —optimització de costos, rendiment, seguretat, tolerància a errors i límits de servei—, quines comprovacions veus de debò amb el pla de suport Basic i quines no, com suplir el que falta amb el que ja saps, un recorregut comentat per un informe real de l'arquitectura de MercadoFresco, les quotes de servei i el cas concret de l'ASG que no pot passar de quatre instàncies per un límit de vCPU que ningú no havia mirat, i la rutina de revisió mensual que adopta la Marta. I amb ella tancarem el mòdul sencer.

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