c7n.actions package

Submodules

c7n.actions.autotag module

class c7n.actions.autotag.AutoTagUser(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.EventAction

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

get_permissions()[source]
process(resources, event)[source]
schema = {'additionalProperties': False, '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'}}, 'required': ['tag', 'type'], 'type': 'object'}
schema_alias = True
validate()[source]
c7n.actions.autotag.register_action_tag_user(registry, _)[source]

c7n.actions.core module

Actions to take on resources

class c7n.actions.core.Action(data=None, manager=None, log_dir=None)[source]

Bases: object

executor_factory

alias of concurrent.futures.thread.ThreadPoolExecutor

get_permissions()[source]
log = <Logger custodian.actions (DEBUG)>
metrics = ()
name
permissions = ()
process(resources)[source]
schema = {'type': 'object'}
schema_alias = None
validate()[source]
class c7n.actions.core.ActionRegistry(*args, **kw)[source]

Bases: c7n.registry.PluginRegistry

factory(data, manager)[source]
parse(data, manager)[source]
c7n.actions.core.BaseAction

alias of c7n.actions.core.Action

class c7n.actions.core.EventAction(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.Action

Actions which receive lambda event if present

c7n.actions.invoke module

class c7n.actions.invoke.LambdaInvoke(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.EventAction

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

Note if your synchronously invoking the lambda, you may also need to configure the timeout, to avoid multiple invokes. The default 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

permissions = ('lambda:InvokeFunction',)
process(resources, event=None)[source]
schema = {'properties': {'async': {'type': 'boolean'}, 'batch_size': {'type': 'integer'}, 'function': {'type': 'string'}, 'qualifier': {'type': 'string'}, 'timeout': {'type': 'integer'}, 'type': {'enum': ['invoke-lambda']}}, 'required': ['type', 'function'], 'type': 'object'}
schema_alias = True
c7n.actions.invoke.register_action_invoke_lambda(registry, _)[source]

c7n.actions.metric module

class c7n.actions.metric.PutMetric(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.Action

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.

permissions = {'cloudwatch:PutMetricData'}
process(resources)[source]
schema = {'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'], 'type': 'object'}
schema_alias = True
c7n.actions.metric.average(numbers)[source]
c7n.actions.metric.distinct_count(values)[source]
c7n.actions.metric.register_action_put_metric(registry, _)[source]

c7n.actions.network module

class c7n.actions.network.ModifyVpcSecurityGroupsAction(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.Action

Common action for modifying security groups on a vpc attached resources.

Security groups for add or remove can be specified via group id or name. Group removal also supports symbolic names such as ‘matched’, ‘network-location’ or ‘all’. ‘matched’ uses the annotations/output of the ‘security-group’ filter filter. ‘network-location’ uses the annotations of the ‘network-location’ interface filter for SecurityGroupMismatch.

Note a vpc attached resource requires at least one security group, this action will use the sg specified in isolation-group to ensure resources always have at least one security-group.

type: modify-security-groups

add: [] remove: [] | matched | network-location isolation-group: sg-xyz

SYMBOLIC_SGS = {'all', 'matched', 'network-location'}
get_action_group_names()[source]

Return all the security group names configured in this action.

get_group_names(groups)[source]
get_groups(resources)[source]

Return lists of security groups to set on each resource

For each input resource, parse the various add/remove/isolation- group policies for ‘modify-security-groups’ to find the resulting set of VPC security groups to attach to that resource.

Returns a list of lists containing the resulting VPC security groups that should end up on each resource passed in.

Parameters

resources – List of resources containing VPC Security Groups

Returns

List of lists of security groups per resource

get_groups_by_names(names)[source]

Resolve security names to security groups resources.

resolve_group_names(r, target_group_ids, groups)[source]

Resolve any security group names to the corresponding group ids

With the context of a given network attached resource.

resolve_remove_symbols(r, target_group_ids, rgroups)[source]

Resolve the resources security groups that need be modified.

Specifically handles symbolic names that match annotations from policy filters for groups being removed.

schema = {'additionalProperties': False, 'anyOf': [{'required': ['isolation-group', 'remove', 'type']}, {'required': ['add', 'remove', 'type']}, {'required': ['add', 'type']}], 'properties': {'add': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}, 'isolation-group': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}, 'remove': {'oneOf': [{'type': 'array', 'items': {'type': 'string'}}, {'enum': ['matched', 'network-location', 'all', {'type': 'string'}]}]}, 'type': {'enum': ['modify-security-groups']}}, 'type': 'object'}
schema_alias = True
sg_expr = None
validate()[source]
vpc_expr = None

c7n.actions.notify module

class c7n.actions.notify.BaseNotify(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.EventAction

batch_size = 250
expand_variables(message)[source]

expand any variables in the action to_from/cc_from fields.

pack(message)[source]
class c7n.actions.notify.Notify(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.notify.BaseNotify

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
C7N_DATA_MESSAGE = 'maidmsg/1.0'
get_permissions()[source]
prepare_asg(resources)[source]
prepare_ec2(resources)[source]
prepare_launch_config(resources)[source]
prepare_resources(resources)[source]

Resources preparation for transport.

If we have sensitive or overly large resource metadata we want to remove or additional serialization we need to perform, this provides a mechanism.

TODO: consider alternative implementations, at min look at adding provider as additional discriminator to resource type. One alternative would be dynamically adjusting buffer size based on underlying transport.

process(resources, event=None)[source]
schema = {'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']}, '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']}, 'url': {'type': 'string'}}, 'required': ['url'], 'type': 'object'}, 'transport': {'oneOf': [{'type': 'object', 'required': ['type', 'queue'], 'properties': {'queue': {'type': 'string'}, 'type': {'enum': ['sqs']}}}, {'type': 'object', 'required': ['type', 'topic'], 'properties': {'topic': {'type': 'string'}, 'type': {'enum': ['sns']}, 'attributes': {'type': 'object'}}}]}, 'type': {'enum': ['notify']}}, 'type': 'object'}
schema_alias = True
send_data_message(message)[source]
send_sns(message)[source]
send_sqs(message)[source]
type = 'notify'
validate()[source]

c7n.actions.policy module

class c7n.actions.policy.ModifyPolicyBase(data=None, manager=None)[source]

Bases: c7n.actions.core.Action

add_statements(policy_statements)[source]
remove_statements(policy_statements, resource, matched_key)[source]
schema = {'additionalProperties': False, 'properties': {'add-statements': {'items': {'$ref': '#/definitions/iam-statement'}, 'type': 'array'}, 'remove-statements': {'oneOf': [{'enum': ['matched', '*']}, {'type': 'array', 'items': {'type': 'string'}}], 'type': ['array', 'string']}, 'type': {'enum': ['modify-policy']}}, 'required': ['type'], 'type': 'object'}
schema_alias = True
class c7n.actions.policy.RemovePolicyBase(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.Action

process_policy(policy, resource, matched_key)[source]
schema = {'additionalProperties': False, 'properties': {'statement_ids': {'oneOf': [{'enum': ['matched']}, {'type': 'array', 'items': {'type': 'string'}}]}, 'type': {'enum': ['remove-statements']}}, 'required': ['statement_ids', 'type'], 'type': 'object'}
c7n.actions.policy.remove_statements(match_ids, statements, matched=())[source]

c7n.actions.securityhub module

class c7n.actions.securityhub.OtherResourcePostFinding(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.securityhub.PostFinding

fields = ()
format_resource(r)[source]
classmethod register_resource(registry, event)[source]
class c7n.actions.securityhub.PostFinding(data=None, manager=None, log_dir=None)[source]

Bases: c7n.actions.core.Action

Report a finding to AWS Security Hub.

Custodian acts as a finding provider, allowing users to craft policies that report to the AWS SecurityHub.

For resources that are taggable, we will tag the resource with an identifier such that further findings generate updates.

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

Example

policies:

 - name: account-shield-enabled
   resource: account
   filters:
     - shield-enabled
   actions:
     - type: post-finding
       severity_normalized: 6
       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"
       confidence: 100
       compliance_status: FAILED
FindingVersion = '2018-10-08'
NEW_FINDING = 'New'
ProductName = 'default'
format_resource(r)[source]
get_finding(resources, existing_finding_id, created_at, updated_at)[source]
get_finding_tag(resource)[source]
group_resources(resources)[source]
permissions = ('securityhub:BatchImportFindings',)
process(resources, event=None)[source]
schema = {'additionalProperties': False, 'properties': {'batch_size': {'maximum': 10, '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'}, 'fields': {'type': 'object'}, 'recommendation': {'type': 'string'}, 'recommendation_url': {'type': 'string'}, 'region': {'description': 'cross-region aggregation target', 'type': 'string'}, 'severity': {'default': 0, 'type': 'number'}, 'severity_normalized': {'default': 0, 'max': 100, 'min': 0, 'type': 'number'}, 'title': {'type': 'string'}, 'type': {'enum': ['post-finding']}, 'types': {'items': {'enum': ['Software and Configuration Checks/Vulnerabilities', 'Software and Configuration Checks/Vulnerabilities/CVE', 'Software and Configuration Checks/AWS Security Best Practices', 'Software and Configuration Checks/AWS Security Best Practices/Network Reachability', 'Software and Configuration Checks/Industry and Regulatory Standards', 'Software and Configuration Checks/Industry and Regulatory Standards/CIS Host Hardening Benchmarks', 'Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark', 'Software and Configuration Checks/Industry and Regulatory Standards/PCI-DSS Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/Cloud Security Alliance Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/ISO 90001 Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/ISO 27001 Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/ISO 27017 Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/ISO 27018 Controls', 'Software and Configuration Checks/Industry and Regulatory Standards/SOC 1', 'Software and Configuration Checks/Industry and Regulatory Standards/SOC 2', 'Software and Configuration Checks/Industry and Regulatory Standards/HIPAA Controls (USA)', 'Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls (USA)', 'Software and Configuration Checks/Industry and Regulatory Standards/NIST CSF Controls (USA)', 'Software and Configuration Checks/Industry and Regulatory Standards/IRAP Controls (Australia)', 'Software and Configuration Checks/Industry and Regulatory Standards/K-ISMS Controls (Korea)', 'Software and Configuration Checks/Industry and Regulatory Standards/MTCS Controls (Singapore)', 'Software and Configuration Checks/Industry and Regulatory Standards/FISC Controls (Japan)', 'Software and Configuration Checks/Industry and Regulatory Standards/My Number Act Controls (Japan)', 'Software and Configuration Checks/Industry and Regulatory Standards/ENS Controls (Spain)', 'Software and Configuration Checks/Industry and Regulatory Standards/Cyber Essentials Plus Controls (UK)', 'Software and Configuration Checks/Industry and Regulatory Standards/G-Cloud Controls (UK)', 'Software and Configuration Checks/Industry and Regulatory Standards/C5 Controls (Germany)', 'Software and Configuration Checks/Industry and Regulatory Standards/IT-Grundschutz Controls (Germany)', 'Software and Configuration Checks/Industry and Regulatory Standards/GDPR Controls (Europe)', 'Software and Configuration Checks/Industry and Regulatory Standards/TISAX Controls (Europe)', 'TTPs/Initial Access', 'TTPs/Execution', 'TTPs/Persistence', 'TTPs/Privilege Escalation', 'TTPs/Defense Evasion', 'TTPs/Credential Access', 'TTPs/Discovery', 'TTPs/Lateral Movement', 'TTPs/Collection', 'TTPs/Command and Control', 'Effects/Data Exposure', 'Effects/Data Exfiltration', 'Effects/Data Destruction', 'Effects/Denial of Service', 'Effects/Resource Consumption'], 'type': 'string'}, 'type': 'array'}}, 'required': ['types', 'type'], 'type': 'object'}
schema_alias = True
c7n.actions.securityhub.build_vocabulary()[source]

Module contents