You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add field-level redaction for denied_resources
Add redacted_fields and redaction_mode to denied_resources config entries.
When redacted_fields is set, the resource is allowed through the access
control layer but specified fields have their values replaced with a
redaction marker before being returned to the agent.
Two modes are supported:
- opaque: replaces values with [REDACTED]
- hashed: replaces values with [REDACTED:gen_<id>:<hash>] using
HMAC-SHA256 with a per-startup random salt for cross-resource
value correlation without exposing actual content.
Fields use dot-separated paths with * wildcard support that adapts
to the runtime type (map keys or array items).
Config validation ensures redacted_fields requires kind to be set,
preventing accidental security bypasses on entire API groups.
Signed-off-by: Yury Sokov <me@yurzs.dev>
Copy file name to clipboardExpand all lines: docs/configuration.md
+63-3Lines changed: 63 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -369,13 +369,23 @@ description = "Get a Kubernetes resource by name. Always specify the namespace e
369
369
370
370
### Denied Resources
371
371
372
-
Prevent access to specific Kubernetes resource types.
372
+
Prevent access to specific Kubernetes resource types, or allow access with field-level redaction.
373
373
374
374
| Field | Type | Default | Description |
375
375
|-------|------|---------|-------------|
376
-
| `denied_resources` | array | `[]` | List of GroupVersionKind objects that should not be accessible. |
376
+
| `denied_resources` | array | `[]` | List of GroupVersionKind objects that should not be accessible (or should be accessible with redacted fields). |
377
377
378
-
**Example:**
378
+
Each entry in `denied_resources` supports the following fields:
379
+
380
+
| Field | Type | Default | Description |
381
+
|-------|------|---------|-------------|
382
+
| `group` | string | required | API group (e.g. `""` for core, `"apps"` for apps/v1) |
383
+
| `version` | string | required | API version (e.g. `"v1"`) |
384
+
| `kind` | string | optional | Resource kind (e.g. `"Secret"`). If omitted, denies the entire group/version. |
385
+
| `redacted_fields` | array | `[]` | Dot-separated field paths to redact instead of denying the resource entirely. Requires `kind` to be set. |
386
+
| `redaction_mode` | string | `"opaque"` | How to redact values: `"opaque"`or `"hashed"`. |
387
+
388
+
**Example — fully deny resources:**
379
389
```toml
380
390
# Deny access to Secrets and ConfigMaps
381
391
[[denied_resources]]
@@ -410,6 +420,56 @@ version = "v1"
410
420
kind = "ClusterRoleBinding"
411
421
```
412
422
423
+
#### Field-Level Redaction
424
+
425
+
Instead of fully denying a resource, you can allow access but redact sensitive fields. This is useful for resources like Secrets where the agent needs to see metadata (name, namespace, keys, type, ownership) but should not see actual values.
426
+
427
+
When `redacted_fields` is set, the resource is allowed through the access control layer and the specified fields have their values replaced with a redaction marker before being returned.
428
+
429
+
**Example — redact Secret values while keeping metadata and key names visible:**
430
+
```toml
431
+
[[denied_resources]]
432
+
group = ""
433
+
version = "v1"
434
+
kind = "Secret"
435
+
redacted_fields = ["data.*", "stringData.*"]
436
+
redaction_mode = "hashed"
437
+
```
438
+
439
+
**Path syntax:**
440
+
441
+
Fields are specified as dot-separated paths with `*` wildcard support. The wildcard adapts to the type it encounters — it iterates keys in a map and items in an array.
442
+
443
+
| Path | Behavior |
444
+
|------|----------|
445
+
| `data.*` | Redact all values in a map (keys remain visible) |
446
+
| `spec.credentials` | Redact a single field |
447
+
| `spec.template.spec.containers.*.env.*.value` | Traverse arrays and maps to reach nested fields |
448
+
449
+
**Redaction modes:**
450
+
451
+
- `opaque` (default): replaces values with `[REDACTED]`
452
+
- `hashed`: replaces values with `[REDACTED:gen_<id>:<hash>]`
453
+
454
+
Hashed mode uses HMAC-SHA256 with a random salt generated once at server startup. This allows the agent to detect when two different resources reference the same value (e.g. two services using the same connection string) without exposing the actual content. The salt is never persisted and changes on restart. A generation ID is included so consumers can detect when the salt changed and know that hashes from different generations are not comparable.
0 commit comments