ESEN

What changed in the fine print

Every gotcha added, fixed, re-verified or removed, taken from the repo history. Also as an Atom feed for your reader.

⌁ Subscribe (Atom)

· fix(content): respalda con fuente o reformula los hallazgos de la verificación de centralized-audit-logging

commit 6d37065

  • FixedAWSCloudTrail creates the organization trail in member accounts even if the bucket or key validation fails(sources changed)
    Show the change

    CloudTrail creates the organization trail in member accounts even if a resource validation fails; the documentation gives an incorrect bucket policy and insufficient permissions to encrypt with a KMS key as examples. A successful apply doesn't prove there is delivery. Check get-trail-status: if there is a problem with the bucket, the LatestDeliveryError field shows the S3 error (it only appears for problems with the destination bucket, not for requests that time out). Fix it with the bucket policy, or by creating another bucket and calling update-trail.

  • FixedAWSIn the official example, an organization trail's bucket policy needs its own statement and the logs are accessible only to management
    Show the change

    Scope of the source: the official example is a bucket owned by the organization's management account; the documentation doesn't cover a bucket in another account (such as this module's log archive account), so test it in a non-production environment. The bucket of an organization trail needs a policy that lets CloudTrail write the organization's logs: the official example has three statements (GetBucketAcl, PutObject on the management account prefix and PutObject on the AWSLogs/o-<organization id>/ prefix). The aws:SourceArn must be the ARN of a trail owned by the management account, using that account's ID. That policy doesn't give access to users in member accounts: by default, the organization's log files are accessible only to the management account. List explicitly who you want to grant read access to and don't assume member accounts can read.

  • FixedAWSIf a multi-Region trail's home Region is opt-in, only accounts that enabled that Region send activity(sources changed)
    Show the change

    If the organization trail is multi-Region and its home Region is an opt-in Region, member accounts don't send activity to the trail unless they opt into that Region; the documentation's example is Europe (Spain): only accounts that enabled it send their activity. Organization trails created in the console are multi-Region. Choose a Region that is enabled by default as the home Region, or verify that each account enabled the Region; if an account doesn't show up in the bucket, check this point.

  • FixedAWSA misconfigured trail retries delivery for 30 days and those attempts are charged(sources changed)
    Show the change

    If the trail is misconfigured (for example, the bucket is unreachable), CloudTrail attempts to redeliver the log files to the bucket for 30 days, and those delivery attempts are subject to standard CloudTrail charges. To avoid charges on a misconfigured trail you need to delete it. Fix the bucket policy and the key policy before creating the trail (in Terraform, with a depends_on of the trail on both) and check get-trail-status afterwards.

· fix(content): respalda con fuente o reformula los hallazgos de la verificación de preventive-guardrails

commit 004f543

  • FixedAWSTest SCPs and RCPs in an OU or test accounts before moving up to the root; removing FullAWSAccess without a replacement cuts all actions
    Show the change

    AWS strongly recommends not attaching an SCP to the root without testing its impact on the accounts: create an OU and move accounts into it one at a time, or in small groups, so you don't lock anyone out of key services. For RCPs it recommends starting with test accounts, moving up through the OUs and reviewing CloudTrail for Access Denied errors. Also, don't remove the FullAWSAccess policy without modifying it or replacing it with another that has the allowed actions: otherwise all AWS actions from member accounts fail. For an S3 policy, after each change check the effective policy of representative accounts with DescribeEffectivePolicy.

· fix(content): respalda con fuente o reformula los hallazgos de la verificación de protected-origin-cdn

commit ff55dad

  • FixedGCPIf the bucket stays public, signed URLs don't protect the content
    Show the change

    For signed URLs to protect the content, the origin must not grant public access: the documentation says to remove the allUsers (and allAuthenticatedUsers, if applicable) read permissions from the bucket, which is commonly left public during testing. Even without public access, anyone who already has permission on the bucket, such as OWNER, can access Cloud Storage without a signed URL. And a signed URL gives time-limited access to anyone who holds it, whether or not they have a Google Account. The same page warns that Cloud CDN doesn't block requests without a Signature query parameter or Cloud-CDN-Cookie cookie (it rejects those with invalid parameters) and that the origin must validate signatures and accept or reject unsigned requests. Check that the bucket has neither allUsers nor allAuthenticatedUsers before calling the entry closed, and sign only HTTPS URLs.

· feat(content): patrón borrador centralized-audit-logging con Terraform validado

commit 3a7ea88

  • NewAzureThe Activity Log is deleted after 90 days; to keep it longer you have to export it with a diagnostic setting
  • NewAzureA diagnostic setting on the management group doesn't capture every subscription-level event
  • NewAzureThe destination can be in another subscription if whoever creates the setting has RBAC access to both
  • NewAzureA destination storage account with virtual networks must allow trusted services and can't be Premium
  • NewAzureExporting the Activity Log to Log Analytics has no ingestion charge; retention is charged only past 90 days
  • NewAWSCloudTrail creates the organization trail in member accounts even if the bucket or key validation fails
  • NewAWSAn organization trail's bucket policy needs its own statement, and by default only management reads the logs
  • NewAWSIf a multi-Region trail's home Region is opt-in, only accounts that enabled that Region send activity
  • NewAWSLogs encrypted with KMS can only be read by whoever has kms:Decrypt: grant it before attaching the key to the trail
  • NewAWSEnabling integrity validation delivers digest files, but validates nothing
  • NewAWSA misconfigured trail retries delivery for 30 days and those attempts are charged
  • NewGCPAn organization or folder sink with includeChildren set to false only exports the parent resource's own logs
  • NewGCPThe sink doesn't export until its writer identity has write permission on the destination
  • NewGCPIf the destination is a project, Admin Activity and System Event logs aren't stored in it without a sink of its own
  • NewGCPAn aggregated sink that intercepts takes logs away from the child projects' sinks
  • NewGCPA destination inside a VPC Service Controls perimeter requires an ingress rule for the sink's identity
  • NewGCPData Access logs are enabled at the source, at organization or folder level; the sink only routes what exists
  • NewGCPA bucket's retention in an organization or folder can't be extended, and locking a bucket is irreversible

· feat(content): patrón preventive-guardrails (borrador) con Terraform validado

commit e42985e

  • NewAzureWith deny, an existing account that doesn't comply can't take configuration changes until it's fixed
  • NewAzureWith the audit effect, the account with anonymous access is created anyway
  • NewAzureIn DoNotEnforce mode the assignment evaluates compliance without applying the effect
  • NewAzureAn Azure Policy exemption only expires if you set expiresOn, and once expired it stays as a record
  • NewAWSSCPs don't reach the management account or service-linked roles
  • NewAWSAn SCP doesn't stop external principals accessing an organization's bucket; that's what RCPs are for
  • NewAWSAn S3 policy applies to all S3 resources in the accounts it reaches: the exception is handled by OU or account
  • NewAWSWith the S3 policy, public access that already existed is ignored; it isn't removed
  • NewAWSTest the policy in an OU before attaching it to the root; removing FullAWSAccess without a replacement cuts all actions
  • NewAWSDisabling the SCP policy type in a root detaches all SCPs, and the attachments are lost
  • NewGCPWith the constraint enforced, allUsers permissions that already existed stay in place, overridden
  • NewGCPThe exception to the constraint is made per project, and a bucket with the enforced setting stays protected
  • NewGCPThe storage.publicAccessPrevention constraint isn't among those that support dry-run
  • NewGCPPrevention takes time to apply and doesn't affect signed URLs

· feat(content): patrón protected-origin-cdn (borrador) con Terraform en las tres nubes

commit 4b9b896

  • NewAzureAn origin group can't mix public origins and Private Link origins
  • NewAWSCloudFront's access to the bucket is limited to your distribution with the AWS:SourceArn condition
  • NewAWSA bucket configured as a website endpoint can't use OAC
  • NewAWSWith SSE-KMS the distribution also needs permission on the key
  • NewGCPCloud CDN reads the bucket with its own service account, which appears when you add the first key
  • NewGCPIf the bucket stays public, signed URLs don't protect the content
  • NewGCPCloud CDN caches responses to signed requests regardless of the origin's Cache-Control

· fix(content): ajusta a su fuente las frases parciales de gcp que dejó la segunda verificación

commit 651a32f

  • FixedGCPPrincipals use the project number, and permissions take minutes to propagate
    Show the change

    TheWhen principalSetgranting androles theto workload_identity_providerexternal youidentities passyou touse the action areproject projects/NUMBER/locations/global/...,number, not the project ID.ID: the principalSet is principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/.... Also, an IAM change usually applies within 2 minutes but can take 7 or more, so a freshly configured pipeline can fail its first run with nothing actually wrong.more.

  • FixedGCPTo Type 1 and 2 targets queries come from 35.199.192.0/19; with Type 2, on-premises needs a route to it
    Show the change

    Cloud DNS doesn'tuses usethe your35.199.192.0/19 VPC'srange IPsfor toall forward:customers, everyand queryit is the source of queries to aType forwarding1 targetand comesType from2 35.199.192.0/19.targets The(VPC internal IPs and on-premises firewallover mustVPN allowor UDPInterconnect). andType TCP3 53targets fromuse thatGoogle range,Public DNS source ranges, and for Type 4 the range depends on the IPs the name resolves to. For a Type 2 target, on-premises needs a return route through theto VPN35.199.192.0/19 tunnelswhose ornext Interconnecthop attachmentsis in the same VPC. With BGPVPC, that'sthrough a customCloud advertisementVPN ontunnel theor a Cloud Router.Interconnect WithoutVLAN theattachment. route,With theBGP on-premisesthat's DNSa getscustom theroute queryadvertisement andon the replyCloud isRouter's lost.BGP session.

  • FixedGCPPrivate Google Access gives reach to Google APIs; filtering the bucket's origin is another control(sources changed)
    Show the change

    PrivateVM Googleinstances Accessthat only letshave VMsinternal withoutIP publicaddresses IPscan use Private Google Access to reach Google APIs.APIs Toand restrictservices. That solves reachability, not origin filtering. Bucket IP filtering lets you needrestrict access to the bucket based on client IP filteringranges orand VPC Servicenetworks, Controls.and works alongside IAM.

  • FixedGCP"Internal" is a network control; authentication is separate IAM
    Show the change

    With internal ingress, Cloud Run rejectsonly accepts requests notfrom comingsources fromsuch as VPCs in the same projectproject, (ora VPC SC perimeter)perimeter or an internal Application Load Balancer, and from otherproducts Googlesuch services,as evenCloud viaScheduler, Cloud Tasks, Eventarc, Pub/Sub or Workflows if they're in the same project or perimeter and use the default run.app URL. Other sources, including the internet, can't reach it. But IAM authentication still applies: the client must present an ID token and its service account needs roles/run.invoker.

· fix(content): ajusta a su fuente las frases parciales de aws que dejó la segunda verificación

commit acdfa6c

  • FixedAWSFor GitHub, IAM doesn't use the thumbprint to verify (and you don't need to set it)
    Show the change

    IAM validates GitHub's certificate against its library of trusted root CAs, so thumbprint_list is optional and, in the Terraform provider, for IdPs like GitHub it's stored but not used for verification. Thumbprints only come into play if the IdP uses a certificate not signed by one of those CAs, or if AWS can't retrieve the TLS certificate or TLS v1.3 is required. Many old modules still hardcode a thumbprint "that must be rotated": for GitHub that's not what breaks login.

  • FixedAWSForwarding from on-premises to the VPC's .2 address isn't supported
    Show the change

    The VPC resolver (CIDR baseAWS +states 2)that answersforwarding resourcesprivate inDNS thequeries VPC.to AWSany statesVPC thatCIDR forwardingbase queries+ to2 itaddress from on-premises or other VPC DNS servers isn't supported and can givecause unstable results, even if it sometimes seems to work. That's what the inbound endpoint isresults. for,Instead, justAWS likerecommends Azure'susing ora GCP'sResolver inbound policy.endpoint.

  • FixedAWSThe private hosted zone must be associated with the inbound endpoint's VPC
    Show the change

    The inbound endpoint resolves with what its VPC sees. IfFor the zone is associated only with application VPCs,VPC on-premisesResolver getsto NXDOMAINresolve eveninbound thoughDNS everythingqueries resolvesusing finethe fromrecords thein VMs.a Inprivate multi-accounthosted setups,zone, the zone must also be associated with the hubVPC VPC.where you created the inbound endpoint.

  • FixedAWSBlock Public Access and disabled ACLs are default on new buckets (but declare them anyway)
    Show the change

    SinceBy default, Object Ownership is BucketOwnerEnforced and all ACLs are disabled. AWS announced that, starting in April 20232023, S3 enableswould enable Block Public Access and disablesdisable ACLs on all new buckets (Object Ownership set to BucketOwnerEnforced).buckets, It'swith no longer "the"change differencefor withexisting Azure.ones. Still declare them in IaC: existing buckets didn't change, and declaring the state prevents drift if someone edits them in the console.

  • FixedAWSThe IAM auth token lasts 15 minutes and is only used to open the connection
    Show the change

    The token expires after 15 minutes and is used only to authenticate: it doesn't affect the session once established, but an expired token makes a new connection request fail. An app that opens a connection per request must generate a freshif tokenyou eachtry time;to keepconnect awith poolan andexpired refreshtoken, the token when openingconnection newis connections.rejected.

  • FixedAWSFargate in a private subnet without NAT needs several paid VPC endpoints
    Show the change

    To pull the image and ship logs without internet egress, the task needs ECR (api and dkr) and CloudWatch Logs interface endpoints, plus the S3 gateway endpoint (where ECR stores layers). If it uses the awslogs log driver, it also needs the CloudWatch Logs interface endpoint. Each interface endpoint is billed hourly per AZ. The alternative (NAT Gateway) is also billed hourly and per GB.

  • FixedAWSHTTPS on an internal ALB still needs an SSL server certificate
    Show the change

    To create an HTTPS listener you must deploy at least one SSL server certificate (from ACM or IAM). ACM requires proving domain ownership for a public certificate via DNS, email or HTTP, and cannot validate resources in a VPC private hosted zone or any other private domain, even if the ALB is internal. ACM does not validate domain ownership for imported certificates or for certificates signed by a private CA.

  • FixedAWSLet Secrets Manager manage the master user password
    Show the change

    With manage_master_user_password = true, RDS generates the master password and stores it in Secrets Manager. The Terraform provider doesn't allow combining it with password, and RDS doesn't support it in some scenarios (for example Blue/Green deployments), so decide upfront.

· fix(content): ajusta a su fuente las frases parciales de azure que dejó la segunda verificación

commit 6efb439

  • FixedAzurePrivate networking on Service Bus requires Premium, which has a high fixed cost
    Show the change

    Private Endpoints, VNet rules and CMK onlyrequire existPremium-tier innamespaces, Premium,which are billed per messaging unit per hour even with zero messages.unit. Standard only supports IP firewall rules. This pattern uses Standard with Entra ID-only auth: if the requirement is private networking, you have to move to Premium. In AWS, SQS connects through an interface VPC endpoint.

  • FixedAzureThe scale rule authenticates with the identity property, not auth
    Show the change

    KEDA queriesFor the queue length on its own. Toscale haverule itto use a managed identity, the scale rule usesset the identity property instead of auth. The portal can'tdoesn't configuresupport it: use IaC or CLI.

  • FixedAzureRole assignments are per account or container; by prefix you need ABAC conditions
    Show the change

    In S3Azure youStorage scopesupports therole policyassignments tofor arn:...:bucket/incoming/*both andstorage inaccounts GCPand youblob usecontainers. IAMTo Conditionsscope by prefix. In Azure a role assignment reaches the container at minimum; to scopeprefix byor path you need ABAC conditions on the role assignment.assignment (Blob prefix and Blob path attributes). Simple alternative: a container dedicated to ingestion (what this module does).

  • FixedAzurePrivate Endpoint without a private DNS zone: the service firewall can answer 403
    Show the change

    Creating the Private Endpoint is not enough: the FQDN <account>.blob.core.windows.net must resolve to the private IP via the privatelink.blob.core.windows.net zone linked to the VNet (or your hybrid DNS). If it resolves to the public IP,IP and the serviceaccount firewallhas a firewall, it rejects the request with 403 and looks like a permissions issue.

  • FixedAzureARM adds Entra admins; the app's role is created with SQL
    Show the change

    Terraform/ARM adds Entra principals are added as administrators (azure_pg_admin,from CREATEROLE,the CREATEDB).Azure portal or the ARM API. With isAdmin=true, pgaadauth_create_principal gives them azure_pg_admin, CREATEROLE and CREATEDB. For the app identity to be a regular user, an Entra admin can run pgaadauth_create_principal('<name>', false, false). For managed identities and service principals the name is the display name. The module outputs the exact SQL.

  • FixedAzureStopping the database stops compute billing, but it restarts on its own after 7 days
    Show the change

    ACA can go down to zero replicas, but PostgreSQL Flexible bills compute while it's on. Stopping it stops compute billing (not storage), but the service automatically restarts it after 7 days. For dev environments, automate the stop instead of relying on a manual one.

· fix(content): respalda o recorta los hallazgos de la verificación independiente de hub-and-spoke

commit 99b711a

  • FixedAzureSpoke-to-spoke through the firewall needs a UDR in every spoke and peerings that accept forwarded traffic
    Show the change

    VNet peering is a nontransitive relationship: two spokes peered with the same hub can't see each other. For the hub to connect them, the subnets in each spoke need a UDR pointing to Azure Firewall as the default gateway, and the peerings must accept forwarded traffic. If either is missing, spoke-to-spoke traffic either doesn't arrive or doesn't go through the firewall. Make the UDR part of onboarding each spoke, not a separate manual step.

  • FixedAWSWithout appliance mode on the inspection attachment, request and response can cross different AZs
    Show the change

    When appliance mode isn't enabled, the transit gateway keepsattempts to keep traffic in the originating AZ. With it enabled, it selects a single network interface in the inspection VPC using a flow hash for the life of the flow and uses the same one for return traffic, so bidirectional traffic is symmetric. A stateful firewall needs to see both the request and the response. Enable it on the inspection VPC's attachment (in Terraform, appliance_mode_support = "enable") and connect exactly one transit gateway to that VPC: with several, AWS doesn't guarantee flow stickiness. Changing it on an existing attachment can alter its current routing.

  • FixedGCPRoutes to on-premises and custom static routes don't cross the peering unless you turn on export and import
    Show the change

    Subnet routes are always exchanged (except IPv4 subnet routes using privately used public IPv4 addresses), but dynamic routes and IPv4 static routes without network tags with a next hop other than the default internet gateway aren't exported or imported by default. You enable them with --export-custom-routes on the VPC that has them and --import-custom-routes on the one that receives them. Static routes with network tags or with the default internet gateway as next hop can't be exported or imported. ATo spokeprovide thata doesn'tpath importfrom on-premises to the hub'speered routesVPC, can'tyou reachalso on-premiseshave throughto configure Cloud Router custom advertisement mode with the hub.peered VPC's subnet ranges.

  • FixedGCPWith Network Connectivity Center the design changes: there are limits to using peering between VPC spokes
    Show the change

    NCC VPC spokes exchangecan export and import all subnet routes withfrom the other spokes on theVPC hub.spokes. You can't use VPC Network Peering between two VPC spokes that are also connected through an NCC hub, and static route exchange across VPC spokes isn't supported,supported. andYou incan thehave staran topologyNCC-connected NCCVPC doesn'tspoke connectpeered thewith a separate VPC that isn't part of NCC, and use peering between two VPC spokes in the edge group to eachof other.a Choosehub thewith modelstar beforetopology, creatingbecause theNCC VPCs,doesn't becauseconnect youthe can'tspokes mixin themthat betweengroup theto sameeach spokes.other.

  • FixedGCPThe firewall endpoint is zonal, a VPC associates with only one endpoint per zone, and it only inspects traffic that a rule selects
    Show the change

    A firewall endpoint is a zonal resource, and the association links it to a VPC network in the same zone. A VPC network can associate with only one endpoint per zone, organization-level or project-level. Cloud NGFW redirects traffic to the endpoint only when it matches a policy rule with the apply_security_profile_group action. ToAn coverendpoint thecan zonesbe whereattached workloadsto run,one createor onemore endpointVPC networks in the same zone, and if a VPC network spans several zones you attach one associationendpoint per zone; in a zone andwith perno VPC,endpoint andattached checkthere is no layer 7 inspection. Check that every flow to inspect has its rule.

· fix(content): respalda o recorta los hallazgos de la verificación independiente de controlled-egress

commit df57e76

  • FixedAzureWithout an explicit outbound method the VM uses an IP that Microsoft owns and can change
    Show the change

    A VM without an explicit outbound method gets a default outbound public IP. That IP is owned by Microsoft and can change without notice, so it is no good for a third-party allowlist. For the API version released after March 31, 2026, subnets in new VNets have defaultOutboundAccess set to false; existing VNets don't change, and new VMs in them keep getting the default IP unless the subnet is made private. Tools that pin an earlier API version (the doc names Terraform) leave the value as null, which allows implicit outbound access. Declare an explicit method (NAT Gateway) and set the subnet to private explicitly; existing VMs must be stopped and deallocated for the change to take effect. WithoutIn a private subnet without explicit outbound, Windows Update and Windows activation don't work.

  • FixedAzureNAT Gateway and Azure Firewall are billed hourly, plus per GB processed
    Show the change

    The NAT Gateway pricing page charges resource hours and data processed (outbound and return traffic), and states that the hourly rate is charged regardless of the NAT gateway having subnets or public IPs attached; bandwidth charges also apply. Azure Firewall charges a fixed hourly fee per deployment, regardless of scale, plus a per-GB processed charge. With both in the path, both meters run. If you don't need to filter by destination, the NAT gateway alone already gives the fixed IP without the firewall.

  • FixedAWSThe Network Firewall domain list relies on the SNI or Host, not on IPs, and by default looks at its own VPC's traffic
    Show the change

    For HTTPS, Network Firewall uses the SNI from the TLS handshake and for HTTP the Host header; it doesn't pause the connection to do DNS lookups or evaluate IPs, so it relies on what the client asserts. A domain list can't scope by port or by a single protocol: for that you need Suricata or 5-tuple stateful rules. By default inspection uses the CIDR of the firewall's VPC as HOME_NET; to filter traffic from other VPCs (for example through a transit gateway) you must set HOME_NET to include those CIDRs. With the Allow action the firewall denies non-matching traffic only if the policy uses default action order; under strict order that denial doesn't apply. If you also want to validate the domain the destination IP was resolved for, the AWS_ROUTE_53_RESOLVED_DOMAIN target exists.

  • FixedGCPCloud NAT allocates ports per VM: the default minimum is low and you need to size the ports
    Show the change

    Each NAT IP address offers 64,512 TCP source ports. If you don't specify the minimum ports per VM, the default applies: 64 with static allocation and 32 with dynamic, and for Public NAT the default allocation is static. With static allocation a VM can't use more than its allocated ports, even during traffic bursts. In addition, the gateway can process 1,024 simultaneous connections to each unique destination 3-tuple. The doc recommends dynamic allocation if egress usage varies, but it can't be combined with endpoint-independent mapping and, while additional ports are being allocated, you might see timeouts or latency. Dropped packets are logged only ifwhen you turn onuse Cloud NAT logging to turn on error logging. The module enables dynamic allocation and error logging.

  • FixedGCPCloud NAT adds up four charges: gateway per hour, GiB processed, external IPs per hour and outbound transfer(sources changed)
    Show the change

    For Public NAT, the pricing page defines the total cost as the gateway's hourly cost plus the cost per GiB processed by the gateway, the hourly cost of the external IP addresses it uses and the cost of outbound data transfer. The gateway's hourly price depends on the number of VMs using it and is capped at 32 VMs. When budgeting, add up all four parts: with static IPs reserved for the allowlist, each IP is charged hourly. Separately, the Cloud NGFW pricing page says that when a traffic flow is evaluated by a rule containing Cloud NGFW Standard features you are charged for data processing, and it lists FQDN objects among those features.

  • FixedGCPFQDN objects resolve to IPs: no wildcards, capped at 32 IPv4 and 32 IPv6, and not suited for googleapis.com
    Show the change

    Cloud NGFW periodically resolves each FQDN object to IPs, following the VPC's Cloud DNS name resolution order. It doesn't support wildcards (`*`) or top-level domains. Each FQDN object maps to a maximum of 32 IPv4 and 32 IPv6 addresses, and the extra ones are dropped. If the answer is NXDOMAIN, has no usable IP or the DNS server is unreachable, the object is ignored. The doc says to avoid A records with a TTL under 90 seconds and notes that most Google domain names, such as googleapis.com, fall under these situations: it recommends IP addresses or address groups. It also can't be used if the VPC has an outbound server policy.policy with an alternative name server. A DNS query can return different answers depending on the client's location, so the programmed IPs may not include every address of the domain. Use FQDNs for third-party APIs with stable DNS and check each domain's TTL.

  • FixedGCPTraffic to Google APIs doesn't leave through Cloud NAT: it goes through Private Google Access
    Show the change

    The Cloud NAT doc says that traffic sent to Google APIs and services is routed through Private Google Access, even when the VM uses Public NAT. Those calls don't leave with the NAT IPs, so a control that depends on the egress IP doesn't apply to those destinations. Don't expect to see the NAT IP on those calls, and treatTreat Google domains separately in the egress rules.

· fix(content): respalda o recorta los hallazgos de la verificación independiente de app-secrets

commit 2c819ba

  • FixedAzureThe Private Endpoint isn't enough: if the private zone isn't linked to the VNet, the vault resolves to its public IP
    Show the change

    For the VNet to reach the vault through the Private Endpoint you need a private zone named exactly privatelink.vaultcore.azure.net, linked to that VNet and holding the vault's A record. If the zone isn't linked, the query returns the public IP. With public network access disabled and no firewall allow-list, the service rejects every request at that ingress, so the symptom is an access error, not public traffic.ingress. From on-premises you need conditional forwarders for vault.azure.net and vaultcore.azure.net to a resolver with access to Azure resolution (see the hybrid private DNS pattern). The vault name still resolves in public DNS even when the vault is private: don't put environment or customer in the name if that's part of your threat model.

  • FixedAzureKey Vault tells you the secret is about to expire; changing the credential at the third party is yours to build
    Show the change

    Thirty days before a secret's expiration date, Key Vault publishes the SecretNearExpiry event to Event Grid. To rotate, you have to create the event subscription and provide the function that creates the new version in the vault and updates the external service. Microsoft's tutorial shows it for a SQL Server password. Between those two steps there can be a lag during which the vault's secret doesn't authenticate, and if a step fails Event Grid retries for two hours. The event depends on the secret having an expiration date. If the vault is private, the function has to reach it: the two-credential tutorial's template asks for a Premium plan only when the vault is behind a firewall.

  • FixedAzureKey Vault encrypts secrets with a service-owned key hierarchy; in AWS and GCP you pick a key of your own
    Show the change

    Key Vault stores all secrets as encrypted data, with a service-owned key hierarchy, and the documentation states that this encryption is transparent and requires no action from you. The keys you store in Key Vault serve, for example, as a wrapping key (BYOK) to encrypt Azure Storage data. In AWS, when you create a secret you can pick a KMS customer managed key, and in GCP a Cloud KMS key (CMEK). If a compliance requirement demands controlling the key of the secrets store itself, check that Key Vault covers it before choosing it; the key role in this pattern is partial in Azure.

  • FixedAWSYou pay per secret, per replica, per KMS key and per endpoint hour and AZ
    Show the change

    Secrets Manager charges based on the number of secrets stored and API calls made. A replica counts as a distinct secret and is billed separately; creating new versions when rotating isn't charged and neither is a secret marked for deletion. Each KMS key you create has a monthly cost (prorated hourly), and the interface endpoint is billed for each hour it stays provisioned in each AZ. Use one subnet per AZ you actually need, one secret per credential, and replicas only if another region requires them. Each GetSecretValue is a billable call: read the secret at startup or cache the value.

  • FixedGCPThe latest alias can roll out a bad value immediately; in production reference a version number
    Show the change

    The latest alias points to the most recently added version. Google describes it as convenient for development but problematic for some production workloads, because a bad value can be rolled out immediately and cause a service-wide outage. The best practices guide asks to reference secrets by version number and deploy changes through your release process, and to disable a version before destroying it so the step is reversible. Every rotation adds a version and moves latest:version: resolve the number when rotating, store it in the deploy configuration and read it at startup.

  • FixedGCPReading the secret value is a Data Access log, and those logs are off by default
    Show the change

    AccessSecretVersion requires a DATA_READ permission and generates a Data Access audit log. Those logs are disabled by default for all services except some BigQuery ones, so you have to enable them explicitly. In the meantime, AdminOperations Activitythat logsmodify recordversions changes(add, todisable, thedestroy) secretare butADMIN_WRITE notand whogo readto theAdmin value.Activity. The best practices guide recommends enabling data access logs to analyze AccessSecretVersion requests, and doing it at the folder or organization level so you don't configure it in every project.

  • FixedGCPPrivate Google Access doesn't cover regional endpoints, which are the ones for Secret Manager's regional service
    Show the change

    Private Google Access is a per-subnet setting: it lets VMs that only have an internal IP reach the external IPs of Google APIs, and has no effect on instances with an external IP. If you disable it, those VMs lose access. It doesn't support regional and multi-regional endpoints, the ones ending in rep.googleapis.com. Secret Manager's regional service is accessed through a regional endpoint (secretmanager.<location>.rep.googleapis.com in the documentation's examples) and its secrets can only be accessed from that region. ForGoogle thatdocuments youhow needto ause Private Service Connect endpointendpoints to thereach regional endpoints.

· feat(content): borrador del patrón app-secrets (secretos de aplicación)

commit 120904b

  • NewAzureA deleted vault keeps its name during retention, and recovering it loses the role assignments
  • NewAzureWith access policies, whoever can write the vault can grant themselves secret access; with RBAC they can't
  • NewAzureThe Private Endpoint isn't enough: if the private zone isn't linked to the VNet, the vault resolves to its public IP
  • NewAzureKey Vault tells you the secret is about to expire; changing the credential at the third party is yours to build
  • NewAzureWithout a diagnostic setting, nobody records who read the secret
  • NewAzureIn Key Vault you don't pick the key that encrypts the secrets; in AWS and GCP you do
  • NewAzureEvery secret read is a billable operation, and the Private Endpoint is billed hourly
  • NewAWSThe rotation function must reach Secrets Manager, and in a VPC without internet that means an endpoint
  • NewAWSThe endpoint's default policy allows full access to Secrets Manager
  • NewAWSRequiring the endpoint in the secret's policy also denies anyone reading from outside the VPC
  • NewAWSThe secret's name, description, tags and rotation settings aren't encrypted
  • NewAWSWith your own CMK, reading the secret needs permission on both the secret and the key
  • NewAWSYou pay per secret, per replica, per KMS key and per endpoint hour and AZ, even if nobody reads
  • NewGCPThe latest alias rolls out a bad value immediately; in production reference a version number
  • NewGCPSecret Manager doesn't rotate the credential: it publishes a SECRET_ROTATE message and someone has to do the change
  • NewGCPReading the secret value is a Data Access log, and those logs are off by default
  • NewGCPPrivate Google Access doesn't cover regional endpoints, which are the ones for Secret Manager's regional service
  • NewGCPThe CMEK key must be in the replica's location, and if you disable or destroy it the secret becomes unreadable
  • NewGCPWith user-managed replication, a region outage fails writes, and the locations can't be changed
  • NewGCPEvery rotation adds an active version, and a disabled version keeps billing

· feat(content): add controlled-egress pattern draft (topology and gotchas)

commit a3a6bb6

  • NewAzureWithout an explicit outbound method the VM uses an IP that Microsoft owns and can change
  • NewAzureA Standard NAT gateway is zonal, and moving to StandardV2 forces new egress IPs
  • NewAzureA 0.0.0.0/0 route to the firewall overrides the subnet's NAT gateway: attach it to AzureFirewallSubnet
  • NewAzureNetwork FQDN rules require DNS proxy and don't allow wildcards; application rules cover only HTTP/S and MSSQL
  • NewAzureNAT Gateway and Azure Firewall are billed hourly even with no traffic, plus per GB processed
  • NewAWSA zonal NAT gateway lives in a single AZ: sharing it across AZs is a single point of failure
  • NewAWSEach NAT gateway IP supports up to 55,000 simultaneous connections to the same destination
  • NewAWSThe NAT gateway charges per hour and per GB processed; one NAT per AZ multiplies the fixed part
  • NewAWSThe Network Firewall domain list looks only at HTTP/HTTPS, by SNI or Host, and only at its own VPC's traffic
  • NewAWSNetwork Firewall charges per endpoint per AZ and per GB; with the NAT gateway in the same path, AWS waives the NAT charge
  • NewGCPCloud NAT allocates ports per VM: the default minimum is low and each destination has its own connection cap
  • NewGCPCloud NAT adds up four charges: gateway per hour, GiB processed, external IPs per hour and outbound transfer
  • NewGCPEgress is allowed by an implied rule: Cloud NAT is not the destination control
  • NewGCPFQDN objects resolve to IPs: no wildcards, capped at 32 IPv4 and 32 IPv6, and not suited for googleapis.com
  • NewGCPTraffic to Google APIs doesn't leave through Cloud NAT: it goes through Private Google Access

· feat(content): hub-and-spoke con inspección centralizada (borrador) y capability managed-firewall

commit 5732151

  • NewAzureSpoke-to-spoke through the firewall needs a UDR in every spoke and peerings that accept forwarded traffic
  • NewAzureA summarized UDR loses to the more specific peering route, and traffic bypasses the firewall
  • NewAzureThe firewall subnet must be named AzureFirewallSubnet, at least /26, and doesn't support NSGs
  • NewAzureFor spokes to use the hub's gateway you need three peering flags, and the spoke can't have its own gateway
  • NewAzureAzure Firewall charges a fixed hourly fee per deployment, plus data processing
  • NewAWSWithout appliance mode on the inspection attachment, request and response can cross different AZs
  • NewAWSWith the default route table every attachment sees every other, and inspection never runs
  • NewAWSOnly resources in AZs with an attachment ENI can reach the transit gateway
  • NewAWSA firewall endpoint can't filter its own subnet's traffic, and using another AZ's endpoint adds cross-zone charges
  • NewAWSEach attachment and each firewall endpoint is billed hourly, and data is billed per GB on both services
  • NewGCPTwo spokes peered with the same hub can't see each other: peering doesn't provide transitive routing
  • NewGCPRoutes to on-premises and custom static routes don't cross the peering unless you turn on export and import
  • NewGCPWith Network Connectivity Center the design changes: it can't be combined with peering between the same spokes
  • NewGCPThe firewall endpoint is zonal, associates with a VPC per zone, and only inspects traffic that a rule selects

· fix(content): respalda la comparación con SQS, prolija el envoltorio y agrega la guía de setup del mantenedor

commit 073bfb8

  • FixedAzurePrivate networking on Service Bus requires Premium, which has a high fixed cost(sources changed)
    Show the change

    Private Endpoints, VNet rules and CMK only exist in Premium, billed per messaging unit per hour even with zero messages. Standard only supports IP rules. This pattern uses Standard with Entra ID-only auth: if the requirement is private networking, you have to move to Premium. In AWS, SQS supportsconnects through an interface endpoint without changingVPC tier.endpoint.

· fix(content): respalda con fuente o recorta 17 gotchas parciales y sube el timeout del test del changelog

commit 82d0459

  • FixedAzurePrivate networking on Service Bus requires Premium, which has a high fixed cost
    Show the change

    Private Endpoints, VNet rules and CMK only exist in Premium, billed per messaging unit per hour even with zero messages. Standard only supports IP rules and also has a monthly base charge.rules. This pattern uses Standard with Entra ID-only auth: if the requirement is private networking, the cost floor changesyou byhave anto ordermove ofto magnitude.Premium. In AWS, SQS supports an interface endpoint without changing tier.

  • FixedAWSLimit the event source mapping's concurrency, not just the function's
    Show the change

    Onscaling_config.maximum_concurrency alimits messagehow spikemany Lambdaconcurrent scalesinstances fastof andthe function the queue can overwhelminvoke. It's an event source mapping setting, independent of the downstreamfunction's databasereserved orconcurrency API.and scaling_config.maximum_concurrencyfree limitsof howcharge, manyand concurrentit invocationskeeps theone queue triggers,from withoutusing all of the sidereserved effectsconcurrency ofor the function'saccount's concurrency quota. Note: the reserved concurrency (whichmust canbe alsogreater causethan throttlingor andequal retries).to the sum of the maximums of all the function's event sources; otherwise Lambda might throttle your messages.

  • FixedGCPWith push, the ack is the HTTP response and must arrive within the ack deadline
    Show the change

    Pub/Sub considers the message processed when the endpoint responds 2xx. Ifwith the102, worker200, takes201, longer202 thanor the204; ackany deadlineother (maxcode 600is s),a Pub/Subnack redeliversand itPub/Sub whileresends it'sthe stillmessage. running.The Alignsame ack_deadline_secondshappens withif the Cloudworker Runtakes servicelonger timeoutthan and,the forack longdeadline: jobs,Pub/Sub useredelivers pullit orwhile Cloudit's Runstill Jobs.running.

  • FixedGCPPub/Sub offers exactly-once delivery, but only on pull subscriptions
    Show the change

    It's the only one ofPub/Sub thesupports pattern'sexactly-once threedelivery servicesonly with native exactly-once delivery,pull butsubscriptions: push (what triggers Cloud Run) doesn't support it. Withit, push,because asthe withclient Servicedoesn't Busknow andwhether SQSPub/Sub Standard,received the workerresponse mustand beprocessed idempotent.it.

  • FixedAWSThere's only one OIDC provider per URL per account
    Show the change

    Creating a second provider for token.actions.githubusercontent.com in the same account failsfails: withIAM EntityAlreadyExists.doesn't let you register the same URL twice in an account. If each repo ships its own Terraform stack with the provider inside, the second apply breaks. Create it once (in the account stack) and reference it with the data source; the module supports that with create_oidc_provider = false.

  • FixedAWSFor GitHub, the thumbprint is no longer used (and you don't need to set it)
    Show the change

    IAM validates GitHub's certificate against its library of trusted root CAs, so thumbprint_list is optional and, in the Terraform provider sinceprovider, 5.0for and,IdPs iflike set,GitHub it's stored but not used for verification. Thumbprints only come into play if the IdP uses a certificate not signed by one of those CAs, or if AWS can't retrieve the TLS certificate or TLS v1.3 is required. Many old modules still hardcode a thumbprint "that must be rotated": for GitHub that's not what breaks login.

  • FixedGCPIdentifiers use the project number, and permissions take minutes to propagate
    Show the change

    The principalSet and the workload_identity_provider you pass to the action are projects/NUMBER/locations/global/..., not the project ID: with the ID, the token exchange fails.ID. Also, an IAM change usually applies within 2 minutes but can take 7 or more, so a freshly configured pipeline can fail its first run with nothing actually wrong.

  • FixedAWSA forward rule beats a private hosted zone with the same name(sources changed)
    Show the change

    If a VPC has a FORWARD rule for corp.example.com and also a corp.example.com private hosted zone, the rule wins. Among rules the most specific wins, and a SYSTEM rule excludes a subdomain from forwarding. In Azure it's the other way around: the linked private zone is checked before the ruleset.

  • FixedGCPForwarded queries come from 35.199.192.0/19, and on-premises must be able to reply to it
    Show the change

    Cloud DNS doesn't use your VPC's IPs to forward: every query to a forwarding target comes from 35.199.192.0/19. The on-premises firewall must allow UDP and TCP 53 from that range, and on-premises needs a return route through the VPN tunnels or Interconnect attachments in the same VPC and region.VPC. With BGP that's a custom advertisement on the Cloud Router. Without the route, the on-premises DNS gets the query and the reply is lost: it looks like a timeout.lost.

  • FixedGCPVPC Network Peering doesn't share private zones; you need peering zones(sources changed)
    Show the change

    AVPC peeredNetwork VPCPeering doesn't seeautomatically privateshare zonesDNS orinformation, forwardingso zonesa authorizedpeered onlyVPC fordoesn't resolve the hub VPC.VPC's zones on its own. In hub-and-spoke, each spoke needs a DNS peering zone to the hub, and transitive DNS peering only goes one hop. That's the difference from Azure, where a ruleset links to VNets that aren't even peered.

  • FixedAzurePrivate Endpoint without a private DNS zone = 403 from the VNet(sources changed)
    Show the change

    Creating the Private Endpoint is not enough: the FQDN <account>.blob.core.windows.net must resolve to the private IP via the privatelink.blob.core.windows.net zone linked to the VNet (or your hybrid DNS). If it resolves to the public IP, withthe publicservice accessfirewall disabledrejects the request fails with 403 and looks like a permissions issue.

  • FixedAWSExpiration is asynchronous, but billing stops at the expiration date(sources changed)
    Show the change

    S3 queues expirations and can take days to physicallyprocesses delete.them Unlikeasynchronously: Azure,anywhere youfrom don'tdays payto storageweeks forcan anpass expiredbetween objectthe evenexpiration ifdate itand stillthe showsactual updeletion. inYou're listings.not Samecharged asfor the otherexpiration clouds:or it'sfor notthe astorage securitytime control,of thean object remains readablethat untilhas it'salready deleted.expired.

  • FixedAWSIncomplete multipart uploads keep being billed(sources changed)
    Show the change

    PartsS3 fromkeeps the parts of a multipart upload thatuntil neveryou completedcomplete takeor upstop storageit, and don'ttheir showstorage upis whenbilled listingthe objects.whole time. Always add an AbortIncompleteMultipartUpload rule; ingestion bucketsrule: areaborting wherethe theyupload piledeletes upthe most.parts.

  • FixedGCPPrivate Google Access doesn't restrict who reaches the bucket
    Show the change

    Private Google Access only lets VMs without public IPs reach Google APIs. The bucket still accepts authenticated requests from the internet. To restrict origin you need bucket IP filtering or VPC Service Controls; the latter is organization-level and often out of reach for an application team.Controls.

  • FixedAzureStopping the database stops compute billing, but it restarts on its own after 7 days(sources changed)
    Show the change

    ACA can go down to zero replicas, but PostgreSQL Flexible bills compute while it's on. Stopping it stops compute billing (not storage), but the service automatically restarts it after 7 days. For dev environments, automate the stop instead of relying on a manual one.

  • FixedAWSFargate in a private subnet without NAT needs several paid VPC endpoints(sources changed)
    Show the change

    To pull the image and ship logs without internet egress, the task needs ECR (api and dkr) and CloudWatch Logs interface endpoints, plus the S3 gateway endpoint (where ECR stores layers). Each interface endpoint is billed hourly per AZ: it's the fixed cost that doesn't exist in ACA or Cloud Run.AZ. The alternative (NAT Gateway) is also billed hourly and per GB.

  • FixedGCPCloud SQL's private IP goes over a VPC peering that isn't transitive
    Show the change

    Private services access is implemented with VPC Network Peering to Google's network. AnotherIt VPConly peeredallows withconnections yoursfrom can'tone reachVPC, theand database,peering anddoesn't forprovide on-premisestransitive yourouting: mustanother exportVPC custompeered routeswith onyours can't reach the peering.database. If your topology is hub-and-spoke, consider Private Service Connect instead of PSA.

· fix(content): respalda con fuente o recorta 11 gotchas de iam y security marcados como parciales

commit ca78528

  • FixedAzureThe scaler needs an identity too, not just the container
    Show the change

    KEDA queries the queue length on its own. IfTo thehave namespaceit hasuse locala authmanaged disabled,identity, the scale rule must useuses the managed identity (identity_id on the rule); a connectionproperty stringinstead won'tof work.auth. The portal can't configure it: use IaC or CLI.

  • FixedAzureWith Contributor the pipeline can't create role assignments(sources changed)
    Show the change

    Contributor lacksdoes Microsoft.Authorization/roleAssignments/write.not allow assigning roles in Azure RBAC (it excludes Microsoft.Authorization/*/Write). If your Terraform assigns roles (say, an app's identity on a Key Vault), applyContributor failsis withnot AuthorizationFailed.enough. The quick fix is giving the pipeline Owner or User Access Administrator, which is exactly what you don't want. The right fix is Role Based Access Control Administrator with a condition limiting which roles it can assign (and excluding privileged ones).

  • FixedAWSIf the job declares an environment, the sub no longer contains the branch(sources changed)
    Show the change

    GitHub buildsincludes the subenvironment in prioritythe order:sub environment,when thenthe pull_request,job references one; pull_request and the ref only thenappear if the ref.job doesn't reference an environment. A job on main with environment production presents repo:org/repo:environment:production, so a trust policy expecting repo:org/repo:ref:refs/heads/main rejects AssumeRoleWithWebIdentity. Same on Azure and GCP; here the error is "Not authorized to perform sts:AssumeRoleWithWebIdentity".

  • FixedAzureThe smallest RBAC scope is the container, not the prefix(sources changed)
    Show the change

    In S3 you scope the policy to arn:...:bucket/incoming/* and in GCP you use IAM Conditions by prefix. In Azure a role assignment reaches the container at minimum; to scope by path you need ABAC conditions on the role assignment. Simple alternative: a container dedicated to ingestion (what this module does).

  • FixedAWSBlock Public Access and disabled ACLs are already default (but declare them anyway)(sources changed)
    Show the change

    Since April 2023 new buckets are createdS3 withenables Block Public Access and disables ACLs on andall Objectnew buckets (Object Ownership set to BucketOwnerEnforced.BucketOwnerEnforced). It's no longer "the" difference with Azure. Still declare them in IaC: olderexisting buckets didn't change, and declaring the state prevents drift if someone edits them in the console.

  • FixedAzureARM adds Entra admins; the app's role is created with SQL
    Show the change

    Terraform/ARM adds Entra principals as administrators (azure_pg_admin, CREATEROLE, CREATEDB). For the app identity to havebe leasta privilege,regular user, an Entra admin mustcan run pgaadauth_create_principal('<name>', false, false) and then the GRANTs.false). For managed identities and service principals the name is the display name. The module outputs the exact SQL.

  • FixedAWSHTTPS on an internal ALB still needs a certificate for a domain you control
    Show the change

    TheTo create an HTTPS listener needs anyou ACMmust certificate.deploy Aat publicleast ACMone certificateSSL isserver validatedcertificate via(from DNSACM or emailIAM). forACM arequires realproving domain evenownership iffor thea ALBpublic iscertificate internal;via theDNS, alternativeemail isor AWSHTTP, Privateand CA,cannot whichvalidate hasresources in a monthlyVPC fee.private Inhosted ACAzone andor Cloudany Runother theprivate platformdomain, manageseven if the defaultALB domain'sis certificate.internal.

  • FixedAWSThe master user always exists; let Secrets Manager manage its password(sources changed)
    Show the change

    With manage_master_user_password = true, RDS generates the master password and stores it in Secrets Manager: it never goesManager. throughThe variablesTerraform orprovider Terraformdoesn't state.allow It'scombining incompatibleit with passing apassword, passwordand manually,RDS anddoesn't isn'tsupport supportedit in some scenarios (for example Blue/Green deployments), so decide upfront.

  • FixedGCP"Internal" is a network control; authentication is separate IAM(sources changed)
    Show the change

    With internal ingress, Cloud Run rejects requests not coming from VPCs in the same project (or VPC SC perimeter) or from other Google services, even via the run.app URL. On top of that, byBut defaultIAM itauthentication requiresstill run.routes.invoke:applies: the client must sendpresent an ID token from an identity with roles/run.invoker. In ACA and the internal ALB the network is the only control unless you addits authservice inaccount theneeds app.roles/run.invoker.

· fix(content): corrige dos gotchas de AWS señalados por la pre-verificación

commit d6e8bba

· feat(patterns): hybrid private DNS (on-premises <-> cloud)

commit a5321b0

· feat(patterns): secretless CI/CD deployments with OIDC federation

commit c33734d

· feat(content): two new patterns, 26 capabilities and pattern scaffolder

commit 1277919

· feat(content): content-as-code schema, validator and object-storage-ttl pattern

commit 7276221