Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
saurabh3460 committed Dec 19, 2024
1 parent 0c65a84 commit 0011355
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 51 deletions.
104 changes: 74 additions & 30 deletions codebundles/aws-c7n-ec2-health/runbook.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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=
Expand All @@ -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}
50 changes: 32 additions & 18 deletions codebundles/aws-c7n-ec2-health/sli.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 %}
Expand Down
10 changes: 10 additions & 0 deletions codebundles/aws-c7n-ec2-health/unpatched-ec2-instances.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
Loading

0 comments on commit 0011355

Please sign in to comment.