Disclaimer: I’m not a REGEX expert :smile:
Lately, I was working for one of my customers on a custom configuration of AWS Config recorder.
My customer wanted to record using AWS Config All resources except a few of them:
'AWS::EC2::Subnet'
'AWS::EC2::VPC'
'AWS::EC2::SecurityGroup'
Unfortunately, the AWS API and Console do not allow you to do this, you should cherry-pick manually which resource you want to record.
The trade-off of this method is that if a new AWS Config resource type came out, it won’t be recorded until you manually select it in your AWS Config recorder setting.
To deal with this, I’ve created a very simple python script that is using AWS documentation web-scraping to extract supported resource types, and then apply all resources except those which are blacklisted by my customer.
The idea is to schedule this script once a week to be up-to-date.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
import boto3
import re
from urllib.request import urlopen
import logging
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/config.html#ConfigService.Client.put_configuration_recorder
# Purpose:
# Activate Custom AWS Record for AWS Config
# Supported resource type: https://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources
# Scraping AWS Docs using: https://realpython.com/python-web-scraping-practical-introduction/
# Get information about the current regional config recorder: aws configservice describe-configuration-recorders --region eu-west-1
# Logging
root = logging.getLogger()
if root.handlers:
for handler in root.handlers:
root.removeHandler(handler)
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',level=logging.INFO)
recorder_name = "<AWS Config recorder name>"
role_arn = "<role arn used for AWS Config>"
# Put here the AWS Config resources type to exclude
exclusion_list = [
'AWS::EC2::Subnet',
'AWS::EC2::VPC',
'AWS::EC2::SecurityGroup'
]
def get_config_resources():
url = "https://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources"
page = urlopen(url)
html = page.read().decode("utf-8")
# Target format: AWS::ApiGateway::Stage
pattern = "AWS::.*"
match_results = re.findall(pattern, html)
cleaned_list = []
count = 0
for result in match_results:
# remove HTML tags
results = re.sub("<.*?>", "", result)
# remove ending *
results = results.replace("*", "")
# remove space
results = results.replace(" ", "")
# remove long items (sentences)
if len(results) >= 60:
continue
# distinct list while preserving order
list(dict.fromkeys(results))
# Count items
count += 1
# Create the target cleaned list
cleaned_list.append(results)
logging.info("Scraped Config supported resources: %s", count)
return cleaned_list
def apply_custom_recorder(config_resources):
# Remove excluded resources from the globql list
result_list = list(set(config_resources) - set(exclusion_list))
# counter
count_result = 0
# Count resulted number of resource types (minus excluded types)
for type in result_list:
count_result += 1
logging.info("result_types: %s", count_result)
client = boto3.client('config')
try:
r = client.put_configuration_recorder(
ConfigurationRecorder={
'name': recorder_name,
'roleARN': role_arn,
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': result_list
}
}
)
except Exception as e:
logging.error(e)
logging.info("Response: %s", r)
if __name__ == "__main__":
config_resources = get_config_resources()
apply_custom_recorder(config_resources)
|
Gist version if you want to contribute.
I think this approach could help someone else, so I’m sharing it with you. Don’t hesitate to comment, and enhance it as you like.
That’s all folks!
zoph.