AWS DynamoDB Table Autoscaling


Description

DynamoDB Auto Scaling can dynamically adjust provisioned throughput capacity in response to traffic patterns. This enables a table to increase its provisioned read and write capacity to handle sudden increases in traffic

Query · python

from panther_base_helpers import deep_get

# If you do not wish to enforce application auto-scaling on your dynamo tables Global
# Secondary Indices, set this variable to False
CHECK_GSI = True


def policy(resource):
    # Check if this table has never had auto scaling configured
    if resource["BillingModeSummary"] is None and resource["AutoScalingDescriptions"] is None:
        return False

    # Check if this table is not on provisioned billing (and therefore auto scaling does not apply)
    if deep_get(resource, "BillingModeSummary", "BillingMode") != "PROVISIONED":
        return True

    # Check if application auto scaling is configured
    if resource["AutoScalingDescriptions"] is None:
        return False

    # Build a list of all the resources (the table and optionally the GSI's) to be checked
    table_id = "table/" + resource["Name"]
    resource_auto_scaling = {table_id: False}
    if CHECK_GSI:
        # We cannot use resource.get('GSI', []) here as the value is present, it is just a NoneType
        for gsi in resource["GlobalSecondaryIndexes"] or []:
            resource_auto_scaling[table_id + "/index/" + gsi["IndexName"]] = False

    # Check that each resource that requires application autoscaling has it enabled
    for auto_scale_target in resource["AutoScalingDescriptions"]:
        resource_auto_scaling[auto_scale_target["ResourceId"]] = True

    # Return True if all resources have autoscaling enabled
    return all(resource_auto_scaling.values())

Analyst notes

https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-dynamodb-table-has-autoscaling-enabled

Raw source AWS DynamoDB Table Autoscaling · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: policy
Filename: aws_dynamodb_autoscaling.py
PolicyID: "AWS.DynamoDB.Autoscaling"
DisplayName: "AWS DynamoDB Table Autoscaling"
Enabled: true
ResourceTypes:
  - AWS.DynamoDB.Table
Tags:
  - AWS
  - Availability
Severity: Low
Description: >
  DynamoDB Auto Scaling can dynamically adjust provisioned throughput capacity in response to
  traffic patterns. This enables a table to increase its provisioned read and write capacity
  to handle sudden increases in traffic
Runbook: >
  https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-dynamodb-table-has-autoscaling-enabled
Reference: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html
Tests:
  - Name: AutoScaling Enabled
    ExpectedResult: true
    Resource:
      {
        "AutoScalingDescriptions":
          [
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:table:ReadCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:table:WriteCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:ReadCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:WriteCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
          ],
        "AttributeDefinitions":
          [
            { "AttributeName": "attribute_one", "AttributeType": "S" },
            { "AttributeName": "attribute_two", "AttributeType": "S" },
          ],
        "BillingModeSummary":
          {
            "BillingMode": "PROVISIONED",
            "LastUpdateToPayPerRequestDateTime": "2019-01-01T00:00:00Z",
          },
        "CreationDateTime": "2019-01-01T100:00:00Z",
        "GlobalSecondaryIndexes":
          [
            {
              "Backfilling": null,
              "IndexArn": "arn:aws:dynamodb:us-west-2:123456789012:table/panther-internal-poller-test-table/index/high_score-index",
              "IndexName": "example-index",
              "IndexSizeBytes": 0,
              "IndexStatus": "ACTIVE",
              "ItemCount": 0,
              "KeySchema":
                [{ "AttributeName": "high_score", "KeyType": "HASH" }],
              "Projection":
                { "NonKeyAttributes": null, "ProjectionType": "ALL" },
              "ProvisionedThroughput":
                {
                  "LastDecreaseDateTime": "2019-01-01T00:00:00Z",
                  "LastIncreaseDateTime": "2019-01-01T00:00:00Z",
                  "NumberOfDecreasesToday": 0,
                  "ReadCapacityUnits": 5,
                  "WriteCapacityUnits": 5,
                },
            },
          ],
        "ItemCount": 42,
        "KeySchema":
          [
            { "AttributeName": "attribute_one", "KeyType": "HASH" },
            { "AttributeName": "attribute_two", "KeyType": "RANGE" },
          ],
        "LatestStreamArn": null,
        "LatestStreamLabel": null,
        "LocalSecondaryIndexes": null,
        "ProvisionedThroughput":
          {
            "LastDecreaseDateTime": null,
            "LastIncreaseDateTime": null,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 0,
            "WriteCapacityUnits": 0,
          },
        "RestoreSummary": null,
        "SSEDescription":
          {
            "KMSMasterKeyArn": "arn:aws:kms:us-west-2:123456789012:key/111222333",
            "SSEType": "KMS",
            "Status": "ENABLED",
          },
        "StreamSpecification": null,
        "TableArn": "arn:aws:dynamodb:us-west-2:123456789012:table/example-table",
        "TableId": "aaaaaaaa-bbbb-1111-2222-1111222233334444",
        "Name": "example-table",
        "TableSizeBytes": 20000,
        "TableStatus": "ACTIVE",
      }
  - Name: AutoScaling Never Configured
    ExpectedResult: false
    Resource:
      {
        "AutoScalingDescriptions": null,
        "AttributeDefinitions":
          [
            { "AttributeName": "attribute_one", "AttributeType": "S" },
            { "AttributeName": "attribute_two", "AttributeType": "S" },
          ],
        "BillingModeSummary": null,
        "CreationDateTime": "2019-01-01T100:00:00Z",
        "GlobalSecondaryIndexes":
          [
            {
              "Backfilling": null,
              "IndexArn": "arn:aws:dynamodb:us-west-2:123456789012:table/panther-internal-poller-test-table/index/high_score-index",
              "IndexName": "example-index",
              "IndexSizeBytes": 0,
              "IndexStatus": "ACTIVE",
              "ItemCount": 0,
              "KeySchema":
                [{ "AttributeName": "high_score", "KeyType": "HASH" }],
              "Projection":
                { "NonKeyAttributes": null, "ProjectionType": "ALL" },
              "ProvisionedThroughput":
                {
                  "LastDecreaseDateTime": "2019-01-01T00:00:00Z",
                  "LastIncreaseDateTime": "2019-01-01T00:00:00Z",
                  "NumberOfDecreasesToday": 0,
                  "ReadCapacityUnits": 5,
                  "WriteCapacityUnits": 5,
                },
            },
          ],
        "ItemCount": 42,
        "KeySchema":
          [
            { "AttributeName": "attribute_one", "KeyType": "HASH" },
            { "AttributeName": "attribute_two", "KeyType": "RANGE" },
          ],
        "LatestStreamArn": null,
        "LatestStreamLabel": null,
        "LocalSecondaryIndexes": null,
        "ProvisionedThroughput":
          {
            "LastDecreaseDateTime": null,
            "LastIncreaseDateTime": null,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 0,
            "WriteCapacityUnits": 0,
          },
        "RestoreSummary": null,
        "SSEDescription":
          {
            "KMSMasterKeyArn": "arn:aws:kms:us-west-2:123456789012:key/111222333",
            "SSEType": "KMS",
            "Status": "ENABLED",
          },
        "StreamSpecification": null,
        "TableArn": "arn:aws:dynamodb:us-west-2:123456789012:table/example-table",
        "TableId": "aaaaaaaa-bbbb-1111-2222-1111222233334444",
        "Name": "example-table",
        "TableSizeBytes": 20000,
        "TableStatus": "ACTIVE",
      }
  - Name: AutoScaling Not Enabled For Table
    ExpectedResult: false
    Resource:
      {
        "AutoScalingDescriptions":
          [
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:ReadCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:WriteCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
          ],
        "AttributeDefinitions":
          [
            { "AttributeName": "attribute_one", "AttributeType": "S" },
            { "AttributeName": "attribute_two", "AttributeType": "S" },
          ],
        "BillingModeSummary":
          {
            "BillingMode": "PROVISIONED",
            "LastUpdateToPayPerRequestDateTime": "2019-01-01T00:00:00Z",
          },
        "CreationDateTime": "2019-01-01T100:00:00Z",
        "GlobalSecondaryIndexes":
          [
            {
              "Backfilling": null,
              "IndexArn": "arn:aws:dynamodb:us-west-2:123456789012:table/panther-internal-poller-test-table/index/high_score-index",
              "IndexName": "example-index",
              "IndexSizeBytes": 0,
              "IndexStatus": "ACTIVE",
              "ItemCount": 0,
              "KeySchema":
                [{ "AttributeName": "high_score", "KeyType": "HASH" }],
              "Projection":
                { "NonKeyAttributes": null, "ProjectionType": "ALL" },
              "ProvisionedThroughput":
                {
                  "LastDecreaseDateTime": "2019-01-01T00:00:00Z",
                  "LastIncreaseDateTime": "2019-01-01T00:00:00Z",
                  "NumberOfDecreasesToday": 0,
                  "ReadCapacityUnits": 5,
                  "WriteCapacityUnits": 5,
                },
            },
          ],
        "ItemCount": 42,
        "KeySchema":
          [
            { "AttributeName": "attribute_one", "KeyType": "HASH" },
            { "AttributeName": "attribute_two", "KeyType": "RANGE" },
          ],
        "LatestStreamArn": null,
        "LatestStreamLabel": null,
        "LocalSecondaryIndexes": null,
        "ProvisionedThroughput":
          {
            "LastDecreaseDateTime": null,
            "LastIncreaseDateTime": null,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 0,
            "WriteCapacityUnits": 0,
          },
        "RestoreSummary": null,
        "SSEDescription":
          {
            "KMSMasterKeyArn": "arn:aws:kms:us-west-2:123456789012:key/111222333",
            "SSEType": "KMS",
            "Status": "ENABLED",
          },
        "StreamSpecification": null,
        "TableArn": "arn:aws:dynamodb:us-west-2:123456789012:table/example-table",
        "TableId": "aaaaaaaa-bbbb-1111-2222-1111222233334444",
        "Name": "example-table",
        "TableSizeBytes": 20000,
        "TableStatus": "ACTIVE",
      }
  - Name: Billing Mode Pay Per Request
    ExpectedResult: true
    Resource:
      {
        "AutoScalingDescriptions":
          [
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:table:ReadCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:table:WriteCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:ReadCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
            {
              "CreationTime": "2019-01-01T00:00:00Z",
              "MaxCapacity": 40000,
              "MinCapacity": 5,
              "ResourceId": "table/example-table/index/example-index",
              "RoleARN": "arn:aws:iam::123456789012:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable",
              "ScalableDimension": "dynamodb:index:WriteCapacityUnits",
              "ServiceNamespace": "dynamodb",
            },
          ],
        "AttributeDefinitions":
          [
            { "AttributeName": "attribute_one", "AttributeType": "S" },
            { "AttributeName": "attribute_two", "AttributeType": "S" },
          ],
        "BillingModeSummary":
          {
            "BillingMode": "PAY-PER-REQUEST",
            "LastUpdateToPayPerRequestDateTime": "2019-01-01T00:00:00Z",
          },
        "CreationDateTime": "2019-01-01T100:00:00Z",
        "GlobalSecondaryIndexes":
          [
            {
              "Backfilling": null,
              "IndexArn": "arn:aws:dynamodb:us-west-2:123456789012:table/panther-internal-poller-test-table/index/high_score-index",
              "IndexName": "example-index",
              "IndexSizeBytes": 0,
              "IndexStatus": "ACTIVE",
              "ItemCount": 0,
              "KeySchema":
                [{ "AttributeName": "high_score", "KeyType": "HASH" }],
              "Projection":
                { "NonKeyAttributes": null, "ProjectionType": "ALL" },
              "ProvisionedThroughput":
                {
                  "LastDecreaseDateTime": "2019-01-01T00:00:00Z",
                  "LastIncreaseDateTime": "2019-01-01T00:00:00Z",
                  "NumberOfDecreasesToday": 0,
                  "ReadCapacityUnits": 5,
                  "WriteCapacityUnits": 5,
                },
            },
          ],
        "ItemCount": 42,
        "KeySchema":
          [
            { "AttributeName": "attribute_one", "KeyType": "HASH" },
            { "AttributeName": "attribute_two", "KeyType": "RANGE" },
          ],
        "LatestStreamArn": null,
        "LatestStreamLabel": null,
        "LocalSecondaryIndexes": null,
        "ProvisionedThroughput":
          {
            "LastDecreaseDateTime": null,
            "LastIncreaseDateTime": null,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 0,
            "WriteCapacityUnits": 0,
          },
        "RestoreSummary": null,
        "SSEDescription":
          {
            "KMSMasterKeyArn": "arn:aws:kms:us-west-2:123456789012:key/111222333",
            "SSEType": "KMS",
            "Status": "ENABLED",
          },
        "StreamSpecification": null,
        "TableArn": "arn:aws:dynamodb:us-west-2:123456789012:table/example-table",
        "TableId": "aaaaaaaa-bbbb-1111-2222-1111222233334444",
        "Name": "example-table",
        "TableSizeBytes": 20000,
        "TableStatus": "ACTIVE",
      }


# ------ paired body: aws_dynamodb_autoscaling.py ------

from panther_base_helpers import deep_get

# If you do not wish to enforce application auto-scaling on your dynamo tables Global
# Secondary Indices, set this variable to False
CHECK_GSI = True


def policy(resource):
    # Check if this table has never had auto scaling configured
    if resource["BillingModeSummary"] is None and resource["AutoScalingDescriptions"] is None:
        return False

    # Check if this table is not on provisioned billing (and therefore auto scaling does not apply)
    if deep_get(resource, "BillingModeSummary", "BillingMode") != "PROVISIONED":
        return True

    # Check if application auto scaling is configured
    if resource["AutoScalingDescriptions"] is None:
        return False

    # Build a list of all the resources (the table and optionally the GSI's) to be checked
    table_id = "table/" + resource["Name"]
    resource_auto_scaling = {table_id: False}
    if CHECK_GSI:
        # We cannot use resource.get('GSI', []) here as the value is present, it is just a NoneType
        for gsi in resource["GlobalSecondaryIndexes"] or []:
            resource_auto_scaling[table_id + "/index/" + gsi["IndexName"]] = False

    # Check that each resource that requires application autoscaling has it enabled
    for auto_scale_target in resource["AutoScalingDescriptions"]:
        resource_auto_scaling[auto_scale_target["ResourceId"]] = True

    # Return True if all resources have autoscaling enabled
    return all(resource_auto_scaling.values())

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.