├── LICENSE ├── README.md └── terraform-coverage.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 C Tarwater 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 | # DEMO 2 | 3 | ## AWS 4 | 5 | #### US-EAST-1 6 | 7 | ![ec2-instances-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-instances-current-coverage.svg?maxAge=60) ![ec2-sgs-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-security-groups-current-coverage.svg?maxAge=60) ![ec2-ami-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-ami-current-coverage.svg?maxAge=60) ![ec2-volumes-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-volumes-current-coverage.svg?maxAge=60) ![ec2-albs-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-albs-current-coverage.svg?maxAge=60) ![ec2-elbs-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-ec2-elbs-current-coverage.svg?maxAge=60) ![lambda-functions-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-lambda-functions-current-coverage.svg?maxAge=60) ![rds-instances-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-rds-instances-current-coverage.svg?maxAge=60) ![vpcs-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-vpcs-current-coverage.svg?maxAge=60) ![subnets-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-subnets-current-coverage.svg?maxAge=60) ![route-tables-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-route-tables-current-coverage.svg?maxAge=60) ![internet-gateways-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-internet-gateways-current-coverage.svg?maxAge=60) ![dhcp-option-sets-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-dhcp-opts-current-coverage.svg?maxAge=60) ![network-acls-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-network-acls-current-coverage.svg?maxAge=60) ![s3-buckets-coverage](https://s3-us-west-2.amazonaws.com/terraform-infra-as-code-coverage-badges/us-east-1-s3-buckets-current-coverage.svg?maxAge=60) 8 | 9 | # WHAT 10 | A small script that is useful to track the level of 'infrastructure-as-code' coverage; ie how much of your AWS infrastructure is managed by Terraform? 11 | 12 | It checks the following AWS resources: 13 | - EC2 Instances 14 | - EC2 Security Groups 15 | - EC2 AMIs 16 | - EC2 Volumes 17 | - EC2 ALBs 18 | - EC2 ELBs 19 | - Lambda Functions 20 | - RDS Instances 21 | - VPCs 22 | - VPC Subnets 23 | - VPC Route Tables 24 | - VPC IGWs 25 | - VPC DHCP Options 26 | - VPC Network ACLs 27 | - S3 Buckets 28 | 29 | # WHY 30 | It can be difficult track the status of existing AWS resources when attempting to import a large existing project into Terraform managed infrastructure-as-code. One of the challenges is identifying what AWS resources are currently managed by Terraform and which ones still need to be imported. This script is an initial attempt. 31 | 32 | # HOW 33 | A series of bash functions that call the AWS API, performs some basic mathematics as needed, and writes the output to a badge using [http://shields.io/](http://shields.io/) 34 | 35 | - `git clone` this repo 36 | - configure the variables at the top of the script 37 | - run the script 38 | - it will make the AWS API calls, checking all AWS resources in the specified region of your specified account for the existence of the specified tag. 39 | - it will calculate the total number of resources vs the total number of tagged resources 40 | - it will use the output of the above function as the input for the badges.io API to create coverage badges 41 | - it will write the badges to the specified S3 bucket 42 | - you can point to the URL of the S3 badges in order to embed anywhere you want, see above Demo for an example. 43 | 44 | # REQUIREMENTS 45 | - An existing AWS account. 46 | - Permissions: Create S3 bucket 47 | - what else? 48 | - Locally configured [AWS profile](http://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html) with AWS credentials 49 | - AWS resources that are consistently identified via a single tag 50 | - tag is configurable. Our example is "Terraform = True" 51 | - Any resource containing this tag is assumed to be managed via Terraform 52 | - jq 53 | 54 | # FAQ 55 | - Q) Why bash? 56 | - A) I like bash. It's simple and is easy for coders of all levels to contribute to. 57 | - Q) Does this show my coverage for ALL AWS resources? 58 | - A) No. It currently checks for over a dozen resources that 1) support AWS tags & 2) Have Terraform support for reading/writing AWS tags. 59 | - Q) Do you plan on extending this? 60 | - A) Sure, see the TODO section. 61 | 62 | # TODO 63 | [Issues](https://github.com/chrisanthropic/terraform-infra-as-code-coverage-badges/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement) 64 | -------------------------------------------------------------------------------- /terraform-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -euo pipefail 3 | 4 | ### 5 | ## VARS 6 | ### 7 | AWS_PROFILE="default" 8 | AWS_REGION="us-east-1" 9 | MANAGED_TAG="Terraform" 10 | BADGES_S3_BUCKET_NAME="terraform-infra-as-code-coverage-badges" 11 | 12 | ### 13 | ## FUNCTIONS 14 | ### 15 | 16 | # Instances 17 | find_all_instances () { 18 | aws ec2 describe-instances --region $AWS_REGION --profile "${AWS_PROFILE}" --query "Reservations[].Instances[].{ID: InstanceId}" --output text 19 | } 20 | 21 | find_untagged_instances () { 22 | aws ec2 describe-instances --region $AWS_REGION --profile "${AWS_PROFILE}" --query "Reservations[].Instances[].{ID: InstanceId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 23 | } 24 | 25 | create_ec2_instances_badge () { 26 | TOTAL_INSTANCES="$(find_all_instances | wc -l)" 27 | UNTAGGED_INSTANCES="$(find_untagged_instances | wc -l)" 28 | PERCENT_INSTANCES_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_INSTANCES}/${TOTAL_INSTANCES}; i=int(pc); print (pc-i<0.5)?i:i+1 }") 29 | TOTAL_INSTANCES_COVERED=$(( TOTAL_INSTANCES - UNTAGGED_INSTANCES )) 30 | PERCENT_INSTANCES_COVERED=$(( 100 - PERCENT_INSTANCES_REMAINING )) 31 | 32 | if (( $PERCENT_INSTANCES_COVERED == 100 )); then 33 | COLOR=green 34 | elif (( $PERCENT_INSTANCES_COVERED >= 67 )) && (( $PERCENT_INSTANCES_COVERED <= 99 )); then 35 | COLOR=yellow 36 | elif (( $PERCENT_INSTANCES_COVERED >= 34 )) && (( $PERCENT_INSTANCES_COVERED <= 66 )); then 37 | COLOR=orange 38 | else 39 | COLOR=red 40 | fi 41 | 42 | echo "https://img.shields.io/badge/managed--ec2--instances-$PERCENT_INSTANCES_COVERED%25-$COLOR.svg" 43 | } 44 | 45 | write_ec2_instances_badge_to_s3 () { 46 | wget -O '/tmp/ec2-instances-current-coverage.svg' $(create_ec2_instances_badge) >/dev/null 2>&1 47 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-instances-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-instances-current-coverage.svg 48 | } 49 | 50 | # Security Groups 51 | find_all_security_groups () { 52 | aws ec2 describe-security-groups --region $AWS_REGION --profile "${AWS_PROFILE}" --query "SecurityGroups[].{ID: GroupId}" --output text 53 | } 54 | 55 | find_untagged_security_groups () { 56 | aws ec2 describe-security-groups --region $AWS_REGION --profile "${AWS_PROFILE}" --query "SecurityGroups[].{ID: GroupId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 57 | } 58 | 59 | create_ec2_security_groups_badge () { 60 | TOTAL_SGS="$(find_all_security_groups | wc -l)" 61 | UNTAGGED_SGS="$(find_untagged_security_groups | wc -l)" 62 | PERCENT_SGS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_SGS}/${TOTAL_SGS}; i=int(pc); print (pc-i<0.5)?i:i+1 }") 63 | TOTAL_SGS_COVERED=$(( TOTAL_SGS - UNTAGGED_SGS )) 64 | PERCENT_SGS_COVERED=$(( 100 - PERCENT_SGS_REMAINING )) 65 | 66 | if (( $PERCENT_SGS_COVERED == 100 )); then 67 | COLOR=green 68 | elif (( $PERCENT_SGS_COVERED >= 67 )) && (( $PERCENT_SGS_COVERED <= 99 )); then 69 | COLOR=yellow 70 | elif (( $PERCENT_SGS_COVERED >= 34 )) && (( $PERCENT_SGS_COVERED <= 66 )); then 71 | COLOR=orange 72 | else 73 | COLOR=red 74 | fi 75 | 76 | echo "https://img.shields.io/badge/managed--ec2--security--groups-$PERCENT_SGS_COVERED%25-$COLOR.svg" 77 | } 78 | 79 | write_ec2_security_groups_badge_to_s3 () { 80 | wget -O '/tmp/ec2-security-groups-current-coverage.svg' $(create_ec2_security_groups_badge) >/dev/null 2>&1 81 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-security-groups-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-security-groups-current-coverage.svg 82 | } 83 | 84 | # AMIs 85 | find_aws_account_id () { 86 | aws sts get-caller-identity --output text --query 'Account' 87 | } 88 | 89 | find_all_amis () { 90 | aws ec2 describe-images --region $AWS_REGION --profile "${AWS_PROFILE}" --owners $(find_aws_account_id) --query "Images[].ImageId" --output text 91 | } 92 | 93 | find_untagged_amis () { 94 | aws ec2 describe-images --region $AWS_REGION --profile "${AWS_PROFILE}" --owners $(find_aws_account_id) --query "Images[].{ID: ImageId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 95 | } 96 | 97 | create_ec2_amis_badge () { 98 | TOTAL_AMIS="$(find_all_amis | wc -l)" 99 | UNTAGGED_AMIS="$(find_untagged_amis | wc -l)" 100 | PERCENT_AMIS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_AMIS}/${TOTAL_AMIS}; i=int(pc); print (pc-i<0.5)?i:i+1 }") 101 | TOTAL_AMIS_COVERED=$(( TOTAL_AMIS - UNTAGGED_AMIS )) 102 | PERCENT_AMIS_COVERED=$(( 100 - PERCENT_AMIS_REMAINING )) 103 | 104 | if (( $PERCENT_AMIS_COVERED == 100 )); then 105 | COLOR=green 106 | elif (( $PERCENT_AMIS_COVERED >= 67 )) && (( $PERCENT_AMIS_COVERED <= 99 )); then 107 | COLOR=yellow 108 | elif (( $PERCENT_AMIS_COVERED >= 34 )) && (( $PERCENT_AMIS_COVERED <= 66 )); then 109 | COLOR=orange 110 | else 111 | COLOR=red 112 | fi 113 | 114 | echo "https://img.shields.io/badge/managed--ec2--amis-$PERCENT_AMIS_COVERED%25-$COLOR.svg" 115 | } 116 | 117 | write_ec2_amis_badge_to_s3 () { 118 | wget -O '/tmp/ec2-ami-current-coverage.svg' $(create_ec2_amis_badge) >/dev/null 2>&1 119 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-ami-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-ami-current-coverage.svg 120 | } 121 | 122 | # Volumes 123 | find_all_volumes () { 124 | aws ec2 describe-volumes --region $AWS_REGION --profile "${AWS_PROFILE}" --query "Volumes[].{ID: VolumeId}" --output text 125 | } 126 | 127 | find_untagged_volumes () { 128 | aws ec2 describe-volumes --region $AWS_REGION --profile "${AWS_PROFILE}" --query "Volumes[].{ID: VolumeId}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 129 | } 130 | 131 | create_ec2_volumes_badge () { 132 | TOTAL_VOLUMES="$(find_all_volumes | wc -l)" 133 | UNTAGGED_VOLUMES="$(find_untagged_volumes | wc -l)" 134 | PERCENT_VOLUMES_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_VOLUMES}/${TOTAL_VOLUMES}; i=int(pc); print (pc-i<0.5)?i:i+1 }") 135 | TOTAL_VOLUMES_COVERED=$(( TOTAL_VOLUMES - UNTAGGED_VOLUMES )) 136 | PERCENT_VOLUMES_COVERED=$(( 100 - PERCENT_VOLUMES_REMAINING )) 137 | 138 | if (( $PERCENT_VOLUMES_COVERED == 100 )); then 139 | COLOR=green 140 | elif (( $PERCENT_VOLUMES_COVERED >= 67 )) && (( $PERCENT_VOLUMES_COVERED <= 99 )); then 141 | COLOR=yellow 142 | elif (( $PERCENT_VOLUMES_COVERED >= 34 )) && (( $PERCENT_VOLUMES_COVERED <= 66 )); then 143 | COLOR=orange 144 | else 145 | COLOR=red 146 | fi 147 | 148 | echo "https://img.shields.io/badge/managed--ec2--volumes-$PERCENT_VOLUMES_COVERED%25-$COLOR.svg" 149 | } 150 | 151 | write_ec2_volumes_badge_to_s3 () { 152 | wget -O '/tmp/ec2-volumes-current-coverage.svg' $(create_ec2_volumes_badge) >/dev/null 2>&1 153 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-volumes-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-volumes-current-coverage.svg 154 | } 155 | 156 | # ALBs 157 | find_all_albs () { 158 | aws elbv2 describe-load-balancers --region $AWS_REGION --profile "${AWS_PROFILE}" --query "LoadBalancers[].{ID: LoadBalancerArn}" --output text 159 | } 160 | 161 | find_untagged_albs () { 162 | aws elbv2 describe-load-balancers --region $AWS_REGION --profile "${AWS_PROFILE}" --query "LoadBalancers[].{ID: LoadBalancerArn}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 163 | } 164 | 165 | create_ec2_albs_badge () { 166 | TOTAL_ALBS="$(find_all_albs | wc -l)" 167 | UNTAGGED_ALBS="$(find_untagged_albs | wc -l)" 168 | PERCENT_ALBS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_ALBS}/${TOTAL_ALBS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" 2> /dev/null) 169 | TOTAL_ALBS_COVERED=$(( TOTAL_ALBS - UNTAGGED_ALBS )) 170 | PERCENT_ALBS_COVERED=$(( 100 - PERCENT_ALBS_REMAINING )) 171 | 172 | if (( $PERCENT_ALBS_COVERED == 100 )); then 173 | COLOR=green 174 | elif (( $PERCENT_ALBS_COVERED >= 67 )) && (( $PERCENT_ALBS_COVERED <= 99 )); then 175 | COLOR=yellow 176 | elif (( $PERCENT_ALBS_COVERED >= 34 )) && (( $PERCENT_ALBS_COVERED <= 66 )); then 177 | COLOR=orange 178 | else 179 | COLOR=red 180 | fi 181 | 182 | echo "https://img.shields.io/badge/managed--ec2--albs-$PERCENT_ALBS_COVERED%25-$COLOR.svg" 183 | } 184 | 185 | write_ec2_albs_badge_to_s3 () { 186 | wget -O '/tmp/ec2-albs-current-coverage.svg' $(create_ec2_albs_badge) >/dev/null 2>&1 187 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-albs-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-albs-current-coverage.svg 188 | } 189 | 190 | # ELBs 191 | find_all_elbs () { 192 | aws elb describe-load-balancers --region $AWS_REGION --profile "${AWS_PROFILE}" --query "LoadBalancerDescriptions[].{ID: LoadBalancerName}" --output text 193 | } 194 | 195 | find_untagged_elbs () { 196 | UNTAGGED=0 197 | for elb in `find_all_elbs`; do 198 | if 199 | aws elb describe-tags --region $AWS_REGION --profile "${AWS_PROFILE}" --load-balancer-names "${elb}" --query "TagDescriptions[].Tags[].Key" --output text | grep -v $MANAGED_TAG 200 | then 201 | ((UNTAGGED++)) 202 | fi 203 | done 204 | echo $UNTAGGED 205 | } 206 | 207 | create_ec2_elbs_badge () { 208 | TOTAL_ELBS="$(find_all_elbs | wc -l)" 209 | UNTAGGED_ELBS="$(find_untagged_elbs | tail -1)" 210 | PERCENT_ELBS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_ELBS}/${TOTAL_ELBS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" 2> /dev/null) 211 | TOTAL_ELBS_COVERED=$(( TOTAL_ELBS - UNTAGGED_ELBS )) 212 | PERCENT_ELBS_COVERED=$(( 100 - PERCENT_ELBS_REMAINING )) 213 | 214 | if (( $PERCENT_ELBS_COVERED == 100 )); then 215 | COLOR=green 216 | elif (( $PERCENT_ELBS_COVERED >= 67 )) && (( $PERCENT_ELBS_COVERED <= 99 )); then 217 | COLOR=yellow 218 | elif (( $PERCENT_ELBS_COVERED >= 34 )) && (( $PERCENT_ELBS_COVERED <= 66 )); then 219 | COLOR=orange 220 | else 221 | COLOR=red 222 | fi 223 | 224 | echo "https://img.shields.io/badge/managed--ec2--elbs-$PERCENT_ELBS_COVERED%25-$COLOR.svg" 225 | } 226 | 227 | write_ec2_elbs_badge_to_s3 () { 228 | wget -O '/tmp/ec2-elbs-current-coverage.svg' $(create_ec2_elbs_badge) >/dev/null 2>&1 229 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/ec2-elbs-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-ec2-elbs-current-coverage.svg 230 | } 231 | 232 | # S3 Buckets 233 | find_all_buckets () { 234 | BUCKET_LIST=$(aws s3api list-buckets --region $AWS_REGION --profile "${AWS_PROFILE}" --query "Buckets[].Name" --output text) 235 | echo $BUCKET_LIST | tr " " "\n" 236 | } 237 | 238 | find_untagged_s3_buckets () { 239 | for bucket in `find_all_buckets`; do 240 | if 241 | ! aws s3api get-bucket-tagging --region $AWS_REGION --profile "${AWS_PROFILE}" --bucket $bucket --query "TagSet[].Key[]" 2> /dev/null | sed 's/[][]//g' | grep -v $MANAGED_TAG 242 | then 243 | ((UNTAGGED++)) 244 | fi 245 | done 246 | echo $UNTAGGED 247 | } 248 | 249 | create_s3_buckets_badge () { 250 | TOTAL_BUCKETS="$(find_all_buckets | wc -l)" 251 | UNTAGGED_BUCKETS="$(find_untagged_s3_buckets | tail -1)" 252 | 253 | PERCENT_BUCKETS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_BUCKETS}/${TOTAL_BUCKETS}; i=int(pc); print (pc-i<0.5)?i:i+1 }") 254 | TOTAL_BUCKETS_COVERED=$(( TOTAL_BUCKETS - UNTAGGED_BUCKETS )) 255 | PERCENT_BUCKETS_COVERED=$(( 100 - PERCENT_BUCKETS_REMAINING )) 256 | 257 | if (( $PERCENT_BUCKETS_COVERED == 100 )); then 258 | COLOR=green 259 | elif (( $PERCENT_BUCKETS_COVERED >= 67 )) && (( $PERCENT_BUCKETS_COVERED <= 99 )); then 260 | COLOR=yellow 261 | elif (( $PERCENT_BUCKETS_COVERED >= 34 )) && (( $PERCENT_BUCKETS_COVERED <= 66 )); then 262 | COLOR=orange 263 | else 264 | COLOR=red 265 | fi 266 | 267 | echo "https://img.shields.io/badge/managed--s3--buckets-$PERCENT_BUCKETS_COVERED%25-$COLOR.svg" 268 | } 269 | 270 | write_s3_buckets_badge_to_s3 () { 271 | wget -O '/tmp/s3-buckets-current-coverage.svg' $(create_s3_buckets_badge) >/dev/null 2>&1 272 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/s3-buckets-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-s3-buckets-current-coverage.svg 273 | } 274 | 275 | # Lambda Functions 276 | find_all_lambda_functions () { 277 | aws lambda list-functions --profile "${AWS_PROFILE}" --region $AWS_REGION --query "Functions[].{ID: FunctionArn}" --output text 278 | } 279 | 280 | find_untagged_lambda_functions () { 281 | for func in `find_all_lambda_functions`; do 282 | if 283 | ! aws lambda list-functions --profile "${AWS_PROFILE}" --region $AWS_REGION --query "TagDescriptions[].Tags[].Key" | sed 's/[][]//g' | grep -v $MANAGED_TAG 284 | then 285 | ((UNTAGGED++)) 286 | fi 287 | done 288 | echo $UNTAGGED 289 | } 290 | 291 | create_lambda_functions_badge () { 292 | TOTAL_FUNCS="$(find_all_lambda_functions| wc -l)" 293 | UNTAGGED_FUNCS="$(find_untagged_lambda_functions | tail -1)" 294 | PERCENT_FUNCS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_FUNCS}/${TOTAL_FUNCS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" 2> /dev/null) 295 | TOTAL_FUNCS_COVERED=$(( TOTAL_FUNCS - UNTAGGED_FUNCS )) 296 | PERCENT_FUNCS_COVERED=$(( 100 - PERCENT_FUNCS_REMAINING )) 297 | 298 | if (( $PERCENT_FUNCS_COVERED == 100 )); then 299 | COLOR=green 300 | elif (( $PERCENT_FUNCS_COVERED >= 67 )) && (( $PERCENT_FUNCS_COVERED <= 99 )); then 301 | COLOR=yellow 302 | elif (( $PERCENT_FUNCS_COVERED >= 34 )) && (( $PERCENT_FUNCS_COVERED <= 66 )); then 303 | COLOR=orange 304 | else 305 | COLOR=red 306 | fi 307 | 308 | echo "https://img.shields.io/badge/managed--lambda--functions-$PERCENT_FUNCS_COVERED%25-$COLOR.svg" 309 | } 310 | 311 | write_lambda_functions_badge_to_s3 () { 312 | wget -O '/tmp/lambda-functions-current-coverage.svg' $(create_lambda_functions_badge) >/dev/null 2>&1 313 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/lambda-functions-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-lambda-functions-current-coverage.svg 314 | } 315 | 316 | # RDS 317 | find_all_rds_instances () { 318 | aws rds describe-db-instances --profile "${AWS_PROFILE}" --region $AWS_REGION --query "DBInstances[].{ID: DBInstanceArn}" --output text 319 | } 320 | 321 | find_untagged_rds_instances () { 322 | for db in `find_all_rds_instances`; do 323 | if 324 | ! aws rds list-tags-for-resource --profile "${AWS_PROFILE}" --region $AWS_REGION --resource-name $db --query "TagList[].Key" | grep -v $MANAGED_TAG 325 | then 326 | ((UNTAGGED++)) 327 | fi 328 | done 329 | echo $UNTAGGED 330 | } 331 | 332 | create_rds_instances_badge () { 333 | TOTAL_RDS="$(find_all_rds_instances | wc -l)" 334 | UNTAGGED_RDS="$(find_untagged_rds_instances | tail -1)" 335 | PERCENT_RDS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_RDS}/${TOTAL_RDS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" 2> /dev/null) 336 | TOTAL_RDS_COVERED=$(( TOTAL_RDS - UNTAGGED_RDS )) 337 | PERCENT_RDS_COVERED=$(( 100 - PERCENT_RDS_REMAINING )) 338 | 339 | if (( $PERCENT_RDS_COVERED == 100 )); then 340 | COLOR=green 341 | elif (( $PERCENT_RDS_COVERED >= 67 )) && (( $PERCENT_RDS_COVERED <= 99 )); then 342 | COLOR=yellow 343 | elif (( $PERCENT_RDS_COVERED >= 34 )) && (( $PERCENT_RDS_COVERED <= 66 )); then 344 | COLOR=orange 345 | else 346 | COLOR=red 347 | fi 348 | 349 | echo "https://img.shields.io/badge/managed--rds--instances-$PERCENT_RDS_COVERED%25-$COLOR.svg" 350 | } 351 | 352 | write_rds_instances_badge_to_s3 () { 353 | wget -O '/tmp/rds-instances-current-coverage.svg' $(create_rds_instances_badge) >/dev/null 2>&1 354 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/rds-instances-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-rds-instances-current-coverage.svg 355 | } 356 | 357 | # VPC 358 | find_all_vpcs () { 359 | aws ec2 describe-vpcs --profile "${AWS_PROFILE}" --region $AWS_REGION --query "Vpcs[].{ID: VpcId}" --output text 360 | } 361 | 362 | find_untagged_vpcs () { 363 | aws ec2 describe-vpcs --profile "${AWS_PROFILE}" --region $AWS_REGION --query "Vpcs[].{ID: VpcId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 364 | } 365 | 366 | create_vpc_badge () { 367 | TOTAL_VPC="$(find_all_vpcs| wc -l)" 368 | UNTAGGED_VPC="$(find_untagged_vpcs | wc -l)" 369 | PERCENT_VPC_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_VPC}/${TOTAL_VPC}; i=int(pc); print (pc-i<0.5)?i:i+1 }" 2> /dev/null) 370 | TOTAL_VPC_COVERED=$(( TOTAL_VPC - UNTAGGED_VPC )) 371 | PERCENT_VPC_COVERED=$(( 100 - PERCENT_VPC_REMAINING )) 372 | 373 | if (( $PERCENT_VPC_COVERED == 100 )); then 374 | COLOR=green 375 | elif (( $PERCENT_VPC_COVERED >= 67 )) && (( $PERCENT_VPC_COVERED <= 99 )); then 376 | COLOR=yellow 377 | elif (( $PERCENT_VPC_COVERED >= 34 )) && (( $PERCENT_VPC_COVERED <= 66 )); then 378 | COLOR=orange 379 | else 380 | COLOR=red 381 | fi 382 | 383 | echo "https://img.shields.io/badge/managed--vpcs-$PERCENT_VPC_COVERED%25-$COLOR.svg" 384 | } 385 | 386 | write_vpcs_badge_to_s3 () { 387 | wget -O '/tmp/vpcs-current-coverage.svg' $(create_vpc_badge) >/dev/null 2>&1 388 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/vpcs-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-vpcs-current-coverage.svg 389 | } 390 | 391 | # SUBNETS 392 | find_all_subnets () { 393 | aws ec2 describe-subnets --profile "${AWS_PROFILE}" --region $AWS_REGION --query "Subnets[].{ID: SubnetId}" --output text 394 | } 395 | 396 | find_untagged_subnets () { 397 | aws ec2 describe-subnets --profile "${AWS_PROFILE}" --region $AWS_REGION --query "Subnets[].{ID: SubnetId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 398 | } 399 | 400 | create_subnets_badge () { 401 | TOTAL_SUBNETS="$(find_all_subnets| wc -l)" 402 | UNTAGGED_SUBNETS="$(find_untagged_subnets | wc -l)" 403 | PERCENT_SUBNETS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_SUBNETS}/${TOTAL_SUBNETS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) 404 | TOTAL_SUBNETS_COVERED=$(( TOTAL_SUBNETS - UNTAGGED_SUBNETS )) 405 | PERCENT_SUBNETS_COVERED=$(( 100 - PERCENT_SUBNETS_REMAINING )) 406 | 407 | if (( $PERCENT_SUBNETS_COVERED == 100 )); then 408 | COLOR=green 409 | elif (( $PERCENT_SUBNETS_COVERED >= 67 )) && (( $PERCENT_SUBNETS_COVERED <= 99 )); then 410 | COLOR=yellow 411 | elif (( $PERCENT_SUBNETS_COVERED >= 34 )) && (( $PERCENT_SUBNETS_COVERED <= 66 )); then 412 | COLOR=orange 413 | else 414 | COLOR=red 415 | fi 416 | 417 | echo "https://img.shields.io/badge/managed--subnets-$PERCENT_SUBNETS_COVERED%25-$COLOR.svg" 418 | } 419 | 420 | write_subnets_badge_to_s3 () { 421 | wget -O '/tmp/subnets-current-coverage.svg' $(create_subnets_badge) >/dev/null 2>&1 422 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/subnets-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-subnets-current-coverage.svg 423 | } 424 | 425 | # ROUTE_TABLES 426 | find_all_route_tables () { 427 | aws ec2 describe-route-tables --profile "${AWS_PROFILE}" --region $AWS_REGION --query "RouteTables[].{ID: RouteTableId}" --output text 428 | } 429 | 430 | find_untagged_route_tables () { 431 | aws ec2 describe-route-tables --profile "${AWS_PROFILE}" --region $AWS_REGION --query "RouteTables[].{ID: RouteTableId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 432 | } 433 | 434 | create_route_tables_badge () { 435 | TOTAL_ROUTE_TABLES="$(find_all_route_tables| wc -l)" 436 | UNTAGGED_ROUTE_TABLES="$(find_untagged_route_tables | wc -l)" 437 | PERCENT_ROUTE_TABLES_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_ROUTE_TABLES}/${TOTAL_ROUTE_TABLES}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) 438 | TOTAL_ROUTE_TABLES_COVERED=$(( TOTAL_ROUTE_TABLES - UNTAGGED_ROUTE_TABLES )) 439 | PERCENT_ROUTE_TABLES_COVERED=$(( 100 - PERCENT_ROUTE_TABLES_REMAINING )) 440 | 441 | if (( $PERCENT_ROUTE_TABLES_COVERED == 100 )); then 442 | COLOR=green 443 | elif (( $PERCENT_ROUTE_TABLES_COVERED >= 67 )) && (( $PERCENT_ROUTE_TABLES_COVERED <= 99 )); then 444 | COLOR=yellow 445 | elif (( $PERCENT_ROUTE_TABLES_COVERED >= 34 )) && (( $PERCENT_ROUTE_TABLES_COVERED <= 66 )); then 446 | COLOR=orange 447 | else 448 | COLOR=red 449 | fi 450 | 451 | echo "https://img.shields.io/badge/managed--route--tables-$PERCENT_ROUTE_TABLES_COVERED%25-$COLOR.svg" 452 | } 453 | 454 | write_route_tables_badge_to_s3 () { 455 | wget -O '/tmp/route-tables-current-coverage.svg' $(create_route_tables_badge) >/dev/null 2>&1 456 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/route-tables-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-route-tables-current-coverage.svg 457 | } 458 | # INTERNET GATEWAY 459 | find_all_igws () { 460 | aws ec2 describe-internet-gateways --profile "${AWS_PROFILE}" --region $AWS_REGION --query "InternetGateways[].{ID: InternetGatewayId}" --output text 461 | } 462 | 463 | find_untagged_igws () { 464 | aws ec2 describe-internet-gateways --profile "${AWS_PROFILE}" --region $AWS_REGION --query "InternetGateways[].{ID: InternetGatewayId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 465 | } 466 | 467 | create_igws_badge () { 468 | TOTAL_IGWS="$(find_all_igws | wc -l)" 469 | UNTAGGED_IGWS="$(find_untagged_igws | wc -l)" 470 | PERCENT_IGWS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_IGWS}/${TOTAL_IGWS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) 471 | TOTAL_IGWS_COVERED=$(( TOTAL_IGWS - UNTAGGED_IGWS )) 472 | PERCENT_IGWS_COVERED=$(( 100 - PERCENT_IGWS_REMAINING )) 473 | 474 | if (( $PERCENT_IGWS_COVERED == 100 )); then 475 | COLOR=green 476 | elif (( $PERCENT_IGWS_COVERED >= 67 )) && (( $PERCENT_IGWS_COVERED <= 99 )); then 477 | COLOR=yellow 478 | elif (( $PERCENT_IGWS_COVERED >= 34 )) && (( $PERCENT_IGWS_COVERED <= 66 )); then 479 | COLOR=orange 480 | else 481 | COLOR=red 482 | fi 483 | 484 | echo "https://img.shields.io/badge/managed--internet--gateways-$PERCENT_IGWS_COVERED%25-$COLOR.svg" 485 | } 486 | 487 | write_igws_badge_to_s3 () { 488 | wget -O '/tmp/internet-gateways-current-coverage.svg' $(create_igws_badge) >/dev/null 2>&1 489 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/internet-gateways-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-internet-gateways-current-coverage.svg 490 | } 491 | 492 | # DHCP OPTION SETS 493 | find_all_dhcp_opts () { 494 | aws ec2 describe-dhcp-options --profile "${AWS_PROFILE}" --region $AWS_REGION --query "DhcpOptions[].{ID: DhcpOptionsId}" --output text 495 | } 496 | 497 | find_untagged_dhcp_opts () { 498 | aws ec2 describe-dhcp-options --profile "${AWS_PROFILE}" --region $AWS_REGION --query "DhcpOptions[].{ID: DhcpOptionsId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 499 | } 500 | 501 | create_dhcp_opts_badge () { 502 | TOTAL_DHCP_OPTS="$(find_all_dhcp_opts | wc -l)" 503 | UNTAGGED_DHCP_OPTS="$(find_untagged_dhcp_opts | wc -l)" 504 | PERCENT_DHCP_OPTS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_DHCP_OPTS}/${TOTAL_DHCP_OPTS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) 505 | TOTAL_DHCP_OPTS_COVERED=$(( TOTAL_DHCP_OPTS - UNTAGGED_DHCP_OPTS )) 506 | PERCENT_DHCP_OPTS_COVERED=$(( 100 - PERCENT_DHCP_OPTS_REMAINING )) 507 | 508 | if (( $PERCENT_DHCP_OPTS_COVERED == 100 )); then 509 | COLOR=green 510 | elif (( $PERCENT_DHCP_OPTS_COVERED >= 67 )) && (( $PERCENT_DHCP_OPTS_COVERED <= 99 )); then 511 | COLOR=yellow 512 | elif (( $PERCENT_DHCP_OPTS_COVERED >= 34 )) && (( $PERCENT_DHCP_OPTS_COVERED <= 66 )); then 513 | COLOR=orange 514 | else 515 | COLOR=red 516 | fi 517 | 518 | echo "https://img.shields.io/badge/managed--dhcp--option--sets-$PERCENT_DHCP_OPTS_COVERED%25-$COLOR.svg" 519 | } 520 | 521 | write_dhcp_opts_badge_to_s3 () { 522 | wget -O '/tmp/dhcp-opts-current-coverage.svg' $(create_dhcp_opts_badge) >/dev/null 2>&1 523 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/dhcp-opts-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-dhcp-opts-current-coverage.svg 524 | } 525 | 526 | # NETWORK ACLS 527 | find_all_network_acls () { 528 | aws ec2 describe-network-acls --profile "${AWS_PROFILE}" --region $AWS_REGION --query "NetworkAcls[].{ID: NetworkAclId}" --output text 529 | } 530 | 531 | find_untagged_network_acls () { 532 | aws ec2 describe-network-acls --profile "${AWS_PROFILE}" --region $AWS_REGION --query "NetworkAcls[].{ID: NetworkAclId, Tag: Tags[].Key}" --output json | jq -c '.[]' | grep -v $MANAGED_TAG 533 | } 534 | 535 | create_network_acls_badge () { 536 | TOTAL_NETWORK_ACLS="$(find_all_network_acls| wc -l)" 537 | UNTAGGED_NETWORK_ACLS="$(find_untagged_network_acls | wc -l)" 538 | PERCENT_NETWORK_ACLS_REMAINING=$(awk "BEGIN { pc=100*${UNTAGGED_NETWORK_ACLS}/${TOTAL_NETWORK_ACLS}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) 539 | TOTAL_NETWORK_ACLS_COVERED=$(( TOTAL_NETWORK_ACLS - UNTAGGED_NETWORK_ACLS )) 540 | PERCENT_NETWORK_ACLS_COVERED=$(( 100 - PERCENT_NETWORK_ACLS_REMAINING )) 541 | 542 | if (( $PERCENT_NETWORK_ACLS_COVERED == 100 )); then 543 | COLOR=green 544 | elif (( $PERCENT_NETWORK_ACLS_COVERED >= 67 )) && (( $PERCENT_NETWORK_ACLS_COVERED <= 99 )); then 545 | COLOR=yellow 546 | elif (( $PERCENT_NETWORK_ACLS_COVERED >= 34 )) && (( $PERCENT_NETWORK_ACLS_COVERED <= 66 )); then 547 | COLOR=orange 548 | else 549 | COLOR=red 550 | fi 551 | 552 | echo "https://img.shields.io/badge/managed--network--acls-$PERCENT_NETWORK_ACLS_COVERED%25-$COLOR.svg" 553 | } 554 | 555 | write_network_acls_badge_to_s3 () { 556 | wget -O '/tmp/network-acls-current-coverage.svg' $(create_network_acls_badge) >/dev/null 2>&1 557 | aws s3 mv --profile "${AWS_PROFILE}" --quiet --acl public-read --cache-control max-age=60 /tmp/network-acls-current-coverage.svg s3://"$BADGES_S3_BUCKET_NAME"/"$AWS_REGION"-network-acls-current-coverage.svg 558 | } 559 | 560 | # CLOUDFRONT 561 | find_all_cloudfront_distros () { 562 | aws cloudfront list-distributions --profile "${AWS_PROFILE}" --region $AWS_REGION 563 | } 564 | 565 | ### 566 | ## What DO? 567 | ### 568 | 569 | write_ec2_instances_badge_to_s3 & 570 | write_ec2_security_groups_badge_to_s3 & 571 | write_ec2_amis_badge_to_s3 & 572 | write_ec2_volumes_badge_to_s3 & 573 | write_ec2_albs_badge_to_s3 & 574 | write_ec2_elbs_badge_to_s3 & 575 | write_lambda_functions_badge_to_s3 & 576 | write_rds_instances_badge_to_s3 & 577 | write_vpcs_badge_to_s3 & 578 | write_subnets_badge_to_s3 & 579 | write_route_tables_badge_to_s3 & 580 | write_igws_badge_to_s3 & 581 | write_dhcp_opts_badge_to_s3 & 582 | write_network_acls_badge_to_s3 & 583 | write_s3_buckets_badge_to_s3 584 | 585 | ### 586 | ## WHAT NEXT? 587 | ### 588 | 589 | ## CLOUDFRONT DISTROS 590 | #find_all_cloudfront_distros 591 | 592 | ## CLOUDTRAIL TRAILS 593 | ## SQS 594 | 595 | --------------------------------------------------------------------------------