[Tuning] Multiple Cloud Secrets Accessed by Source Address (#5884)
* Update credential_access_multi_could_secrets_via_api.toml * Update credential_access_multi_could_secrets_via_api.toml * Update credential_access_multi_could_secrets_via_api.toml * Apply suggestion from @Mikaayenson Co-authored-by: Mika Ayenson, PhD <Mikaayenson@users.noreply.github.com> * Apply suggestion from @Mikaayenson Co-authored-by: Mika Ayenson, PhD <Mikaayenson@users.noreply.github.com> --------- Co-authored-by: Mika Ayenson, PhD <Mikaayenson@users.noreply.github.com> Co-authored-by: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com>
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
[metadata]
|
||||
creation_date = "2025/12/01"
|
||||
integration = ["aws", "gcp", "azure"]
|
||||
integration = ["aws", "gcp", "azure", "kubernetes"]
|
||||
maturity = "production"
|
||||
updated_date = "2026/01/26"
|
||||
updated_date = "2026/03/26"
|
||||
|
||||
[rule]
|
||||
author = ["Elastic"]
|
||||
description = """
|
||||
This rule detects authenticated sessions accessing secret stores across multiple cloud providers from the same source
|
||||
address within a short period of time. Adversaries with access to compromised credentials or session tokens may attempt
|
||||
to retrieve secrets from services such as AWS Secrets Manager, Google Secret Manager, or Azure Key Vault in rapid
|
||||
succession to expand their access or exfiltrate sensitive information.
|
||||
This rule detects authenticated sessions accessing secret stores across multiple environments from the same source
|
||||
address within a short period of time, including cloud providers (AWS, GCP, Azure) and Kubernetes clusters.
|
||||
Adversaries with access to compromised credentials or session tokens may attempt to retrieve secrets from services such
|
||||
as AWS Secrets Manager, Google Secret Manager, Azure Key Vault, or Kubernetes Secrets in rapid succession to expand
|
||||
their access or exfiltrate sensitive information.
|
||||
"""
|
||||
from = "now-9m"
|
||||
interval = "5m"
|
||||
@@ -52,6 +53,11 @@ Unexpected cross-cloud secret retrieval is uncommon and typically indicates auto
|
||||
- Assess potential compromise scope
|
||||
- If compromise is suspected, enumerate other assets accessed by the same identity in the last 24 hours.
|
||||
- Look for lateral movement, privilege escalation, or abnormal API usage.
|
||||
- Review Kubernetes activity
|
||||
- Identify the Kubernetes user, service account, or workload performing the secret access.
|
||||
- Determine whether the access originated from a pod, node, or external client.
|
||||
- Validate whether the identity is expected to access secrets in the affected namespaces.
|
||||
- Investigate whether the activity corresponds to application behavior or manual/API access.
|
||||
|
||||
### False positive analysis
|
||||
|
||||
@@ -60,6 +66,8 @@ Unexpected cross-cloud secret retrieval is uncommon and typically indicates auto
|
||||
- Confirm that the identity is authorized to access secrets across multiple cloud services.
|
||||
- If activity is expected, consider adding exceptions that pair account identity, source IP, and expected user agent
|
||||
to reduce noise.
|
||||
- Determine whether the source IP is associated with Kubernetes nodes, controllers, or internal workloads
|
||||
that legitimately retrieve secrets alongside cloud provider integrations.
|
||||
|
||||
### Response and remediation
|
||||
|
||||
@@ -72,6 +80,10 @@ Unexpected cross-cloud secret retrieval is uncommon and typically indicates auto
|
||||
- Reduce permissions to least privilege.
|
||||
- Review trust relationships, workload identities, and cross-cloud integrations.
|
||||
- Search for persistence mechanisms** such as newly created keys, roles, or service accounts.
|
||||
- If Kubernetes access is involved:
|
||||
- Rotate Kubernetes secrets and service account tokens.
|
||||
- Review RBAC permissions and restrict secret access to least privilege.
|
||||
- Inspect affected pods or nodes for compromise.
|
||||
- Improve monitoring and audit visibility** by ensuring logging is enabled across all cloud environments.
|
||||
- Determine root cause** (phishing, malware, token replay, exposed credential, etc.) and close the vector to prevent recurrence.
|
||||
"""
|
||||
@@ -102,6 +114,7 @@ tags = [
|
||||
"Data Source: Azure Activity Logs",
|
||||
"Data Source: GCP",
|
||||
"Data Source: Google Cloud Platform",
|
||||
"Data Source: Kubernetes",
|
||||
"Tactic: Credential Access",
|
||||
"Resources: Investigation Guide",
|
||||
]
|
||||
@@ -109,31 +122,30 @@ timestamp_override = "event.ingested"
|
||||
type = "esql"
|
||||
|
||||
query = '''
|
||||
FROM logs-azure.platformlogs-*, logs-aws.cloudtrail-*, logs-gcp.audit-* METADATA _id, _version, _index
|
||||
FROM logs-azure.platformlogs-*, logs-aws.cloudtrail-*, logs-gcp.audit-*, logs-kubernetes.audit_logs-* METADATA _id, _version, _index
|
||||
| WHERE
|
||||
(
|
||||
/* AWS Secrets Manager */
|
||||
(event.dataset == "aws.cloudtrail" AND event.provider == "secretsmanager.amazonaws.com" AND event.action == "GetSecretValue") OR
|
||||
(event.dataset == "aws.cloudtrail" AND event.action == "GetSecretValue") OR
|
||||
|
||||
// Azure Key Vault (platform logs)
|
||||
(event.dataset == "azure.platformlogs" AND event.action IN ("SecretGet", "KeyGet")) or
|
||||
|
||||
/* Google Secret Manager */
|
||||
(event.dataset IN ("googlecloud.audit", "gcp.audit") AND
|
||||
event.action IN ("google.cloud.secretmanager.v1.SecretManagerService.AccessSecretVersion", "google.cloud.secretmanager.v1.SecretManagerService.GetSecretRequest"))
|
||||
event.action IN ("google.cloud.secretmanager.v1.SecretManagerService.AccessSecretVersion", "google.cloud.secretmanager.v1.SecretManagerService.GetSecretRequest")) OR
|
||||
|
||||
/* Kubernetes Secrets */
|
||||
(event.dataset == "kubernetes.audit_logs" AND kubernetes.audit.objectRef.resource == "secrets" AND kubernetes.audit.verb IN ("get", "list"))
|
||||
|
||||
) AND source.ip IS NOT NULL
|
||||
// Unified user identity (raw)
|
||||
| EVAL Esql_priv.user_id =
|
||||
COALESCE(
|
||||
client.user.id,
|
||||
aws.cloudtrail.user_identity.arn,
|
||||
NULL
|
||||
)
|
||||
|
||||
// Cloud vendor label based on dataset
|
||||
| EVAL Esql.cloud_vendor = CASE(
|
||||
event.dataset == "aws.cloudtrail", "aws",
|
||||
event.dataset == "azure.platformlogs", "azure",
|
||||
event.dataset IN ("googlecloud.audit","gcp.audit"), "gcp",
|
||||
event.dataset == "kubernetes.audit_logs", "k8s",
|
||||
"unknown"
|
||||
)
|
||||
// Vendor+tenant label, e.g. aws:123456789012, azure:tenant, gcp:project
|
||||
@@ -141,8 +153,10 @@ FROM logs-azure.platformlogs-*, logs-aws.cloudtrail-*, logs-gcp.audit-* METADAT
|
||||
Esql.cloud_vendor == "aws", CONCAT("aws:", cloud.account.id),
|
||||
Esql.cloud_vendor == "azure", CONCAT("azure:", cloud.account.id),
|
||||
Esql.cloud_vendor == "gcp", CONCAT("gcp:", cloud.account.id),
|
||||
NULL
|
||||
Esql.cloud_vendor == "k8s", CONCAT("k8s:", orchestrator.cluster.name),
|
||||
"unknown"
|
||||
)
|
||||
| WHERE Esql.cloud_vendor != "unknown"
|
||||
| STATS
|
||||
// Core counts
|
||||
Esql.events_count = COUNT(*),
|
||||
@@ -154,18 +168,15 @@ FROM logs-azure.platformlogs-*, logs-aws.cloudtrail-*, logs-gcp.audit-* METADAT
|
||||
Esql.cloud_vendor_values = VALUES(Esql.cloud_vendor),
|
||||
Esql.tenant_label_values = VALUES(Esql.tenant_label),
|
||||
// Hyperscaler-specific IDs
|
||||
Esql.aws_account_id_values = VALUES(CASE(Esql.cloud_vendor == "aws", cloud.account.id, NULL)),
|
||||
Esql.azure_tenant_id_values = VALUES(CASE(Esql.cloud_vendor == "azure", cloud.account.id, NULL)),
|
||||
Esql.gcp_project_id_values = VALUES(CASE(Esql.cloud_vendor == "gcp", cloud.account.id, NULL)),
|
||||
Esql.aws_account_id_values = VALUES(CASE(Esql.cloud_vendor == "aws", cloud.account.id, "unknown")),
|
||||
Esql.azure_tenant_id_values = VALUES(CASE(Esql.cloud_vendor == "azure", cloud.account.id, "unknown")),
|
||||
Esql.gcp_project_id_values = VALUES(CASE(Esql.cloud_vendor == "gcp", cloud.account.id, "unknown")),
|
||||
// Generic cloud metadata
|
||||
Esql.cloud_region_values = VALUES(cloud.region),
|
||||
Esql.cloud_service_name_values = VALUES(cloud.service.name),
|
||||
// Identity (privileged)
|
||||
Esql_priv.user_values = VALUES(Esql_priv.user_id),
|
||||
Esql_priv.client_user_id_values = VALUES(client.user.id),
|
||||
Esql_priv.aws_user_identity_arn_values = VALUES(aws.cloudtrail.user_identity.arn),
|
||||
Esql.k8s_namespace_values = VALUES(kubernetes.audit.objectRef.namespace),
|
||||
// Namespace values
|
||||
Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
|
||||
Esql.data_stream_namespace_values = VALUES(data_stream.namespace),
|
||||
Esql_priv.user_name_values = VALUES(user.name)
|
||||
BY source.ip
|
||||
// Require multi-vendor cred-access from same source IP
|
||||
| WHERE Esql.vendor_count_distinct >= 2
|
||||
|
||||
Reference in New Issue
Block a user