Provisions a Google SecOps (Chronicle) retrohunt, targeting
hashicorp/google ~> 7.0.
- Creates exactly one
google_chronicle_retrohuntresource β a one-time execution of aterraform-google-chronicle-ruleover a specified past time range. ruletakes the SHORT rule ID, identical reference pattern toterraform-google-chronicle-rule-deployment's ownruleargument β confirmed via the resource's own live doc example.- This resource is effectively create-only β its own
timeoutsblock confirms onlycreate/deleteare supported, noupdate. - A documented discrepancy: the resource's own prose docs mention a
deletion_policyargument, but the live schema-JSON (ground truth) confirms it does not exist on this resource at this provider version.
π‘ Why it matters: Retrohunts let a SOC validate a new or changed detection rule against historical data before trusting it against live traffic β modeling the retrohunt request as code keeps that validation step reviewable and repeatable.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- β Star this repository to help others discover this Terraform module.
- π€ Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- β Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
flowchart LR
RULE["terraform-google-chronicle-rule<br/>(same batch, required)"]:::keystone
THIS["terraform-google-chronicle-retrohunt<br/>(this module β standalone)"]:::thismodule
RULE -.->|"basename(name) -> rule"| THIS
classDef thismodule fill:#4285F4,color:#FFFFFF,stroke:#174EA6,stroke-width:1px;
classDef keystone fill:#174EA6,color:#FFFFFF,stroke:#174EA6,stroke-width:1px;
Validated via the Mermaid Chart MCP (valid: true).
flowchart TB
subgraph Inputs
RULEV["var.rule"]
PI["var.process_interval<br/>(start_time / end_time)"]
RID["var.retrohunt_id"]
end
KEYSTONE["google_chronicle_retrohunt.this"]:::keystone
subgraph Outputs
ID["id / name"]
STATE["state / progress_percentage"]
EI["execution_interval"]
end
RULEV --> KEYSTONE
PI --> KEYSTONE
RID --> KEYSTONE
KEYSTONE --> ID
KEYSTONE --> STATE
KEYSTONE --> EI
classDef keystone fill:#174EA6,color:#FFFFFF,stroke:#174EA6,stroke-width:1px;
Validated via the Mermaid Chart MCP (valid: true).
Resource inventory: google_chronicle_retrohunt.this (1 resource).
| Component | Requirement |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/google |
~> 7.0 (resolved v7.39.0 during authoring) |
| Provider block | None β the caller configures google |
Schema notes that bite:
rulewants the SHORT rule ID β confirmed via the resource's own live doc example, identical pattern toterraform-google-chronicle-rule-deployment.- No
updatetimeout β confirmed this resource is effectively create-only; changingprocess_intervalorruleforces a new resource. deletion_policydoc/schema mismatch β confirmed no such argument exists in the live schema-JSON despite prose docs referencing it. This module does not model it.- No
labels, noself_linkβ family-wide facts.
roles/chronicle.adminβ same family-wide role as every other Chronicle module.
chronicle.googleapis.comenabled.- A Chronicle (Google SecOps) instance must already be activated for the target project.
- The referenced rule must already exist.
terraform-google-chronicle-retrohunt/
βββ providers.tf
βββ variables.tf # instance, location, rule, retrohunt_id, process_interval, timeouts
βββ main.tf # google_chronicle_retrohunt.this
βββ outputs.tf # id, name, retrohunt_id, state, progress_percentage, execution_interval
βββ README.md
βββ SCOPE.md
βββ examples/
βββ basic/
module "excessive_login_failures" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-rule.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
text = <<-EOT
rule excessive_login_failures {
meta:
author = "casey-secops"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "BLOCK"
$userid = $e.principal.user.userid
match:
$userid over 10m
condition:
#e > 10
}
EOT
}
module "excessive_login_failures_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = basename(module.excessive_login_failures.name)
process_interval = {
start_time = "2026-01-01T00:00:00Z"
end_time = "2026-02-01T00:00:00Z"
}
}Consumes:
| Input | Type | Source module |
|---|---|---|
rule |
string (short rule ID) |
terraform-google-chronicle-rule (required) |
Emits:
| Output | Description | Consumed by |
|---|---|---|
id |
Terraform-internal id | None |
name |
Resource name of the retrohunt | None |
retrohunt_id |
Echoes the resource's own retrohunt argument | None |
state |
Computed: RUNNING, DONE, CANCELLED, or FAILED | None |
progress_percentage |
Computed percent progress, 0.00 to 100.00 | None |
execution_interval |
Computed actual executed time interval | None |
No self_link row.
1 Β· Minimal one-month retrohunt
module "excessive_login_failures_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = "ru_a1b2c3d4"
process_interval = {
start_time = "2026-01-01T00:00:00Z"
end_time = "2026-02-01T00:00:00Z"
}
}2 Β· One-week window
module "recent_week_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = "ru_b2c3d4e5"
process_interval = {
start_time = "2026-07-01T00:00:00Z"
end_time = "2026-07-08T00:00:00Z"
}
}3 Β· Full-quarter historical validation
module "quarter_validation_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = "ru_c3d4e5f6"
process_interval = {
start_time = "2026-01-01T00:00:00Z"
end_time = "2026-04-01T00:00:00Z"
}
}
β οΈ Longer windows take proportionally longer to complete β checkstate/progress_percentagebefore assuming the retrohunt has finished.
4 Β· Explicit retrohunt_id
module "named_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = "ru_d4e5f6a7"
retrohunt_id = "jan-2026-validation"
process_interval = {
start_time = "2026-01-01T00:00:00Z"
end_time = "2026-02-01T00:00:00Z"
}
}5 Β· Custom create timeout for a long historical window
module "year_long_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = "ru_e5f6a7b8"
process_interval = {
start_time = "2025-01-01T00:00:00Z"
end_time = "2026-01-01T00:00:00Z"
}
timeouts = {
create = "60m"
}
}βΉοΈ This resource's
timeoutsblock only supportscreate/deleteβ there is noupdatetimeout, since the resource is effectively create-only.
6 Β· ποΈ End-to-end composition
module "excessive_login_failures" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-rule.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
text = <<-EOT
rule excessive_login_failures {
meta:
author = "casey-secops"
severity = "Medium"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "BLOCK"
$userid = $e.principal.user.userid
match:
$userid over 10m
condition:
#e > 10
}
EOT
}
module "excessive_login_failures_retrohunt" {
source = "git::https://github.com/microsoftexpert/terraform-google-chronicle-retrohunt.git?ref=v1.0.0"
instance = "00000000-0000-0000-0000-000000000000"
location = "us"
rule = basename(module.excessive_login_failures.name)
process_interval = {
start_time = "2026-01-01T00:00:00Z"
end_time = "2026-02-01T00:00:00Z"
}
}π Wires
terraform-google-chronicle-rule'snameoutput throughbasenameinto this module'sruleβ the confirmed short-ID reference form, identical to the rule-deployment module's pattern.
| Variable | Type | Default | Notes |
|---|---|---|---|
instance |
string |
β (required) | Caller-supplied literal |
location |
string |
β (required) | e.g. "us" |
rule |
string |
β (required) | Short rule ID; source via basename |
retrohunt_id |
string |
null |
Optional+computed; force-new |
process_interval |
object({ start_time, end_time }) |
β (required) | RFC3339 UTC timestamps |
timeouts |
object({ create, delete }) |
null |
No update β confirmed absent |
No labels variable. No deletion_policy variable (see Architecture Notes).
| Output | Description |
|---|---|
id |
Terraform-internal id |
name |
Resource name of the retrohunt |
retrohunt_id |
Echoes the resource's own retrohunt argument |
state |
Computed: RUNNING, DONE, CANCELLED, or FAILED |
progress_percentage |
Computed percent progress, 0.00 to 100.00 |
execution_interval |
Computed actual executed time interval |
No self_link, no labels-related outputs.
ruleis the short rule ID, not the full resource name β confirmed via the resource's own live doc example, identical toterraform-google-chronicle-rule-deployment's own pattern.- This resource is effectively create-only β no
updatetimeout exists; any change toprocess_intervalorruleforces replacement, not an in-place update. deletion_policydoc/schema discrepancy, confirmed and documented: this resource's published prose documentation references adeletion_policyargument, but the live schema-JSON dump (ground truth per house standard) confirms it does not exist at this provider version. This module intentionally omits it β do not add adeletion_policyvariable without first re-verifying against a freshterraform providers schema -jsondump.- No
labels, noself_linkβ family-wide facts.
| Concern | Secure default | Opt-out (explicit) |
|---|---|---|
Malformed time range reaching apply |
This module's own validation{} requires both start_time and end_time to be non-empty |
N/A β this is a hard requirement |
No deletion_policy-based secure default applies to this resource β see Architecture Notes.
cd terraform-google-chronicle-retrohunt
terraform init -backend=false
terraform validate
terraform fmt -checkvalidate/fmt confirm process_interval's non-empty timestamp requirement and internal type
consistency, but cannot validate that start_time/end_time are well-formed RFC3339 values, that
start_time precedes end_time, or that the referenced rule actually exists β those are
API-level rejections only apply can surface.
$ terraform output
id = "projects/casey-prod/locations/us/instances/00000000-0000-0000-0000-000000000000/rules/ru_a1b2c3d4/retrohunts/rh_a1b2c3d4"
name = "projects/casey-prod/locations/us/instances/00000000-0000-0000-0000-000000000000/rules/ru_a1b2c3d4/retrohunts/rh_a1b2c3d4"
retrohunt_id = "rh_a1b2c3d4"
state = "RUNNING"
progress_percentage = 42.5
execution_interval = [
{
"start_time" = "2026-01-01T00:00:00Z"
"end_time" = "2026-02-01T00:00:00Z"
},
]
| Symptom | Cause | Fix |
|---|---|---|
| Apply hangs waiting for completion | Retrohunt over a long historical window still RUNNING |
Increase timeouts.create, or poll state/progress_percentage separately |
state shows FAILED |
Malformed rule text, or a backend processing error | Confirm the referenced rule compiles successfully (terraform-google-chronicle-rule's compilation_state output) |
| Apply fails: process_interval invalid | start_time is after end_time, or timestamps are not valid RFC3339 |
Correct the interval; start_time must be β€ end_time |
A change to process_interval triggers a full replace |
Confirmed β this resource is create-only; there is no in-place update path | Expected behavior; a new retrohunt resource is the correct outcome |
google_chronicle_retrohuntprovider docsterraform-google-chronicle-ruleterraform-google-chronicle-rule-deployment- This module's
SCOPE.md