1	# ---------------------------------------------------------------------------------------------------------------------
2	# VECTOR
3	# ---------------------------------------------------------------------------------------------------------------------
4	locals {
5	  vector_enabled = (
6	    var.vector_enabled != null
7	    ? var.vector_enabled
8	    : lookup(var.vector_enabled_cluster_types, local.cluster_type, true)
9	  )
10	  vector_endpoint = "http://vector.vector.svc.cluster.local:4317"
11	}
12
13	module "vector" {
14	  source = "git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/vector.git?ref=v1.0.0"
15	  count  = local.vector_enabled ? 1 : 0
16
17	  providers = {
18	    kubernetes = kubernetes.local-cluster
19	    helm       = helm.local-cluster
20	  }
21
22	  chart_version               = var.vector_chart_version
23	  image                       = var.vector_image
24	  image_tag_version           = var.vector_image_tag
25	  replicas                    = var.vector_replicas
26	  datadog_site                = var.vector_datadog_site
27	  datadog_api_key_vault_path  = var.vector_datadog_api_key_vault_path
28	  audit_drop_patterns         = var.vector_audit_drop_patterns
29	  email_redaction_enabled     = var.vector_email_redaction_enabled
30	  email_redaction_replacement = var.vector_email_redaction_replacement
31	  additional_config           = var.vector_additional_config
32
33	  # NOTE: The external-secrets internal-module (v1.2.0) has an empty outputs.tf
34	  # and does not expose cluster_secret_store_name. Until that output is added
35	  # to the external-secrets module, the ClusterSecretStore name is passed
36	  # explicitly via var.vector_external_secrets_cluster_store_name.
37	  # TODO: replace with module.external_secrets[0].cluster_secret_store_name
38	  # once the external-secrets internal-module exposes that output.
39	  external_secrets_cluster_store_name = var.vector_external_secrets_cluster_store_name
40
41	  depends_on = [
42	    module.cilium,
43	    module.external_secrets,
44	  ]
45	}
46
47	data "external" "vector_validate" {
48	  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0
49
50	  program = ["Error: vector can only be set if external-secrets is enabled as well"]
51	}
52
53	# ---------------------------------------------------------------------------------------------------------------------
54	# REQUIRED PARAMETERS
55	# These variables must be set.
56	# ---------------------------------------------------------------------------------------------------------------------
57	variable "vector_chart_version" {
58	  description = "Version of vector helm chart"
59	  type        = string
60	  default     = ""
61	  validation {
62	    condition     = var.vector_chart_version == "" && local.vector_enabled ? false : true
63	    error_message = "vector_chart_version must be set when vector is enabled"
64	  }
65	}
66
67	variable "vector_image_tag" {
68	  description = "Vector image tag"
69	  type        = string
70	  default     = ""
71	  validation {
72	    condition     = var.vector_image_tag == "" && local.vector_enabled ? false : true
73	    error_message = "vector_image_tag must be set when vector is enabled"
74	  }
75	}
76
77	variable "vector_datadog_site" {
78	  description = "Datadog site for vector sinks (e.g. datadoghq.com)"
79	  type        = string
80	  default     = ""
81	  validation {
82	    condition     = var.vector_datadog_site == "" && local.vector_enabled ? false : true
83	    error_message = "vector_datadog_site must be set when vector is enabled"
84	  }
85	}
86
87	variable "vector_datadog_api_key_vault_path" {
88	  description = "Vault path for the Datadog API key (consumed by ExternalSecret in vector ns)"
89	  type        = string
90	  default     = ""
91	  validation {
92	    condition     = var.vector_datadog_api_key_vault_path == "" && local.vector_enabled ? false : true
93	    error_message = "vector_datadog_api_key_vault_path must be set when vector is enabled"
94	  }
95	}
96
97	variable "vector_external_secrets_cluster_store_name" {
98	  description = "Name of the ClusterSecretStore to use for vector ExternalSecret resources. Pass the name created by the external-secrets module (typically 'vault-cluster-store'). Required when vector is enabled."
99	  type        = string
100	  default     = ""
101	  validation {
102	    condition     = var.vector_external_secrets_cluster_store_name == "" && local.vector_enabled ? false : true
103	    error_message = "vector_external_secrets_cluster_store_name must be set when vector is enabled"
104	  }
105	}
106
107	# ---------------------------------------------------------------------------------------------------------------------
108	# OPTIONAL PARAMETERS
109	# These variables are configurable, but have reasonable defaults set.
110	# ---------------------------------------------------------------------------------------------------------------------
111	variable "vector_enabled_cluster_types" {
112	  description = "Types of clusters Vector should be enabled on by default"
113	  type        = map(string)
114	  default = {
115	    "mgmt"  = true
116	    "cps"   = true
117	    "saas"  = true
118	    "infra" = false
119	    "dev"   = false
120	  }
121	}
122
123	variable "vector_enabled" {
124	  description = "Override for explicitly enabling or disabling Vector"
125	  type        = bool
126	  default     = null
127	}
128
129	variable "vector_image" {
130	  description = "Image for Vector"
131	  type        = string
132	  default     = "registry.ic-ops.net/cache-docker-hub/timberio/vector"
133	}
134
135	variable "vector_replicas" {
136	  description = "Number of Vector aggregator replicas"
137	  type        = number
138	  default     = 3
139	}
140
141	variable "vector_audit_drop_patterns" {
142	  description = "Regex patterns; matching log message bodies are dropped"
143	  type        = list(string)
144	  default = [
145	    "Audit\\s-\\s.+",
146	    "\"level\":\"audit\"",
147	  ]
148	}
149
150	variable "vector_email_redaction_enabled" {
151	  description = "Toggle the email-redact VRL transform across all signals"
152	  type        = bool
153	  default     = true
154	}
155
156	variable "vector_email_redaction_replacement" {
157	  description = "String that replaces matched email addresses"
158	  type        = string
159	  default     = "[REDACTED-EMAIL]"
160	}
161
162	variable "vector_additional_config" {
163	  description = "Alternate helm chart customConfig (overwrites entire helm config)"
164	  type        = any
165	  default     = null
166	}
167


1	# ---------------------------------------------------------------------------------------------------------------------
2	# METRICS SERVER
3	# ---------------------------------------------------------------------------------------------------------------------
4	locals {
5	  otel_collector_enabled = (
6	    var.otel_collector_enabled != null
7	    ? var.otel_collector_enabled
8	    : lookup(var.otel_collector_enabled_cluster_types, local.cluster_type, true)
9	  )
10	}
11
12	# OTEL Collector
13	module "otel_collector" {
14	  source = "git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/otel-collector.git?ref=v1.1.0"
15	  count  = local.otel_collector_enabled ? 1 : 0
16
17	  providers = {
18	    kubernetes = kubernetes.local-cluster
19	    helm       = helm.local-cluster
20	  }
21
22	  chart_version           = var.otel_collector_version
23	  otellb_image            = var.otel_lb_image
24	  otel_image              = var.otel_image
25	  otel_lb_replicas        = var.otel_lb_replicas
26	  otel_collector_replicas = var.otel_collector_replicas
27	  image_tag_version       = var.otel_collector_image_tag
28	  downstream_endpoint     = local.vector_enabled ? local.vector_endpoint : ""
29
30	  depends_on = [
31	    module.vector,
32	  ]
33	}
34
35	# ---------------------------------------------------------------------------------------------------------------------
36	# REQUIRED PARAMETERS
37	# These variables must be set.
38	# ---------------------------------------------------------------------------------------------------------------------
39	variable "otel_collector_version" {
40	  description = "Version of otel-collector helm chart"
41	  type        = string
42	  default     = ""
43	  validation {
44	    condition     = var.otel_collector_version == "" && local.otel_collector_enabled ? false : true
45	    error_message = "otel_collector_version must be set when otel_collector is enabled"
46	  }
47	}
48
49	variable "otel_collector_image_tag" {
50	  description = "Version of otel-collector image tag"
51	  type        = string
52	  default     = ""
53	  validation {
54	    condition     = var.otel_collector_image_tag == "" && local.otel_collector_enabled ? false : true
55	    error_message = "otel_collector_image_tag must be set when otel_collector is enabled"
56	  }
57	}
58
59	# ---------------------------------------------------------------------------------------------------------------------
60	# OPTIONAL PARAMETERS
61	# These variables are configurable, but have reasonable defaults set.
62	# ---------------------------------------------------------------------------------------------------------------------
63	variable "otel_collector_enabled_cluster_types" {
64	  description = "Types of clusters otel_collector should be enabled on by default"
65	  type        = map(string)
66	  default = {
67	    "mgmt"  = true
68	    "cps"   = true
69	    "saas"  = true
70	    "infra" = false
71	    "dev"   = false
72	  }
73	}
74
75	variable "otel_collector_enabled" {
76	  description = "Override for explicitly enabling or disabling otel-collector"
77	  type        = bool
78	  default     = null
79	}
80
81	variable "otel_lb_image" {
82	  description = "image for the otel collector loadbalancer"
83	  type        = string
84	  default     = "registry.ic-ops.net/cache-docker-hub/otel/opentelemetry-collector-contrib"
85	}
86
87	variable "otel_image" {
88	  description = "image for the otel collector/processor"
89	  type        = string
90	  default     = "registry.ic-ops.net/cache-docker-hub/otel/opentelemetry-collector-contrib"
91	}
92
93	variable "otel_lb_replicas" {
94	  description = "number of replicas for the otel loadbalancer to have"
95	  type        = number
96	  default     = 3
97	}
98
99	variable "otel_collector_replicas" {
100	  description = "number of replicas for the otel collector/processor to have"
101	  type        = number
102	  default     = 3
103	}
104
105	variable "otel_collector_additional_config" {
106	  description = "Alternate helm chart config to be used (overwrites entire helm config, does not merge)"
107	  type        = any
108	  default     = null
109	}
110


Now I have everything I need. The README is terraform-docs generated format. The structure is:
1. No title or preamble — starts directly with `## Requirements`
2. All inputs are in one large alphabetical table
3. No hand-written narrative sections

I need to:
1. Add a narrative section before `## Requirements` (or after `## Outputs`) documenting the Vector integration with data-flow, how-to-enable snippet, and variable table
2. Add the `module_vector` row to the Modules table
3. Add the 12 `vector_*` variable rows to the Inputs table in alphabetical order
4. Update the otel-collector module row version (v1.0.7 → v1.1.0)

Let me check the exact format of the module entry for otel_collector in the README and where `vector_*` vars would fall alphabetically:


Bash

Find otel_collector references in README


23:|  [addon-netpol](#module\_addon-netpol) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/network-policy.git | v1.1.0 |
37:|  [datadog\_agent](#module\_datadog\_agent) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/datadog-agent | v1.1.0 |
50:|  [otel\_collector](#module\_otel\_collector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/otel-collector.git | v1.0.7 |
256:|  [otel\_collector\_additional\_config](#input\_otel\_collector\_additional\_config) | Alternate helm chart config to be used (overwrites entire helm config, does not merge) | `any` | `null` | no |
257:|  [otel\_collector\_enabled](#input\_otel\_collector\_enabled) | Override for explicitly enabling or disabling otel-collector | `bool` | `null` | no |
258:|  [otel\_collector\_enabled\_cluster\_types](#input\_otel\_collector\_enabled\_cluster\_types) | Types of clusters otel\_collector should be enabled on by default | `map(string)` |
{
  "cps": true,
  "dev": false,
  "infra": false,
  "mgmt": true,
  "saas": true
}
 | no |
259:|  [otel\_collector\_image\_tag](#input\_otel\_collector\_image\_tag) | Version of otel-collector image tag | `string` | `""` | no |
260:|  [otel\_collector\_replicas](#input\_otel\_collector\_replicas) | number of replicas for the otel collector/processor to have | `number` | `3` | no |
261:|  [otel\_collector\_version](#input\_otel\_collector\_version) | Version of otel-collector helm chart | `string` | `""` | no |


grep -n "wireguard\|vpc_id\|## Outputs" "/Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md"

Find end of inputs table and outputs section


319:|  [vpc\_id](#input\_vpc\_id) | VPC in which to deploy the cluster | `string` | n/a | yes |
320:|  [wireguard\_enabled](#input\_wireguard\_enabled) | Enables Wireguard Encryption on clusters | `bool` | `true` | no |
322:## Outputs


Now I know where everything is. The `vector_*` variables come alphabetically between `vault_sidecar_injector_version` (line 318) and `vpc_id` (line 319). Let me check what's right before `vpc_id`:


315	|  [vault\_sidecar\_injector\_image\_tag](#input\_vault\_sidecar\_injector\_image\_tag) | Image tag for the vault sidecar injector | `string` | `""` | no |
316	|  [vault\_sidecar\_injector\_logformat](#input\_vault\_sidecar\_injector\_logformat) | Logging format for vault sidecar | `string` | `"json"` | no |
317	|  [vault\_sidecar\_injector\_loglevel](#input\_vault\_sidecar\_injector\_loglevel) | Logging level for vault sidecar | `string` | `"warn"` | no |
318	|  [vault\_sidecar\_injector\_version](#input\_vault\_sidecar\_injector\_version) | Version of the Vault helm chart, used to deploy the sidecar injector | `string` | `""` | no |
319	|  [vpc\_id](#input\_vpc\_id) | VPC in which to deploy the cluster | `string` | n/a | yes |
320	|  [wireguard\_enabled](#input\_wireguard\_enabled) | Enables Wireguard Encryption on clusters | `bool` | `true` | no |
321
322	## Outputs
323
324	| Name | Description |


Now let me check where the module table ends to find the right place to insert `module_vector`. It needs to be alphabetically between `module_vault_sidecar_injector` and... let me check:


Find module table entries near vault and end of modules section


51:|  [reloader](#module\_reloader) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/compute/reloader.git | v1.0.1 |
52:|  [s3\_csi\_driver](#module\_s3\_csi\_driver) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/storage/s3-csi-driver.git | v1.1.1 |
53:|  [s3\_csi\_driver\_sa](#module\_s3\_csi\_driver\_sa) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/aws/security/kubernetes-iam-serviceaccount.git | v7.0.0 |
54:|  [sysdig\_agent](#module\_sysdig\_agent) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/sysdig-agent.git | v4.0.0 |
55:|  [teleport](#module\_teleport) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/teleport-agent.git | v3.0.0 |
56:|  [teleport\_agent\_sa](#module\_teleport\_agent\_sa) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/aws/security/kubernetes-iam-serviceaccount.git | v7.0.0 |
57:|  [vault\_sidecar\_injector](#module\_vault\_sidecar\_injector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/vault-sidecar-injector.git | v4.1.0 |


57	|  [vault\_sidecar\_injector](#module\_vault\_sidecar\_injector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/vault-sidecar-injector.git | v4.1.0 |
58
59	## Resources
60
61	| Name | Type |
62	|------|------|
63	| [aws_eks_addon.aws_ebs_csi_driver](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_addon) | resource |
64	| [aws_eks_addon.kube_proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_addon) | resource |
65	| [aws_iam_role_policy_attachment.ebs_csi_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
66	| [aws_vpc_security_group_ingress_rule.cluster_mesh_cidrs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |


Good. `vector` comes after `vault_sidecar_injector` alphabetically (`ve` > `va`). So `module_vector` goes after line 57 (the vault_sidecar_injector module row), before the blank line at line 58.

Now I have a complete picture. Let me plan all the changes:

1. **Add narrative section** before `## Requirements` (at the start of the file, line 0) — a `## Vector (telemetry redaction aggregator)` section covering data-flow, how-to-enable, and cross-link to spec.

2. **Add `module_vector` row** after line 57 (vault_sidecar_injector), alphabetically correct.

3. **Update `module_otel_collector` version** from `v1.0.7` to `v1.1.0` on line 50.

4. **Add 12 `vector_*` input rows** between `vault_sidecar_injector_version` (line 318) and `vpc_id` (line 319).

Let me now make all the changes:


Edit

## Vector (telemetry redaction aggregator)

Vector is an optional in-cluster aggregator that sits between the OTel collector and Datadog. When enabled it applies VRL-based transforms — dropping audit log lines and redacting email addresses — across logs, traces, and metrics before shipping to Datadog. See the [design spec](../../../../docs/superpowers/specs/2026-05-05-vector-redaction-design.md) for full architecture, failure-mode analysis, and rollout guidance.

### Data flow

When `vector_enabled = true`:

```
apps → otel-lb → otel-collector → vector → Datadog
```

The otel-collector's terminal exporter switches from `datadog` to `otlp` (gRPC pointed at `vector.vector.svc.cluster.local:4317`). The Datadog API key ownership moves from the otel-collector to the Vector module's ExternalSecret. The otel-collector module is pinned to `v1.1.0` which introduced the `downstream_endpoint` variable; `v1.0.7` and earlier are not compatible with this mode.

When `vector_enabled = false` (or unset and the cluster type defaults to disabled):

```
apps → otel-lb → otel-collector → Datadog
```

The `otel-collector` module reverts to its original `datadog` exporter. No Vector resources are created.

### Enabling Vector for a cluster

The five required variables must be set together with `vector_enabled = true`. The remaining variables have defaults that are suitable for most clusters.

```hcl
vector_enabled                             = true
vector_chart_version                       = "0.36.0"
vector_image_tag                           = "0.40.0-distroless-libc"
vector_datadog_site                        = "datadoghq.com"
vector_datadog_api_key_vault_path          = "secret/data/datadog/api-key"
vector_external_secrets_cluster_store_name = "vault-cluster-store"
```

Vector requires `external_secrets_enabled = true` (or a cluster type that enables it by default). A Terraform validation block enforces this dependency.

### Vector variables

| Variable | Description | Type | Default | Required when enabled |
|---|---|---|---|---|
| `vector_chart_version` | Vector helm chart version pin | `string` | `""` | yes |
| `vector_image_tag` | Vector image tag | `string` | `""` | yes |
| `vector_datadog_site` | Datadog site for Vector sinks (e.g. `datadoghq.com`) | `string` | `""` | yes |
| `vector_datadog_api_key_vault_path` | Vault path for the Datadog API key consumed by Vector's ExternalSecret | `string` | `""` | yes |
| `vector_external_secrets_cluster_store_name` | Name of the ClusterSecretStore created by the external-secrets module | `string` | `""` | yes |
| `vector_enabled` | Override for explicitly enabling or disabling Vector | `bool` | `null` | no |
| `vector_enabled_cluster_types` | Per-cluster-type defaults (`mgmt/cps/saas=true`, `infra/dev=false`) | `map(bool)` | see below | no |
| `vector_image` | Vector container image (registry/path) | `string` | `registry.ic-ops.net/cache-docker-hub/timberio/vector` | no |
| `vector_replicas` | Number of Vector aggregator replicas | `number` | `3` | no |
| `vector_audit_drop_patterns` | Regex patterns; matching log message bodies are dropped before Datadog | `list(string)` | Immuta audit patterns | no |
| `vector_email_redaction_enabled` | Toggle the email-redact VRL transform across all three signals | `bool` | `true` | no |
| `vector_email_redaction_replacement` | Replacement string for redacted email addresses | `string` | `[REDACTED-EMAIL]` | no |
| `vector_additional_config` | Escape-hatch: overwrites the entire Vector `customConfig` helm value | `any` | `null` | no |

---

## Requirements


The file /Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md has been updated successfully. (file state is current in your context — no need to Read it back)


Now update the otel_collector module version from v1.0.7 to v1.1.0:


|  [otel\_collector](#module\_otel\_collector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/otel-collector.git | v1.0.7 |

|  [otel\_collector](#module\_otel\_collector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/otel-collector.git | v1.1.0 |


Now add the `module_vector` row after `module_vault_sidecar_injector`:


|  [vault\_sidecar\_injector](#module\_vault\_sidecar\_injector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/vault-sidecar-injector.git | v4.1.0 |

## Resources

|  [vault\_sidecar\_injector](#module\_vault\_sidecar\_injector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/security/vault-sidecar-injector.git | v4.1.0 |
|  [vector](#module\_vector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/vector.git | v1.0.0 |

## Resources


Now add the 12 `vector_*` input rows. They go between `vault_sidecar_injector_version` and `vpc_id`. Let me construct the rows in alphabetical order:

- `vector_additional_config` (va < vc... actually `vector_a` < `vector_c` < `vector_d` < `vector_e` (x2) < `vector_i` < `vector_r` < `vector_enabled`, `vector_enabled_cluster_types`... let me sort properly)

Alphabetical order of the 12 variables:
1. `vector_additional_config`
2. `vector_audit_drop_patterns`
3. `vector_chart_version`
4. `vector_datadog_api_key_vault_path`
5. `vector_datadog_site`
6. `vector_email_redaction_enabled`
7. `vector_email_redaction_replacement`
8. `vector_enabled`
9. `vector_enabled_cluster_types`
10. `vector_external_secrets_cluster_store_name`
11. `vector_image`
12. `vector_image_tag`
13. `vector_replicas`

Wait, that's 13. Let me re-count from the task: the task lists 12+1=13 variables. The task says "12 new variables" but lists 13. Let me count from the actual `vector.tf`:
1. `vector_chart_version`
2. `vector_image_tag`
3. `vector_datadog_site`
4. `vector_datadog_api_key_vault_path`
5. `vector_external_secrets_cluster_store_name`
6. `vector_enabled_cluster_types`
7. `vector_enabled`
8. `vector_image`
9. `vector_replicas`
10. `vector_audit_drop_patterns`
11. `vector_email_redaction_enabled`
12. `vector_email_redaction_replacement`
13. `vector_additional_config`

That's 13 variables. The task description says 12 but the task context lists 13 (including `vector_external_secrets_cluster_store_name`). I'll document all 13.

Alphabetical sort:
1. `vector_additional_config`
2. `vector_audit_drop_patterns`
3. `vector_chart_version`
4. `vector_datadog_api_key_vault_path`
5. `vector_datadog_site`
6. `vector_email_redaction_enabled`
7. `vector_email_redaction_replacement`
8. `vector_enabled`
9. `vector_enabled_cluster_types`
10. `vector_external_secrets_cluster_store_name`
11. `vector_image`
12. `vector_image_tag`
13. `vector_replicas`

Now I need to format these exactly like the existing input rows. The default for `vector_enabled_cluster_types` is a map with 5 entries. Let me look at a comparable map default to get the exact format:

Looking at `otel_collector_enabled_cluster_types` (line 258):
```
`map(string)` | <pre>{<br/>  "cps": true,<br/>  "dev": false,<br/>  "infra": false,<br/>  "mgmt": true,<br/>  "saas": true<br/>}</pre>
```

Note: the vector type is `map(string)` in the README even though the actual type is `map(bool)` — the README uses `map(string)` for all such defaults. I'll match the existing convention: use `map(string)` to be consistent with the existing pattern (though technically `map(bool)` is correct). Actually looking at the README, `application_deployment_enabled_cluster_types` uses `map(bool)` at line 88. Let me check — yes it shows `map(bool)`. For `vector_enabled_cluster_types` the actual type is `map(string)` per the vector.tf file (line 113: `type = map(string)`). So I'll use `map(string)`.

For `vector_audit_drop_patterns`, the default is a list of two strings. Looking at `cluster_mesh_tls_names` or similar for a list default format:
```
`list(string)` | `[]` | no
```
But we have non-empty defaults. Looking at how other lists with values are shown... Actually the file doesn't seem to have a list with a non-empty default other than `kyverno_cluster_role_rules`. I'll use `<pre>` format for the list.

The `vector_email_redaction_replacement` default `[REDACTED-EMAIL]` contains brackets — in the table it should be escaped or wrapped. I'll wrap it in backticks within the cell.

Let me now construct the rows:


|  [vault\_sidecar\_injector\_version](#input\_vault\_sidecar\_injector\_version) | Version of the Vault helm chart, used to deploy the sidecar injector | `string` | `""` | no |
|  [vpc\_id](#input\_vpc\_id) | VPC in which to deploy the cluster | `string` | n/a | yes |

|  [vault\_sidecar\_injector\_version](#input\_vault\_sidecar\_injector\_version) | Version of the Vault helm chart, used to deploy the sidecar injector | `string` | `""` | no |
|  [vector\_additional\_config](#input\_vector\_additional\_config) | Alternate helm chart customConfig for Vector (overwrites entire helm config, does not merge) | `any` | `null` | no |
|  [vector\_audit\_drop\_patterns](#input\_vector\_audit\_drop\_patterns) | Regex patterns; log message bodies matching any pattern are dropped before Datadog | `list(string)` |
[
  "Audit\\s-\\s.+",
  "\"level\":\"audit\""
]
 | no |
|  [vector\_chart\_version](#input\_vector\_chart\_version) | Version of Vector helm chart | `string` | `""` | no |
|  [vector\_datadog\_api\_key\_vault\_path](#input\_vector\_datadog\_api\_key\_vault\_path) | Vault path for the Datadog API key consumed by Vector's ExternalSecret | `string` | `""` | no |
|  [vector\_datadog\_site](#input\_vector\_datadog\_site) | Datadog site for Vector sinks (e.g. `datadoghq.com`) | `string` | `""` | no |
|  [vector\_email\_redaction\_enabled](#input\_vector\_email\_redaction\_enabled) | Toggle the email-redact VRL transform across logs, traces, and metrics | `bool` | `true` | no |
|  [vector\_email\_redaction\_replacement](#input\_vector\_email\_redaction\_replacement) | String that replaces matched email addresses | `string` | `"[REDACTED-EMAIL]"` | no |
|  [vector\_enabled](#input\_vector\_enabled) | Override for explicitly enabling or disabling Vector | `bool` | `null` | no |
|  [vector\_enabled\_cluster\_types](#input\_vector\_enabled\_cluster\_types) | Types of clusters Vector should be enabled on by default | `map(string)` |
{
  "cps": true,
  "dev": false,
  "infra": false,
  "mgmt": true,
  "saas": true
}
 | no |
|  [vector\_external\_secrets\_cluster\_store\_name](#input\_vector\_external\_secrets\_cluster\_store\_name) | Name of the ClusterSecretStore (created by the external-secrets module) used by Vector's ExternalSecret. Required when Vector is enabled. | `string` | `""` | no |
|  [vector\_image](#input\_vector\_image) | Image for the Vector aggregator | `string` | `"registry.ic-ops.net/cache-docker-hub/timberio/vector"` | no |
|  [vector\_image\_tag](#input\_vector\_image\_tag) | Vector image tag | `string` | `""` | no |
|  [vector\_replicas](#input\_vector\_replicas) | Number of Vector aggregator replicas | `number` | `3` | no |
|  [vpc\_id](#input\_vpc\_id) | VPC in which to deploy the cluster | `string` | n/a | yes |


Now let me verify all the changes look correct:


Bash

grep -n "vector\|Vector\|otel_collector.*v1\." "/Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md" | head -60

Verify all vector and otel_collector references in README


1:## Vector (telemetry redaction aggregator)
3:Vector is an optional in-cluster aggregator that sits between the OTel collector and Datadog. When enabled it applies VRL-based transforms — dropping audit log lines and redacting email addresses — across logs, traces, and metrics before shipping to Datadog. See the [design spec](../../../../docs/superpowers/specs/2026-05-05-vector-redaction-design.md) for full architecture, failure-mode analysis, and rollout guidance.
7:When `vector_enabled = true`:
10:apps → otel-lb → otel-collector → vector → Datadog
13:The otel-collector's terminal exporter switches from `datadog` to `otlp` (gRPC pointed at `vector.vector.svc.cluster.local:4317`). The Datadog API key ownership moves from the otel-collector to the Vector module's ExternalSecret. The otel-collector module is pinned to `v1.1.0` which introduced the `downstream_endpoint` variable; `v1.0.7` and earlier are not compatible with this mode.
15:When `vector_enabled = false` (or unset and the cluster type defaults to disabled):
21:The `otel-collector` module reverts to its original `datadog` exporter. No Vector resources are created.
23:### Enabling Vector for a cluster
25:The five required variables must be set together with `vector_enabled = true`. The remaining variables have defaults that are suitable for most clusters.
28:vector_enabled                             = true
29:vector_chart_version                       = "0.36.0"
30:vector_image_tag                           = "0.40.0-distroless-libc"
31:vector_datadog_site                        = "datadoghq.com"
32:vector_datadog_api_key_vault_path          = "secret/data/datadog/api-key"
33:vector_external_secrets_cluster_store_name = "vault-cluster-store"
36:Vector requires `external_secrets_enabled = true` (or a cluster type that enables it by default). A Terraform validation block enforces this dependency.
38:### Vector variables
42:| `vector_chart_version` | Vector helm chart version pin | `string` | `""` | yes |
43:| `vector_image_tag` | Vector image tag | `string` | `""` | yes |
44:| `vector_datadog_site` | Datadog site for Vector sinks (e.g. `datadoghq.com`) | `string` | `""` | yes |
45:| `vector_datadog_api_key_vault_path` | Vault path for the Datadog API key consumed by Vector's ExternalSecret | `string` | `""` | yes |
46:| `vector_external_secrets_cluster_store_name` | Name of the ClusterSecretStore created by the external-secrets module | `string` | `""` | yes |
47:| `vector_enabled` | Override for explicitly enabling or disabling Vector | `bool` | `null` | no |
48:| `vector_enabled_cluster_types` | Per-cluster-type defaults (`mgmt/cps/saas=true`, `infra/dev=false`) | `map(bool)` | see below | no |
49:| `vector_image` | Vector container image (registry/path) | `string` | `registry.ic-ops.net/cache-docker-hub/timberio/vector` | no |
50:| `vector_replicas` | Number of Vector aggregator replicas | `number` | `3` | no |
51:| `vector_audit_drop_patterns` | Regex patterns; matching log message bodies are dropped before Datadog | `list(string)` | Immuta audit patterns | no |
52:| `vector_email_redaction_enabled` | Toggle the email-redact VRL transform across all three signals | `bool` | `true` | no |
53:| `vector_email_redaction_replacement` | Replacement string for redacted email addresses | `string` | `[REDACTED-EMAIL]` | no |
54:| `vector_additional_config` | Escape-hatch: overwrites the entire Vector `customConfig` helm value | `any` | `null` | no |
107:|  [otel\_collector](#module\_otel\_collector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/otel-collector.git | v1.1.0 |
115:|  [vector](#module\_vector) | git@gitlab.infrastructure.immuta.io:infrastructure/terraform/internal-modules/kubernetes/monitoring/vector.git | v1.0.0 |
377:|  [vector\_additional\_config](#input\_vector\_additional\_config) | Alternate helm chart customConfig for Vector (overwrites entire helm config, does not merge) | `any` | `null` | no |
378:|  [vector\_audit\_drop\_patterns](#input\_vector\_audit\_drop\_patterns) | Regex patterns; log message bodies matching any pattern are dropped before Datadog | `list(string)` |
[
  "Audit\\s-\\s.+",
  "\"level\":\"audit\""
]
 | no |
379:|  [vector\_chart\_version](#input\_vector\_chart\_version) | Version of Vector helm chart | `string` | `""` | no |
380:|  [vector\_datadog\_api\_key\_vault\_path](#input\_vector\_datadog\_api\_key\_vault\_path) | Vault path for the Datadog API key consumed by Vector's ExternalSecret | `string` | `""` | no |
381:|  [vector\_datadog\_site](#input\_vector\_datadog\_site) | Datadog site for Vector sinks (e.g. `datadoghq.com`) | `string` | `""` | no |
382:|  [vector\_email\_redaction\_enabled](#input\_vector\_email\_redaction\_enabled) | Toggle the email-redact VRL transform across logs, traces, and metrics | `bool` | `true` | no |
383:|  [vector\_email\_redaction\_replacement](#input\_vector\_email\_redaction\_replacement) | String that replaces matched email addresses | `string` | `"[REDACTED-EMAIL]"` | no |
384:|  [vector\_enabled](#input\_vector\_enabled) | Override for explicitly enabling or disabling Vector | `bool` | `null` | no |
385:|  [vector\_enabled\_cluster\_types](#input\_vector\_enabled\_cluster\_types) | Types of clusters Vector should be enabled on by default | `map(string)` |
{
  "cps": true,
  "dev": false,
  "infra": false,
  "mgmt": true,
  "saas": true
}
 | no |
386:|  [vector\_external\_secrets\_cluster\_store\_name](#input\_vector\_external\_secrets\_cluster\_store\_name) | Name of the ClusterSecretStore (created by the external-secrets module) used by Vector's ExternalSecret. Required when Vector is enabled. | `string` | `""` | no |
387:|  [vector\_image](#input\_vector\_image) | Image for the Vector aggregator | `string` | `"registry.ic-ops.net/cache-docker-hub/timberio/vector"` | no |
388:|  [vector\_image\_tag](#input\_vector\_image\_tag) | Vector image tag | `string` | `""` | no |
389:|  [vector\_replicas](#input\_vector\_replicas) | Number of Vector aggregator replicas | `number` | `3` | no |


Count final line count


397 /Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md


All changes are in place. Let me do a final verification pass:


Count total vector_ references


grep -n "v1.0.7" "/Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md"

Confirm v1.0.7 is gone from README


13:The otel-collector's terminal exporter switches from `datadog` to `otlp` (gRPC pointed at `vector.vector.svc.cluster.local:4317`). The Datadog API key ownership moves from the otel-collector to the Vector module's ExternalSecret. The otel-collector module is pinned to `v1.1.0` which introduced the `downstream_endpoint` variable; `v1.0.7` and earlier are not compatible with this mode.


The `v1.0.7` reference that remains is intentional — it's in the narrative prose explaining that v1.0.7 and earlier are not compatible with Vector mode (it's the "before" version called out for context, not a version reference to update). The Modules table now correctly shows `v1.1.0`.


grep -n "input_vector" "/Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md" | wc -l

Count vector input anchors in inputs table


All 13 variables are present in the inputs table. Everything checks out.

---

**Status: DONE**

**Summary of changes to `/Users/steve.briggs/projects/IAC/terraform/iac-library/aws/compute/eks-cluster-applications/README.md`:**

- **Lines added:** 71 lines (file grew from 326 to 397 lines)
- **Lines modified:** 1 (otel_collector module version bump)

**Specific changes:**

1. **New narrative section** (`## Vector (telemetry redaction aggregator)`) prepended before `## Requirements` (lines 1–55). Covers:
   - What Vector does and a link to the design spec at `../../../../docs/superpowers/specs/2026-05-05-vector-redaction-design.md`
   - Dual-mode data-flow diagrams (with-Vector vs. without-Vector)
   - Note about the otel-collector exporter swap and API key ownership move
   - How-to-enable HCL snippet with all 6 required variables
   - External-secrets dependency callout
   - Summary variable table (13 rows)

2. **Module table** (Modules section): Added `module_vector` row (`v1.0.0`) in alphabetical position after `module_vault_sidecar_injector`.

3. **Module table** (Modules section): Updated `module_otel_collector` version from `v1.0.7` to `v1.1.0`.

4. **Inputs table**: Added 13 `vector_*` input rows in alphabetical order between `vault_sidecar_injector_version` and `vpc_id`.

**Variables documented:** 13 (the task brief said 12, but `vector_external_secrets_cluster_store_name` is a 13th variable present in `vector.tf` — it's documented in both the narrative table and the Inputs table).

**Existing otel-collector copy updated:** Yes — the Modules table version was bumped from `v1.0.7` to `v1.1.0`. The narrative section also explains the behavioral change (exporter swap from `datadog` to `otlp`, API key ownership moving to Vector). The `v1.0.7` mention that remains in the prose is intentional context ("v1.0.7 and earlier are not compatible with this mode").

**Self-review findings:** Structure and formatting matches the existing terraform-docs style. No existing sections were disrupted. The narrative section follows the pattern of being placed before the auto-generated terraform-docs block (which is the only sensible place since the rest is pure table rows). The `vector_enabled_cluster_types` map default in the Inputs table uses `map(string)` to match `otel_collector_enabled_cluster_types` (the actual type in `vector.tf` is also `map(string)`). The `vector_email_redaction_replacement` default is quoted as `"[REDACTED-EMAIL]"` so the brackets don't break the Markdown table.