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.
Note
The notify
action does not produce complete, human-readable messages
on its own. Instead, the c7n-mailer tool renders and delivers
messages by combining notify
output with formatted templates.
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
query:
type: string
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
query:
type: string
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