Foto de SuPatMaN en Shutterstock
Antes que nada, quiero decir que AWS Config es un excelente servicio. Si todavía no lo conoces, AWS Config evalúa, monitorea y registra de forma continua los cambios en la configuración de tus recursos. No voy a enumerar todas sus funcionalidades, pero puedes leer más al respecto aquí. La sección de precios de AWS Config explica cómo se cobra el servicio e incluye buenos ejemplos para entenderlo mejor. En resumen, los cargos de AWS Config dependen de la cantidad de configuration items registrados, la cantidad de evaluaciones activas de reglas de AWS Config y la cantidad de evaluaciones de conformance packs en tu cuenta, además de algunos costos adicionales como el almacenamiento en S3 y SNS. Si tu infraestructura es dinámica y se realizan muchos cambios de configuración, los costos de AWS Config pueden dispararse. El objetivo de este blog es desglosar los costos de AWS Config, compartir estrategias para reducirlos y dar consejos para investigar picos de costo inesperados.
NOTA — Por temas de políticas de privacidad, voy a usar mi entorno de pruebas de AWS para los ejemplos. No tengo demasiados datos de Config, pero deberían bastar para entender la estrategia que utilicé.
- Configuration Items registrados — Revisa los configuration items registrados por AWS Config desde el dashboard de AWS Config (imagen1) o consulta las mismas métricas disponibles en CloudWatch Metrics (imagen2).

imagen1 — Configuration Items registrados — Dashboard de AWS Config

imagen2 — Configuration Items registrados — AWS CloudWatch Metrics
- Bueno, esto no nos dice mucho, ¿verdad? Pero estos elementos registrados pueden pasar de unos cientos a varios miles al día, según lo que esté ocurriendo en tu cuenta. Para entender mejor qué se está registrando, usé los datos de AWS Config almacenados en mi bucket de S3 configurado (imagen3) e intenté analizarlos con el servicio AWS Athena. Lo encuentras en AWS Config > Settings > Delivery Method.

imagen3 — S3 utilizado como método de entrega de los registros de AWS Config
- Si entras a S3, vas a ver varios archivos JSON entregados por AWS Config y organizados por ID de organización, ID de cuenta, región, mes, fecha, etc. Por ejemplo, lo que se muestra abajo. El tamaño de los archivos varía según los elementos registrados por AWS Config.

Archivos entregados por Config en S3
- Después intenté leer esos archivos para ver qué contenían. Por ejemplo, tomé los primeros 2 archivos.
nikhilpawar@MacBookPro Downloads % cat xxxxxxxxxx_Config_us-east-1_ConfigHistory_AWS__AppConfig__DeploymentStrategy_20241029T013419Z_20241029T013419Z_1.json
{"fileVersion":"1.0","configurationItems":[{"relatedEvents":[],"relationships":[],"configuration":{"Id":"AppConfig.AllAtOnce","ReplicateTo":"NONE","GrowthType":"LINEAR","Description":"Quick","DeploymentDurationInMinutes":0,"GrowthFactor":100.0,"FinalBakeTimeInMinutes":10,"Name":"AppConfig.AllAtOnce","Tags":[]},"supplementaryConfiguration":{},"tags":{},"configurationItemVersion":"1.3","configurationItemCaptureTime":"2024-10-29T01:34:19.420Z","configurationStateId":1730165659420,"awsAccountId":"xxxxxxxxxx","configurationItemStatus":"ResourceDiscovered","resourceType":"AWS::AppConfig::DeploymentStrategy","resourceId":"AppConfig.AllAtOnce","resourceName":"AppConfig.AllAtOnce","ARN":"arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.AllAtOnce","awsRegion":"us-east-1","availabilityZone":"Regional","configurationStateMd5Hash":""},{"relatedEvents":[],"relationships":[],"configuration":{"Id":"AppConfig.Canary10Percent20Minutes","ReplicateTo":"NONE","GrowthType":"EXPONENTIAL","Description":"AWS Recommended","DeploymentDurationInMinutes":20,"GrowthFactor":10.0,"FinalBakeTimeInMinutes":10,"Name":"AppConfig.Canary10Percent20Minutes","Tags":[]},"supplementaryConfiguration":{},"tags":{},"configurationItemVersion":"1.3","configurationItemCaptureTime":"2024-10-29T01:34:19.546Z","configurationStateId":1730165659546,"awsAccountId":"xxxxxxxxxx","configurationItemStatus":"ResourceDiscovered","resourceType":"AWS::AppConfig::DeploymentStrategy","resourceId":"AppConfig.Canary10Percent20Minutes","resourceName":"AppConfig.Canary10Percent20Minutes","ARN":"arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.Canary10Percent20Minutes","awsRegion":"us-east-1","availabilityZone":"Regional","configurationStateMd5Hash":""},{"relatedEvents":[],"relationships":[],"configuration":{"Id":"AppConfig.Linear20PercentEvery6Minutes","ReplicateTo":"NONE","GrowthType":"LINEAR","Description":"AWS Recommended","DeploymentDurationInMinutes":30,"GrowthFactor":20.0,"FinalBakeTimeInMinutes":30,"Name":"AppConfig.Linear20PercentEvery6Minutes","Tags":[]},"supplementaryConfiguration":{},"tags":{},"configurationItemVersion":"1.3","configurationItemCaptureTime":"2024-10-29T01:34:19.625Z","configurationStateId":1730165659625,"awsAccountId":"xxxxxxxxxx","configurationItemStatus":"ResourceDiscovered","resourceType":"AWS::AppConfig::DeploymentStrategy","resourceId":"AppConfig.Linear20PercentEvery6Minutes","resourceName":"AppConfig.Linear20PercentEvery6Minutes","ARN":"arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.Linear20PercentEvery6Minutes","awsRegion":"us-east-1","availabilityZone":"Regional","configurationStateMd5Hash":""},{"relatedEvents":[],"relationships":[],"configuration":{"Id":"AppConfig.Linear50PercentEvery30Seconds","ReplicateTo":"NONE","GrowthType":"LINEAR","Description":"Test/Demo","DeploymentDurationInMinutes":1,"GrowthFactor":50.0,"FinalBakeTimeInMinutes":1,"Name":"AppConfig.Linear50PercentEvery30Seconds","Tags":[]},"supplementaryConfiguration":{},"tags":{},"configurationItemVersion":"1.3","configurationItemCaptureTime":"2024-10-29T01:34:19.475Z","configurationStateId":1730165659475,"awsAccountId":"xxxxxxxxxx","configurationItemStatus":"ResourceDiscovered","resourceType":"AWS::AppConfig::DeploymentStrategy","resourceId":"AppConfig.Linear50PercentEvery30Seconds","resourceName":"AppConfig.Linear50PercentEvery30Seconds","ARN":"arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.Linear50PercentEvery30Seconds","awsRegion":"us-east-1","availabilityZone":"Regional","configurationStateMd5Hash":""}]}% nikhilpawar@MacBookPro Downloads % cat xxxxxxxxxx_Config_us-east-1_ConfigHistory_AWS__AppConfig__DeploymentStrategy_20241029T013419Z_20241029T013419Z_1.json | jq
{
"fileVersion": "1.0",
"configurationItems": [\
{\
"relatedEvents": [],\
"relationships": [],\
"configuration": {\
"Id": "AppConfig.AllAtOnce",\
"ReplicateTo": "NONE",\
"GrowthType": "LINEAR",\
"Description": "Quick",\
"DeploymentDurationInMinutes": 0,\
"GrowthFactor": 100.0,\
"FinalBakeTimeInMinutes": 10,\
"Name": "AppConfig.AllAtOnce",\
"Tags": []\
},\
"supplementaryConfiguration": {},\
"tags": {},\
"configurationItemVersion": "1.3",\
"configurationItemCaptureTime": "2024-10-29T01:34:19.420Z",\
"configurationStateId": 1730165659420,\
"awsAccountId": "xxxxxxxxxx",\
"configurationItemStatus": "ResourceDiscovered",\
"resourceType": "AWS::AppConfig::DeploymentStrategy",\
"resourceId": "AppConfig.AllAtOnce",\
"resourceName": "AppConfig.AllAtOnce",\
"ARN": "arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.AllAtOnce",\
"awsRegion": "us-east-1",\
"availabilityZone": "Regional",\
"configurationStateMd5Hash": ""\
},\
{\
"relatedEvents": [],\
"relationships": [],\
"configuration": {\
"Id": "AppConfig.Canary10Percent20Minutes",\
"ReplicateTo": "NONE",\
"GrowthType": "EXPONENTIAL",\
"Description": "AWS Recommended",\
"DeploymentDurationInMinutes": 20,\
"GrowthFactor": 10.0,\
"FinalBakeTimeInMinutes": 10,\
"Name": "AppConfig.Canary10Percent20Minutes",\
"Tags": []\
},\
"supplementaryConfiguration": {},\
"tags": {},\
"configurationItemVersion": "1.3",\
"configurationItemCaptureTime": "2024-10-29T01:34:19.546Z",\
"configurationStateId": 1730165659546,\
"awsAccountId": "xxxxxxxxxx",\
"configurationItemStatus": "ResourceDiscovered",\
"resourceType": "AWS::AppConfig::DeploymentStrategy",\
"resourceId": "AppConfig.Canary10Percent20Minutes",\
"resourceName": "AppConfig.Canary10Percent20Minutes",\
"ARN": "arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.Canary10Percent20Minutes",\
"awsRegion": "us-east-1",\
"availabilityZone": "Regional",\
"configurationStateMd5Hash": ""\
},\
{\
"relatedEvents": [],\
"relationships": [],\
"configuration": {\
"Id": "AppConfig.Linear50PercentEvery30Seconds",\
"ReplicateTo": "NONE",\
"GrowthType": "LINEAR",\
"Description": "Test/Demo",\
"DeploymentDurationInMinutes": 1,\
"GrowthFactor": 50.0,\
"FinalBakeTimeInMinutes": 1,\
"Name": "AppConfig.Linear50PercentEvery30Seconds",\
"Tags": []\
},\
"supplementaryConfiguration": {},\
"tags": {},\
"configurationItemVersion": "1.3",\
"configurationItemCaptureTime": "2024-10-29T01:34:19.475Z",\
"configurationStateId": 1730165659475,\
"awsAccountId": "xxxxxxxxxx",\
"configurationItemStatus": "ResourceDiscovered",\
"resourceType": "AWS::AppConfig::DeploymentStrategy",\
"resourceId": "AppConfig.Linear50PercentEvery30Seconds",\
"resourceName": "AppConfig.Linear50PercentEvery30Seconds",\
"ARN": "arn:aws:appconfig:us-east-1:xxxxxxxxxx:deploymentstrategy/AppConfig.Linear50PercentEvery30Seconds",\
"awsRegion": "us-east-1",\
"availabilityZone": "Regional",\
"configurationStateMd5Hash": ""\
}\
]
}
- Leer los datos de esos archivos JSON manualmente o con scripts es complicado. La mejor opción es usar AWS Athena, otro servicio muy potente.
- Crear tabla en Athena — Al crear tablas en Athena para los datos de AWS Config, puedes personalizar las consultas según el período y el alcance de los datos. La sintaxis de creación de la tabla varía según lo que quieras analizar:
- Snapshots de un solo día
- Datos que abarcan varios días
- Un mes o año específico
- Todo el histórico de datos de Config
NOTA — Reemplaza 'xxxxxxxxxx' con tu ID de cuenta de AWS en las siguientes consultas. Además, te recomiendo que, en lugar de escanear todos los datos, obtengas únicamente los del período que necesitas. (Precios de Athena)
1. Snapshot de un solo día
1.1:- Crear tabla en Athena: p. ej. aws_config_table_single_day_2024_11_08
CREATE EXTERNAL TABLE aws_config_table_single_day_2024_11_08 (
fileversion string,
configSnapshotId string,
configurationitems ARRAY<STRUCT<
configurationItemVersion: STRING,
configurationItemCaptureTime: STRING,
configurationStateId: BIGINT,
awsAccountId: STRING,
configurationItemStatus: STRING,
resourceType: STRING,
resourceId: STRING,
resourceName: STRING,
ARN: STRING,
awsRegion: STRING,
availabilityZone: STRING,
configurationStateMd5Hash: STRING,
resourceCreationTime: STRING
>>
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://config-bucket-xxxxxxxxxxxx/AWSLogs/xxxxxxxxxxxx/Config/us-east-1/2024/11/8';

1.1:- Tabla en Athena — Snapshot de un solo día
1.2:- Contar el total de registros: (Opcional. Puedes verificar el total de registros, que debería coincidir con las métricas de CloudWatch que vimos al inicio).
SELECT
COUNT(1) AS record_count
FROM
default.aws_config_table_single_day_2024_11_08
CROSS JOIN
UNNEST(configurationitems) AS t(configurationItem)
WHERE
configurationItem.resourceType IS NOT NULL

1.2:- Total de registros del día
1.3:- Obtener el tipo de recurso y la cantidad de cambios registrados: La siguiente consulta te ayuda a identificar los tipos de recursos que generan la mayor cantidad de cambios de configuración, lo que te permite ubicar los posibles factores que disparan los costos en tu monitoreo de AWS Config.
SELECT
configurationItem.resourceType,
COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM
default.aws_config_table_single_day_2024_11_08
CROSS JOIN
UNNEST(configurationitems) AS t(configurationItem)
GROUP BY
configurationItem.resourceType
ORDER BY
NumberOfChanges DESC;

1.3:- Tipos de recursos y cantidad de cambios registrados
1.4:- Obtener IDs de recursos: Para profundizar en los tipos de recursos con más cambios, puedes ir al detalle de recursos específicos. Por ejemplo, la consulta anterior reveló que AWS:EC2:Subnet es el que tiene más cambios de configuración. La siguiente consulta ayuda a identificar qué IDs de subnet específicos están detrás de esa frecuencia de cambios.
SELECT
configurationItem.resourceType,
configurationItem.resourceId,
COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM
default.aws_config_table_single_day_2024_11_08
CROSS JOIN
UNNEST(configurationitems) AS t(configurationItem)
GROUP BY
configurationItem.resourceType,
configurationItem.resourceId
ORDER BY
NumberOfChanges DESC

1.4:- IDs de recursos identificados
Con esto deberías tener una idea clara de lo que está pasando. Los mismos patrones de consulta se aplican a distintos rangos de tiempo. Ya sea que necesites analizar tendencias mensuales, rangos de fechas específicos o todo tu histórico de Config, basta con modificar los parámetros de tiempo manteniendo el mismo enfoque analítico.
2. Mes específico
2.1:- Crear tabla en Athena: p. ej. aws_config_table_november_2024
CREATE EXTERNAL TABLE aws_config_table_november_2024 (
fileversion string,
configSnapshotId string,
configurationitems ARRAY<STRUCT<
configurationItemVersion: STRING,
configurationItemCaptureTime: STRING,
configurationStateId: BIGINT,
awsAccountId: STRING,
configurationItemStatus: STRING,
resourceType: STRING,
resourceId: STRING,
resourceName: STRING,
ARN: STRING,
awsRegion: STRING,
availabilityZone: STRING,
configurationStateMd5Hash: STRING,
resourceCreationTime: STRING
>>
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://config-bucket-xxxxxxxxxxxx/AWSLogs/xxxxxxxxxxxx/Config/us-east-1/2024/10/';

2.1:- Tabla en Athena — datos de un mes
2.2:- Contar el total de registros: Consulta el paso 1.2 (Contar el total de registros) y actualiza el nombre de la tabla.

2.2:- Total de registros del mes
2.3:- Obtener el tipo de recurso y la cantidad de cambios registrados: Consulta el paso 1.3 (Obtener el tipo de recurso y la cantidad de cambios registrados) y actualiza el nombre de la tabla.

2.3:- Tipos de recursos y cantidad de cambios registrados
2.4:- Obtener IDs de recursos: Consulta el paso 1.4 (Obtener IDs de recursos) y actualiza el nombre de la tabla.

2.4:- IDs de recursos identificados
3. Todos los datos de Config
3.1:- Crear tabla en Athena: p. ej. aws_config_table_all
CREATE EXTERNAL TABLE aws_config_table_all (
fileversion string,
configSnapshotId string,
configurationitems ARRAY<STRUCT<
configurationItemVersion: STRING,
configurationItemCaptureTime: STRING,
configurationStateId: BIGINT,
awsAccountId: STRING,
configurationItemStatus: STRING,
resourceType: STRING,
resourceId: STRING,
resourceName: STRING,
ARN: STRING,
awsRegion: STRING,
availabilityZone: STRING,
configurationStateMd5Hash: STRING,
resourceCreationTime: STRING
>>
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://config-bucket-XXXXXXXXXXXX/AWSLogs/XXXXXXXXXXXX/Config/us-east-1/';

3.1:- Tabla en Athena — todos los datos de Config
3.2:- Total de registros: Consulta el paso 1.2 (Contar el total de registros) y actualiza el nombre de la tabla.

3.2:- Total de registros
3.3:- Obtener el tipo de recurso y la cantidad de cambios registrados: Consulta el paso 1.3 (Obtener el tipo de recurso y la cantidad de cambios registrados) y actualiza el nombre de la tabla.

3.3:- Tipos de recursos y cantidad de cambios registrados
3.4:- Obtener IDs de recursos: Consulta el paso 1.4 (Obtener IDs de recursos) y actualiza el nombre de la tabla.

3.4:- IDs de recursos identificados
4. Datos que abarcan varios días
4.1 Crear tabla en Athena: En este caso vamos a particionar la tabla de Athena con partition projection del 2024/11/7 al 2024/11/10. Personaliza este período según lo necesites.
CREATE EXTERNAL TABLE aws_config_table_period_2024_11_07to2024_11_10 (
fileversion string,
configSnapshotId string,
configurationitems ARRAY<STRUCT<
configurationItemVersion: STRING,
configurationItemCaptureTime: STRING,
configurationStateId: BIGINT,
awsAccountId: STRING,
configurationItemStatus: STRING,
resourceType: STRING,
resourceId: STRING,
resourceName: STRING,
ARN: STRING,
awsRegion: STRING,
availabilityZone: STRING,
configurationStateMd5Hash: STRING,
resourceCreationTime: STRING
>>
)
PARTITIONED BY (`year` string,`month` string,`day` string)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://config-bucket-xxxxxxxxxxxx/AWSLogs/xxxxxxxxxxxx/Config/us-east-1'
TBLPROPERTIES (
'projection.enabled'='true',
'projection.year.interval'='1',
'projection.year.range'='2024,2024',
'projection.year.type'='integer',
'projection.month.interval'='1',
'projection.month.range'='10,11',
'projection.month.type'='integer',
'projection.day.interval'='1',
'projection.day.range'='7,10',
'projection.day.type'='integer',
'storage.location.template'='s3://config-bucket-xxxxxxxxxxxx/AWSLogs/xxxxxxxxxxxx/Config/us-east-1/${year}/${month}/${day}/ConfigHistory/')

4.1:- Tabla en Athena — período seleccionado
4.2:- Total de registros:
SELECT result.configurationitemcapturetime,
count(result.configurationitemcapturetime) AS NumberOfChanges
FROM
(SELECT regexp_replace(configurationItem.configurationItemCaptureTime,
'(.+)(T.+)', '$1') AS configurationitemcapturetime
FROM default.aws_config_table_period_2024_11_07to2024_11_10
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
AND configurationItem.configurationItemCaptureTime >= '2024-11-05T%'
AND configurationItem.configurationItemCaptureTime <= '2024-11-12T%') result
GROUP BY result.configurationitemcapturetime
ORDER BY result.configurationitemcapturetime

4.2:- Total de registros
4.3:- Obtener el tipo de recurso y la cantidad de cambios registrados:
SELECT configurationItem.resourceType,
configurationItem.resourceId,
COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM default.aws_config_table_period_2024_11_07to2024_11_10
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
AND configurationItem.configurationItemCaptureTime >= '2024-11-05T%'
AND configurationItem.configurationItemCaptureTime <= '2024-11-12T%'
GROUP BY configurationItem.resourceType, configurationItem.resourceId
ORDER BY NumberOfChanges DESC
### o ###
SELECT configurationItem.resourceType,
configurationItem.resourceId,
CAST(COUNT(configurationItem.resourceId) AS INTEGER) AS NumberOfChanges
FROM default.aws_config_table_period_2024_11_07to2024_11_10
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
AND configurationItem.configurationItemCaptureTime >= '2024-11-05T%'
AND configurationItem.configurationItemCaptureTime <= '2024-11-12T%'
GROUP BY configurationItem.resourceType, configurationItem.resourceId
ORDER BY NumberOfChanges DESC

4.3:- Tipos de recursos y cantidad de cambios registrados
4.4:- Obtener IDs de recursos
SELECT configurationItem.resourceId,
configurationItem.resourceType,
COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM default.aws_config_table_period_2024_11_07to2024_11_10
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
AND configurationItem.configurationItemCaptureTime >= '2024-11-05T%'
AND configurationItem.configurationItemCaptureTime <= '2024-11-12T%'
GROUP BY
configurationItem.resourceId,
configurationItem.resourceType
ORDER BY NumberOfChanges DESC

4.4:- IDs de recursos identificados
- Listo, ya identificaste el ID y el tipo de recurso con más elementos registrados durante el período que necesitas.
Desde junio de 2023, AWS Config admite la exclusión del registro por tipo de recurso. Ahora puedes revisar tu configuración para los tipos de recursos y ajustarla según corresponda, o investigar picos de costo inusuales en días específicos.

Recursos registrados
Otro punto que quiero destacar es el período de retención de datos. Puedes ajustarlo según tus necesidades.

Período de retención
En conclusión, AWS Config es un servicio muy potente, pero puede volverse costoso rápidamente, sobre todo en entornos dinámicos. Con enfoques estratégicos como analizar el registro de configuration items, apoyarse en AWS Athena para investigaciones detalladas, sacar partido a la exclusión del registro de configuración y gestionar con cuidado los períodos de retención de datos, las organizaciones pueden obtener información granular sobre sus costos de AWS Config sin perder visibilidad sobre su infraestructura. La clave no está en eliminar el monitoreo, sino en optimizar cómo y qué se rastrea. Al entender los patrones de cambios en tus recursos y registrar las configuraciones de forma selectiva, se logra equilibrar un monitoreo integral con una gestión rentable.
Si quieres aprovechar al máximo el potencial de AWS Config o te interesan nuestros servicios, escríbenos. Puedes contactarnos aquí.