AWS

Tutorials

Tracking Changes in AWS Resource Tagging Over Time

AWS resource tags are a way to add metadata to your AWS resources for a variety of purposes, such as Attribute Based Access Control (ABAC), Cloud Financial Management, and automation.

Keeping track of your AWS resource tags is crucial for effective management and cost allocation. AWS resources such as EC2 instances, Lambda functions, and S3 buckets can have tags that change over time, affecting your organization’s resource management and billing. With CloudQuery, you can export your cloud data to any database available in our destination integrations. This allows you to track changes to your AWS resource tags efficiently.

Getting Started with CloudQuery

To get started, download the CloudQuery CLI and set up your CloudQuery configuration file by following the AWS Source Integration documentation. When writing your CloudQuery AWS configuration, make sure that you add the tables for the AWS resources you want to track. For this example, you will want to focus on aws_lambda_functions. However, you can use any AWS resource. Your schema will contain the _cq_sync_time, arn and tags columns for any AWS resource.

Ensure your CloudQuery configuration includes append mode for syncing data over time. This will allow you to gather historical data on tags.

To do that, make sure you include write_mode: append in your CloudQuery destination configuration and deterministic_cq_id: true in your AWS configuration. Here is an example using the PostgreSQL Destination Integration:

kind: source
spec:
name: 'aws'
path: 'cloudquery/aws'
version: 'v34.9.0'
tables: ['aws_lambda_functions']
deterministic_cq_id: true
destinations: ['postgresql']
spec:
---
kind: destination
spec:
name: 'postgresql'
path: 'cloudquery/postgresql'
version: 'v8.16.0'
write_mode: 'append'
spec:
connection_string: ''

Ensure your configuration uses the latest plugin versions, and includes all the settings relevant to you use case by visiting the AWS Source plugin docs and PostgreSQL destination integration docs.

Tracking AWS Lambda Function Tags

Once you’ve synced data from AWS, the table aws_lambda_functions will be created. This table includes a tags column that contains a JSON object representing the tags of each Lambda function. To analyze changes in these tags over time, we can use SQL’s Lag() window function in combination with a few PostgreSQL JSON functions.

WITH prev_tag AS (
SELECT
arn,
_cq_sync_time,
tags,
LAG(tags) OVER (PARTITION BY arn ORDER BY _cq_sync_time) AS previous_tags
FROM
aws_lambda_functions
ORDER BY
arn, _cq_sync_time
)
SELECT
_cq_sync_time,
arn,
tags,
previous_tags,
jsonb_build_object(
'removed',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(previous_tags) j1
LEFT JOIN jsonb_each(tags) j2 ON j1.key = j2.key
WHERE j2.key IS NULL
) AS removed
),
'added',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(tags) j1
LEFT JOIN jsonb_each(previous_tags) j2 ON j1.key = j2.key
WHERE j2.key IS NULL
) AS added
),
'changed',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(tags) j1
JOIN jsonb_each(previous_tags) j2 ON j1.key = j2.key
WHERE j1.value <> j2.value
) AS changed
)
) AS tag_diff
FROM
prev_tag
WHERE previous_tags IS NOT NULL
ORDER BY arn, _cq_sync_time;

In this query, the main column is tag_diff, which will hold a JSON showing the change between the tags from the previous sync to the current for each row. For example, if there is no change in tags, you will see:

{
"added": null,
"changed": null,
"removed": null
}

However, if your team starts tagging resources with an Owner tag, you will see:

{
"added": {
"Owner": "Bob"
},
"changed": null,
"removed": null
}

If there is a new owner for the function in the next sync, you will see:

{
"added": null,
"changed": {
"Owner": "Alice"
},
"removed": null
}

The changed property will hold the key and the new value of the tag.

Lastly, if your team decides to stop using the Owner tag in the next sync, you will see:

{
"removed": {
"Owner": "Alice"
},
"added": null,
"changed": null
}

To simplify this query and make the JSON comparison reusable in other queries, you can create a PostgreSQL function that can be used in a repeatable process:

CREATE OR REPLACE FUNCTION jsonb_diff(tags JSONB, previous_tags JSONB)
RETURNS JSONB LANGUAGE plpgsql AS $$
BEGIN
RETURN jsonb_build_object(
'removed',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(previous_tags) j1
LEFT JOIN jsonb_each(tags) j2 ON j1.key = j2.key
WHERE j2.key IS NULL
) AS removed
),
'added',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(tags) j1
LEFT JOIN jsonb_each(previous_tags) j2 ON j1.key = j2.key
WHERE j2.key IS NULL
) AS added
),
'changed',
(
SELECT jsonb_object_agg(key, value)
FROM (
SELECT j1.key, j1.value
FROM jsonb_each(tags) j1
JOIN jsonb_each(previous_tags) j2 ON j1.key = j2.key
WHERE j1.value <> j2.value
) AS changed
)
);
END;
$$;

This would then result in the following query for Lambda functions:

WITH prev_tag AS (
SELECT
arn,
_cq_sync_time,
tags,
LAG(tags) OVER (PARTITION BY arn ORDER BY _cq_sync_time) AS previous_tags
FROM
aws_lambda_functions
ORDER BY
arn, _cq_sync_time
)
SELECT
_cq_sync_time,
arn,
tags,
previous_tags,
jsonb_diff(tags, previous_tags) AS tag_diff
FROM
prev_tag
WHERE previous_tags IS NOT NULL
ORDER BY arn, _cq_sync_time;

To adapt this query for tracking other AWS resources, simply replace aws_lambda_functions with any table available from our AWS Source Integration. This will enable you to monitor tag changes over time for the selected resource.

Summary

By leveraging CloudQuery to track changes in tags across all AWS resources, you can gain a deeper understanding of your cloud infrastructure’s organization and cost allocation. Whether you are using EC2 instances, Lambda functions, or S3 buckets, tracking tag changes over time allows you to maintain accurate resource management, ensure compliance, and optimize cost efficiency. Start syncing your AWS resources with CloudQuery today and enhance your resource management capabilities like never before.

Ready to learn more about your AWS resource tagging data? Try CloudQuery today and gain comprehensive insights into your AWS resources and their tags. Contact us or Join the CloudQuery Community to connect with other users and our engineering team, and explore the full potential of CloudQuery.

Try CloudQuery yourself

Self-hosted, open source, and free to start. Or schedule a demo to see the managed version.

Related posts

AWS

Security

Tutorials

Finding AWS Unrestricted Outbound Access in 2026: EC2, Lambda, and Beyond

Find EC2, Lambda, and ECS Fargate resources with unrestricted outbound access in AWS using SQL. Why egress controls still break attack chains in 2026.

Joe Karlsson

Joe Karlsson

May 5, 2026

AWS

Security

Tutorials

AWS IAM Identity Center with Google Workspace as an IdP: 2026 Step-by-Step Guide

Set up AWS IAM Identity Center with Google Workspace: SAML authentication, SCIM user provisioning, and group sync with CLI or ssosync. Updated for 2026.

Joe Karlsson

Joe Karlsson

May 5, 2026

AWS

Cloud Infrastructure

Security

Tutorials

Integrate AbuseIPDB Threat Intelligence with CloudQuery

Enrich your cloud asset inventory with AbuseIPDB threat intelligence to identify public cloud IPs with known abuse reports.

Joe Karlsson

Joe Karlsson

April 20, 2026

AWS

Cloud Infrastructure

Tutorials

How to Query ipinfo.io Data with CloudQuery

Learn how to enrich your cloud asset inventory with ipinfo.io IP geolocation and threat intelligence data using CloudQuery.

Joe Karlsson

Joe Karlsson

April 20, 2026

AWS

Security

Tutorials

AWS IAM Identity Center (Formerly AWS SSO): The Complete 2026 Guide

AWS IAM Identity Center replaced AWS SSO in 2022. Learn how to set it up, configure permission sets, use the AWS CLI, and audit access with CloudQuery.

Joe Karlsson

Joe Karlsson

April 6, 2026

AWS

Tutorials

AWS Pinpoint Is Being Deprecated: How to Assess Your Migration Scope

AWS Pinpoint reaches end of support October 2026. Query your Pinpoint usage across all accounts to find what needs migrating before the deadline.

Joe Karlsson

Joe Karlsson

March 24, 2026

AWS

Best Practices

Tutorials

CloudQuery Sync Performance: A Practical Troubleshooting Guide

Diagnose why CloudQuery syncs slow down after plugin upgrades, identify expensive tables, and use the CLI command that replaces the tables wildcard.

Joe Karlsson

Joe Karlsson

March 6, 2026

AWS

Security

Tutorials

Set Up AWS CLI with SSO (IAM Identity Center) — Step by Step

Set up AWS CLI v2 with IAM Identity Center in 5 minutes. Covers SSO registration scopes, sso-session config, token refresh, and multi-account profiles.

Yevgeny Pats

Yevgeny Pats

February 25, 2026

AWS

Cloud Infrastructure

Tutorials

AWS Lambda Python 3.9 End-of-Support: Find and Upgrade Every Affected Function

AWS Lambda Python 3.9 security patches stopped Dec 15, 2025. Find every affected function across all accounts with SQL queries and upgrade to 3.12 or 3.13.

Joe Karlsson

Joe Karlsson

February 10, 2026

Own your pipeline.
Own your data.