├── LICENSE ├── README.md └── policies ├── README.md ├── ami-deregister-old-unused.yml ├── asg-off-hours-enforcement.yml ├── asg-off-hours.yml ├── aws-cis-benchmarks.yml ├── aws-service-limit-increase.yml ├── ebs-volume-delete-unattached.yml ├── ebs-volume-delete-unencrypted-on-creation.yml ├── ebs-volume-missing-recent-snapshot.yml ├── ebs-volume-notify-if-unencrypted.yml ├── ebs-volume-tag-enforcement.yml ├── ec2-off-hours-enforcement.yml ├── ec2-off-hours.yml ├── ec2-tag-enforcement.yml ├── iam-basic-deny.yml ├── log-group-missing-retention-days.yml ├── rds-off-hours-enforcement.yml ├── rds-off-hours.yml ├── rds-tag-enforcement.yml ├── rds-terminate-publicly-available-on-creation.yml ├── s3-delete-unencrypted-on-creation.yml ├── s3-global-grants.yml ├── s3-tag-enforcement.yml ├── security-group-default-deny.yml └── security-group-restrict-admin-ingress.yml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Code42 Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Purpose 2 | 3 | This repo is meant to house some example Cloud Custodian policies that are in use by Code42 as of this writing. While we hope these examples drive value for you and your organization, it is important to note that these policies may need to be tuned to your specifc environments needs. We are not currently accepting PRs at this time but wanted to share with the community. 4 | 5 | ## USE 6 | 7 | It is important to understand how the Cloud Custodian works, please refer to the documentation in the support resources section, specifically the `getting started` guide and the `code42 custodian blog post` may be the most helpful if this is new material. 8 | 9 | Once you're ready for policies, you may clone this repo and begin working with the contents! Note, these policies will need to be tuned to your specific needs, they are not applicable or tuned for all enviroments. 10 | 11 | Some specific callouts to make it easier to work with these files: 12 | 13 | ### Variables 14 | 15 | There are several variables that are capitalized throughout, some include `MESSAGEQUEUENAME, BUCKETNAME, and REQUIREDTAGS` These should be substituted and variablized to your environment needs. 16 | 17 | ### Custodian Logging/Metrics 18 | 19 | `execution-options:output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/` 20 | This specific option is used to send the cusotdian run log and resources log to an s3 bucket. The data in the s3 bucket may be ingested by SIEM or other tools for customized metrics and data visualization. 21 | 22 | Note, there are other ways to ingest these files that can be found in the `custodian reporting features` link below 23 | 24 | ### Slack integration 25 | `to: ["slack"]` 26 | Here you can see the configuration in how we use SQS to send to directly to SLACK. This actually sends the content of the "resources.json.gz" file directly into a slack channel. This option requires you to create a message queue that is used by the Custodian to send to slack. We speak more about the logs/metrics file contents in our blog post below. 27 | 28 | ## Support Resources 29 | 30 | * [official cloud custodian repo](https://github.com/cloud-custodian/cloud-custodian) 31 | * [official cloud custodian docs](https://www.capitalone.io/docs/index.html) 32 | * [cloud custodian getting started](https://www.capitalone.io/docs/quickstart/index.html) 33 | * [custodian reporting features](https://www.capitalone.io/docs/quickstart/usage.html) 34 | * [official code42 github](https://github.com/code42) 35 | * [code42 custodian blog post](https://tbd.com) -------------------------------------------------------------------------------- /policies/README.md: -------------------------------------------------------------------------------- 1 | # Purpose 2 | 3 | This repo is meant to house some example Cloud Custodian policies that are in use by Code42 as of this writing. While we hope these examples drive value for you and your organization, it is important to note that these policies may need to be tuned to your specifc environments needs. We are not currently accepting PRs at this time but wanted to share with the community. 4 | 5 | ## USE 6 | 7 | It is important to understand how the Cloud Custodian works, please refer to the documentation in the support resources section, specifically the `getting started` guide and the `code42 custodian blog post` may be the most helpful if this is new material. 8 | 9 | Once you're ready for policies, you may clone this repo and begin working with the contents! Note, these policies will need to be tuned to your specific needs, they are not applicable or tuned for all enviroments. 10 | 11 | Some specific callouts to make it easier to work with these files: 12 | 13 | ### Variables 14 | 15 | There are several variables that are capitalized throughout, some include `MESSAGEQUEUENAME, BUCKETNAME, and REQUIREDTAGS` These should be substituted and variablized to your environment needs. 16 | 17 | ### Custodian Logging/Metrics 18 | 19 | `execution-options:output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/` 20 | This specific option is used to send the cusotdian run log and resources log to an s3 bucket. The data in the s3 bucket may be ingested by SIEM or other tools for customized metrics and data visualization. 21 | 22 | Note, there are other ways to ingest these files that can be found in the `custodian reporting features` link below 23 | 24 | ### Slack integration 25 | `to: ["slack"]` 26 | Here you can see the configuration in how we use SQS to send to directly to SLACK. This actually sends the content of the "resources.json.gz" file directly into a slack channel. This option requires you to create a message queue that is used by the Custodian to send to slack. We speak more about the logs/metrics file contents in our blog post below. 27 | 28 | ## Support Resources 29 | 30 | * [official cloud custodian repo](https://github.com/cloud-custodian/cloud-custodian) 31 | * [official cloud custodian docs](https://www.capitalone.io/docs/index.html) 32 | * [cloud custodian getting started](https://www.capitalone.io/docs/quickstart/index.html) 33 | * [custodian reporting features](https://www.capitalone.io/docs/quickstart/usage.html) 34 | * [official code42 github](https://github.com/code42) 35 | * [code42 custodian blog post](https://tbd.com) -------------------------------------------------------------------------------- /policies/ami-deregister-old-unused.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ami-deregister-old-unused-mark 4 | comment: | 5 | Mark AMIs that are unused and 30+ days old for deregistration in 5 days and 6 | send a notification. 7 | resource: ami 8 | filters: 9 | - "tag:c7n_ami_deregister_old_unused": absent 10 | - "tag:c7n_ami_deregister_old_unused_exempt": absent 11 | - type: unused 12 | value: true 13 | - type: image-age 14 | days: 30 15 | mode: 16 | schedule: "rate(60 minutes)" 17 | type: periodic 18 | execution-options: 19 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 20 | actions: 21 | - type: mark-for-op 22 | days: 5 23 | op: deregister 24 | tag: c7n_ami_deregister_old_unused 25 | - type: notify 26 | action_desc: | 27 | Custodian has marked the AMIs for automatic deregistration in 5 days. 28 | Please review AMI usage. 29 | subject: "AMI Deregistration" 30 | to: ["slack"] 31 | transport: 32 | type: sqs 33 | queue: MESSAGEQUEUENAME 34 | violation_desc: "Custodian detected unused AMI(s) that are 30+ days old." 35 | 36 | - name: ami-deregister-old-unused-unmark 37 | comment: | 38 | Unmark any AMI that was previosly marked but is now in use or exempt. 39 | resource: ami 40 | filters: 41 | - "tag:c7n_ami_deregister_old_unused": present 42 | - or: 43 | - "tag:c7n_ami_deregister_old_unused_exempt": present 44 | - type: unused 45 | value: false 46 | mode: 47 | schedule: "rate(30 minutes)" 48 | type: periodic 49 | execution-options: 50 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 51 | actions: 52 | - type: unmark 53 | tags: [c7n_ami_deregister_old_unused] 54 | - type: notify 55 | action_desc: | 56 | No action required. Custodian unmarked the AMIs to 57 | prevent deregistration. 58 | cc: ["good"] 59 | subject: "AMI Deregistration" 60 | to: ["slack"] 61 | transport: 62 | type: sqs 63 | queue: MESSAGEQUEUENAME 64 | violation_desc: | 65 | AMIs previously marked for deregistration are now in use. 66 | 67 | - name: ami-deregister-old-unused 68 | comment: | 69 | Deregister marked AMIs after verifying they remain unused and not exempt. 70 | resource: ami 71 | filters: 72 | - "tag:c7n_ami_deregister_old_unused": present 73 | - "tag:c7n_ami_deregister_old_unused_exempt": absent 74 | - type: unused 75 | value: true 76 | - type: marked-for-op 77 | op: deregister 78 | tag: c7n_ami_deregister_old_unused 79 | mode: 80 | schedule: "rate(6 hours)" 81 | type: periodic 82 | execution-options: 83 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 84 | actions: 85 | - deregister 86 | - type: notify 87 | action_desc: | 88 | No action required. Custodian completed the AMI deregistration. 89 | cc: ["#000000"] 90 | subject: "AMI Deregistration" 91 | to: ["slack"] 92 | transport: 93 | type: sqs 94 | queue: MESSAGEQUEUENAME 95 | violation_desc: | 96 | Old, unused AMIs have been deregistered. 97 | -------------------------------------------------------------------------------- /policies/asg-off-hours-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: asg-off-hours-enforcement 4 | resource: asg 5 | comments: | 6 | Opt in autoscaling groups without a c7n_off_hours tag 7 | filters: 8 | - "tag:c7n_off_hours": absent 9 | mode: 10 | schedule: "rate(24 hours)" 11 | type: periodic 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | actions: 15 | - type: tag 16 | key: c7n_off_hours 17 | value: "on" 18 | -------------------------------------------------------------------------------- /policies/asg-off-hours.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: asg-off-hours-stop 4 | resource: asg 5 | comments: | 6 | Suspend autoscaling groups as per schedule in c7n_off_hours 7 | filters: 8 | - "tag:c7n_do_not_shut_down": absent 9 | - type: offhour 10 | default_tz: gmt 11 | offhour: 1 12 | tag: c7n_off_hours 13 | mode: 14 | schedule: "rate(60 minutes)" 15 | type: periodic 16 | execution-options: 17 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 18 | actions: 19 | - suspend 20 | 21 | - name: asg-off-hours-start 22 | resource: asg 23 | comments: | 24 | Resume autoscaling groups as per schedule in c7n_off_hours 25 | filters: 26 | - "tag:c7n_do_not_shut_down": absent 27 | - type: onhour 28 | default_tz: gmt 29 | onhour: 11 30 | tag: c7n_off_hours 31 | mode: 32 | schedule: "rate(60 minutes)" 33 | type: periodic 34 | actions: 35 | - resume 36 | -------------------------------------------------------------------------------- /policies/aws-cis-benchmarks.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | # 1.1 Avoid the use of the "root" account 4 | # Level 1 5 | # Satified via 3.3 6 | 7 | # 1.2: Ensure multi-factor authentication (MFA) is enabled for all IAM users 8 | # that have a console password 9 | # Level 1 10 | - name: cis-iam-user-needs-mfa 11 | resource: iam-user 12 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.2)" 13 | region: us-east-1 14 | filters: 15 | - type: credential 16 | key: password_enabled 17 | value: true 18 | - type: credential 19 | key: mfa_active 20 | value: false 21 | mode: 22 | schedule: "rate(24 hours)" 23 | type: periodic 24 | execution-options: 25 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 26 | actions: 27 | - type: notify 28 | action_desc: "Enable MFA or remove users password." 29 | to: ["slack"] 30 | transport: 31 | type: sqs 32 | queue: MESSAGEQUEUENAME 33 | violation_desc: | 34 | Password enabled IAM user does not have MFA. 35 | CIS Amazon Web Services Foundations v1.1.0 (1.2) 36 | 37 | # 1.3 Ensure credentials unused for 90 days or greater are disabled 38 | # Level 1 39 | - name: cis-iam-stale-credentials 40 | resource: iam-user 41 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.3)" 42 | region: us-east-1 43 | filters: 44 | - or: 45 | - and: 46 | - type: credential 47 | key: password_enabled 48 | value: true 49 | - type: credential 50 | key: password_last_used 51 | value_type: age 52 | value: 90 53 | op: gt 54 | - and: 55 | - type: credential 56 | key: access_keys.active 57 | value: true 58 | - type: credential 59 | key: access_keys.last_used_date 60 | value_type: age 61 | value: 90 62 | op: gt 63 | mode: 64 | schedule: "rate(24 hours)" 65 | type: periodic 66 | execution-options: 67 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 68 | actions: 69 | - type: notify 70 | action_desc: "Disable stale credentials." 71 | to: ["slack"] 72 | transport: 73 | type: sqs 74 | queue: MESSAGEQUEUENAME 75 | violation_desc: | 76 | IAM user password and/or access keys are older than 90 days. 77 | CIS Amazon Web Services Foundations v1.1.0 (1.3) 78 | 79 | # 1.4 Ensure access keys are rotated every 90 days or less 80 | # Level 1 81 | - name: cis-iam-user-key-rotation 82 | resource: iam-user 83 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.4)" 84 | region: us-east-1 85 | filters: 86 | - type: credential 87 | key: access_keys.active 88 | value: true 89 | - type: credential 90 | key: access_keys.last_rotated 91 | value_type: age 92 | value: 90 93 | op: gt 94 | mode: 95 | schedule: "rate(24 hours)" 96 | type: periodic 97 | execution-options: 98 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 99 | actions: 100 | - type: notify 101 | action_desc: "Rotate users access keys." 102 | to: ["slack"] 103 | transport: 104 | type: sqs 105 | queue: MESSAGEQUEUENAME 106 | violation_desc: | 107 | IAM user has access keys older than 90 days. 108 | CIS Amazon Web Services Foundations v1.1.0 (1.4) 109 | 110 | # 1.5 Ensure IAM password policy requires at least one uppercase letter 111 | # 1.6 Ensure IAM password policy require at least one lowercase letter 112 | # 1.7 Ensure IAM password policy require at least one symbol 113 | # 1.8 Ensure IAM password policy require at least one number 114 | # 1.9 Ensure IAM password policy requires minimum length of 14 or greater 115 | # 1.10 Ensure IAM password policy prevents password reuse 116 | # 1.11 Ensure IAM password policy expires passwords within 90 days or less 117 | # Level 1 118 | - name: cis-password-policy 119 | resource: account 120 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.5 through 1.11)" 121 | region: us-east-1 122 | filters: 123 | - or: 124 | - type: password-policy 125 | key: RequireLowercaseCharacters 126 | value: false 127 | - type: password-policy 128 | key: RequireUppercaseCharacters 129 | value: false 130 | - type: password-policy 131 | key: RequireSymbols 132 | value: false 133 | - type: password-policy 134 | key: RequireNumbers 135 | value: false 136 | - type: password-policy 137 | key: MinimumPasswordLength 138 | value: 14 139 | op: lt 140 | - type: password-policy 141 | key: PasswordReusePrevention 142 | value: 24 143 | op: lt 144 | - type: password-policy 145 | key: MaxPasswordAge 146 | value: 90 147 | op: gt 148 | mode: 149 | schedule: "rate(24 hours)" 150 | type: periodic 151 | execution-options: 152 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 153 | actions: 154 | - type: notify 155 | action_desc: | 156 | Modify account password policy to meet, or exceed, CIS benchmarks. 157 | to: ["slack"] 158 | transport: 159 | type: sqs 160 | queue: MESSAGEQUEUENAME 161 | violation_desc: | 162 | Account password policy does not meet CIS benchmarks. 163 | CIS Amazon Web Services Foundations v1.1.0 (1.5 through 1.11) 164 | 165 | # 1.12 Ensure no root account access key exists 166 | # Level 1 167 | - name: cis-no-root-access-keys 168 | resource: account 169 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.12)" 170 | region: us-east-1 171 | filters: 172 | - type: credential 173 | key: access_keys.active 174 | value: true 175 | mode: 176 | schedule: "rate(24 hours)" 177 | type: periodic 178 | execution-options: 179 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 180 | actions: 181 | - type: notify 182 | action_desc: "Remove access keys from the root user." 183 | to: ["slack"] 184 | transport: 185 | type: sqs 186 | queue: MESSAGEQUEUENAME 187 | violation_desc: | 188 | Root user must not have access keys. 189 | CIS Amazon Web Services Foundations v1.1.0 (1.12) 190 | 191 | # 1.13 Ensure MFA is enabled for the "root" account 192 | # Level 1 193 | - name: cis-root-must-use-mfa 194 | resource: account 195 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.13)" 196 | region: us-east-1 197 | filters: 198 | - type: credential 199 | key: mfa_active 200 | value: false 201 | mode: 202 | schedule: "rate(24 hours)" 203 | type: periodic 204 | execution-options: 205 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 206 | actions: 207 | - type: notify 208 | action_desc: "Enable MFA for the account root user." 209 | to: ["slack"] 210 | transport: 211 | type: sqs 212 | queue: MESSAGEQUEUENAME 213 | violation_desc: | 214 | Account root user does not have MFA enabled. 215 | CIS Amazon Web Services Foundations v1.1.0 (1.13) 216 | 217 | # 1.14 Ensure hardware MFA is enabled for the "root" account 218 | # Level 2 219 | # Not implemented 220 | 221 | # 1.15 Ensure security questions are registered in the AWS account 222 | # Level 1 - Not Scored 223 | # Not implemented 224 | 225 | # 1.16 Ensure IAM policies are attached only to groups or roles 226 | # Level 1 227 | - name: cis-iam-users-with-policies 228 | resource: iam-user 229 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.16)" 230 | region: us-east-1 231 | filters: 232 | - type: policy 233 | key: 'PolicyName' 234 | value: present 235 | mode: 236 | schedule: "rate(24 hours)" 237 | type: periodic 238 | execution-options: 239 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 240 | actions: 241 | - type: notify 242 | action_desc: | 243 | Detach the policy from the IAM user. Attach the policy to a group or 244 | role that is associated with the user. 245 | to: ["slack"] 246 | transport: 247 | type: sqs 248 | queue: MESSAGEQUEUENAME 249 | violation_desc: | 250 | IAM user has policies directly attached. 251 | CIS Amazon Web Services Foundations v1.1.0 (1.16) 252 | 253 | # 1.17 Enable detailed billing 254 | # Level 1 255 | # Not implemented 256 | 257 | # 1.18 Ensure IAM Master and IAM Manager roles are active 258 | # Level 1 259 | # Not implemented 260 | 261 | # 1.19 Maintain current contact details 262 | # Level 1 263 | # Not implemented 264 | 265 | # 1.20 Ensure security contact information is registered 266 | # Level 1 267 | # Not implemented 268 | 269 | # 1.21 Ensure IAM instance roles are used for AWS resource access from 270 | # instances 271 | # Level 2 - Not Scored 272 | - name: cis-ec2-iam-instance-role-is-present 273 | resource: ec2 274 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.21)" 275 | filters: 276 | - type: value 277 | key: IamInstanceProfile 278 | value: absent 279 | mode: 280 | schedule: "rate(24 hours)" 281 | type: periodic 282 | execution-options: 283 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 284 | actions: 285 | - type: notify 286 | action_desc: | 287 | Assure instance role is used for AWS resource access. 288 | to: ["slack"] 289 | transport: 290 | type: sqs 291 | queue: MESSAGEQUEUENAME 292 | violation_desc: | 293 | IAM instance role is absent. 294 | CIS Amazon Web Services Foundations v1.1.0 (1.21) 295 | 296 | # 1.22 Ensure a support role has been created to manage incidents with AWS 297 | # support 298 | # Level 1 299 | - name: cis-iam-policy-for-support-is-used 300 | resource: iam-policy 301 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.22)" 302 | region: us-east-1 303 | filters: 304 | - type: unused 305 | - type: value 306 | key: 'PolicyName' 307 | value: AWSSupportAccess 308 | mode: 309 | schedule: "rate(24 hours)" 310 | type: periodic 311 | execution-options: 312 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 313 | actions: 314 | - type: notify 315 | action_desc: | 316 | Attach the AWSSupportAccess policy to a support group or role to 317 | manage incidents with AWS support. 318 | to: ["slack"] 319 | transport: 320 | type: sqs 321 | queue: MESSAGEQUEUENAME 322 | violation_desc: | 323 | IAM policy AWSSupportAccess is not used. 324 | CIS Amazon Web Services Foundations v1.1.0 (1.22) 325 | 326 | # 1.23 Do not setup access keys during initial user setup for all IAM users 327 | # that have a console password 328 | # Level 1 - Not Scored 329 | - name: cis-iam-user-with-unused-access-keys 330 | resource: iam-user 331 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.23)" 332 | region: us-east-1 333 | filters: 334 | - type: credential 335 | key: password_enabled 336 | value: true 337 | - type: credential 338 | key: access_keys.active 339 | value: true 340 | - type: credential 341 | key: access_keys.last_used_date 342 | value: absent 343 | mode: 344 | schedule: "rate(24 hours)" 345 | type: periodic 346 | execution-options: 347 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 348 | actions: 349 | - type: notify 350 | action_desc: "Remove or deactivate users access keys." 351 | to: ["slack"] 352 | transport: 353 | type: sqs 354 | queue: MESSAGEQUEUENAME 355 | violation_desc: | 356 | IAM user has unused access keys, possibly from initial user setup, 357 | and a console password. 358 | CIS Amazon Web Services Foundations v1.1.0 (1.23) 359 | 360 | # 1.24 Ensure IAM policies that allow full "*:*" administrative privileges 361 | # are not created 362 | # Level 1 363 | - name: cis-iam-no-used-all-all-policy 364 | resource: iam-policy 365 | comment: "CIS Amazon Web Services Foundations v1.1.0 (1.24)" 366 | region: us-east-1 367 | filters: 368 | - type: used 369 | - type: has-allow-all 370 | mode: 371 | schedule: "rate(24 hours)" 372 | type: periodic 373 | execution-options: 374 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 375 | actions: 376 | - type: notify 377 | action_desc: | 378 | Detach the policy or restict the policy to least privileges required. 379 | to: ["slack"] 380 | transport: 381 | type: sqs 382 | queue: MESSAGEQUEUENAME 383 | violation_desc: | 384 | IAM policy allows full '*.*' admistrative privileges. 385 | CIS Amazon Web Services Foundations v1.1.0 (1.24) 386 | 387 | # 2.1 Ensure CloudTrail is enabled in all regions (Level 1) 388 | # 2.2 Ensure CloudTrail log file validation is enabled (Level 2) 389 | # 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Level 1) 390 | # 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Level 2) 391 | - name: cis-cloudtrail-is-secure-and-running 392 | resource: account 393 | comment: "CIS Amazon Web Services Foundations v1.1.0 (2.1,2.2,2.4,2.7)" 394 | filters: 395 | - type: check-cloudtrail 396 | current-region: true 397 | file-digest: true 398 | global-events: true 399 | kms: true 400 | running: true 401 | - type: value 402 | key: CloudWatchLogsLogGroupArn 403 | value: present 404 | mode: 405 | schedule: "rate(24 hours)" 406 | type: periodic 407 | execution-options: 408 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 409 | actions: 410 | - type: notify 411 | action_desc: "Configure CloudTrail to meet CIS benchmarks." 412 | to: ["slack"] 413 | transport: 414 | type: sqs 415 | queue: MESSAGEQUEUENAME 416 | violation_desc: | 417 | CloudTrail is not enabled or properly secured. 418 | CIS Amazon Web Services Foundations v1.1.0 (2.1,2.2,2.4,2.7) 419 | 420 | # 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible 421 | # Level 1 422 | # TBD 423 | 424 | 425 | # 2.5 Ensure AWS Config is enabled in all regions 426 | # Level 1 427 | - name: cis-check-config-is-enabled 428 | resource: account 429 | comment: "CIS Amazon Web Services Foundations v1.1.0 (2.5)" 430 | filters: 431 | - type: check-config 432 | all-resources: true 433 | global-resources: true 434 | running: true 435 | mode: 436 | schedule: "rate(24 hours)" 437 | type: periodic 438 | execution-options: 439 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 440 | actions: 441 | - type: notify 442 | action_desc: "Enable AWS Config Service to meet benchmarks." 443 | to: ["slack"] 444 | transport: 445 | type: sqs 446 | queue: MESSAGEQUEUENAME 447 | violation_desc: | 448 | AWS Config Service must be enabled in all regions. 449 | CIS Amazon Web Services Foundations v1.1.0 (2.5) 450 | 451 | # 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket 452 | # Level 1 453 | # TBD 454 | 455 | 456 | # 2.8 Ensure rotation for customer created CMKs is enabled 457 | # Level 2 458 | - name: cis-kms-key-rotation-is-enabled 459 | resource: kms-key 460 | comment: "CIS Amazon Web Services Foundations v1.1.0 (2.5)" 461 | filters: 462 | - type: key-rotation-status 463 | key: KeyRotationEnabled 464 | value: false 465 | mode: 466 | schedule: "rate(24 hours)" 467 | type: periodic 468 | execution-options: 469 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 470 | actions: 471 | - type: notify 472 | action_desc: "Enable annual key rotation." 473 | to: ["slack"] 474 | transport: 475 | type: sqs 476 | queue: MESSAGEQUEUENAME 477 | violation_desc: | 478 | AWS KMS keys do not have annual key rotation enabled. 479 | CIS Amazon Web Services Foundations v1.1.0 (2.8) 480 | 481 | # 3.1 Ensure a log metric filter and alarm exist for unauthorized API calls 482 | # Level 1 483 | 484 | # 3.2 Ensure a log metric filter and alarm exist for Management Console 485 | # sign-in without MFA 486 | # Level 1 487 | 488 | # 3.3 Ensure a log metric filter and alarm exist for usage of "root" account 489 | # Level 1 490 | #resource: alarm 491 | 492 | # 3.4 Ensure a log metric filter and alarm exist for IAM policy changes 493 | # Level 1 494 | 495 | # 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration 496 | # changes 497 | # Level 1 498 | 499 | # 3.6 Ensure a log metric filter and alarm exist for AWS Management Console 500 | # authentication failures 501 | # Level 2 502 | 503 | # 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled 504 | # deletion of customer created CMKs 505 | # Level 2 506 | 507 | # 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes 508 | # Level 1 509 | 510 | # 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration 511 | # changes 512 | # Level 2 513 | 514 | # 3.10 Ensure a log metric filter and alarm exist for security group changes 515 | # Level 2 516 | 517 | # 3.11 Ensure a log metric filter and alarm exist for changes to Network 518 | # Access Control Lists (NACL) 519 | # Level 2 520 | 521 | # 3.12 Ensure a log metric filter and alarm exist for changes to network 522 | # gateways 523 | # Level 1 524 | 525 | # 3.13 Ensure a log metric filter and alarm exist for route table changes 526 | # Level 1 527 | 528 | # 3.14 Ensure a log metric filter and alarm exist for VPC changes 529 | # Level 1 530 | 531 | # 3.15 Ensure appropriate subscribers to each SNS topic 532 | # Level 1 - Not Scored 533 | # Not implemented 534 | 535 | # 4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 536 | # 4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 537 | # Level 1 538 | - name: cis-security-group-ingress-is-restricted 539 | resource: security-group 540 | comment: "CIS Amazon Web Services Foundations v1.1.0 (4.1,4.2)" 541 | filters: 542 | - type: ingress 543 | Ports: [22,3389] 544 | Cidr: 545 | value: 0.0.0.0/0 546 | op: eq 547 | value_type: cidr 548 | mode: 549 | schedule: "rate(24 hours)" 550 | type: periodic 551 | execution-options: 552 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 553 | actions: 554 | - type: notify 555 | action_desc: "Restrict ingress to ports 22 and 3389." 556 | to: ["slack"] 557 | transport: 558 | type: sqs 559 | queue: MESSAGEQUEUENAME 560 | violation_desc: | 561 | AWS security group allows unrestricted access to ports 22 and/or 3389. 562 | CIS Amazon Web Services Foundations v1.1.0 (4.1,4.2) 563 | 564 | # 4.3 Ensure VPC flow logging is enabled in all VPCs 565 | # Level 2 566 | - name: cis-vpc-flow-log-enabled 567 | resource: vpc 568 | comment: "CIS Amazon Web Services Foundations v1.1.0 (4.3)" 569 | filters: 570 | - not: 571 | - type: flow-logs 572 | enabled: true 573 | mode: 574 | schedule: "rate(24 hours)" 575 | type: periodic 576 | execution-options: 577 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 578 | actions: 579 | - type: notify 580 | action_desc: "Enable VPC flow logging." 581 | to: ["slack"] 582 | transport: 583 | type: sqs 584 | queue: MESSAGEQUEUENAME 585 | violation_desc: | 586 | VPC flow logging is not enabled for all VPCs. 587 | CIS Amazon Web Services Foundations v1.1.0 (4.3) 588 | 589 | # 4.4 Ensure the default security group of every VPC restricts all traffic 590 | # Level 2 591 | - name: cis-security-group-default-deny 592 | resource: security-group 593 | filters: 594 | - type: value 595 | key: "GroupName" 596 | value: "default" 597 | - or: 598 | - type: value 599 | key: IpPermissions 600 | value: not-null 601 | - type: value 602 | key: IpPermissionsEgress 603 | value: not-null 604 | mode: 605 | schedule: "rate(24 hours)" 606 | type: periodic 607 | execution-options: 608 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 609 | actions: 610 | - type: notify 611 | action_desc: | 612 | "Remove all ingress and egress rules from the default security group." 613 | to: ["slack"] 614 | transport: 615 | type: sqs 616 | queue: MESSAGEQUEUENAME 617 | violation_desc: | 618 | The default security group must deny all traffic. 619 | CIS Amazon Web Services Foundations v1.1.0 (4.4) 620 | 621 | # 4.5 Ensure routing tables for VPC peering are "least access" 622 | # Level 2 - Not Scored 623 | -------------------------------------------------------------------------------- /policies/aws-service-limit-increase.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: account-service-limit-increase 4 | resource: account 5 | comment: | 6 | Request a 25% increase in any service limit that reaches 80% of maximum. 7 | filters: 8 | - type: service-limit 9 | mode: 10 | schedule: "rate(24 hours)" 11 | type: periodic 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | actions: 15 | - type: request-limit-increase 16 | percent-increase: 25 17 | - type: notify 18 | action_desc: "Submitted service limit increase request of 25 percent." 19 | cc: ["#000000"] 20 | subject: "Limit Increase Was Requested" 21 | to: ["slack"] 22 | transport: 23 | type: sqs 24 | queue: MESSAGEQUEUENAME 25 | violation_desc: "Service limit hit 80 percent of max." 26 | -------------------------------------------------------------------------------- /policies/ebs-volume-delete-unattached.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ebs-volume-delete-unattached-mark 4 | comment: "Mark unattached, EBS volumes for deletion." 5 | resource: ebs 6 | filters: 7 | - "tag:c7n_ebs_volume_delete_unattached": absent 8 | - Attachments: [] 9 | mode: 10 | schedule: "rate(60 minutes)" 11 | type: periodic 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | actions: 15 | - type: mark-for-op 16 | tag: c7n_ebs_volume_delete_unattached 17 | op: delete 18 | days: 14 19 | - type: notify 20 | action_desc: | 21 | Custodian has marked the volumes for deletion in 14 days. Please backup 22 | the volume and/or attach it. 23 | subject: "EBS Volume Maintenance" 24 | to: ["slack"] 25 | transport: 26 | type: sqs 27 | queue: MESSAGEQUEUENAME 28 | violation_desc: | 29 | Custodian detected unattached EBS volume(s). 30 | 31 | - name: ebs-volume-delete-unattached-unmark 32 | comments: | 33 | Unmark attached, EBS volumes that were previously marked for deletion. 34 | resource: ebs 35 | filters: 36 | - "tag:c7n_ebs_volume_delete_unattached": not-null 37 | - type: value 38 | key: "Attachments[0].Device" 39 | value: not-null 40 | mode: 41 | schedule: "rate(30 minutes)" 42 | type: periodic 43 | execution-options: 44 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 45 | actions: 46 | - type: unmark 47 | tags: [c7n_ebs_volume_delete_unattached] 48 | 49 | - name: ebs-volume-delete-unattached 50 | comments: | 51 | Delete unattached, EBS volumes that were marked for deletion. 52 | resource: ebs 53 | filters: 54 | - type: marked-for-op 55 | tag: c7n_ebs_volume_delete_unattached 56 | op: delete 57 | - Attachments: [] 58 | mode: 59 | schedule: "rate(6 hours)" 60 | type: periodic 61 | execution-options: 62 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 63 | actions: 64 | - delete 65 | - type: notify 66 | action_desc: | 67 | Custodian has deleted unattached, EBS volumes that were maked for 68 | deletion. No action is required. 69 | cc: ["#000000"] 70 | subject: "EBS Volume Maintenance" 71 | to: ["slack"] 72 | transport: 73 | type: sqs 74 | queue: MESSAGEQUEUENAME 75 | violation_desc: | 76 | Custodian detected unattached EBS volume(s). 77 | -------------------------------------------------------------------------------- /policies/ebs-volume-delete-unencrypted-on-creation.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ebs-volume-delete-unencrypted-on-creation 4 | comment: "Delete unencrypted, non-root, EBS volumes on creation." 5 | resource: ebs 6 | filters: 7 | - "tag:c7n_ebs_volume_encryption_exempt": absent 8 | - Encrypted: false 9 | - not: 10 | - type: value 11 | key: "Attachments[].Device" 12 | op: regex 13 | value: ^/dev/(sda1|xvda|nvme0n1)$ 14 | mode: 15 | type: cloudtrail 16 | execution-options: 17 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 18 | events: 19 | - CreateVolume 20 | actions: 21 | - delete 22 | - type: notify 23 | action_desc: | 24 | Custodian has deleted the unencrypted volume. Please modify volume 25 | creation to include encryption. 26 | subject: "EBS Volume Not Encrypted" 27 | to: ["slack"] 28 | transport: 29 | type: sqs 30 | queue: MESSAGEQUEUENAME 31 | violation_desc: "Custodian caught the creation of an unencrypted volume." 32 | -------------------------------------------------------------------------------- /policies/ebs-volume-missing-recent-snapshot.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ebs-volume-missing-recent-snapshot 4 | resource: ebs 5 | comment: | 6 | Warn about EBS volumes missing a recent snapshot and create one. 7 | filters: 8 | - "tag:c7n_ebs_volume_missing_recent_snapshot_exempt": absent 9 | - type: fault-tolerant 10 | tolerant: False 11 | mode: 12 | schedule: "rate(60 minutes)" 13 | type: periodic 14 | execution-options: 15 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 16 | actions: 17 | - snapshot 18 | - type: notify 19 | action_desc: | 20 | Custodian has created a snapshot. Please review volume backup and 21 | recovery requirements. 22 | cc: ["#000000"] 23 | subject: "EBS Volume Missing Recent Snapshot" 24 | to: ["slack"] 25 | transport: 26 | type: sqs 27 | queue: MESSAGQUEUENAME 28 | violation_desc: | 29 | Custodian detected EBS volume(s) w/o a snapshot in the last 7 days. 30 | -------------------------------------------------------------------------------- /policies/ebs-volume-notify-if-unencrypted.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ebs-volume-notify-if-unencrypted 4 | comment: "Notify of non-root, unencrypted, EBS volumes when created." 5 | resource: ebs 6 | filters: 7 | - Encrypted: false 8 | - not: 9 | - type: value 10 | key: "Attachments[].Device" 11 | op: regex 12 | value: ^/dev/(sda1|xvda)$ 13 | mode: 14 | type: cloudtrail 15 | execution-options: 16 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 17 | events: 18 | - CreateVolume 19 | actions: 20 | - type: notify 21 | action_desc: "Please encrypt the volume." 22 | subject: "EBS Volume Encryption" 23 | to: ["slack"] 24 | transport: 25 | type: sqs 26 | queue: MESSAGEQUEUENAME 27 | violation_desc: | 28 | Custodian detected the creation of an unencrypted volume. 29 | -------------------------------------------------------------------------------- /policies/ebs-volume-tag-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ebs-volume-tag-compliance-mark 4 | resource: ebs 5 | comment: | 6 | Find all attached EBS volumes that are not compliant to tagging policies, 7 | attempt to copy the instance tags, and tag as not compliant. 8 | filters: 9 | - "tag:c7n_tag_compliance": absent 10 | - type: value 11 | key: "Attachments[0].Device" 12 | value: not-null 13 | - or: 14 | - "tag:REQUIREDTAG1": absent 15 | - "tag:REQUIREDTAG2": absent 16 | - "tag:REQUIREDTAG3": absent 17 | - "tag:REQUIREDTAG4": absent 18 | - "tag:REQUIREDTAG5": absent 19 | - "tag:REQUIREDTAG6": absent 20 | mode: 21 | schedule: "rate(60 minutes)" 22 | type: periodic 23 | execution-options: 24 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 25 | actions: 26 | - type: copy-instance-tags 27 | tags: 28 | - REQUIREDTAG1 29 | - REQUIREDTAG2 30 | - REQUIREDTAG3 31 | - REQUIREDTAG4 32 | - REQUIREDTAG5 33 | - REQUIREDTAG6 34 | - type: tag 35 | key: c7n_tag_compliance 36 | value: 'non-conformant' 37 | 38 | - name: ebs-volume-tag-compliance-unmark 39 | resource: ebs 40 | comment: | 41 | Unmark all EBS volumes that are now compliant to tagging policies. 42 | filters: 43 | - "tag:c7n_tag_compliance": not-null 44 | - "tag:REQUIREDTAG1": not-null 45 | - "tag:REQUIREDTAG2": not-null 46 | - "tag:REQUIREDTAG3": not-null 47 | - "tag:REQUIREDTAG4": not-null 48 | - "tag:REQUIREDTAG5": not-null 49 | - "tag:REQUIREDTAG6": not-null 50 | mode: 51 | schedule: "rate(30 minutes)" 52 | type: periodic 53 | execution-options: 54 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 55 | actions: 56 | - type: unmark 57 | tags: [c7n_tag_compliance] 58 | 59 | - name: ebs-volume-tag-compliance-notify 60 | resource: ebs 61 | comment: | 62 | Notify on EBS volumes that remain non-compliant to tagging policies in 63 | spite of an automated correction attempt. 64 | filters: 65 | - "tag:c7n_tag_compliance": not-null 66 | - or: 67 | - "tag:REQUIREDTAG1": absent 68 | - "tag:REQUIREDTAG2": absent 69 | - "tag:REQUIREDTAG3": absent 70 | - "tag:REQUIREDTAG4": absent 71 | - "tag:REQUIREDTAG5": absent 72 | - "tag:REQUIREDTAG6": absent 73 | mode: 74 | schedule: "rate(24 hours)" 75 | type: periodic 76 | execution-options: 77 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 78 | actions: 79 | - type: notify 80 | action_desc: | 81 | Custodian attempted to copy ec2 instance tags to the EBS volume but it 82 | remains non-comformant. Please correctly tag the EBS volume. 83 | subject: "EBS Volume Tag Compliance" 84 | to: ["slack"] 85 | transport: 86 | type: sqs 87 | queue: MESSAGEQUEUENAME 88 | violation_desc: "EBS volumes must have the required tags." 89 | -------------------------------------------------------------------------------- /policies/ec2-off-hours-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ec2-off-hours-enforcement 4 | resource: ec2 5 | comments: | 6 | Opt in EC2 instances without a c7n_off_hours tag 7 | filters: 8 | - "tag:c7n_off_hours": absent 9 | - "tag:aws:autoscaling:groupName": absent 10 | mode: 11 | schedule: "rate(24 hours)" 12 | type: periodic 13 | execution-options: 14 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 15 | actions: 16 | - type: tag 17 | key: c7n_off_hours 18 | value: "on" 19 | -------------------------------------------------------------------------------- /policies/ec2-off-hours.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ec2-off-hours-stop 4 | resource: ec2 5 | comments: | 6 | Stop EC2 instances as per schedule in c7n_off_hours 7 | filters: 8 | - "tag:c7n_do_not_shut_down": absent 9 | - "tag:aws:autoscaling:groupName": absent 10 | - type: offhour 11 | default_tz: gmt 12 | offhour: 1 13 | tag: c7n_off_hours 14 | - type: instance-age 15 | hours: 1 16 | mode: 17 | schedule: "rate(60 minutes)" 18 | type: periodic 19 | execution-options: 20 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 21 | actions: 22 | - stop 23 | 24 | - name: ec2-off-hours-start 25 | resource: ec2 26 | comments: | 27 | Start EC2 instances as per schedule in c7n_off_hours 28 | filters: 29 | - "tag:c7n_do_not_shut_down": absent 30 | - "tag:aws:autoscaling:groupName": absent 31 | - type: onhour 32 | default_tz: gmt 33 | onhour: 11 34 | tag: c7n_off_hours 35 | mode: 36 | schedule: "rate(60 minutes)" 37 | type: periodic 38 | execution-options: 39 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 40 | actions: 41 | - start 42 | -------------------------------------------------------------------------------- /policies/ec2-tag-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: ec2-tag-compliance-mark 4 | resource: ec2 5 | comment: | 6 | Find all (non-ASG) instances that are not compliant 7 | to tagging policies, tag them for stoppage in 1 day, 8 | and send a notification. 9 | filters: 10 | - "tag:aws:autoscaling:groupName": absent 11 | - "tag:c7n_tag_compliance": absent 12 | - or: 13 | - "tag:REQUIREDTAG1": absent 14 | - "tag:REQUIREDTAG2": absent 15 | - "tag:REQUIREDTAG3": absent 16 | - "tag:REQUIREDTAG4": absent 17 | - "tag:REQUIREDTAG5": absent 18 | - "tag:REQUIREDTAG6": absent 19 | mode: 20 | schedule: "rate(60 minutes)" 21 | type: periodic 22 | execution-options: 23 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 24 | actions: 25 | - type: mark-for-op 26 | tag: c7n_tag_compliance 27 | op: stop 28 | days: 1 29 | - type: notify 30 | action_desc: | 31 | Offending EC2 instance(s) are now marked to be stopped if the 32 | required tags not added within 24 hours. 33 | subject: "EC2 Tag Compliance" 34 | to: ["slack"] 35 | transport: 36 | type: sqs 37 | queue: MESSAGEQUEUENAME 38 | violation_desc: "EC2 instances must have the required tags." 39 | 40 | - name: ec2-tag-compliance-unmark 41 | resource: ec2 42 | comment: | 43 | Unmark any instances which have previously been marked as 44 | not complying with tag policies but are now compliant. 45 | filters: 46 | - "tag:aws:autoscaling:groupName": absent 47 | - "tag:c7n_tag_compliance": not-null 48 | - "tag:REQUIREDTAG1": not-null 49 | - "tag:REQUIREDTAG2": not-null 50 | - "tag:REQUIREDTAG3": not-null 51 | - "tag:REQUIREDTAG4": not-null 52 | - "tag:REQUIREDTAG5": not-null 53 | - "tag:REQUIREDTAG6": not-null 54 | mode: 55 | schedule: "rate(30 minutes)" 56 | type: periodic 57 | execution-options: 58 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 59 | actions: 60 | - type: unmark 61 | tags: [c7n_tag_compliance] 62 | - type: notify 63 | action_desc: | 64 | EC2 instance(s) are no longer marked to be stopped. 65 | cc: ["good"] 66 | subject: "EC2 Tag Compliance" 67 | to: ["slack"] 68 | transport: 69 | type: sqs 70 | queue: MESSAGEQUEUENAME 71 | violation_desc: "EC2 instances have the required tags." 72 | 73 | - name: ec2-tag-compliance-stop 74 | resource: ec2 75 | comment: | 76 | Stop all (non-ASG) instances previously marked for stoppage by today's 77 | date, and schedule them for termination after verifying that they continue 78 | to be non-compliant to tagging policies. 79 | filters: 80 | - "tag:aws:autoscaling:groupName": absent 81 | - type: marked-for-op 82 | tag: c7n_tag_compliance 83 | op: stop 84 | - or: 85 | - "tag:REQUIREDTAG1": absent 86 | - "tag:REQUIREDTAG2": absent 87 | - "tag:REQUIREDTAG3": absent 88 | - "tag:REQUIREDTAG4": absent 89 | - "tag:REQUIREDTAG5": absent 90 | - "tag:REQUIREDTAG6": absent 91 | mode: 92 | schedule: "rate(60 minutes)" 93 | type: periodic 94 | execution-options: 95 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 96 | actions: 97 | - stop 98 | - type: mark-for-op 99 | tag: c7n_tag_compliance 100 | op: terminate 101 | days: 3 102 | - type: notify 103 | action_desc: | 104 | Offending EC2 instance(s) are now marked to be terminated if the 105 | required tags not added within 24 hours. 106 | cc: ["warning"] 107 | subject: "EC2 Tag Compliance" 108 | to: ["slack"] 109 | transport: 110 | type: sqs 111 | queue: MESSAGEQUEUENAME 112 | violation_desc: "EC2 instances must have the required tags." 113 | 114 | - name: ec2-tag-compliance-terminate 115 | resource: ec2 116 | comment: | 117 | Terminate all stopped instances marked for termination 118 | by today's date after verifying that they continue 119 | to be non-compliant to tagging policies. 120 | filters: 121 | - "tag:aws:autoscaling:groupName": absent 122 | - type: marked-for-op 123 | tag: c7n_tag_compliance 124 | op: terminate 125 | - or: 126 | - "tag:REQUIREDTAG1": absent 127 | - "tag:REQUIREDTAG2": absent 128 | - "tag:REQUIREDTAG3": absent 129 | - "tag:REQUIREDTAG4": absent 130 | - "tag:REQUIREDTAG5": absent 131 | - "tag:REQUIREDTAG6": absent 132 | mode: 133 | schedule: "rate(6 hours)" 134 | type: periodic 135 | execution-options: 136 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 137 | actions: 138 | - type: terminate 139 | force: true 140 | - type: notify 141 | action_desc: | 142 | Offending EC2 instance(s) have been terminated since the 143 | required tags were not added. No further action is required. 144 | cc: ["#000000"] 145 | subject: "EC2 Tag Compliance" 146 | to: ["slack"] 147 | transport: 148 | type: sqs 149 | queue: MESSAGEQUEUENAME 150 | violation_desc: "EC2 instances must have the required tags." 151 | 152 | - name: ec2-tag-compliance-nag-stop 153 | resource: ec2 154 | comment: | 155 | Stop all instances marked for termination every hour, starting 1 day before 156 | their termination, after verifying that they continue to be non-compliant 157 | to tagging policies. 158 | filters: 159 | - "tag:aws:autoscaling:groupName": absent 160 | - type: marked-for-op 161 | tag: c7n_tag_compliance 162 | op: terminate 163 | skew: 1 164 | - or: 165 | - "tag:REQUIREDTAG1": absent 166 | - "tag:REQUIREDTAG2": absent 167 | - "tag:REQUIREDTAG3": absent 168 | - "tag:REQUIREDTAG4": absent 169 | - "tag:REQUIREDTAG5": absent 170 | - "tag:REQUIREDTAG6": absent 171 | mode: 172 | schedule: "rate(60 minutes)" 173 | type: periodic 174 | execution-options: 175 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 176 | actions: 177 | - stop 178 | -------------------------------------------------------------------------------- /policies/iam-basic-deny.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: iam-role-basic-deny 4 | comment: "Ensure that all IAM roles have the basic_deny policy attached unless it has an exception" 5 | resource: iam-role 6 | filters: 7 | - and: 8 | - type: no-specific-managed-policy 9 | value: basic_deny 10 | - type: value 11 | key: RoleName 12 | op: ni 13 | value: 14 | - ROLE1 15 | - ROLE2 16 | - ROLE3 17 | - ROLE4 18 | - ROLE5 19 | - not: 20 | - type: value 21 | key: RoleName 22 | op: glob 23 | value: NOTROLE1 24 | - not: 25 | - type: value 26 | key: RoleName 27 | value: NOTROLE2 28 | mode: 29 | schedule: "rate(24 hours)" 30 | type: periodic 31 | execution-options: 32 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 33 | actions: 34 | - type: notify 35 | action_desc: | 36 | Custodian has identified a role without the basic_deny policy attached 37 | cc: ["#000000"] 38 | subject: "IAM Role without basic_deny" 39 | to: ["slack"] 40 | transport: 41 | type: sqs 42 | queue: MESSAGEQUEUENAME 43 | violation_desc: | 44 | All IAM Roles must have the basic_deny policy attached unless there is a documented exception 45 | -------------------------------------------------------------------------------- /policies/log-group-missing-retention-days.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | - name: log-group-missing-retention-days 3 | resource: log-group 4 | comment: | 5 | Detect CloudWatch Log Groups with no retention setting and set it to 6 | one day. 7 | filters: 8 | - type: value 9 | key: retentionInDays 10 | value: absent 11 | mode: 12 | schedule: "rate(24 hours)" 13 | type: periodic 14 | execution-options: 15 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 16 | actions: 17 | - type: retention 18 | days: 1 19 | - type: notify 20 | action_desc: "Custodian has set the retention period to 1 day." 21 | cc: ["#000000"] 22 | subject: "Log Group Missing Retention Settings" 23 | to: ["slack"] 24 | transport: 25 | type: sqs 26 | queue: MESSAGEQUEUENAME 27 | violation_desc: "CloudWatch Log Group has no retention setting." 28 | -------------------------------------------------------------------------------- /policies/rds-off-hours-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: rds-off-hours-enforcement 4 | resource: rds 5 | comments: | 6 | Opt in RDS instances without a c7n_off_hours tag 7 | filters: 8 | - "tag:c7n_off_hours": absent 9 | mode: 10 | schedule: "rate(24 hours)" 11 | type: periodic 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | actions: 15 | - type: tag 16 | key: c7n_off_hours 17 | value: "on" 18 | -------------------------------------------------------------------------------- /policies/rds-off-hours.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: rds-off-hours-stop 4 | resource: rds 5 | comments: | 6 | Stop RDS instances as per schedule in c7n_off_hours 7 | filters: 8 | - "tag:c7n_do_not_shut_down": absent 9 | - type: offhour 10 | default_tz: gmt 11 | offhour: 1 12 | tag: c7n_off_hours 13 | mode: 14 | schedule: "rate(60 minutes)" 15 | type: periodic 16 | execution-options: 17 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 18 | actions: 19 | - stop 20 | 21 | - name: rds-off-hours-start 22 | resource: rds 23 | comments: | 24 | Start RDS instances as per schedule in c7n_off_hours 25 | filters: 26 | - "tag:c7n_do_not_shut_down": absent 27 | - type: onhour 28 | default_tz: gmt 29 | onhour: 11 30 | tag: c7n_off_hours 31 | mode: 32 | schedule: "rate(60 minutes)" 33 | type: periodic 34 | execution-options: 35 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 36 | actions: 37 | - start 38 | -------------------------------------------------------------------------------- /policies/rds-tag-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: rds-tag-compliance-mark 4 | resource: rds 5 | comment: | 6 | Find all rds that are not compliant to tagging policies 7 | and tag as such. 8 | filters: 9 | - "tag:c7n_tag_compliance": absent 10 | - or: 11 | - "tag:REQUIREDTAG1": absent 12 | - "tag:REQUIREDTAG2": absent 13 | - "tag:REQUIREDTAG3": absent 14 | - "tag:REQUIREDTAG4": absent 15 | - "tag:REQUIREDTAG5": absent 16 | - "tag:REQUIREDTAG6": absent 17 | mode: 18 | schedule: "rate(60 minutes)" 19 | type: periodic 20 | execution-options: 21 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 22 | actions: 23 | - type: tag 24 | key: c7n_tag_compliance 25 | value: 'non-conformant' 26 | 27 | - name: rds-tag-compliance-unmark 28 | resource: rds 29 | comment: | 30 | Unmark all rds that are now compliant to tagging policies. 31 | filters: 32 | - "tag:c7n_tag_compliance": not-null 33 | - "tag:REQUIREDTAG1": not-null 34 | - "tag:REQUIREDTAG2": not-null 35 | - "tag:REQUIREDTAG3": not-null 36 | - "tag:REQUIREDTAG4": not-null 37 | - "tag:REQUIREDTAG5": not-null 38 | - "tag:REQUIREDTAG6": not-null 39 | mode: 40 | schedule: "rate(30 minutes)" 41 | type: periodic 42 | execution-options: 43 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 44 | actions: 45 | - type: unmark 46 | tags: [c7n_tag_compliance] 47 | 48 | - name: rds-tag-compliance-notify 49 | resource: rds 50 | comment: | 51 | Notify on rds that remain non-compliant to tagging policies. 52 | filters: 53 | - "tag:c7n_tag_compliance": not-null 54 | - or: 55 | - "tag:REQUIREDTAG1": absent 56 | - "tag:REQUIREDTAG2": absent 57 | - "tag:REQUIREDTAG3": absent 58 | - "tag:REQUIREDTAG4": absent 59 | - "tag:REQUIREDTAG5": absent 60 | - "tag:REQUIREDTAG6": absent 61 | mode: 62 | schedule: "rate(24 hours)" 63 | type: periodic 64 | execution-options: 65 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 66 | actions: 67 | - type: notify 68 | action_desc: | 69 | Custodian has tagged rds that are not compliant with tagging 70 | requirements. Please correctly tag rds resources. 71 | subject: "RDS Tag Compliance" 72 | to: ["slack"] 73 | transport: 74 | type: sqs 75 | queue: MESSAGEQUEUENAME 76 | violation_desc: "RDS resources must have the required tags." 77 | -------------------------------------------------------------------------------- /policies/rds-terminate-publicly-available-on-creation.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: rds-terminate-publicly-available-instance-on-creation 4 | resource: rds 5 | comment: | 6 | Terminate publicly available RDS upon creation 7 | filters: 8 | - "tag:c7n_rds_publicly_available_exempt": absent 9 | - PubliclyAccessible: true 10 | mode: 11 | type: cloudtrail 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | events: 15 | - CreateDBInstance 16 | actions: 17 | - type: delete 18 | skip-snapshot: true 19 | - type: notify 20 | action_desc: | 21 | Custodian has terminated publicly available RDS instance. Please modify the RDS 22 | instance to be private or correctly tag for exemption. 23 | subject: "RDS Instance Available to Public" 24 | to: ["slack"] 25 | transport: 26 | type: sqs 27 | queue: MESSAGEQUEUENAME 28 | violation_desc: "RDS Instance available to public." 29 | 30 | -------------------------------------------------------------------------------- /policies/s3-delete-unencrypted-on-creation.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: s3-delete-unencrypted-on-creation 4 | comment: "Delete unencrypted s3 bucket on creation." 5 | resource: s3 6 | filters: 7 | - "tag:c7n_s3_encryption_exempt": absent 8 | - type: bucket-encryption 9 | state: False 10 | mode: 11 | type: cloudtrail 12 | execution-options: 13 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 14 | events: 15 | - CreateBucket 16 | actions: 17 | - delete 18 | - type: notify 19 | action_desc: | 20 | Custodian has deleted the unencrypted s3 bucket on creation. Please modify s3 bucket 21 | creation to include encryption. 22 | subject: "S3 Bucket Not Encrypted on Creation" 23 | to: ["slack"] 24 | transport: 25 | type: sqs 26 | queue: MESSAGEQUEUENAME 27 | violation_desc: "Custodian caught the creation of an unencrypted s3 bucket." 28 | -------------------------------------------------------------------------------- /policies/s3-global-grants.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: s3-global-grants-mark 4 | comment: | 5 | Find all S3 buckets with global grants, tag them for grant removal, and 6 | send a notification. 7 | region: us-east-1 8 | resource: s3 9 | filters: 10 | - "tag:c7n_s3_global_grants": absent 11 | - type: global-grants 12 | mode: 13 | schedule: "rate(24 hours)" 14 | type: periodic 15 | execution-options: 16 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 17 | actions: 18 | - type: mark-for-op 19 | tag: c7n_s3_global_grants 20 | op: delete-global-grants 21 | days: 7 22 | - type: notify 23 | action_desc: | 24 | Custodian marked the S3 buckets for global grant removal in 7 days. 25 | subject: "S3 Bucket Security" 26 | to: ["slack"] 27 | transport: 28 | type: sqs 29 | queue: MESSAGEQUEUENAME 30 | violation_desc: | 31 | Custodian detected S3 bucket(s) with global grants. 32 | 33 | - name: s3-global-grants-unmark 34 | comment: | 35 | Unmark all S3 buckets which no longer have global grants. 36 | region: us-east-1 37 | resource: s3 38 | filters: 39 | - "tag:c7n_s3_global_grants": not-null 40 | - not: 41 | - type: global-grants 42 | mode: 43 | schedule: "rate(24 hours)" 44 | type: periodic 45 | execution-options: 46 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 47 | actions: 48 | - type: unmark 49 | tags: [c7n_s3_global_grants] 50 | - type: notify 51 | action_desc: | 52 | Custodian unmarked S3 bucket(s) that have had global grants removed. 53 | No further action is required. 54 | cc: ["good"] 55 | subject: "S3 Bucket Security" 56 | to: ["slack"] 57 | transport: 58 | type: sqs 59 | queue: MESSAGEQUEUENAME 60 | violation_desc: "S3 bucket(s) had global grants." 61 | 62 | - name: s3-global-grants-remove 63 | resource: s3 64 | comment: | 65 | Remove global grants from S3 buckets marked for today's date. 66 | region: us-east-1 67 | filters: 68 | - type: global-grants 69 | - type: marked-for-op 70 | tag: c7n_s3_global_grants 71 | op: delete-global-grants 72 | mode: 73 | schedule: "rate(24 hours)" 74 | type: periodic 75 | execution-options: 76 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 77 | actions: 78 | - type: delete-global-grants 79 | - type: unmark 80 | tags: [c7n_s3_global_grants] 81 | - type: notify 82 | action_desc: | 83 | Custodian removed global grants from previously marked S3 bucket(s). 84 | No further action is required. 85 | cc: ["#000000"] 86 | subject: "S3 Bucket Security" 87 | to: ["slack"] 88 | transport: 89 | type: sqs 90 | queue: MESSAGEQUEUENAME 91 | violation_desc: "S3 bucket had global grants." 92 | -------------------------------------------------------------------------------- /policies/s3-tag-enforcement.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: s3-tag-compliance-mark 4 | resource: s3 5 | comment: | 6 | Find all s3 buckets that are not compliant 7 | to tagging policies, tags them as such, 8 | and sends a notification. 9 | region: us-east-1 10 | filters: 11 | - "tag:c7n_tag_compliance": absent 12 | - or: 13 | - "tag:REQUIREDTAG1": absent 14 | - "tag:REQUIREDTAG2": absent 15 | - "tag:REQUIREDTAG3": absent 16 | - "tag:REQUIREDTAG4": absent 17 | - "tag:REQUIREDTAG5": absent 18 | - "tag:REQUIREDTAG6": absent 19 | mode: 20 | schedule: "rate(24 hours)" 21 | type: periodic 22 | execution-options: 23 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 24 | actions: 25 | - type: tag 26 | key: c7n_tag_compliance 27 | value: 'non-conformant' 28 | - type: notify 29 | action_desc: | 30 | Please correctly tag S3 buckets. 31 | subject: "S3 Bucket Tag Compliance" 32 | to: ["slack"] 33 | transport: 34 | type: sqs 35 | queue: MESSAGEQUEUENAME 36 | violation_desc: "S3 buckets must have the required tags." 37 | 38 | - name: s3-tag-compliance-unmark 39 | resource: s3 40 | comment: | 41 | Unmark s3 buckets that are now compliant to tagging policies. 42 | region: us-east-1 43 | filters: 44 | - "tag:c7n_tag_compliance": not-null 45 | - "tag:REQUIREDTAG1": not-null 46 | - "tag:REQUIREDTAG2": not-null 47 | - "tag:REQUIREDTAG3": not-null 48 | - "tag:REQUIREDTAG4": not-null 49 | - "tag:REQUIREDTAG5": not-null 50 | - "tag:REQUIREDTAG6": not-null 51 | mode: 52 | schedule: "rate(24 hours)" 53 | type: periodic 54 | execution-options: 55 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 56 | actions: 57 | - type: unmark 58 | tags: [c7n_tag_compliance] 59 | 60 | - name: s3-tag-compliance-notify 61 | resource: s3 62 | comment: | 63 | Notify of s3 buckets that remain not compliant to tagging policies. 64 | region: us-east-1 65 | filters: 66 | - "tag:c7n_tag_compliance": not-null 67 | - or: 68 | - "tag:REQUIREDTAG1": absent 69 | - "tag:REQUIREDTAG2": absent 70 | - "tag:REQUIREDTAG3": absent 71 | - "tag:REQUIREDTAG4": absent 72 | - "tag:REQUIREDTAG5": absent 73 | - "tag:REQUIREDTAG6": absent 74 | mode: 75 | schedule: "rate(24 hours)" 76 | type: periodic 77 | execution-options: 78 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 79 | actions: 80 | - type: notify 81 | action_desc: | 82 | Please correctly tag S3 buckets. 83 | subject: "S3 Bucket Tag Compliance" 84 | to: ["slack"] 85 | transport: 86 | type: sqs 87 | queue: MESSAGEQUEUENAME 88 | violation_desc: "S3 buckets must have the required tags." 89 | -------------------------------------------------------------------------------- /policies/security-group-default-deny.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: security-group-default-deny 4 | comment: "Remove all rules from the VPC default security group" 5 | resource: security-group 6 | filters: 7 | - type: value 8 | key: "GroupName" 9 | value: "default" 10 | - or: 11 | - type: value 12 | key: IpPermissions 13 | value: not-null 14 | - type: value 15 | key: IpPermissionsEgress 16 | value: not-null 17 | mode: 18 | schedule: "rate(24 hours)" 19 | type: periodic 20 | execution-options: 21 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 22 | actions: 23 | - type: remove-permissions 24 | ingress: all 25 | - type: remove-permissions 26 | egress: all 27 | - type: notify 28 | action_desc: | 29 | Custodian removed all rules, ingress and egress, from the default 30 | security group. This security group should never be used. No further 31 | action is required. 32 | subject: "Default VPC Security Group Set to Deny" 33 | to: ["slack"] 34 | transport: 35 | type: sqs 36 | queue: MESSAGEQUEUENAME 37 | violation_desc: | 38 | The default security group must deny all traffic. 39 | CIS Amazon Web Services Foundations v1.1.0 (4.4) 40 | -------------------------------------------------------------------------------- /policies/security-group-restrict-admin-ingress.yml: -------------------------------------------------------------------------------- 1 | policies: 2 | 3 | - name: security-group-restrict-admin-ingress 4 | resource: security-group 5 | comment: "Remove rules allowing unrestricted ingress to ports [22, 3389]" 6 | filters: 7 | - "tag:c7n_security_group_restrict_admin_ingress_exempt": absent 8 | - type: ingress 9 | Ports: [22,3389] 10 | Cidr: 11 | value: 0.0.0.0/0 12 | op: eq 13 | value_type: cidr 14 | mode: 15 | type: cloudtrail 16 | execution-options: 17 | output_dir: s3://BUCKETNAME/CustodianLogs/{account_id}/ 18 | events: 19 | - source: ec2.amazonaws.com 20 | event: AuthorizeSecurityGroupIngress 21 | ids: "requestParameters.groupId" 22 | actions: 23 | - type: remove-permissions 24 | ingress: matched 25 | - type: notify 26 | action_desc: "Ingress to ports [22, 3389] have been removed." 27 | cc: ["warning"] 28 | to: ["slack"] 29 | transport: 30 | type: sqs 31 | queue: MESSAGEQUEUENAME 32 | violation_desc: | 33 | AWS security group allowed unrestricted access to ports [22, 3389]. 34 | Offending rules were removed. 35 | --------------------------------------------------------------------------------