Custodian demo 1 & 2
2023年08月14日
name是自定义的。执行
% custodian -h
Create an EC2 instance, and tag it with the key
InstanceType: t4g.micro
SecurityGroupIds: sg-02****f2
For the Sandbox environment, refer to OneNote page.
% aws configure set region eu-central-1
% custodian run --output-dir=. custodian.yml
其中,参数flag "-s"等效于"--output-dir",用来指定OUTPUT_DIR,即directory or S3 URL for policy output。
Stop all EC2 instances that are tagged with
% custodian run --output-dir=. custodian.yml
You should find the instance stopping or stopped in your AWS console.
You should also find a new
% tree my-first-policy
% cat my-first-policy/custodian-run.log
Create an IAM role CloudCustodian-QuickStart with below inline policy.
Create another file ec2_volume_unencrypted.yaml.
这里的condition要和aws profile对应上。
profile里的region设置为us-west-1。
Get you the current region at that point in your script.
% aws configure get region
Validate the configuration (note this happens by default on run)
% custodian validate ec2_volume_unencrypted.yaml
Dryrun on the policies (no actions executed) to see what resources match each policy.
% custodian run --dryrun -s out ec2_volume_unencrypted.yaml
Run the policy
% custodian run -s out ec2_volume_unencrypted.yaml
增加actions。请谨慎操作!
% custodian validate ec2_volume_unencrypted.yaml
% custodian run --dryrun -s out ec2_volume_unencrypted.yaml
Now I create an EC2 instance with EBS volume unencrypted.
It will be terminated immediately.
Check the CloudWatch logs generated by the Lambda function.
[Cleanup]
Delete Lambda function "custodian-ec2-require-non-public-and-encrypted-volumes".
Delete IAM role "CloudCustodian-QuickStart".
Delete Log group "/aws/lambda/custodian-ec2-require-non-public-and-encrypted-volumes".
# vim s3_access_log.yml
# custodian run --output-dir=. s3_access_log.yml
There will be a new
# tree check-bucket-logging/
# cat check-bucket-logging/custodian-run.log
# cat check-bucket-logging/resources.json
列出了所有没有启用S3 server access logging的S3 buckets。
-
References
Getting Started
% source custodian/bin/activate
% touch custodian.yml
File content:
policies: - name: my-first-policy resource: aws.ec2 filters: - "tag:Custodian": present说明:
name是自定义的。执行
custodian run
命令后,在参数"--output-dir
"所指定的路径下会创建一个同名的文件夹。Special Values
These meta-values can be used to test whether or not a resource contains a specific value, and if the value is empty.present
: matches when a key does exist% custodian -h
usage: custodian [-h] {run,schema,report,logs,metrics,version,validate} ... Cloud Custodian - Cloud fleet management optional arguments: -h, --help show this help message and exit commands: {run,schema,report,logs,metrics,version,validate} run Execute the policies in a config file schema Interactive cli docs for policy authors report Tabular report on policy matched resources version Display installed version of custodian validate Validate config files against the json schema
Create an EC2 instance, and tag it with the key
Custodian
with any value.AWSTemplateFormatVersion: '2010-09-09' Description: An EC2 instance with tag key Custodian Parameters: ImageId: Type: AWS::EC2::Image::Id Description: The AMI ID for the EC2 instance InstanceType: Type: String Description: The instance type for the EC2 instance SecurityGroupIds: Type: List<AWS::EC2::SecurityGroup::Id> Description: The security group IDs for the EC2 instance SubnetId: Type: AWS::EC2::Subnet::Id Description: The subnet ID for the EC2 instance Resources: EC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType SubnetId: !Ref SubnetId SecurityGroupIds: !Ref SecurityGroupIds Tags: - Key: Custodian Value: blablabla # You can change the value as needed Outputs: InstanceId: Description: The instance ID Value: !Ref EC2InstanceImageId: ami-0e****14
InstanceType: t4g.micro
SecurityGroupIds: sg-02****f2
For the Sandbox environment, refer to OneNote page.
% aws configure set region eu-central-1
% custodian run --output-dir=. custodian.yml
2023-08-14 16:16:06,821: custodian.policy:INFO policy:my-first-policy resource:aws.ec2 region:us-west-2 count:0 time:6.03PS:
其中,参数flag "-s"等效于"--output-dir",用来指定OUTPUT_DIR,即directory or S3 URL for policy output。
Stop all EC2 instances that are tagged with
Custodian
.policies: - name: my-first-policy resource: aws.ec2 filters: - "tag:Custodian": present actions: - stop
% custodian run --output-dir=. custodian.yml
2023-08-14 16:31:36,590: custodian.policy:INFO policy:my-first-policy resource:aws.ec2 region:us-west-2 count:1 time:7.43 2023-08-14 16:31:39,055: custodian.policy:INFO policy:my-first-policy action:stop resources:1 execution_time:2.46
You should find the instance stopping or stopped in your AWS console.
You should also find a new
my-first-policy
directory with a log and other files (subsequent runs will append to the log by default rather than overwriting it).% tree my-first-policy
my-first-policy ├── action-stop ├── custodian-run.log ├── metadata.json └── resources.json 0 directories, 4 filesPS: 如果系统找不到这个命令,执行
yum install tree
命令安装。-bash: tree: command not found
% cat my-first-policy/custodian-run.log
2023-08-14 16:16:06,821 - custodian.policy - INFO - policy:my-first-policy resource:aws.ec2 region:us-west-2 count:0 time:6.03 2023-08-14 16:31:36,590 - custodian.policy - INFO - policy:my-first-policy resource:aws.ec2 region:us-west-2 count:1 time:7.43 2023-08-14 16:31:39,055 - custodian.policy - INFO - policy:my-first-policy action:stop resources:1 execution_time:2.46
Create an IAM role CloudCustodian-QuickStart with below inline policy.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowCustodianToActOnEc2Instances", "Action": [ "ec2:CreateTags", "ec2:DeleteTags", "ec2:DescribeInstances", "ec2:TerminateInstances", "ec2:DescribeVolumes" ], "Effect": "Allow", "Resource": "*" }, { "Sid": "AllowCustodianToLogLambdaActions", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", "Resource": "*" } ] }This role need to be assumed by Lambda, so I use below trust relationship.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Create another file ec2_volume_unencrypted.yaml.
policies: - name: ec2-require-non-public-and-encrypted-volumes resource: aws.ec2 conditions: - region: us-west-1 description: | Provision a Lambda and CloudWatch event target that looks at all NEW EC2 instances and terminates those with unencrypted volumes. mode: type: cloudtrail role: CloudCustodian-QuickStart events: - RunInstances filters: - type: ebs key: Encrypted value: false
这里的condition要和aws profile对应上。
... conditions: - region: us-west-1 ...
profile里的region设置为us-west-1。
Get you the current region at that point in your script.
% aws configure get region
us-west-1
Validate the configuration (note this happens by default on run)
% custodian validate ec2_volume_unencrypted.yaml
2023-08-15 06:18:06,003: custodian.commands:INFO Configuration valid: ec2_volume_unencrypted.yaml
Dryrun on the policies (no actions executed) to see what resources match each policy.
% custodian run --dryrun -s out ec2_volume_unencrypted.yaml
2023-08-15 06:30:23,482: custodian.policy:INFO policy:ec2-require-non-public-and-encrypted-volumes resource:aws.ec2 region:us-west-1 count:1 time:0.85
Run the policy
% custodian run -s out ec2_volume_unencrypted.yaml
2023-08-15 06:27:50,286: custodian.policy:INFO Provisioning policy lambda: ec2-require-non-public-and-encrypted-volumes region: us-west-1 2023-08-15 06:27:51,104: custodian.serverless:INFO Publishing custodian policy lambda function custodian-ec2-require-non-public-and-encrypted-volumes
增加actions。请谨慎操作!
policies: - name: ec2-require-non-public-and-encrypted-volumes resource: aws.ec2 conditions: - region: us-west-1 description: | Provision a Lambda and CloudWatch event target that looks at all new instances and terminates those with unencrypted volumes. mode: type: cloudtrail role: CloudCustodian-QuickStart events: - RunInstances filters: - type: ebs key: Encrypted value: false actions: - terminate
% custodian validate ec2_volume_unencrypted.yaml
2023-08-15 06:33:47,039: custodian.commands:INFO Configuration valid: ec2_volume_unencrypted.yaml
% custodian run --dryrun -s out ec2_volume_unencrypted.yaml
2023-08-15 06:34:21,126: custodian.policy:INFO policy:ec2-require-non-public-and-encrypted-volumes resource:aws.ec2 region:us-west-1 count:1 time:1.29
Now I create an EC2 instance with EBS volume unencrypted.
It will be terminated immediately.
Check the CloudWatch logs generated by the Lambda function.
[Cleanup]
Delete Lambda function "custodian-ec2-require-non-public-and-encrypted-volumes".
Delete IAM role "CloudCustodian-QuickStart".
Delete Log group "/aws/lambda/custodian-ec2-require-non-public-and-encrypted-volumes".
# vim s3_access_log.yml
policies: - name: check-bucket-logging resource: s3 filters: - type: bucket-logging op: disabled这个policy的目的是列出所有没有启用S3 server access logging的S3 buckets。
# custodian run --output-dir=. s3_access_log.yml
2024-04-15 05:37:15,675: custodian.policy:INFO policy:check-bucket-logging resource:s3 region:eu-central-1 count:5 time:2.52
There will be a new
check-bucket-logging
directory with a log and other files (subsequent runs will append to the log by default rather than overwriting it).# tree check-bucket-logging/
check-bucket-logging/ ├── custodian-run.log ├── metadata.json └── resources.json 0 directories, 3 files
# cat check-bucket-logging/custodian-run.log
2024-04-15 05:37:15,675 - custodian.policy - INFO - policy:check-bucket-logging resource:s3 region:eu-central-1 count:5 time:2.52
# cat check-bucket-logging/resources.json
[ { "Name": "aws-cloudtrail-logs-211125714651-ea036076", "CreationDate": "2024-03-04T06:24:30+00:00", "Location": { "LocationConstraint": "eu-west-1" }, "Tags": [], "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"AWSCloudTrailAclCheck20150319\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"cloudtrail.amazonaws.com\"},\"Action\":\"s3:GetBucketAcl\",\"Resource\":\"arn:aws:s3:::aws-cloudtrail-logs-211125714651-ea036076\",\"Condition\":{\"StringEquals\":{\"aws:SourceArn\":\"arn:aws:cloudtrail:eu-west-1:211125714651:trail/verify-cost-mgmt-scp\"}}},{\"Sid\":\"AWSCloudTrailWrite20150319\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"cloudtrail.amazonaws.com\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::aws-cloudtrail-logs-211125714651-ea036076/AWSLogs/211125714651/*\",\"Condition\":{\"StringEquals\":{\"aws:SourceArn\":\"arn:aws:cloudtrail:eu-west-1:211125714651:trail/verify-cost-mgmt-scp\",\"s3:x-amz-acl\":\"bucket-owner-full-control\"}}}]}", "Acl": { "Owner": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53" }, "Grants": [ { "Grantee": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53", "Type": "CanonicalUser" }, "Permission": "FULL_CONTROL" } ] }, "Replication": null, "Versioning": {}, "Website": null, "Logging": {}, "Notification": {}, "Lifecycle": null }, { "Name": "cf-templates-ror5mangohw4-eu-central-1", "CreationDate": "2024-04-15T01:10:44+00:00", "Location": { "LocationConstraint": "eu-central-1" }, "Tags": [], "Policy": null, "Acl": { "Owner": { "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53" }, "Grants": [ { "Grantee": { "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53", "Type": "CanonicalUser" }, "Permission": "FULL_CONTROL" } ] }, "Replication": null, "Versioning": {}, "Website": null, "Logging": {}, "Notification": {}, "Lifecycle": null }, { "Name": "cf-templates-ror5mangohw4-eu-west-1", "CreationDate": "2024-03-05T03:29:16+00:00", "Location": { "LocationConstraint": "eu-west-1" }, "Tags": [], "Policy": null, "Acl": { "Owner": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53" }, "Grants": [ { "Grantee": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53", "Type": "CanonicalUser" }, "Permission": "FULL_CONTROL" } ] }, "Replication": null, "Versioning": {}, "Website": null, "Logging": {}, "Notification": {}, "Lifecycle": null }, { "Name": "cov-macie-repo-result", "CreationDate": "2024-04-07T07:49:58+00:00", "Location": { "LocationConstraint": "eu-central-1" }, "Tags": [], "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Deny non-HTTPS access\",\"Effect\":\"Deny\",\"Principal\":\"*\",\"Action\":\"s3:*\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result/*\",\"Condition\":{\"Bool\":{\"aws:SecureTransport\":\"false\"}}},{\"Sid\":\"Deny incorrect encryption header. This is optional\",\"Effect\":\"Deny\",\"Principal\":{\"Service\":\"macie.amazonaws.com\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result/*\",\"Condition\":{\"StringNotEquals\":{\"s3:x-amz-server-side-encryption-aws-kms-key-id\":\"arn:aws:kms:eu-central-1:211125714651:key/e1254929-b5dd-4bf1-b04d-589ceeee682f\"}}},{\"Sid\":\"Deny unencrypted object uploads. This is optional\",\"Effect\":\"Deny\",\"Principal\":{\"Service\":\"macie.amazonaws.com\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result/*\",\"Condition\":{\"StringNotEquals\":{\"s3:x-amz-server-side-encryption\":\"aws:kms\"}}},{\"Sid\":\"Allow Macie to upload objects to the bucket\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"macie.amazonaws.com\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result/*\",\"Condition\":{\"StringEquals\":{\"aws:SourceAccount\":\"211125714651\"},\"ArnLike\":{\"aws:SourceArn\":[\"arn:aws:macie2:eu-central-1:211125714651:export-configuration:*\",\"arn:aws:macie2:eu-central-1:211125714651:classification-job/*\"]}}},{\"Sid\":\"Allow Macie to use the getBucketLocation operation\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"macie.amazonaws.com\"},\"Action\":\"s3:GetBucketLocation\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result\",\"Condition\":{\"StringEquals\":{\"aws:SourceAccount\":\"211125714651\"},\"ArnLike\":{\"aws:SourceArn\":[\"arn:aws:macie2:eu-central-1:211125714651:export-configuration:*\",\"arn:aws:macie2:eu-central-1:211125714651:classification-job/*\"]}}},{\"Sid\":\"S3PolicyStmt-DO-NOT-MODIFY-1713148053100\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"logging.s3.amazonaws.com\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::cov-macie-repo-result/*\",\"Condition\":{\"StringEquals\":{\"aws:SourceAccount\":\"211125714651\"}}}]}", "Acl": { "Owner": { "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53" }, "Grants": [ { "Grantee": { "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53", "Type": "CanonicalUser" }, "Permission": "FULL_CONTROL" } ] }, "Replication": null, "Versioning": {}, "Website": null, "Logging": {}, "Notification": {}, "Lifecycle": null }, { "Name": "cov-test-drift-s3-lify-cycle-rule", "CreationDate": "2024-03-05T05:58:29+00:00", "Location": { "LocationConstraint": "eu-west-1" }, "Tags": [ { "Key": "aws:cloudformation:stack-id", "Value": "arn:aws:cloudformation:eu-west-1:211125714651:stack/drift-test/c1102f70-daa0-11ee-8946-06d3e2093329" }, { "Key": "aws:cloudformation:stack-name", "Value": "drift-test" }, { "Key": "aws:cloudformation:logical-id", "Value": "S3Bucket" } ], "Policy": null, "Acl": { "Owner": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53" }, "Grants": [ { "Grantee": { "DisplayName": "aws-root-a3789554-7da4-4abe-845d-a970de89e836", "ID": "45d782d7c7923fa7ef543e326633560394568227282ca9a10a8abe20a2762a53", "Type": "CanonicalUser" }, "Permission": "FULL_CONTROL" } ] }, "Replication": null, "Versioning": {}, "Website": null, "Logging": {}, "Notification": {}, "Lifecycle": { "Rules": [ { "Expiration": { "Days": 365 }, "ID": "ExampleRule", "Filter": { "Prefix": "" }, "Status": "Enabled", "Transitions": [ { "Days": 90, "StorageClass": "STANDARD_IA" } ] }, { "Expiration": { "Days": 365 }, "ID": "Rule3IaC", "Filter": { "Prefix": "" }, "Status": "Enabled", "Transitions": [ { "Days": 30, "StorageClass": "STANDARD_IA" } ] } ] } } ]里面包含5个元素。
列出了所有没有启用S3 server access logging的S3 buckets。
-
policies: - name: check-bucket-logging resource: s3 filters: - type: bucket-logging op: disabled - type: value key: tag:cov:access-logging value: not-required op: ne - type: value key: cov:exception:C21.0004 op: not-in value_regex: '^(RITM.*)$' value_from: url: "s3://{{ exception_bucket }}/whitelist-C21.0004.json" format: "json" expr: "[?account=='{account_id}'].reference"
-
-
policies: - name: check-bucket-logging resource: s3 filters: - type: bucket-logging op: disabled - type: value key: tag:cov:access-logging value: not-required op: ne
-
-
policies: - name: check-bucket-logging resource: s3 filters: - type: bucket-logging op: disabled - type: value key: tag:cov:access-logging value: not-required op: ne - type: value key: cov:exception:C21.0004 op: not-in value_regex: '^(RITM.*)$' value_from: url: "s3://{{ exception_bucket }}/whitelist-C21.0004.json" format: "json" expr: "[?account=='{account_id}'].reference"
-
-
References
Getting Started