Detection rules › Panther

Panther rules: source

EKS Audit Log based single sourceIP is generating multiple 403s

#
Severity
informational
Entities
aws_account_ids, aws_arns, ip_addresses, usernames
Log types
Amazon.EKS.Audit
Tags
EKS
Reference
aws.github.io
Source
github.com/panther-labs/panther-analysis

This detection identifies if a public sourceIP is generating multiple 403s with the Kubernetes API server.

MITRE ATT&CK coverage

Detection logic

from ipaddress import ip_address

from panther_aws_helpers import eks_panther_obj_ref


# Alert if
#   state is ResponseComplete
#   sourceIPs[0] is a Public Address
#   responseStatus:code == 403
def rule(event):
    if event.get("stage", "") != "ResponseComplete":
        return False
    # We include only 403
    if event.get("responseStatus", {}).get("code", 0) != 403:
        return False
    # And we only want things that might naively be kubernetes api endpoints
    # we do not want to alert on scanners casting non-kubernetes requests.
    if not event.get("requestURI", "").startswith(("/api/", "/apis/")):
        return False
    p_eks = eks_panther_obj_ref(event)
    if not ip_address(p_eks.get("sourceIPs")[0]).is_global:
        return False
    return True


# If not defined, defaults to the rule display name or rule ID.
def title(event):
    p_eks = eks_panther_obj_ref(event)
    return (
        f"[{p_eks.get('sourceIPs')[0]}] received [403] "
        f"when executing [{p_eks.get('verb')}] "
        f"for resource [{p_eks.get('resource')}] "
        f"in ns [{p_eks.get('ns')}] on "
        f"[{p_eks.get('p_source_label')}] as "
        f"[{p_eks.get('actor')}]"
    )


def dedup(event):
    p_eks = eks_panther_obj_ref(event)
    return f"{p_eks.get('p_source_label')}_403_{p_eks.get('sourceIPs')[0]}"


def alert_context(event):
    p_eks = eks_panther_obj_ref(event)
    mutable_event = event.to_dict()
    mutable_event["p_eks"] = p_eks
    return dict(mutable_event)

Rule specification

AnalysisType: rule
Filename: source_ip_multiple_403.py
RuleID: "Amazon.EKS.Audit.Multiple403"
DisplayName: "EKS Audit Log based single sourceIP is generating multiple 403s"
Enabled: true
LogTypes:
  - Amazon.EKS.Audit
Tags:
  - EKS
Reports:
  MITRE ATT&CK:
    - "TA0007:T1613"
Reference: https://aws.github.io/aws-eks-best-practices/security/docs/detective/
Severity: Info
Description: > # (Optional)
  This detection identifies if a public sourceIP is generating multiple 403s
  with the Kubernetes API server.
DedupPeriodMinutes: 30 # The amount of time in minutes for grouping alerts (Optional, defaults to 60)
Threshold: 10 # The minimum number of event matches prior to an alert sending (Optional, defaults to 1)
SummaryAttributes: # A list of fields in the event to create top 5 summaries for (Optional)
  - user:username
  - p_any_ip_addresses
  - p_source_label

Stages and Predicates

Fires on Amazon.EKS.Audit events when all of the conditions below hold.

Condition

  • stage is ResponseComplete
  • responseStatus.code is 403
  • any of:
    • requestURI starts with /api/
    • requestURI starts with /apis/

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Alert cadence
alerts after 10 matches within 30m

Indicators

These rows show field, operator, and value matches.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "annotations": {
    "authorization.k8s.io/decision": "allow",
    "authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"system:coredns\" of ClusterRole \"system:coredns\" to ServiceAccount \"coredns/kube-system\""
  },
  "apiVersion": "audit.k8s.io/v1",
  "auditID": "e2626946-90e1-4d0c-829e-ad5a78572926",
  "kind": "Event",
  "level": "Metadata",
  "objectRef": {
    "apiGroup": "discovery.k8s.io",
    "apiVersion": "v1",
    "resource": "endpointslices"
  },
  "p_any_ip_addresses": [
    "5.5.5.5"
  ],
  "p_any_usernames": [
    "system:serviceaccount:kube-system:coredns"
  ],
  "p_event_time": "2022-11-29 22:34:06.892",
  "p_log_type": "Amazon.EKS.Audit",
  "p_parse_time": "2022-11-29 22:45:25.024",
  "p_row_id": "c2a7d8dd7c858dcae0a1aaf314b2a207",
  "p_source_id": "4c859cd4-9406-469b-9e0e-c2dc1bee24fa",
  "p_source_label": "example-cluster-eks-logs",
  "requestReceivedTimestamp": "2022-11-29 22:34:06.892",
  "requestURI": "/apis/discovery.k8s.io/v1/endpointslices?allowWatchBookmarks=true&resourceVersion=2528212&timeout=5m56s&timeoutSeconds=356&watch=true",
  "responseStatus": {
    "code": 403
  },
  "sourceIPs": [
    "5.5.5.5"
  ],
  "stage": "ResponseComplete",
  "stageTimestamp": "2022-11-29 22:40:02.903",
  "user": {
    "extra": {
      "authentication_kubernetes_io_slash_pod-name": [
        "coredns-57ff979f67-bl27n"
      ],
      "authentication_kubernetes_io_slash_pod-uid": [
        "5b9488ae-5563-42aa-850b-b0d82edb3e22"
      ]
    },
    "groups": [
      "system:serviceaccounts",
      "system:serviceaccounts:kube-system",
      "system:authenticated"
    ],
    "uid": "5e4461f9-f529-4e66-9343-0b0cc9452284",
    "username": "system:serviceaccount:kube-system:coredns"
  },
  "userAgent": "Go-http-client/2.0",
  "verb": "watch"
}