Skip to content

Commit d6b8942

Browse files
committed
fix: guard DNSRecordSet activity summaries against missing fields
Several DNSRecordSet create/update/delete/system activity rules built their summary from annotations or spec fields that the rule's match did not guarantee were present. When a record set lacked the dereferenced key, summary evaluation errored (no such key) and the activity event was dead-lettered, so the operation never appeared in the activity feed. Tighten each affected rule's match so events missing a field fall through to the existing generic and last-resort fallback rules instead of erroring. Key changes: - A/AAAA, CNAME, ALIAS, MX create/update rules now require the display-value annotation their summary reads - Rules whose summary or match reads spec.recordType now require has(...spec.recordType): type-specific create/update, create/update -other-annotated, create/update-from-request, delete-from-response, and both system-create rules - Summary wording is unchanged; the fallback chain (generic record-type summary, then "a DNS record") requires no field access and stays safe Claude-Session: https://claude.ai/code/session_01KnYuL5Pf1R5ysZoxxNkKiu
1 parent aa17fd8 commit d6b8942

1 file changed

Lines changed: 15 additions & 15 deletions

File tree

config/milo/activity/policies/dnsrecordset-policy.yaml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,43 +49,43 @@ spec:
4949
# ----- CREATE RULES (type-specific with display annotations) -----
5050
# A/AAAA records with display annotations: "added www.example.com pointing to 192.0.2.10"
5151
- name: create-a-aaaa
52-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType in ['A', 'AAAA'] && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
52+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType in ['A', 'AAAA'] && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
5353
summary: "{{ actor }} added {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} pointing to {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
5454

5555
# CNAME records with display annotations: "added api.example.com as an alias for api.internal.example.com"
5656
- name: create-cname
57-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'CNAME' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
57+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'CNAME' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
5858
summary: "{{ actor }} added {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} as an alias for {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
5959

6060
# ALIAS records with display annotations: "added example.com as an alias for lb.example.com"
6161
- name: create-alias
62-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'ALIAS' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
62+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'ALIAS' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
6363
summary: "{{ actor }} added {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} as an alias for {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
6464

6565
# MX records with display annotations: "configured mail for example.com using 10 mail.example.com"
6666
- name: create-mx
67-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'MX' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
67+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'MX' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
6868
summary: "{{ actor }} configured mail for {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} using {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
6969

7070
# TXT records with display annotations: "added TXT record for example.com"
7171
- name: create-txt
72-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'TXT' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
72+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'TXT' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
7373
summary: "{{ actor }} added a TXT record for {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }}"
7474

7575
# NS records with display annotations: "added nameservers for sub.example.com"
7676
- name: create-ns
77-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'NS' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
77+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'NS' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
7878
summary: "{{ actor }} added nameservers for {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }}"
7979

8080
# Generic create with display annotations: "added SRV record for _sip._tcp.example.com"
8181
- name: create-other-annotated
82-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec)"
82+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
8383
summary: "{{ actor }} added a {{ audit.requestObject.spec.recordType }} record for {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }}"
8484

8585
# Create with audit.requestObject.spec but no display annotations: "added an A record"
8686
# Uses audit.requestObject.spec which is available at Request audit level and above.
8787
- name: create-from-request
88-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec)"
88+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
8989
summary: "{{ actor }} added {{ link('a ' + audit.requestObject.spec.recordType + ' record', audit.objectRef) }}"
9090

9191
# Create last resort (no spec available at all): "added a DNS record"
@@ -101,7 +101,7 @@ spec:
101101

102102
# Delete with audit.responseObject.spec available: "removed an A record"
103103
- name: delete-from-response
104-
match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete' && has(audit.responseObject.spec)"
104+
match: "!audit.user.username.startsWith('system:') && audit.verb == 'delete' && has(audit.responseObject.spec) && has(audit.responseObject.spec.recordType)"
105105
summary: "{{ actor }} removed {{ link('a ' + audit.responseObject.spec.recordType + ' record', audit.objectRef) }}"
106106

107107
# Delete last resort: "removed a DNS record"
@@ -112,22 +112,22 @@ spec:
112112
# ----- UPDATE RULES (type-specific with display annotations) -----
113113
# A/AAAA records with display annotations: "updated www.example.com to point to 192.0.2.20"
114114
- name: update-a-aaaa
115-
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec) && audit.requestObject.spec.recordType in ['A', 'AAAA'] && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
115+
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType in ['A', 'AAAA'] && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
116116
summary: "{{ actor }} updated {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} to point to {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
117117

118118
# CNAME records with display annotations: "updated api.example.com to alias api.v2.example.com"
119119
- name: update-cname
120-
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec) && audit.requestObject.spec.recordType == 'CNAME' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations"
120+
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType) && audit.requestObject.spec.recordType == 'CNAME' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && 'dns.networking.miloapis.com/display-value' in audit.responseObject.metadata.annotations"
121121
summary: "{{ actor }} updated {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }} to alias {{ audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-value'] }}"
122122

123123
# Generic update with display annotations
124124
- name: update-other-annotated
125-
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec)"
125+
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
126126
summary: "{{ actor }} updated {{ audit.requestObject.spec.recordType }} record {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }}"
127127

128128
# Update with audit.requestObject.spec but no display annotations: "updated an A record"
129129
- name: update-from-request
130-
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec)"
130+
match: "!audit.user.username.startsWith('system:') && audit.verb in ['update', 'patch'] && !has(audit.objectRef.subresource) && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
131131
summary: "{{ actor }} updated {{ link('a ' + audit.requestObject.spec.recordType + ' record', audit.objectRef) }}"
132132

133133
# Update last resort: "updated a DNS record"
@@ -138,12 +138,12 @@ spec:
138138
# ----- SYSTEM CREATE RULES -----
139139
# System-created records (SOA, NS) with display annotations
140140
- name: system-create-annotated
141-
match: "audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec)"
141+
match: "audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.responseObject.metadata.annotations) && 'dns.networking.miloapis.com/display-name' in audit.responseObject.metadata.annotations && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
142142
summary: "Default {{ audit.requestObject.spec.recordType }} record created for {{ link(audit.responseObject.metadata.annotations['dns.networking.miloapis.com/display-name'], audit.objectRef) }}"
143143

144144
# System-created records with spec but no display annotations
145145
- name: system-create-from-request
146-
match: "audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec)"
146+
match: "audit.user.username.startsWith('system:') && audit.verb == 'create' && has(audit.requestObject.spec) && has(audit.requestObject.spec.recordType)"
147147
summary: "Default {{ audit.requestObject.spec.recordType }} record created for {{ link(audit.objectRef.name, audit.objectRef) }}"
148148

149149
# Event rules for controller-emitted Kubernetes events.

0 commit comments

Comments
 (0)