GKE Certificate Signing Request Self-Approved
Detects when the same non-system GKE identity creates a CertificateSigningRequest (CSR) and then approves that same CSR within five minutes, consistent with self-approval abuse. Attackers who gain CSR create and approval RBAC can submit a certificate request and approve it themselves to obtain a long-lived client certificate without involving cluster operators, a pattern documented in Kubernetes persistence research and adversary emulation.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/07/10"
3integration = ["gcp"]
4maturity = "production"
5updated_date = "2026/07/10"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects when the same non-system GKE identity creates a CertificateSigningRequest (CSR) and then approves that same CSR
11within five minutes, consistent with self-approval abuse. Attackers who gain CSR create and approval RBAC
12can submit a certificate request and approve it themselves to obtain a long-lived client certificate without involving
13cluster operators, a pattern documented in Kubernetes persistence research and adversary emulation.
14"""
15false_positives = [
16 """
17 Automation that both submits and approves CSRs in one workflow may trigger this rule. Baseline cert-manager or
18 internal PKI pipelines and tune exclusions for known service accounts.
19 """,
20]
21from = "now-11m"
22language = "esql"
23license = "Elastic License v2"
24name = "GKE Certificate Signing Request Self-Approved"
25note = """## Triage and analysis
26
27### Investigating GKE Certificate Signing Request Self-Approved
28
29This rule groups CSR create and approval events by `client.user.email` and normalized CSR name (`Esql.csr_name`).
30GKE logs approval on subresource paths (`.../csr-name/approval`), so the query strips `/approval` suffixes before
31correlating. An alert means the same identity both submitted and approved the same CSR within five minutes, a strong
32indicator of manual self-approval rather than normal `system:gcp-controller-manager` auto-approval of node
33certificates.
34
35### Possible investigation steps
36
37- Review `Esql.event_action_values` for the sequence of create followed by `approval.update`.
38- Inspect `gcp.audit.request.spec.signerName` and decode `gcp.audit.request.spec.request` on create events for the
39 requested identity.
40- Validate whether the actor should hold both CSR create and approval permissions.
41- Hunt for subsequent API activity authenticated as the minted certificate identity.
42
43### False positive analysis
44
45- cert-manager or internal PKI automation that creates and approves CSRs under the same service account in one workflow.
46- GitOps or bootstrap tooling that submits and signs CSRs programmatically. Baseline known automation and tune exclusions
47 for those principals.
48- Two unrelated CSR events from the same user within five minutes should not match because the query requires at least
49 one create and one approval-class action on the same normalized CSR name.
50
51### Related rules
52
53- GKE Certificate Signing Request API Client Signer Requested - 1e344fba-a2f7-462b-aaec-d6c8f80d5a28
54- GKE Certificate Signing Request Privileged Identity Requested - 4159bec9-76ad-4cdc-a797-4a8572073bbe
55- GKE Client Certificate Signing Request Created or Approved - ec67ab57-945a-4edb-84f8-1d7a51f46544
56
57### Response and remediation
58
59- Revoke or deny the CSR, remove approval RBAC from untrusted principals, and rotate cluster signing credentials if
60 abuse is confirmed.
61
62"""
63setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
64references = [
65 "https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/",
66 "https://kubernetes.io/docs/concepts/security/rbac-good-practices/",
67 "https://stratus-red-team.cloud/attack-techniques/kubernetes/k8s.persistence.create-client-certificate/",
68 "https://raesene.github.io/blog/2022/12/21/Kubernetes-persistence-with-Tocan-and-Teisteanas/",
69 "https://www.aquasec.com/blog/kubernetes-rbac-privilige-escalation/",
70]
71risk_score = 73
72rule_id = "e155e658-3dcd-4d27-a4e5-1d8da6704b0e"
73severity = "high"
74tags = [
75 "Domain: Cloud",
76 "Domain: Kubernetes",
77 "Data Source: GCP",
78 "Data Source: GCP Audit Logs",
79 "Data Source: Google Cloud Platform",
80 "Use Case: Threat Detection",
81 "Tactic: Persistence",
82 "Tactic: Privilege Escalation",
83 "Resources: Investigation Guide",
84]
85timestamp_override = "event.ingested"
86type = "esql"
87
88query = '''
89from logs-gcp.audit-* metadata _id, _index, _version
90| where data_stream.dataset == "gcp.audit"
91 and service.name == "k8s.io"
92 and event.outcome == "success"
93 and event.action in (
94 "io.k8s.certificates.v1.certificatesigningrequests.create",
95 "io.k8s.certificates.v1.certificatesigningrequests.approval.update"
96 )
97 and client.user.email is not null
98 and gcp.audit.resource_name is not null
99 and not client.user.email in (
100 "system:gcp-controller-manager",
101 "system:kube-controller-manager",
102 "system:serviceaccount:kube-system:certificate-controller",
103 "kubelet-bootstrap",
104 "kubelet-nodepool-bootstrap"
105 )
106 and not client.user.email like "system:node:*"
107| eval Esql.csr_name = replace(gcp.audit.resource_name, "/approval", "")
108| stats
109 Esql.create_count = count(*) where event.action == "io.k8s.certificates.v1.certificatesigningrequests.create",
110 Esql.approval_count = count(*) where event.action == "io.k8s.certificates.v1.certificatesigningrequests.approval.update",
111 Esql.event_action_values = values(event.action),
112 Esql.timestamp_first_seen = min(@timestamp),
113 Esql.timestamp_last_seen = max(@timestamp),
114 Esql.source_ip_values = values(source.ip),
115 Esql.user_agent_original_values = values(user_agent.original),
116 Esql.data_stream_namespace_values = values(data_stream.namespace)
117 by client.user.email, Esql.csr_name
118| where Esql.create_count >= 1
119 and Esql.approval_count >= 1
120 and date_diff("seconds", Esql.timestamp_first_seen, Esql.timestamp_last_seen) <= 300
121| keep client.user.email, Esql.*
122'''
123
124[[rule.threat]]
125framework = "MITRE ATT&CK"
126
127[[rule.threat.technique]]
128id = "T1098"
129name = "Account Manipulation"
130reference = "https://attack.mitre.org/techniques/T1098/"
131
132[[rule.threat.technique.subtechnique]]
133id = "T1098.006"
134name = "Additional Container Cluster Roles"
135reference = "https://attack.mitre.org/techniques/T1098/006/"
136
137[rule.threat.tactic]
138id = "TA0003"
139name = "Persistence"
140reference = "https://attack.mitre.org/tactics/TA0003/"
141
142[[rule.threat]]
143framework = "MITRE ATT&CK"
144
145[[rule.threat.technique]]
146id = "T1098"
147name = "Account Manipulation"
148reference = "https://attack.mitre.org/techniques/T1098/"
149
150[[rule.threat.technique.subtechnique]]
151id = "T1098.006"
152name = "Additional Container Cluster Roles"
153reference = "https://attack.mitre.org/techniques/T1098/006/"
154
155[rule.threat.tactic]
156id = "TA0004"
157name = "Privilege Escalation"
158reference = "https://attack.mitre.org/tactics/TA0004/"
159
160[rule.investigation_fields]
161field_names = [
162 "client.user.email",
163 "Esql.csr_name",
164 "Esql.create_count",
165 "Esql.approval_count",
166 "Esql.event_action_values",
167 "Esql.timestamp_first_seen",
168 "Esql.timestamp_last_seen",
169 "Esql.source_ip_values",
170 "Esql.user_agent_original_values",
171 "Esql.data_stream_namespace_values",
172]
Triage and analysis
Investigating GKE Certificate Signing Request Self-Approved
This rule groups CSR create and approval events by client.user.email and normalized CSR name (Esql.csr_name).
GKE logs approval on subresource paths (.../csr-name/approval), so the query strips /approval suffixes before
correlating. An alert means the same identity both submitted and approved the same CSR within five minutes, a strong
indicator of manual self-approval rather than normal system:gcp-controller-manager auto-approval of node
certificates.
Possible investigation steps
- Review
Esql.event_action_valuesfor the sequence of create followed byapproval.update. - Inspect
gcp.audit.request.spec.signerNameand decodegcp.audit.request.spec.requeston create events for the requested identity. - Validate whether the actor should hold both CSR create and approval permissions.
- Hunt for subsequent API activity authenticated as the minted certificate identity.
False positive analysis
- cert-manager or internal PKI automation that creates and approves CSRs under the same service account in one workflow.
- GitOps or bootstrap tooling that submits and signs CSRs programmatically. Baseline known automation and tune exclusions for those principals.
- Two unrelated CSR events from the same user within five minutes should not match because the query requires at least one create and one approval-class action on the same normalized CSR name.
Related rules
- GKE Certificate Signing Request API Client Signer Requested - 1e344fba-a2f7-462b-aaec-d6c8f80d5a28
- GKE Certificate Signing Request Privileged Identity Requested - 4159bec9-76ad-4cdc-a797-4a8572073bbe
- GKE Client Certificate Signing Request Created or Approved - ec67ab57-945a-4edb-84f8-1d7a51f46544
Response and remediation
- Revoke or deny the CSR, remove approval RBAC from untrusted principals, and rotate cluster signing credentials if abuse is confirmed.
References
Related rules
- GKE Certificate Signing Request API Client Signer Requested
- GKE Certificate Signing Request for Privileged Identity
- GKE Client Certificate Signing Request Created or Approved
- GKE Cluster-Admin Role Binding Created or Modified
- GKE Creation of a RoleBinding Referencing a ServiceAccount