AWS Common Actions

Actions

auto-tag-user

Tag a resource with the user who created/modified it.

policies:
  - name: ec2-auto-tag-ownercontact
    resource: ec2
    description: |
      Triggered when a new EC2 Instance is launched. Checks to see if
      it's missing the OwnerContact tag. If missing it gets created
      with the value of the ID of whomever called the RunInstances API
    mode:
      type: cloudtrail
      role: arn:aws:iam::123456789000:role/custodian-auto-tagger
      events:
        - RunInstances
    filters:
     - tag:OwnerContact: absent
    actions:
     - type: auto-tag-user
       tag: OwnerContact

There’s a number of caveats to usage. Resources which don’t include tagging as part of their api may have some delay before automation kicks in to create a tag. Real world delay may be several minutes, with worst case into hours[0]. This creates a race condition between auto tagging and automation.

In practice this window is on the order of a fraction of a second, as we fetch the resource and evaluate the presence of the tag before attempting to tag it.

References

properties:
  principal_id_tag:
    type: string
  tag:
    type: string
  type:
    enum:
    - auto-tag-user
  update:
    type: boolean
  user-type:
    items:
      enum:
      - IAMUser
      - AssumedRole
      - FederatedUser
      type: string
    type: array
  value:
    enum:
    - userName
    - arn
    - sourceIPAddress
    - principalId
    type: string
required:
- tag
- type

invoke-lambda

Invoke an arbitrary lambda

serialized invocation parameters

  • resources / collection of resources

  • policy / policy that is invoke the lambda

  • action / action that is invoking the lambda

  • event / cloud trail event if any

  • version / version of custodian invoking the lambda

We automatically batch into sets of 250 for invocation, We try to utilize async invocation by default, this imposes some greater size limits of 128kb which means we batch invoke.

Example:

- type: invoke-lambda
  function: my-function
  assume-role: iam-role-arn

Note, if you’re synchronously invoking the lambda, you may also need to configure the timeout to avoid multiple invocations. The default timeout is 90s. If the lambda doesn’t respond within that time, the boto sdk will invoke the lambda again with the same arguments. Alternatively, use async: true

properties:
  assume-role:
    type: string
  async:
    type: boolean
  batch_size:
    type: integer
  function:
    type: string
  qualifier:
    type: string
  region:
    type: string
  timeout:
    type: integer
  type:
    enum:
    - invoke-lambda
  vars:
    type: object
required:
- type
- function

invoke-sfn

Invoke step function on resources.

By default this will invoke a step function for each resource providing both the policy and resource as input.

That behavior can be configured setting policy and bulk boolean flags on the action.

If bulk action parameter is set to true, then the step function will be invoked in bulk, with a set of resource arns under the resources key.

The size of the batch can be configured via the batch-size parameter. Note step function state (input, execution, etc)must fit within 32k, we default to batch size 250.

example:

policies:
  - name: invoke-step-function
    resource: s3
    filters:
      - is-log-target
      - "tag:IngestSetup": absent
    actions:
      - type: invoke-sfn
        # This will cause the workflow to be invoked
        # with many resources arns in a single execution.
        # Note this is *not* the default.
        bulk: true
        batch-size: 10
        state-machine: LogIngestSetup
properties:
  batch-size:
    type: integer
  bulk:
    type: boolean
  policy:
    type: boolean
  state-machine:
    type: string
  type:
    enum:
    - invoke-sfn
required:
- state-machine
- type

mark-for-op

Tag resources for future action.

example:
policies:
- name: ec2-mark-stop
  resource: ec2
  filters:
    - type: image-age
      op: ge
      days: 90
  actions:
    - type: mark-for-op
      tag: custodian_cleanup
      op: terminate
      days: 4
properties:
  days:
    minimum: 0
    type: number
  hours:
    minimum: 0
    type: number
  msg:
    type: string
  op:
    type: string
  tag:
    type: string
  type:
    enum:
    - mark-for-op
  tz:
    type: string
required:
- type

modify-ecr-policy

Action to modify ECR policy statements.

example:

policies:
   - name: ecr-image-prevent-pull
     resource: ecr-image
     filters:
       - type: finding
     actions:
       - type: modify-ecr-policy
         add-statements: [{
             "Sid": "ReplaceWithMe",
             "Effect": "Deny",
             "Principal": "*",
             "Action": ["ecr:BatchGetImage"]
                 }]
         remove-statements: "*"
properties:
  add-statements:
    items:
      oneOf:
      - required:
        - Principal
        - Action
      - required:
        - NotPrincipal
        - Action
      - required:
        - Principal
        - NotAction
      - required:
        - NotPrincipal
        - NotAction
      properties:
        Action:
          anyOf:
          - pattern: ^ecr:([a-zA-Z]*|[*])$
            type: string
          - items:
              pattern: ^ecr:([a-zA-Z]*|[*])$
              type: string
            type: array
        Condition:
          type: object
        Effect:
          enum:
          - Allow
          - Deny
          type: string
        NotAction:
          anyOf:
          - pattern: ^ecr:([a-zA-Z]*|[*])$
            type: string
          - items:
              pattern: ^ecr:([a-zA-Z]*|[*])$
              type: string
            type: array
        NotPrincipal:
          anyOf:
          - type: object
          - type: array
        NotResource:
          anyOf:
          - type: string
          - type: array
        Principal:
          anyOf:
          - type: string
          - type: object
          - type: array
        Resource:
          anyOf:
          - type: string
          - type: array
        Sid:
          type: string
      required:
      - Sid
      - Effect
      type: object
    type: array
  remove-statements:
    oneOf:
    - enum:
      - matched
      - '*'
    - items:
        type: string
      type: array
    type:
    - array
    - string
  schema_alias: false
  type:
    enum:
    - modify-ecr-policy
required:
- type

modify-policy

Action to modify SQS Queue IAM policy statements.

example:

policies:
   - name: sqs-yank-cross-account
     resource: sqs
     filters:
       - type: cross-account
     actions:
       - type: modify-policy
         add-statements: [{
             "Sid": "ReplaceWithMe",
             "Effect": "Allow",
             "Principal": "*",
             "Action": ["sqs:GetQueueAttributes"],
             "Resource": queue_url,
                 }]
         remove-statements: '*'
properties:
  add-statements:
    items:
      additionalProperties: false
      oneOf:
      - required:
        - Principal
        - Action
        - Resource
      - required:
        - NotPrincipal
        - Action
        - Resource
      - required:
        - Principal
        - NotAction
        - Resource
      - required:
        - NotPrincipal
        - NotAction
        - Resource
      - required:
        - Principal
        - Action
        - NotResource
      - required:
        - NotPrincipal
        - Action
        - NotResource
      - required:
        - Principal
        - NotAction
        - NotResource
      - required:
        - NotPrincipal
        - NotAction
        - NotResource
      properties:
        Action:
          anyOf:
          - type: string
          - type: array
        Condition:
          type: object
        Effect:
          enum:
          - Allow
          - Deny
          type: string
        NotAction:
          anyOf:
          - type: string
          - type: array
        NotPrincipal:
          anyOf:
          - type: object
          - type: array
        NotResource:
          anyOf:
          - type: string
          - type: array
        Principal:
          anyOf:
          - type: string
          - type: object
          - type: array
        Resource:
          anyOf:
          - type: string
          - type: array
        Sid:
          type: string
      required:
      - Sid
      - Effect
      type: object
    type: array
  remove-statements:
    oneOf:
    - enum:
      - matched
      - '*'
    - items:
        type: string
      type: array
    type:
    - array
    - string
  type:
    enum:
    - modify-policy
required:
- type

modify-security-groups

Modify security groups on a Redshift cluster

anyOf:
- required:
  - isolation-group
  - remove
  - type
- required:
  - add
  - remove
  - type
- required:
  - add
  - type
- required:
  - add-by-tag
  - type
properties:
  add:
    oneOf:
    - type: string
    - items:
        type: string
      type: array
  add-by-tag:
    additionalProperties: false
    properties:
      key:
        type: string
      values:
        items:
          type: string
        type: array
    required:
    - key
    - values
    type: object
  isolation-group:
    oneOf:
    - type: string
    - items:
        type: string
      type: array
  remove:
    oneOf:
    - items:
        type: string
      type: array
    - enum:
      - matched
      - network-location
      - all
      - type: string
  type:
    enum:
    - modify-security-groups

normalize-tag

Transform the value of a tag.

Set the tag value to uppercase, title, lowercase, or strip text from a tag key.

policies:
  - name: ec2-service-transform-lower
    resource: ec2
    comment: |
      ec2-service-tag-value-to-lower
    query:
      - instance-state-name: running
    filters:
      - "tag:testing8882": present
    actions:
      - type: normalize-tag
        key: lower_key
        action: lower

  - name: ec2-service-strip
    resource: ec2
    comment: |
      ec2-service-tag-strip-blah
    query:
      - instance-state-name: running
    filters:
      - "tag:testing8882": present
    actions:
      - type: normalize-tag
        key: strip_key
        action: strip
        value: blah
properties:
  action:
    items:
      enum:
      - upper
      - lower
      - titlestrip
      - replace
    type: string
  key:
    type: string
  type:
    enum:
    - normalize-tag
  value:
    type: string
required:
- type

notify

Flexible notifications require quite a bit of implementation support on pluggable transports, templates, address resolution, variable extraction, batch periods, etc.

For expedience and flexibility then, we instead send the data to an sqs queue, for processing. ie. actual communications can be enabled with the c7n-mailer tool, found under tools/c7n_mailer.

Attaching additional string message attributes are supported on the SNS transport, with the exception of the mtype attribute, which is a reserved attribute used by Cloud Custodian.

example:

policies:
  - name: ec2-bad-instance-kill
    resource: ec2
    filters:
     - Name: bad-instance
    actions:
     - terminate
     - type: notify
       to:
        - event-user
        - resource-creator
        - email@address
       owner_absent_contact:
        - other_email@address
       # which template for the email should we use
       template: policy-template
       transport:
         type: sqs
         region: us-east-1
         queue: xyz
  - name: ec2-notify-with-attributes
    resource: ec2
    filters:
     - Name: bad-instance
    actions:
     - type: notify
       to:
        - event-user
        - resource-creator
        - email@address
       owner_absent_contact:
        - other_email@address
       # which template for the email should we use
       template: policy-template
       transport:
         type: sns
         region: us-east-1
         topic: your-notify-topic
         attributes:
            attribute_key: attribute_value
            attribute_key_2: attribute_value_2
anyOf:
- required:
  - type
  - transport
  - to
- required:
  - type
  - transport
  - to_from
properties:
  assume_role:
    type: boolean
  cc:
    items:
      type: string
    type: array
  cc_from:
    additionalProperties: 'False'
    properties:
      expr:
        oneOf:
        - type: integer
        - type: string
      format:
        enum:
        - csv
        - json
        - txt
        - csv2dict
      headers:
        patternProperties:
          ? ''
          : type: string
        type: object
      url:
        type: string
    required:
    - url
    type: object
  cc_manager:
    type: boolean
  from:
    type: string
  owner_absent_contact:
    items:
      type: string
    type: array
  subject:
    type: string
  template:
    type: string
  to:
    items:
      type: string
    type: array
  to_from:
    additionalProperties: 'False'
    properties:
      expr:
        oneOf:
        - type: integer
        - type: string
      format:
        enum:
        - csv
        - json
        - txt
        - csv2dict
      headers:
        patternProperties:
          ? ''
          : type: string
        type: object
      url:
        type: string
    required:
    - url
    type: object
  transport:
    oneOf:
    - properties:
        queue:
          type: string
        type:
          enum:
          - sqs
      required:
      - type
      - queue
      type: object
    - properties:
        attributes:
          type: object
        topic:
          type: string
        type:
          enum:
          - sns
      required:
      - type
      - topic
      type: object
  type:
    enum:
    - notify

post-finding

Report a finding to AWS Security Hub.

Custodian acts as a finding provider, allowing users to craft policies that report to the AWS SecurityHub in the AWS Security Finding Format documented at https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html

For resources that are taggable, we will tag the resource with an identifier such that further findings generate updates. The name of the tag comes from the title parameter of the post-finding action, or the policy name if title is empty. This allows different policies to update the same finding if they specify the same title.

Example generate a finding for accounts that don’t have shield enabled.

Note with Cloud Custodian (0.9+) you need to enable the Custodian integration to post-findings, see Getting Started with Security Hub.

example:

policies:

 - name: account-shield-enabled
   resource: account
   filters:
     - shield-enabled
   actions:
     - type: post-finding
       description: |
          Shield should be enabled on account to allow for DDOS protection (1 time 3k USD Charge).
       severity_label: LOW
       types:
         - "Software and Configuration Checks/Industry and Regulatory Standards/NIST CSF Controls (USA)"
       recommendation: "Enable shield"
       recommendation_url: "https://www.example.com/policies/AntiDDoS.html"
       title: "shield-enabled"
       confidence: 100
       compliance_status: FAILED
properties:
  batch_size:
    default: 1
    maximum: 100
    minimum: 1
    type: integer
  compliance_status:
    enum:
    - PASSED
    - WARNING
    - FAILED
    - NOT_AVAILABLE
    type: string
  confidence:
    max: 100
    min: 0
    type: number
  criticality:
    max: 100
    min: 0
    type: number
  description:
    default: policy.description, or if not defined in policy then policy.name
    type: string
  fields:
    type: object
  recommendation:
    type: string
  recommendation_url:
    type: string
  record_state:
    default: ACTIVE
    enum:
    - ACTIVE
    - ARCHIVED
    type: string
  region:
    description: cross-region aggregation target
    type: string
  severity:
    default: 0
    type: number
  severity_label:
    default: INFORMATIONAL
    enum:
    - INFORMATIONAL
    - LOW
    - MEDIUM
    - HIGH
    - CRITICAL
    type: string
  severity_normalized:
    default: 0
    max: 100
    min: 0
    type: number
  title:
    default: policy.name
    type: string
  type:
    enum:
    - post-finding
  types:
    items:
      type: string
    minItems: 1
    type: array
required:
- types
- type

post-item

Post an OpsItem to AWS Systems Manager OpsCenter Dashboard.

https://docs.aws.amazon.com/systems-manager/latest/userguide/OpsCenter.html

Each ops item supports up to a 100 associated resources. This action supports the builtin OpsCenter dedup logic with additional support for associating new resources to existing Open ops items.

: Example :

Create an ops item for ec2 instances with Create User permissions

policies:
  - name: over-privileged-ec2
    resource: aws.ec2
    filters:
      - type: check-permissions
        match: allowed
        actions:
          - iam:CreateUser
    actions:
      - type: post-item
        priority: 3

The builtin OpsCenter dedup logic will kick in if the same resource set (ec2 instances in this case) is posted for the same policy.

: Example :

Create an ops item for sqs queues with cross account access as ops items.

policies:
  - name: sqs-cross-account-access
    resource: aws.sqs
    filters:
      - type: cross-account
    actions:
      - type: mark-for-op
        days: 5
        op: delete
      - type: post-item
        title: SQS Cross Account Access
        description: |
          Cross Account Access detected in SQS resource IAM Policy.
        tags:
          Topic: Security
properties:
  description:
    type: string
  priority:
    enum:
    - 1
    - 2
    - 3
    - 4
    - 5
  tags:
    type: object
  title:
    type: string
  topics:
    type: string
  type:
    enum:
    - post-item
required:
- type

put-metric

Action to put metrics based on an expression into CloudWatch metrics

example:

policies:
  - name: track-attached-ebs
    resource: ec2
    comment: |
      Put the count of the number of EBS attached disks to an instance
    filters:
      - Name: tracked-ec2-instance
    actions:
      - type: put-metric
        key: Reservations[].Instances[].BlockDeviceMappings[].DeviceName
        namespace: Usage Metrics
        metric_name: Attached Disks
        op: count
        units: Count

op and units are optional and will default to simple Counts.

properties:
  dimensions:
    items:
      type: object
    type: array
  key:
    type: string
  metric_name:
    type: string
  namespace:
    type: string
  op:
    enum:
    - count
    - distinct_count
    - sum
    - average
  type:
    enum:
    - put-metric
  units:
    enum:
    - Seconds
    - Microseconds
    - Milliseconds
    - Bytes
    - Kilobytes
    - Megabytes
    - Gigabytes
    - Terabytes
    - Bits
    - Kilobits
    - Megabits
    - Gigabits
    - Terabits
    - Bytes/Second
    - Kilobytes/Second
    - Megabytes/Second
    - Gigabytes/Second
    - Terabytes/Second
    - Bits/Second
    - Kilobits/Second
    - Megabits/Second
    - Gigabits/Second
    - Terabits/Second
    - Count/Second
    - Percent
    - Count
    - None
required:
- type
- key
- namespace
- metric_name

remove-tag

Removes the specified tags from the specified resources.

properties:
  tags:
    items:
      type: string
    type: array
  type:
    enum:
    - remove-tag
    - unmark
    - untag
    - remove-tag
required:
- type

rename-tag

Create a new tag with identical value & remove old tag

properties:
  new_key:
    type: string
  old_key:
    type: string
  type:
    enum:
    - rename-tag
required:
- type

tag

Applies one or more tags to the specified resources.

example:
policies:
- name: multiple-tags-example
  comment: |
    Tags any secrets missing either the Environment or ResourceOwner tag
  resource: aws.secrets-manager
  filters:
    - or:
      - "tag:Environment": absent
      - "tag:ResourceOwner": absent
  actions:
    - type: tag
      tags:
        Environment: Staging
        ResourceOwner: Avengers
properties:
  key:
    type: string
  tag:
    type: string
  tags:
    type: object
  type:
    enum:
    - tag
    - mark
  value:
    type: string
required:
- type

tag-trim

Automatically remove tags from an ec2 resource.

EC2 Resources have a limit of 50 tags, in order to make additional tags space on a set of resources, this action can be used to remove enough tags to make the desired amount of space while preserving a given set of tags.

policies:
  - name: ec2-tag-trim
    comment: |
      Any instances with 48 or more tags get tags removed until
      they match the target tag count, in this case 47 so we
      that we free up a tag slot for another usage.
    resource: ec2
    filters:
          # Filter down to resources which already have 8 tags
          # as we need space for 3 more, this also ensures that
          # metrics reporting is correct for the policy.
        - type: value
          key: "length(Tags)"
          op: ge
          value: 48
    actions:
       - type: tag-trim
         space: 3
         preserve:
           - OwnerContact
           - ASV
           - CMDBEnvironment
           - downtime
           - custodian_status
properties:
  preserve:
    items:
      type: string
    type: array
  space:
    type: integer
  type:
    enum:
    - tag-trim
required:
- type

webhook

Calls a webhook with optional parameters and body populated from JMESPath queries.

policies:
  - name: call-webhook
    resource: ec2
    description: |
      Call webhook with list of resource groups
    actions:
     - type: webhook
       url: http://foo.com
       query-params:
          resource_name: resource.name
          policy_name: policy.name
properties:
  batch:
    type: boolean
  batch-size:
    type: number
  body:
    type: string
  headers:
    additionalProperties:
      description: header values
      type: string
    type: object
  method:
    enum:
    - PUT
    - POST
    - GET
    - PATCH
    - DELETE
    type: string
  query-params:
    additionalProperties:
      description: query string values
      type: string
    type: object
  type:
    enum:
    - webhook
  url:
    type: string
required:
- url
- type