AWS Config Global Resources


Description

You can have AWS Config record supported types of global resources, such as IAM users, groups, roles, and customer managed policies.

Query · python

import json

from panther_aws_helpers import BadLookup, resource_lookup
from panther_base_helpers import deep_get

# TODO: Once Detection Pipelines are merged, implement downgraded (INFO) case for multiple
#       global resource recorders.


def policy(resource):
    if (
        resource.get("GlobalRecorderCount", 0) == 0
        or "Recorders" not in resource
        or not bool(resource.get("Recorders"))
    ):
        return False

    for recorder_name in resource.get("Recorders", []):
        try:
            recorder = resource_lookup(recorder_name)
        except BadLookup:
            continue
        if isinstance(recorder, str):
            recorder = json.loads(recorder)
        resource_records_global_resources = bool(
            deep_get(recorder, "RecordingGroup", "IncludeGlobalResourceTypes")
            and deep_get(recorder, "Status", "Recording")
        )
        if resource_records_global_resources:
            return True
    return False

Analyst notes

https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-config-is-enabled-for-global-resources

Raw source AWS Config Global Resources · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: policy
Filename: aws_config_global_resources.py
PolicyID: "AWS.Config.GlobalResources"
DisplayName: "AWS Config Global Resources"
Enabled: true
ResourceTypes:
  - AWS.Config.Recorder.Meta
Tags:
  - AWS
  - Security Control
Severity: Low
Description: >
  You can have AWS Config record supported types of global resources, such as
  IAM users, groups, roles, and customer managed policies.
Runbook: >
  https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-config-is-enabled-for-global-resources
Reference: https://amzn.to/2MO8xXM
Tests:
  - Name: No Global Recoders Present
    ExpectedResult: false
    Resource:
      {
        "TimeCreated": null,
        "AccountId": "123456789012",
        "ResourceId": "123456789012::AWS.Config.Recorder.Meta",
        "ResourceType": "AWS.Config.Recorder.Meta",
        "Tags": null,
        "Region": "global",
        "Recorders": null,
        "Name": "AWS.Config.Recorder.Meta",
        "GlobalRecorderCount": 0,
      }
  - Name: Global Resources Are Enabled
    ExpectedResult: true
    Mocks:
      - {
          "objectName": "resource_lookup",
          "returnValue": '{ "AccountId": "012345678910", "Name": "Default", "RecordingGroup": { "AllSupported": true, "IncludeGlobalResourceTypes": true, "ResourceTypes": null }, "Region": "us-east-1", "ResourceId": "012345678910:us-east-1:AWS.Config.Recorder", "ResourceType": "AWS.Config.Recorder", "RoleARN": "arn:aws:iam::012345678910:role/PantherAWSConfig", "Status": { "LastErrorCode": null, "LastErrorMessage": null, "LastStartTime": "2018-10-05T22:45:01.838Z", "LastStatus": "SUCCESS", "LastStatusChangeTime": "2021-05-28T17:45:14.916Z", "LastStopTime": null, "Name": "Default", "Recording": true }, "Tags": null, "TimeCreated": null }',
        }
    Resource:
      {
        "TimeCreated": null,
        "AccountId": "123456789012",
        "ResourceId": "123456789012::AWS.Config.Recorder.Meta",
        "ResourceType": "AWS.Config.Recorder.Meta",
        "Tags": null,
        "Region": "global",
        "Recorders":
          [
            "123456789012:us-east-1:AWS.Config.Recorder",
            "123456789012:us-east-2:AWS.Config.Recorder",
            "123456789012:us-west-1:AWS.Config.Recorder",
            "123456789012:us-west-2:AWS.Config.Recorder",
          ],
        "Name": "AWS.Config.Recorder.Meta",
        "GlobalRecorderCount": 4,
      }
  - Name: Global Recorders Present - None Recording Global Resources
    ExpectedResult: false
    Mocks:
      - {
          "objectName": "resource_lookup",
          "returnValue": '{"AccountId":"012345678910","Name":"Default","RecordingGroup":{"AllSupported":true,"IncludeGlobalResourceTypes":true,"ResourceTypes":null},"Region":"us-east-1","ResourceId":"012345678910:us-east-1:AWS.Config.Recorder","ResourceType":"AWS.Config.Recorder","RoleARN":"arn:aws:iam::012345678910:role/PantherAWSConfig","Status":{"LastErrorCode":null,"LastErrorMessage":null,"LastStartTime":"2018-10-05T22:45:01.838Z","LastStatus":"SUCCESS","LastStatusChangeTime":"2021-05-28T17:45:14.916Z","LastStopTime":null,"Name":"Default","Recording":false},"Tags":null,"TimeCreated":null}',
        }
    Resource:
      {
        "TimeCreated": null,
        "Recorders": ["123456789012:us-west-2:AWS.Config.Recorder"],
        "AccountId": "123456789012",
        "Name": "AWS.Config.Recorder.Meta",
        "GlobalRecorderCount": 1,
        "Tags": null,
        "Region": "global",
        "ResourceType": "AWS.Config.Recorder.Meta",
        "ResourceId": "123456789012::AWS.Config.Recorder.Meta",
      }


# ------ paired body: aws_config_global_resources.py ------

import json

from panther_aws_helpers import BadLookup, resource_lookup
from panther_base_helpers import deep_get

# TODO: Once Detection Pipelines are merged, implement downgraded (INFO) case for multiple
#       global resource recorders.


def policy(resource):
    if (
        resource.get("GlobalRecorderCount", 0) == 0
        or "Recorders" not in resource
        or not bool(resource.get("Recorders"))
    ):
        return False

    for recorder_name in resource.get("Recorders", []):
        try:
            recorder = resource_lookup(recorder_name)
        except BadLookup:
            continue
        if isinstance(recorder, str):
            recorder = json.loads(recorder)
        resource_records_global_resources = bool(
            deep_get(recorder, "RecordingGroup", "IncludeGlobalResourceTypes")
            and deep_get(recorder, "Status", "Recording")
        )
        if resource_records_global_resources:
            return True
    return False

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.