PF-03 · Tencent · IaC
Tencent Cloud audit-ready Terraform
Tencent Cloud modules that define CloudAudit tracks per service, so risky changes land in a COS bucket.
- Role
- Design and implementation
- Period
- Personal project · released Nov 2026
- Cloud
- Tencent
- Scale
- 18 modules · 3 examples
- Key tech
- Terraform · Tencent Cloud · CloudAudit · COS · CAM · CLB
- 18
- Terraform modules
- 4
- Audit tracks by service
- 19
- Audit events tracked in code
At a glance
Problem
Changes on Tencent Cloud needed a per-service record of who did what. The provider also ships on an irregular cycle, so a new version could change a plan without any code change.
Approach
CloudAudit tracks are defined per service in code for CAM, CVM, CBS, and VPC, and each stores to its own COS prefix. Every module pins the provider to = 1.81.163.
Result
Permission, server, disk, and security group changes reach COS through the tracks defined in code, including risky events such as CreateApiKey and AttachUserPolicy.
Up close
Audit tracks per service
What this code does: Defines audit tracks as a list, and each entry sets the target service (resource_type), the event names to record, and where to store them. The CAM track records permission events such as adding or deleting users, creating or deleting API keys, and attaching or detaching policies; the CVM track records servers being created, terminated, stopped, started, resized, and disks being attached or detached. Both store to COS but under separate cam and cvm prefixes, so each service’s log can be read and managed on its own.
audit_tracks = [
{
name = "iam_trackingset"
resource_type = "CAM"
event_names = ["AddUser", "DeleteUser", "CreateApiKey", "DeleteApiKey", "AttachUserPolicy", "DetachUserPolicy"]
action_type = "*"
storage = {
storage_prefix = "cam"
storage_type = "cos"
}
},
{
name = "vm_trackingset"
resource_type = "CVM"
event_names = ["RunInstances", "TerminateInstances", "StopInstances", "StartInstances", "ResetInstancesType", "AttachDisks", "DetachDisks"]
action_type = "*"
storage = {
storage_prefix = "cvm"
storage_type = "cos"
}
},
Pinning the provider version
What this code does: Allows Terraform itself from 1.9 up to but not including 2.0, and pins the tencentcloud provider to exactly = 1.81.163. Because it is an exact version rather than a range, a new provider release is never picked up automatically, and the same code keeps producing the same plan.
terraform {
required_version = ">= 1.9, < 2.0"
required_providers {
tencentcloud = {
source = "tencentcloudstack/tencentcloud"
version = "= 1.81.163"
}
}
}What I learned
With audit logs, making them readable later mattered more than keeping them at all. Instead of mixing events into one stream, separate tracks and COS prefixes for CAM, CVM, CBS, and VPC let a reviewer read one kind of change at a time, such as permissions or servers, and set retention per kind. I also learned that pinning the provider to an exact version is not just habit but an audit safeguard: it keeps a plan from changing while the code stays the same. And a passing scan means only as much as the rules behind it, so on Tencent Cloud, where scanners have few rules, I had to decide for myself what to record in code.