diff --git a/codebundles/aws-c7n-ec2-health/runbook.robot b/codebundles/aws-c7n-ec2-health/runbook.robot index 6238e4d..648b51a 100644 --- a/codebundles/aws-c7n-ec2-health/runbook.robot +++ b/codebundles/aws-c7n-ec2-health/runbook.robot @@ -2,7 +2,7 @@ Metadata Author saurabh3460 Metadata Supports AWS EC2 CloudCustodian Metadata Display Name AWS EC2 Health -Documentation Check health of EC2 instances to maintain performance and adherence to best practices. +Documentation Check for EC2 instances that are unpatched or unused Force Tags EC2 Compute AWS Library RW.Core @@ -13,29 +13,27 @@ Suite Setup Suite Initialization *** Tasks *** -List old AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` - [Documentation] List old EC2 instances in AWS Region. - [Tags] ec2 instance aws compute +List unpatched AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` + [Documentation] List unpatched EC2 instances in AWS Region. + [Tags] ec2 instance aws compute unpatched + + # Generate the Cloud Custodian policy ${result}= CloudCustodian.Core.Generate Policy - ... ${CURDIR}/old-ec2-instances.j2 - ... days=${AWS_EC2_AGE} - ... state=${AWS_EC2_STATE} + ... ${CURDIR}/unpatched-ec2-instances.j2 + ... days=${AWS_EC2_AGE} ... tags=${AWS_EC2_TAGS} + + # Run the Cloud Custodian policy ${c7n_output}= RW.CLI.Run Cli - ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/old-ec2-instances.yaml --cache-period 0 + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/unpatched-ec2-instances.yaml --cache-period 0 ... secret__aws_access_key_id=${AWS_ACCESS_KEY_ID} ... secret__aws_secret_access_key=${AWS_SECRET_ACCESS_KEY} - ${report_data}= RW.CLI.Run Cli - ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/old-ec2-instances/resources.json - RW.Core.Add Pre To Report ${c7n_output.stdout} - ${parsed_results}= CloudCustodian.Core.Parse EBS Results - ... input_dir=${OUTPUT_DIR}/aws-c7n-ec2-health - RW.Core.Add Pre To Report ${parsed_results} + # Read the generated report data + ${report_data}= RW.CLI.Run Cli + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/unpatched-ec2-instances/resources.json ${clean_output_dir}= RW.CLI.Run Cli cmd=rm -rf ${OUTPUT_DIR}/aws-c7n-ec2-health/old-ec2-instances - - TRY ${ec2_instances_list}= Evaluate json.loads(r'''${report_data.stdout}''') json EXCEPT @@ -44,19 +42,72 @@ List old AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_A END IF len(@{ec2_instances_list}) > 0 + # Generate and format report + ${parsed_results}= RW.CLI.Run Cli + ... cmd=jq -r --arg region "${AWS_REGION}" '["InstanceId", "InstanceType", "ImageId","REGION", "Tags"], (.[] | [ .InstanceId, .InstanceType, .ImageId, $region, (.Tags | map(.Key + "=" + .Value) | join(","))]) | @tsv' ${OUTPUT_DIR}/aws-c7n-ec2-health/unpatched-ec2-instances/resources.json | column -t + ${formatted_results}= Set Variable Resource Summary:\n${parsed_results.stdout} + RW.Core.Add Pre To Report ${formatted_results} + + # Loop through each EC2 instance in the list FOR ${item} IN @{ec2_instances_list} RW.Core.Add Issue - ... severity=4 - ... expected=EC2 instance in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` should not be older than `${AWS_EC2_AGE}` - ... actual=EC2 instance `${item["InstanceId"]}` is older than `${AWS_EC2_AGE}` in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` detected - ... title=Old EC2 instance `${item["InstanceId"]}` detected in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` + ... severity=3 + ... actual=EC2 instance in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` should not be unpatched for more than `${AWS_EC2_AGE}` days + ... expected=EC2 instance `${item["InstanceId"]}` has been unpatched for more than `${AWS_EC2_AGE}` days in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` + ... title=Unpatched EC2 instance `${item["InstanceId"]}` found in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` ... reproduce_hint=${c7n_output.cmd} ... details=${item} - ... next_steps=Escalate to service owner to review of Old AWS EC2 instance in AWS Region \`${AWS_REGION}\` in AWS account \`${AWS_ACCOUNT_ID}\`.\nDelete Old AWS EC2 instance in AWS Region \`${AWS_REGION}\` in AWS account \`${AWS_ACCOUNT_ID}\` + ... next_steps=Patch unpatched EC2 Instances in AWS Region \`${AWS_REGION}\` in AWS account \`${AWS_ACCOUNT_ID}\`\nDelete unpatched AWS EC2 instance in AWS Region \`${AWS_REGION}\` in AWS account \`${AWS_ACCOUNT_ID}\` END END +List unused AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` + [Documentation] List unused EC2 instances in AWS Region. + [Tags] ec2 instance aws compute + + # Generate the Cloud Custodian policy + ${result}= CloudCustodian.Core.Generate Policy + ... ${CURDIR}/unused-ec2-instances.j2 + ... days=${AWS_EC2_AGE} + ... tags=${AWS_EC2_TAGS} + + # Run the Cloud Custodian policy + ${c7n_output}= RW.CLI.Run Cli + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/unused-ec2-instances.yaml --cache-period 0 + ... secret__aws_access_key_id=${AWS_ACCESS_KEY_ID} + ... secret__aws_secret_access_key=${AWS_SECRET_ACCESS_KEY} + + # Read the generated report data + ${report_data}= RW.CLI.Run Cli + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/unused-ec2-instances/resources.json + + ${clean_output_dir}= RW.CLI.Run Cli cmd=rm -rf ${OUTPUT_DIR}/aws-c7n-ec2-health/old-ec2-instances + TRY + ${ec2_instances_list}= Evaluate json.loads(r'''${report_data.stdout}''') json + EXCEPT + Log Failed to load JSON payload, defaulting to empty list. WARN + ${ec2_instances_list}= Create List + END + + IF len(@{ec2_instances_list}) > 0 + # Generate and format report + ${parsed_results}= RW.CLI.Run Cli + ... cmd=jq -r --arg region "${AWS_REGION}" '["InstanceId", "InstanceType", "ImageId","REGION", "Tags"], (.[] | [ .InstanceId, .InstanceType, .ImageId, $region, (.Tags | map(.Key + "=" + .Value) | join(","))]) | @tsv' ${OUTPUT_DIR}/aws-c7n-ec2-health/unused-ec2-instances/resources.json | column -t + ${formatted_results}= Set Variable Resource Summary:\n${parsed_results.stdout} + RW.Core.Add Pre To Report ${formatted_results} + # Loop through each EC2 instance in the list + FOR ${item} IN @{ec2_instances_list} + RW.Core.Add Issue + ... severity=4 + ... expected=EC2 instance in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` should not be unused for more than `${AWS_EC2_AGE}` days + ... actual=EC2 instance `${item["InstanceId"]}` has been unused for more than `${AWS_EC2_AGE}` days in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` + ... title=Unused EC2 instance `${item["InstanceId"]}` found in AWS Region `${AWS_REGION}` in AWS Account `${AWS_ACCOUNT_ID}` + ... reproduce_hint=${c7n_output.cmd} + ... details=${item} + ... next_steps=Delete unused AWS EC2 instance in AWS Region \`${AWS_REGION}\` in AWS account \`${AWS_ACCOUNT_ID}\` + END + END ** Keywords *** Suite Initialization @@ -76,21 +127,15 @@ Suite Initialization ... type=string ... description=AWS Access Key Secret ... pattern=\w* - ${AWS_EC2_STATE}= RW.Core.Import User Variable AWS_EC2_STATE - ... type=string - ... description=The state of AWS_EC2 instances to filter (e.g., running). - ... pattern=^\d+$ - ... example=running - ... default=running ${AWS_EC2_AGE}= RW.Core.Import User Variable AWS_EC2_AGE ... type=string - ... description=The age of AWS_EC2 instances in days to consider for filtering. + ... description=The age of AWS EC2 instances in days to consider for filtering. ... pattern=^\d+$ ... example=60 ... default=60 ${AWS_EC2_TAGS}= RW.Core.Import User Variable AWS_EC2_TAGS ... type=string - ... description=Comma-separated list of tags to filter AWS_EC2 instances. + ... description=Comma-separated list of tags to filter AWS EC2 instances. ... pattern=^[a-zA-Z0-9,]+$ ... example=Name,Environment ... default= @@ -99,7 +144,6 @@ Suite Initialization ${clean_workding_dir}= RW.CLI.Run Cli cmd=rm -rf ${OUTPUT_DIR}/aws-c7n-ec2-health # Note: Clean out the cloud custoding report dir to ensure accurate data Set Suite Variable ${AWS_EC2_AGE} ${AWS_EC2_AGE} Set Suite Variable ${AWS_EC2_TAGS} ${AWS_EC2_TAGS} - Set Suite Variable ${AWS_EC2_STATE} ${AWS_EC2_STATE} Set Suite Variable ${AWS_REGION} ${AWS_REGION} Set Suite Variable ${AWS_ACCOUNT_ID} ${AWS_ACCOUNT_ID} Set Suite Variable ${AWS_ACCOUNT_NAME} ${aws_account_name_query.stdout} \ No newline at end of file diff --git a/codebundles/aws-c7n-ec2-health/sli.robot b/codebundles/aws-c7n-ec2-health/sli.robot index f568c0e..3b99c6b 100644 --- a/codebundles/aws-c7n-ec2-health/sli.robot +++ b/codebundles/aws-c7n-ec2-health/sli.robot @@ -2,7 +2,7 @@ Metadata Author saurabh3460 Metadata Supports AWS EC2 CloudCustodian Metadata Display Name AWS EC2 Health -Documentation Count the number of EC2 instances with degraded health status in a specified AWS region +Documentation Count the number of EC2 instances that are unpatched or unused Force Tags EC2 Compute AWS Library RW.Core @@ -13,25 +13,46 @@ Suite Setup Suite Initialization *** Tasks *** -Check for old AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` - [Documentation] Check for old EC2 instances in AWS Region. +Check for unpatched AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` + [Documentation] Check for unpatched EC2 instances in AWS Region. [Tags] ec2 instance aws compute ${result}= CloudCustodian.Core.Generate Policy - ... ${CURDIR}/old-ec2-instances.j2 - ... days=${AWS_EC2_AGE} - ... state=${AWS_EC2_STATE} + ... ${CURDIR}/unpatched-ec2-instances.j2 + ... days=${AWS_EC2_AGE} ... tags=${AWS_EC2_TAGS} ${c7n_output}= RW.CLI.Run Cli - ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/old-ec2-instances.yaml --cache-period 0 + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/unpatched-ec2-instances.yaml --cache-period 0 ... secret__aws_access_key_id=${AWS_ACCESS_KEY_ID} ... secret__aws_secret_access_key=${AWS_SECRET_ACCESS_KEY} ${count}= RW.CLI.Run Cli - ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/old-ec2-instances/metadata.json | jq '.metrics[] | select(.MetricName == "ResourceCount") | .Value' + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/unpatched-ec2-instances/metadata.json | jq '.metrics[] | select(.MetricName == "ResourceCount") | .Value' Log ${count} - ${old_ec2_instances_event_score}= Evaluate 1 if int(${count.stdout}) <= int(${EVENT_THRESHOLD}) else 0 - RW.Core.Push Metric ${old_ec2_instances_event_score} + ${unpatched_ec2_instances_event_score}= Evaluate 1 if int(${count.stdout}) <= int(${EVENT_THRESHOLD}) else 0 + Set Global Variable ${unpatched_ec2_instances_event_score} + +Check for unused AWS EC2 instances in AWS Region `${AWS_REGION}` in AWS account `${AWS_ACCOUNT_ID}` + [Documentation] Check for unused EC2 instances in AWS Region. + [Tags] ec2 instance aws compute + ${result}= CloudCustodian.Core.Generate Policy + ... ${CURDIR}/unused-ec2-instances.j2 + ... days=${AWS_EC2_AGE} + ... tags=${AWS_EC2_TAGS} + ${c7n_output}= RW.CLI.Run Cli + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-ec2-health ${CURDIR}/unused-ec2-instances.yaml --cache-period 0 + ... secret__aws_access_key_id=${AWS_ACCESS_KEY_ID} + ... secret__aws_secret_access_key=${AWS_SECRET_ACCESS_KEY} + ${count}= RW.CLI.Run Cli + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-ec2-health/unused-ec2-instances/metadata.json | jq '.metrics[] | select(.MetricName == "ResourceCount") | .Value' + Log ${count} + ${unused_ec2_instances_event_score}= Evaluate 1 if int(${count.stdout}) <= int(${EVENT_THRESHOLD}) else 0 + Set Global Variable ${unused_ec2_instances_event_score} +Generate EBS Score + ${ebs_health_score}= Evaluate (${unpatched_ec2_instances_event_score} + ${unused_ec2_instances_event_score}) / 2 + ${health_score}= Convert to Number ${ebs_health_score} 2 + RW.Core.Push Metric ${health_score} + ** Keywords *** Suite Initialization ${AWS_REGION}= RW.Core.Import User Variable AWS_REGION @@ -52,16 +73,10 @@ Suite Initialization ... pattern=\w* ${EVENT_THRESHOLD}= RW.Core.Import User Variable EVENT_THRESHOLD ... type=string - ... description=The minimum number of old EC2 instance to consider. + ... description=The minimum number of EC2 instance to consider. ... pattern=^\d+$ ... example=2 ... default=0 - ${AWS_EC2_STATE}= RW.Core.Import User Variable AWS_EC2_STATE - ... type=string - ... description=The state of AWS_EC2 instances to filter (e.g., running). - ... pattern=^\d+$ - ... example=running - ... default=running ${AWS_EC2_AGE}= RW.Core.Import User Variable AWS_EC2_AGE ... type=string ... description=The age of AWS_EC2 instances in days to consider for filtering. @@ -77,7 +92,6 @@ Suite Initialization ${clean_workding_dir}= RW.CLI.Run Cli cmd=rm -rf ${OUTPUT_DIR}/aws-c7n-ec2-health # Note: Clean out the cloud custoding report dir to ensure accurate data Set Suite Variable ${AWS_EC2_AGE} ${AWS_EC2_AGE} Set Suite Variable ${AWS_EC2_TAGS} ${AWS_EC2_TAGS} - Set Suite Variable ${AWS_EC2_STATE} ${AWS_EC2_STATE} Set Suite Variable ${AWS_REGION} ${AWS_REGION} Set Suite Variable ${AWS_ACCOUNT_ID} ${AWS_ACCOUNT_ID} Set Suite Variable ${EVENT_THRESHOLD} ${EVENT_THRESHOLD} diff --git a/codebundles/aws-c7n-ec2-health/old-ec2-instances.j2 b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.j2 similarity index 62% rename from codebundles/aws-c7n-ec2-health/old-ec2-instances.j2 rename to codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.j2 index c157fc3..a625b66 100644 --- a/codebundles/aws-c7n-ec2-health/old-ec2-instances.j2 +++ b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.j2 @@ -1,10 +1,10 @@ policies: - - name: old-ec2-instances + - name: unpatched-ec2-instances resource: ec2 comment: | - Report {{ state }} instances older than {{ days }} days + Report unpatched instances older than {{ days }} days filters: - - "State.Name": {{ state }} + - "State.Name": running {%- for tag in tags %} - "tag:{{tag}}": "present" {%- endfor %} diff --git a/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.yaml b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.yaml new file mode 100644 index 0000000..1b322c6 --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.yaml @@ -0,0 +1,10 @@ +policies: + - name: unpatched-ec2-instances + resource: ec2 + comment: | + Report unpatched instances older than 0.00139 days + filters: + - "State.Name": running + - type: instance-age + op: gt + days: 0.00139 \ No newline at end of file diff --git a/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/custodian-run.log b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/custodian-run.log new file mode 100644 index 0000000..0abcd6a --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/custodian-run.log @@ -0,0 +1 @@ +2024-12-19 13:15:15,769 - custodian.policy - INFO - policy:unpatched-ec2-instances resource:ec2 region:us-west-2 count:1 time:1.89 diff --git a/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/metadata.json b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/metadata.json new file mode 100644 index 0000000..ed82700 --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/metadata.json @@ -0,0 +1,81 @@ +{ + "policy": { + "name": "unpatched-ec2-instances", + "resource": "ec2", + "comment": "Report running instances older than 0.00139 days\n", + "filters": [ + { + "State.Name": "running" + }, + { + "type": "instance-age", + "op": "gt", + "days": 0.00139 + } + ] + }, + "version": "0.9.42", + "execution": { + "id": "e6146224-ddf4-4f13-a961-36955e499664", + "start": 1734614113.871247, + "end_time": 1734614115.7713242, + "duration": 1.9000771045684814 + }, + "config": { + "region": "us-west-2", + "regions": [ + "us-west-2" + ], + "cache": "~/.cache/cloud-custodian.cache", + "profile": null, + "account_id": "971422712704", + "assume_role": null, + "session_policy": null, + "external_id": null, + "log_group": null, + "tracer": null, + "metrics_enabled": null, + "metrics": null, + "output_dir": "/home/runwhen/codecollection/codebundles/aws-c7n-ec2-health", + "cache_period": 0, + "dryrun": false, + "authorization_file": null, + "subparser": "run", + "config": null, + "configs": [ + "unpatched-ec2-instances.yaml" + ], + "policy_filters": [], + "resource_types": [], + "verbose": null, + "quiet": null, + "debug": false, + "skip_validation": false, + "command": "c7n.commands.run", + "vars": null + }, + "sys-stats": {}, + "api-stats": { + "ec2.DescribeInstances": 1 + }, + "metrics": [ + { + "MetricName": "ResourceCount", + "Timestamp": "2024-12-19T13:15:15.770326", + "Value": 1, + "Unit": "Count" + }, + { + "MetricName": "ResourceTime", + "Timestamp": "2024-12-19T13:15:15.770349", + "Value": 1.8867526054382324, + "Unit": "Seconds" + }, + { + "MetricName": "ActionTime", + "Timestamp": "2024-12-19T13:15:15.771304", + "Value": 7.867813110351562e-06, + "Unit": "Seconds" + } + ] +} \ No newline at end of file diff --git a/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/resources.json b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/resources.json new file mode 100644 index 0000000..1b05767 --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unpatched-ec2-instances/resources.json @@ -0,0 +1,136 @@ +[ + { + "Architecture": "x86_64", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/xvda", + "Ebs": { + "AttachTime": "2024-12-19T09:50:19+00:00", + "DeleteOnTermination": true, + "Status": "attached", + "VolumeId": "vol-0614c1286b7532529" + } + } + ], + "ClientToken": "terraform-20241219095018188600000001", + "EbsOptimized": false, + "EnaSupport": true, + "Hypervisor": "xen", + "NetworkInterfaces": [ + { + "Attachment": { + "AttachTime": "2024-12-19T09:50:19+00:00", + "AttachmentId": "eni-attach-0947b84e94af6fc0f", + "DeleteOnTermination": true, + "DeviceIndex": 0, + "Status": "attached", + "NetworkCardIndex": 0 + }, + "Description": "", + "Groups": [ + { + "GroupId": "sg-0e759d1c06fb63c4f", + "GroupName": "test-instance-sg" + } + ], + "Ipv6Addresses": [], + "MacAddress": "06:4f:eb:1b:08:97", + "NetworkInterfaceId": "eni-0a6bedf99c7b3b3be", + "OwnerId": "971422712704", + "PrivateIpAddress": "10.0.1.152", + "PrivateIpAddresses": [ + { + "Primary": true, + "PrivateIpAddress": "10.0.1.152" + } + ], + "SourceDestCheck": true, + "Status": "in-use", + "SubnetId": "subnet-082bdf983c5596fcf", + "VpcId": "vpc-05dc7f1dc5222607b", + "InterfaceType": "interface" + } + ], + "RootDeviceName": "/dev/xvda", + "RootDeviceType": "ebs", + "SecurityGroups": [ + { + "GroupId": "sg-0e759d1c06fb63c4f", + "GroupName": "test-instance-sg" + } + ], + "SourceDestCheck": true, + "Tags": [ + { + "Key": "Name", + "Value": "TestInstance" + }, + { + "Key": "ENV", + "Value": "TestInstance" + } + ], + "VirtualizationType": "hvm", + "CpuOptions": { + "CoreCount": 1, + "ThreadsPerCore": 1 + }, + "CapacityReservationSpecification": { + "CapacityReservationPreference": "open" + }, + "HibernationOptions": { + "Configured": false + }, + "MetadataOptions": { + "State": "applied", + "HttpTokens": "optional", + "HttpPutResponseHopLimit": 1, + "HttpEndpoint": "enabled", + "HttpProtocolIpv6": "disabled", + "InstanceMetadataTags": "disabled" + }, + "EnclaveOptions": { + "Enabled": false + }, + "PlatformDetails": "Linux/UNIX", + "UsageOperation": "RunInstances", + "UsageOperationUpdateTime": "2024-12-19T09:50:19+00:00", + "PrivateDnsNameOptions": { + "HostnameType": "ip-name", + "EnableResourceNameDnsARecord": false, + "EnableResourceNameDnsAAAARecord": false + }, + "MaintenanceOptions": { + "AutoRecovery": "default" + }, + "CurrentInstanceBootMode": "legacy-bios", + "InstanceId": "i-067bfad9d95ef2318", + "ImageId": "ami-0caf77f9b87412c51", + "State": { + "Code": 16, + "Name": "running" + }, + "PrivateDnsName": "ip-10-0-1-152.us-west-2.compute.internal", + "PublicDnsName": "", + "StateTransitionReason": "", + "KeyName": "my-ec2-key", + "AmiLaunchIndex": 0, + "ProductCodes": [], + "InstanceType": "t2.micro", + "LaunchTime": "2024-12-19T13:14:08+00:00", + "Placement": { + "GroupName": "", + "Tenancy": "default", + "AvailabilityZone": "us-west-2a" + }, + "Monitoring": { + "State": "disabled" + }, + "SubnetId": "subnet-082bdf983c5596fcf", + "VpcId": "vpc-05dc7f1dc5222607b", + "PrivateIpAddress": "10.0.1.152", + "c7n:MatchedFilters": [ + "State.Name" + ] + } +] \ No newline at end of file diff --git a/codebundles/aws-c7n-ec2-health/unused-ec2-instances.j2 b/codebundles/aws-c7n-ec2-health/unused-ec2-instances.j2 new file mode 100644 index 0000000..106de52 --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unused-ec2-instances.j2 @@ -0,0 +1,13 @@ +policies: + - name: unused-ec2-instances + resource: ec2 + comment: | + Report unused instances older than {{ days }} days + filters: + - "State.Name": stopped + {%- for tag in tags %} + - "tag:{{tag}}": "present" + {%- endfor %} + - type: instance-age + op: gt + days: {{ days }} \ No newline at end of file diff --git a/codebundles/aws-c7n-ec2-health/unused-ec2-instances.yaml b/codebundles/aws-c7n-ec2-health/unused-ec2-instances.yaml new file mode 100644 index 0000000..56cce7a --- /dev/null +++ b/codebundles/aws-c7n-ec2-health/unused-ec2-instances.yaml @@ -0,0 +1,10 @@ +policies: + - name: unused-ec2-instances + resource: ec2 + comment: | + Report unused instances older than 0.00139 days + filters: + - "State.Name": stopped + - type: instance-age + op: gt + days: 0.00139 \ No newline at end of file