Detection rules › Elastic
Azure AKS Certificate Signing Request Created or Approved
Detects an identity creating a client-authentication CertificateSigningRequest (signer kubernetes.io/kube-apiserver-client) or approving a CSR on AKS (Azure Kubernetes Service), excluding node bootstrap and platform controllers. Adversaries submit and self-approve a CSR against the kube-apiserver-client signer to mint a long-lived client certificate for an arbitrary subject (for example a Common Name in system:masters), giving durable authenticated access that survives token revocation. Coverage includes workload service accounts (system:serviceaccount:*), so a compromised in-cluster token forging a certificate is not excluded.
Known false positives
- Node bootstrap, cert-manager, and platform controllers legitimately create and approve CSRs. Validate the requesting identity and the certificate subject, and add exclusions for verified automation.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- GKE Certificate Signing Request API Client Signer Requested (Elastic)
- GKE Certificate Signing Request for Privileged Identity (Elastic)
- GKE Certificate Signing Request Self-Approved (Elastic)
- GKE Client Certificate Signing Request Created or Approved (Elastic)
- Kubernetes Client Certificate Credential Created (Panther)
- Kubernetes Client Certificate Signing Request Created or Approved (Elastic)
Rule body
[metadata]
creation_date = "2026/07/09"
integration = ["azure"]
maturity = "production"
updated_date = "2026/07/09"
[rule]
author = ["Elastic"]
description = """
Detects an identity creating a client-authentication CertificateSigningRequest (signer
kubernetes.io/kube-apiserver-client) or approving a CSR on AKS (Azure Kubernetes Service), excluding node bootstrap and
platform controllers. Adversaries submit and self-approve a CSR against the kube-apiserver-client signer to mint a
long-lived client certificate for an arbitrary subject (for example a Common Name in system:masters), giving durable
authenticated access that survives token revocation. Coverage includes workload service accounts
(system:serviceaccount:*), so a compromised in-cluster token forging a certificate is not excluded.
"""
false_positives = [
"""
Node bootstrap, cert-manager, and platform controllers legitimately create and approve CSRs. Validate the requesting
identity and the certificate subject, and add exclusions for verified automation.
""",
]
from = "now-9m"
index = ["logs-azure.platformlogs-*"]
language = "kuery"
license = "Elastic License v2"
name = "Azure AKS Certificate Signing Request Created or Approved"
note = """## Triage and analysis
### Investigating Azure AKS Certificate Signing Request Created or Approved
AKS kube-audit events are carried under the flattened `azure.platformlogs.properties.log.*` subtree and share the ARM
operation `event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read`. A CSR created against the
`kubernetes.io/kube-apiserver-client` signer lets the requester choose the certificate's subject (Common Name and
organization/groups); once approved it mints a client certificate for an arbitrary identity that yields access not tied
to a token. The default `CertificateSubjectRestriction` admission controller blocks requests for the `system:masters`
group, so attackers commonly request a Common Name matching an existing privileged user (or another privileged group)
instead, making the requested subject the key thing to decode. Node and kubelet certificates use the
`kube-apiserver-client-kubelet` and `kubelet-serving` signers (whose subject is constrained to the node) and are out of
scope; cert-manager and application CSRs use their own signers.
### Possible investigation steps
- Identify the requesting identity in `azure.platformlogs.properties.log.user.username` (and its groups in
`azure.platformlogs.properties.log.user.groups`) and whether it should submit or approve CSRs. A workload service
account (`system:serviceaccount:<ns>:<sa>`) or `masterclient` (the local cluster-admin cert) is the higher-concern
case.
- Confirm the signer in `azure.platformlogs.properties.log.requestObject.spec.signerName` and decode the base64 CSR in
`azure.platformlogs.properties.log.requestObject.spec.request` to read the requested Common Name and organization
(groups); a subject in `system:masters` or another privileged group is the escalation.
- Determine whether the same or a related identity approved the CSR (`verb:update`/`patch` on the `approval`
subresource), which indicates self-approval, and inspect `azure.platformlogs.properties.log.userAgent`.
- Evaluate the source in `azure.platformlogs.properties.log.sourceIPs` and pivot on it for follow-on privileged API
activity using the newly issued certificate.
### False positive analysis
- Node bootstrap (`kube-apiserver-client-kubelet` signer), kubelet-serving CSRs, and cert-manager/application CSRs
(custom signers) are out of scope by design; the kube-controller-manager `certificate-controller` and the AKS
`aksService` approver are excluded by identity.
- Manual CSR approval by an administrator, or an operator that legitimately mints client certificates, may surface;
baseline those identities and exclude the specific validated account rather than re-broadening to all `system:*`,
which would blind the rule to compromised workload service accounts.
### Response and remediation
- If unauthorized, deny or delete the CSR, revoke the issued certificate, and rotate the cluster CA if a privileged
certificate was minted.
- Review the RBAC that allowed CSR creation and approval, and audit actions taken with the certificate.
- Collect kube-audit and identity artifacts per incident response procedures.
"""
references = [
"https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/",
"https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
"https://github.com/inguardians/peirates",
"https://raesene.github.io/blog/2022/12/21/Kubernetes-persistence-with-Tocan-and-Teisteanas/",
"https://cloud.google.com/blog/topics/threat-intelligence/escalating-privileges-azure-kubernetes-services",
"https://www.aquasec.com/blog/kubernetes-rbac-privilige-escalation/",
]
risk_score = 47
rule_id = "3f6c636a-1ca5-410c-bdad-f8b59a1f2b49"
setup = """The Azure Fleet integration collecting AKS diagnostic logs forwarded through Event Hub into the `azure.platformlogs`
data stream is required for this rule. Enable either the `kube-audit` or the `kube-audit-admin` log category (Microsoft
recommends `kube-audit-admin` alone to reduce volume, as it only drops read-only get/list events). CSR create and
approval are mutating operations recorded in both categories with the same `auditID`, so clusters that enable both
categories may generate two alerts per event.
"""
severity = "medium"
tags = [
"Domain: Cloud",
"Domain: Kubernetes",
"Data Source: Azure",
"Data Source: Azure Platform Logs",
"Data Source: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:azure.platformlogs and
event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
azure.platformlogs.category:("kube-audit" or "kube-audit-admin") and
azure.platformlogs.properties.log.stage:"ResponseComplete" and
azure.platformlogs.properties.log.objectRef.resource:"certificatesigningrequests" and
azure.platformlogs.properties.log.responseStatus.code: "200" and
azure.platformlogs.properties.log.requestObject.status.conditions.type: "Approved" and
(
(
azure.platformlogs.properties.log.verb:"create" and
azure.platformlogs.properties.log.requestObject.spec.signerName:"kubernetes.io/kube-apiserver-client"
) or (
azure.platformlogs.properties.log.verb:("update" or "patch") and
azure.platformlogs.properties.log.objectRef.subresource:"approval"
)
) and
not azure.platformlogs.properties.log.user.username:(
system\:node\:* or system\:bootstrap\:* or "aksService" or "hcpService" or
"readinessChecker" or system\:serviceaccount\:kube-system\:*
)
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1649"
name = "Steal or Forge Authentication Certificates"
reference = "https://attack.mitre.org/techniques/T1649/"
[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[rule.investigation_fields]
field_names = [
"@timestamp",
"event.action",
"azure.platformlogs.category",
"azure.platformlogs.properties.log.verb",
"azure.platformlogs.properties.log.user.username",
"azure.platformlogs.properties.log.user.groups",
"azure.platformlogs.properties.log.userAgent",
"azure.platformlogs.properties.log.sourceIPs",
"azure.platformlogs.properties.log.objectRef.resource",
"azure.platformlogs.properties.log.objectRef.name",
"azure.platformlogs.properties.log.objectRef.subresource",
"azure.platformlogs.properties.log.requestObject.spec.signerName",
"azure.platformlogs.properties.log.requestObject.spec.request",
"azure.platformlogs.properties.log.responseStatus.code",
]
Stages and Predicates
Stage 1: query
data_stream.dataset:azure.platformlogs and
event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
azure.platformlogs.category:("kube-audit" or "kube-audit-admin") and
azure.platformlogs.properties.log.stage:"ResponseComplete" and
azure.platformlogs.properties.log.objectRef.resource:"certificatesigningrequests" and
azure.platformlogs.properties.log.responseStatus.code: "200" and
azure.platformlogs.properties.log.requestObject.status.conditions.type: "Approved" and
(
(
azure.platformlogs.properties.log.verb:"create" and
azure.platformlogs.properties.log.requestObject.spec.signerName:"kubernetes.io/kube-apiserver-client"
) or (
azure.platformlogs.properties.log.verb:("update" or "patch") and
azure.platformlogs.properties.log.objectRef.subresource:"approval"
)
) and
not azure.platformlogs.properties.log.user.username:(
system\:node\:* or system\:bootstrap\:* or "aksService" or "hcpService" or
"readinessChecker" or system\:serviceaccount\:kube-system\:*
)
Exclusions
The rule actively suppresses these predicates.
Indicators
These rows show field, operator, and value matches.