La nota sobre lo que sobrevive a una VM tiene un primo en serverless: el log group. Cuando una función Lambda se invoca por primera vez, CloudWatch crea /aws/lambda/<nombre> con retención "Never expire", y cuando borrás la función ese log group no se va con ella. La documentación de Lambda lo dice en una línea: "Log groups aren't deleted automatically when you delete a function". El 9 de noviembre AWS publicó la política de retención a nivel cuenta, que es la primera forma de ponerle un vencimiento a todos a la vez. Lo que sigue sale de docs.aws.amazon.com y de la página de precios; las fuentes están al final.
Por qué queda "Never expire"
CloudWatch guarda los eventos de log indefinidamente salvo que alguien fije una retención; en la consola ese estado se llama "Never Expire". Lambda crea el log group por vos, en la primera invocación, con ese valor. Un stack de Terraform que declara la función pero no el log group deja un recurso que Terraform nunca tuvo en el state: terraform destroy borra la función y el log group sigue ahí, con sus bytes y su línea en la factura. Es el mismo mecanismo que un disco creado fuera del plan.
Encontrarlos: sin retención y ordenados por bytes
describe-log-groups devuelve retentionInDays sólo cuando hay retención; si el grupo nunca expira, el campo no viene. Eso permite filtrarlos con JMESPath comparando contra null, y storedBytes dice cuánto pesa cada uno:
# log groups sin retención, los más pesados primero (la CLI v2 pagina sola) aws logs describe-log-groups --output table \ --query "reverse(sort_by(logGroups[?retentionInDays==null].{name:logGroupName,storedBytes:storedBytes,class:logGroupClass},&storedBytes))" # sólo los de Lambda aws logs describe-log-groups --log-group-name-prefix /aws/lambda \ --query "logGroups[?retentionInDays==null].[logGroupName,storedBytes]" --output text # funciones que existen hoy, para cruzar contra la lista anterior aws lambda list-functions --query "Functions[].FunctionName" --output text Un log group /aws/lambda/x sin una función x en la segunda lista es un huérfano: la función se borró y los logs quedaron. Y los que sí tienen función pero no tienen retención son el otro problema: crecen todos los meses.
Qué cuesta
En us-east-1, la clase Standard cobra US$ 0,50 por GB ingerido y US$ 0,03 por GB-mes almacenado (comprimido); la clase Infrequent Access, US$ 0,25 por GB ingerido y US$ 0,018 por GB-mes. La capa gratuita cubre 5 GB. El almacenamiento es lo que se acumula: 100 GB que nadie lee son US$ 3 por mes para siempre, y una función ruidosa que loguea cada request puede dejar varios cientos de GB antes de que alguien mire.
Retención por log group
# un log group aws logs put-retention-policy --log-group-name /aws/lambda/mi-funcion --retention-in-days 30 # todos los de Lambda sin retención, a 30 días for g in $(aws logs describe-log-groups --log-group-name-prefix /aws/lambda \ --query "logGroups[?retentionInDays==null].logGroupName" --output text); do aws logs put-retention-policy --log-group-name "$g" --retention-in-days 30 done Los valores admitidos son fijos: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288 y 3653 días. Los eventos vencidos pueden tardar hasta 72 horas en borrarse. En Terraform, aws_cloudwatch_log_group con retention_in_days y el nombre /aws/lambda/<función> declarado antes que la función deja el grupo en el state, y skip_destroy = true lo conserva a propósito en un destroy.
Retención por cuenta: lo nuevo del 9 de noviembre
La política de retención a nivel cuenta fija una retención para todos los log groups de la región o para un subconjunto por prefijo de nombre, y elige si aplica a los existentes o sólo a los nuevos. Para los de Lambda:
aws logs put-account-policy \ --policy-name LambdaRetentionPolicy \ --policy-type RETENTION_POLICY \ --policy-document '{"retentionInDays": 90, "enforcementMode": "RETROACTIVE"}' \ --selection-criteria 'LogGroupNamePrefix="/aws/lambda"' # con --dry-run muestra a qué grupos aplicaría sin crear nada -
enforcementMode:RETROACTIVEalcanza a los grupos que ya existen y a los nuevos;NEW_ONLY, sólo a los creados después. - El mínimo es 30 días; el máximo, 3653, o
NEVER_EXPIRE. Hasta 20 políticas por región, y si varias coinciden gana la de retención más larga. - La política de cuenta reemplaza la retención del log group, incluso cuando la del grupo era más larga. Tarda 24 horas en aplicarse.
- Sin costo adicional. No disponible en Bahréin ni en Emiratos.
Lo que la política no hace es borrar el log group: un huérfano con retención de 90 días deja de acumular bytes y en tres meses pesa cero, pero sigue listado. Para que desaparezca hace falta aws logs delete-log-group, y conviene hacerlo con la lista cruzada de arriba, no con un for sobre todos los /aws/lambda/.
Lo que hace Control Cloud con esto
El inventario de AWS de Control Cloud lee instancias, volúmenes, direcciones elásticas, interfaces de red, NAT gateways, balanceadores, RDS, EKS, VPCs y subredes por la API, con una credencial de solo lectura, y marca lo que quedó sin dueño después de un borrado. Todavía no lee funciones Lambda ni log groups de CloudWatch: hoy, para eso, son los comandos de esta nota. Si querés ver el inventario sobre tu cuenta, pedí acceso; para conectarla con permisos de lectura está la guía de AWS.
Fuentes
- AWS Lambda Developer Guide, "Working with the Lambda logging and log groups" ("By default, CloudWatch automatically creates a log group named /aws/lambda/…") y "Logging in Node.js" ("Log groups aren't deleted automatically when you delete a function").
- Amazon CloudWatch Logs User Guide, "Working with log groups and log streams" (retención indefinida por defecto, "Never Expire", políticas de retención a nivel cuenta con el ejemplo de
put-account-policy). - AWS What's New, 9 de noviembre de 2026, "Amazon CloudWatch Logs now supports account-level log retention policies"; referencia de la CLI
logs put-account-policy(RETROACTIVE / NEW_ONLY, mínimo 30 días, 20 políticas, 24 horas, reemplaza la del grupo). - Referencia de la CLI:
logs put-retention-policy(valores admitidos, borrado hasta 72 horas después) ylogs describe-log-groups(retentionInDaysausente cuando nunca expira,storedBytes). - Amazon CloudWatch Pricing, US East (N. Virginia): US$ 0,50 y US$ 0,25 por GB ingerido, US$ 0,03 y US$ 0,018 por GB-mes, 5 GB gratis.
- Terraform Registry,
aws_cloudwatch_log_group(retention_in_days,skip_destroy); hashicorp/terraform-provider-aws, issue #454 ("When you delete the lambda, it doesn't delete anything from CloudWatch").

