-
Notifications
You must be signed in to change notification settings - Fork 635
[New Rule] Azure Arc Kubernetes Cluster Connect Abuse #5824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
terrancedejesus
wants to merge
11
commits into
main
Choose a base branch
from
terrancedejesus/issue5823
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b4c5e33
[New Rule] Azure Arc Kubernetes Cluster Connect Abuse
terrancedejesus ffbf756
rename, adjusted query
terrancedejesus 07dd69b
adding KEEP *
terrancedejesus 1949fde
adjusting maturity
terrancedejesus 52d2905
added to non-ecs schema
terrancedejesus f1016c9
updating rule
terrancedejesus 0ef7c29
addressing unit test failures
terrancedejesus 89677fe
adjustments to logic, mitre mappings, unit test failures, etc.
terrancedejesus bca6542
Merge branch 'main' into terrancedejesus/issue5823
terrancedejesus 08d4013
Update rules/integrations/azure/initial_access_azure_arc_cluster_cred…
terrancedejesus f26f11e
Merge branch 'main' into terrancedejesus/issue5823
terrancedejesus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
...s/azure/credential_access_azure_service_principal_signin_then_arc_credential_listing.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| [metadata] | ||
| creation_date = "2026/03/10" | ||
| integration = ["azure"] | ||
| maturity = "production" | ||
| updated_date = "2026/03/10" | ||
|
|
||
| [rule] | ||
| author = ["Elastic"] | ||
| description = """ | ||
| Detects when a service principal authenticates to Microsoft Entra ID and then lists credentials for an Azure | ||
| Arc-connected Kubernetes cluster within a short time window. The `listClusterUserCredential` action retrieves tokens | ||
| that enable kubectl access through the Arc Cluster Connect proxy. This sequence (service principal sign-in followed by | ||
| Arc credential retrieval), represents the exact attack chain used by adversaries with stolen service principal secrets | ||
| to establish a proxy tunnel into Kubernetes clusters. Service principals that authenticate externally (as opposed to | ||
| managed identities) and immediately access Arc cluster credentials warrant investigation, particularly when the sign-in | ||
| originates from an unexpected location or ASN. | ||
| """ | ||
| false_positives = [ | ||
| """ | ||
| CI/CD pipelines that authenticate as a service principal and then access Arc clusters as part of deployment | ||
| workflows will trigger this rule. Identify and exclude known automation service principal app IDs. | ||
| """, | ||
| """ | ||
| Administrators using service principal credentials to manage Arc-connected clusters during maintenance windows may | ||
| trigger this rule. Correlate with change management records. | ||
| """, | ||
| ] | ||
| from = "now-30m" | ||
| index = ["logs-azure.signinlogs-*", "logs-azure.activitylogs-*"] | ||
| interval = "15m" | ||
| language = "eql" | ||
| license = "Elastic License v2" | ||
| name = "Azure Service Principal Sign-In Followed by Arc Cluster Credential Access" | ||
| note = """## Triage and analysis | ||
|
|
||
| ### Investigating Azure Service Principal Sign-In Followed by Arc Cluster Credential Access | ||
|
|
||
| This rule detects the complete attack entry point for Arc-proxied Kubernetes attacks: a service principal authenticates | ||
| to Azure AD, then immediately retrieves Arc cluster credentials. This is the prerequisite sequence before any | ||
| Kubernetes-level activity can occur through the Arc proxy. | ||
|
|
||
| ### Possible investigation steps | ||
|
|
||
| - Identify the service principal using the `app_id` from the sign-in event and resolve it in Azure AD — is this a | ||
| known application? | ||
| - Check the sign-in source IP and geolocation — does it match expected infrastructure locations for this SP? | ||
| - Review when the SP credentials were last rotated — stale credentials are more likely compromised. | ||
| - Check the ASN of the sign-in source — is it from a known cloud provider, corporate network, or unexpected consumer ISP? | ||
| - Examine Azure Activity Logs after the credential listing for any Arc-proxied operations (secret/configmap CRUD). | ||
| - Correlate with Kubernetes audit logs for operations by the Arc proxy service account | ||
| (`system:serviceaccount:azure-arc:azure-arc-kube-aad-proxy-sa`) in the same time window. | ||
| - Review Azure AD Audit Logs for recent changes to this SP (new credentials, federated identities, owner changes). | ||
|
|
||
| ### Response and remediation | ||
|
|
||
| - Immediately rotate the service principal credentials (secrets and certificates). | ||
| - Revoke active sessions and tokens for the SP. | ||
| - Review and remove any unauthorized Azure role assignments on Arc-connected clusters. | ||
| - Check Kubernetes audit logs for any operations performed through the Arc proxy after credential access. | ||
| - Rotate any Kubernetes secrets that may have been accessed through the proxy tunnel. | ||
| - Enable conditional access policies to restrict service principal authentication by location if supported. | ||
| """ | ||
| references = [ | ||
| "https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/cluster-connect", | ||
| "https://learn.microsoft.com/en-us/cli/azure/connectedk8s#az-connectedk8s-proxy", | ||
| "https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins", | ||
| "https://www.ibm.com/think/x-force/identifying-abusing-azure-arc-for-hybrid-escalation-persistence", | ||
| "https://www.microsoft.com/en-us/security/blog/2025/08/27/storm-0501s-evolving-techniques-lead-to-cloud-based-ransomware/", | ||
| ] | ||
| risk_score = 47 | ||
| rule_id = "dacfbecd-7927-46a7-a8ba-feb65a2e990d" | ||
| severity = "medium" | ||
| tags = [ | ||
| "Domain: Cloud", | ||
| "Domain: Identity", | ||
| "Data Source: Azure", | ||
| "Data Source: Azure Arc", | ||
| "Data Source: Microsoft Entra ID", | ||
| "Data Source: Microsoft Entra ID Sign-In Logs", | ||
| "Use Case: Threat Detection", | ||
| "Tactic: Credential Access", | ||
| "Tactic: Initial Access", | ||
| "Resources: Investigation Guide", | ||
| ] | ||
| timestamp_override = "event.ingested" | ||
| type = "eql" | ||
|
|
||
| query = ''' | ||
| sequence with maxspan=30m | ||
| [authentication where event.dataset == "azure.signinlogs" | ||
| and azure.signinlogs.category == "ServicePrincipalSignInLogs" | ||
| and azure.signinlogs.properties.status.error_code == 0 | ||
| ] by azure.signinlogs.properties.app_id | ||
| [any where event.dataset == "azure.activitylogs" | ||
| and azure.activitylogs.operation_name : "MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/LISTCLUSTERUSERCREDENTIAL/ACTION" | ||
| and event.outcome : ("Success", "success") | ||
| ] by azure.activitylogs.identity.claims.appid | ||
| ''' | ||
|
|
||
|
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1552" | ||
| name = "Unsecured Credentials" | ||
| reference = "https://attack.mitre.org/techniques/T1552/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1552.007" | ||
| name = "Container API" | ||
| reference = "https://attack.mitre.org/techniques/T1552/007/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0006" | ||
| name = "Credential Access" | ||
| reference = "https://attack.mitre.org/tactics/TA0006/" | ||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1078" | ||
| name = "Valid Accounts" | ||
| reference = "https://attack.mitre.org/techniques/T1078/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1078.004" | ||
| name = "Cloud Accounts" | ||
| reference = "https://attack.mitre.org/techniques/T1078/004/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0001" | ||
| name = "Initial Access" | ||
| reference = "https://attack.mitre.org/tactics/TA0001/" | ||
|
|
||
| [rule.investigation_fields] | ||
| field_names = [ | ||
| "@timestamp", | ||
| "azure.signinlogs.properties.app_id", | ||
| "azure.signinlogs.properties.app_display_name", | ||
| "azure.signinlogs.properties.service_principal_name", | ||
| "azure.signinlogs.category", | ||
| "azure.activitylogs.operation_name", | ||
| "azure.activitylogs.identity.claims.appid", | ||
| "azure.resource.id", | ||
| "source.ip", | ||
| "source.geo.country_name", | ||
| "source.geo.city_name", | ||
| "source.as.organization.name", | ||
| ] | ||
|
|
146 changes: 146 additions & 0 deletions
146
...integrations/azure/initial_access_azure_arc_cluster_credential_access_unusual_source.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| [metadata] | ||
| creation_date = "2026/03/10" | ||
| integration = ["azure"] | ||
| maturity = "production" | ||
| updated_date = "2026/03/10" | ||
|
|
||
| [rule] | ||
| author = ["Elastic"] | ||
| description = """ | ||
| Detects when a service principal or user performs an Azure Arc cluster credential listing operation from a source IP not | ||
| previously associated with that identity. The `listClusterUserCredential` action retrieves credentials for the Arc | ||
| Cluster Connect proxy, enabling kubectl access through the Azure ARM API. An adversary using stolen service principal | ||
| credentials will typically call this operation from infrastructure not previously seen for that SP. By tracking the | ||
| combination of caller identity and source IP, this rule avoids false positives from backend services and CI/CD pipelines | ||
| that rotate IPs but maintain consistent identity-to-IP patterns over time. | ||
| """ | ||
| false_positives = [ | ||
| """ | ||
| A service principal used by a CI/CD pipeline may trigger this rule when the pipeline runs from a new IP range for | ||
| the first time (e.g., migrating to a new runner pool). The 14-day history window will learn the new IPs after the | ||
| first occurrence. | ||
| """, | ||
| """ | ||
| Administrators accessing Arc clusters from a new VPN endpoint or travel location. Validate the caller identity | ||
| matches an expected user and correlate with known travel or access patterns. | ||
| """, | ||
| ] | ||
| from = "now-9m" | ||
| index = ["logs-azure.activitylogs-*"] | ||
| language = "kuery" | ||
| license = "Elastic License v2" | ||
| name = "Azure Arc Cluster Credential Access by Identity from Unusual Source" | ||
| note = """## Triage and analysis | ||
|
|
||
| ### Investigating Azure Arc Cluster Credential Access by Identity from Unusual Source | ||
|
|
||
| The `listClusterUserCredential` operation on an Azure Arc-connected cluster returns credentials that allow the caller | ||
| to establish a proxy tunnel via `az connectedk8s proxy`. This proxy routes kubectl commands through the Azure ARM API, | ||
| enabling Kubernetes access without direct network connectivity to the cluster API server. | ||
|
|
||
| ### Possible investigation steps | ||
|
|
||
| - Identify the caller service principal using `azure.activitylogs.identity.claims.appid` and cross-reference with | ||
| Azure AD to determine if this is a known application. | ||
| - Check the source IP and geolocation — is this from a country or ASN where your organization operates? | ||
| - Correlate with Azure Sign-In Logs around the same time to see the full authentication chain (SP login followed by | ||
| credential listing). | ||
| - Verify the Azure role used — the `Azure Arc Enabled Kubernetes Cluster User Role` is required for this operation. | ||
| Was this role recently assigned? | ||
| - Check if subsequent Arc-proxied operations (secret/configmap CRUD) occurred after the credential access. | ||
| - Review the service principal creation date in Azure AD — recently created SPs are more suspicious. | ||
|
|
||
| ### Response and remediation | ||
|
|
||
| - If the source IP is from an unexpected country or the service principal is not recognized, treat as potential | ||
| credential compromise. | ||
| - Revoke the service principal credentials and remove Arc RBAC role assignments. | ||
| - Review Kubernetes audit logs for any operations performed through the Arc proxy after credential access. | ||
| - Rotate any Kubernetes secrets that may have been accessed. | ||
| """ | ||
| references = [ | ||
| "https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/cluster-connect", | ||
| "https://learn.microsoft.com/en-us/cli/azure/connectedk8s#az-connectedk8s-proxy", | ||
| "https://www.ibm.com/think/x-force/identifying-abusing-azure-arc-for-hybrid-escalation-persistence", | ||
| "https://nvd.nist.gov/vuln/detail/cve-2022-37968", | ||
| ] | ||
| risk_score = 47 | ||
| rule_id = "022c37cd-5a4f-422b-8227-b136b7a23180" | ||
| severity = "medium" | ||
| tags = [ | ||
| "Domain: Cloud", | ||
| "Data Source: Azure", | ||
| "Data Source: Azure Arc", | ||
| "Data Source: Azure Activity Logs", | ||
| "Use Case: Threat Detection", | ||
| "Tactic: Initial Access", | ||
| "Tactic: Credential Access", | ||
| "Resources: Investigation Guide", | ||
| ] | ||
| timestamp_override = "event.ingested" | ||
| type = "new_terms" | ||
|
|
||
| query = ''' | ||
| event.dataset: "azure.activitylogs" | ||
| and azure.activitylogs.operation_name: "MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/LISTCLUSTERUSERCREDENTIAL/ACTION" | ||
| and event.outcome: (Success or success) | ||
| ''' | ||
|
|
||
|
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1078" | ||
| name = "Valid Accounts" | ||
| reference = "https://attack.mitre.org/techniques/T1078/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1078.004" | ||
| name = "Cloud Accounts" | ||
| reference = "https://attack.mitre.org/techniques/T1078/004/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0001" | ||
| name = "Initial Access" | ||
| reference = "https://attack.mitre.org/tactics/TA0001/" | ||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1552" | ||
| name = "Unsecured Credentials" | ||
| reference = "https://attack.mitre.org/techniques/T1552/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1552.007" | ||
| name = "Container API" | ||
| reference = "https://attack.mitre.org/techniques/T1552/007/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0006" | ||
| name = "Credential Access" | ||
| reference = "https://attack.mitre.org/tactics/TA0006/" | ||
|
|
||
| [rule.investigation_fields] | ||
| field_names = [ | ||
| "@timestamp", | ||
| "azure.activitylogs.operation_name", | ||
| "azure.activitylogs.identity.claims.appid", | ||
| "azure.activitylogs.identity.authorization.evidence.role", | ||
| "azure.activitylogs.identity.authorization.evidence.principalType", | ||
| "azure.resource.id", | ||
| "source.ip", | ||
| "source.geo.country_name", | ||
| "source.geo.city_name", | ||
| "source.as.organization.name", | ||
| ] | ||
|
|
||
| [rule.new_terms] | ||
| field = "new_terms_fields" | ||
| value = ["azure.activitylogs.identity.claims.appid", "source.ip"] | ||
| [[rule.new_terms.history_window_start]] | ||
| field = "history_window_start" | ||
| value = "now-7d" | ||
|
|
||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.