fix: guard ref names in billingaccountbinding create policy#69
Conversation
The create-with-refs rule matched on has(projectRef) and has(billingAccountRef) but its summary dereferenced projectRef.name and billingAccountRef.name. A create whose refs omit name (rejected by admission, but still recorded in the audit requestObject) raised CEL "no such key: name", sending the event to the DLQ -- the same leak class as milo-os/activity#212. Require the .name leaves in the match so malformed bindings fall through to the create-fallback rule instead of leaking.
create-with-refs reads audit.requestObject.spec refs (always present, safe), but create-fallback derefs audit.responseObject.metadata.name unconditionally. A create that misses the refs guard and is rejected returns a Status as responseObject with no metadata.name, raising "no such key: name" -> DLQ. A generateName create rejected before naming also has an empty objectRef.name. Replace with a per-level-guarded fallback chain: responseObject.metadata.name -> objectRef.name -> responseObject.details.name -> literal The details branch is guarded with has(responseObject.details) because some Status responses carry no details. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@ecv do you have the full audit log that was processed? I would expect it to always have a response object unless it's a non-successful request. We should probably add a check for failed requests and handle those appropriately. |
|
@scotwells the full audit log confirms your intuition: the response object is present, but on a non-successful request it's a The clearest live evidence I have is the same DLQ-leak class on the {
"auditID": "a6d769ee-6417-4620-893a-9364d8b809f9",
"verb": "create",
"level": "RequestResponse",
"requestURI": "/apis/resourcemanager.miloapis.com/v1alpha1/projects",
"objectRef": { "name": "personal-project-30ea0ba6", "resource": "projects" },
"responseObject": {
"apiVersion": "v1",
"kind": "Status",
"status": "Failure",
"reason": "Forbidden",
"code": 403,
"message": "... is forbidden: You've reached your quota for this resource type ...",
"metadata": {},
"details": { "group": "resourcemanager.miloapis.com", "kind": "projects", "name": "personal-project-30ea0ba6" }
},
"responseStatus": { "code": 403, "reason": "Forbidden", "status": "Failure", "metadata": {} }
}Processor error: For |
|
taking your steer on how to address this. set to draft, close, remain? |
What
Tighten the
create-with-refsmatch inbillingaccountbinding-policy.yamltorequire
projectRef.nameandbillingAccountRef.name, the fields its summarydereferences.
Why
Same DLQ-leak class as milo-os/activity#212. The match guarded only
has(projectRef)/has(billingAccountRef), but the summary derefs their.name. A create whose refs omitname(rejected by admission, but stillrecorded in the audit
requestObject) raises CELno such key: name→ eventto DLQ → retries fail.
Fix
Adding the
.nameleaves to the match routes malformed bindings to theexisting
create-fallbackrule (created billing account binding <name>)instead of leaking. Match-based guard, consistent with this file's style.
Remediation
Merge + billing release → the
billing-milo-activity-policiesFluxKustomization re-applies the corrected CR. No
kubectl.Related