1
+ variable "region_id" {
2
+ type = string
3
+ default = " cn-shenzhen"
4
+ }
5
+
6
+ provider "alicloud" {
7
+ region = var. region_id
8
+ }
9
+
10
+ resource "local_file" "python_script" {
11
+ content = << EOF
12
+ #!/usr/bin/env python
13
+ # -*- encoding: utf-8 -*-
14
+ import sys
15
+ sys.path.append('/opt/python')
16
+ import json
17
+ import logging
18
+ import jmespath # 使用jmespath代替jsonpath
19
+ from aliyunsdkcore.client import AcsClient
20
+ from aliyunsdkcore.auth.credentials import AccessKeyCredential
21
+ from aliyunsdkcore.auth.credentials import StsTokenCredential
22
+ from aliyunsdkcore.request import CommonRequest
23
+
24
+
25
+ logger = logging.getLogger()
26
+
27
+
28
+ def handler(event, context):
29
+ logger.info(f"This is event: {str(event, encoding='utf-8')}")
30
+ get_resources_non_compliant(event, context)
31
+
32
+
33
+ def get_resources_non_compliant(event, context):
34
+ # 获取不合规的资源信息
35
+ resources = parse_json(event)
36
+ # 遍历不合规资源,进行修正操作
37
+ for resource in resources:
38
+ remediation(resource, context)
39
+
40
+
41
+ def parse_json(content):
42
+ """
43
+ Parse string to json object
44
+ :param content: json string content
45
+ :return: Json object
46
+ """
47
+ try:
48
+ return json.loads(content)
49
+ except Exception as e:
50
+ logger.error('Parse content:{} to json error:{}.'.format(content, e))
51
+ return None
52
+
53
+
54
+ def remediation(resource, context):
55
+ logger.info(f"需要修复的资源信息: {resource}")
56
+ region_id = resource['regionId']
57
+ account_id = resource['accountId']
58
+ resource_id = resource['resourceId']
59
+ resource_type = resource['resourceType']
60
+ if resource_type == 'ACS::ECS::SecurityGroup' :
61
+ # 获取不合规安全组的配置信息,重新校验,确保不合规安全组的评估准确性
62
+ resource_result = get_discovered_resource(context, resource_id, resource_type, region_id)
63
+ resource_json = json.loads(resource_result)
64
+ configuration = json.loads(resource_json["DiscoveredResourceDetail"]["Configuration"])
65
+ # 判断是否是托管的安全组
66
+ is_managed_security_group = configuration.get('ServiceManaged')
67
+ # 使用jmespath获取入方向为接受且授权0.0.0.0/0的安全组规则id
68
+ delete_security_group_rule_ids = jmespath.search(
69
+ "Permissions.Permission[?SourceCidrIp=='0.0.0.0/0'].SecurityGroupRuleId",
70
+ configuration
71
+ )
72
+ # 非托管的安全组,且授权了0.0.0.0/0的入方向安全组规则,则删除
73
+ if is_managed_security_group is False and delete_security_group_rule_ids:
74
+ logger.info(f"注意:删除安全组规则 {region_id}:{resource_id}:{delete_security_group_rule_ids}")
75
+ revoke_security_group(context, region_id, resource_id, delete_security_group_rule_ids)
76
+
77
+ def revoke_security_group(context, region_id, resource_id, security_group_rule_ids):
78
+ creds = context.credentials
79
+ client = AcsClient(creds.access_key_id, creds.access_key_secret, region_id=region_id)
80
+ request = CommonRequest()
81
+ request.set_accept_format('json')
82
+ request.set_domain(f'ecs.{region_id}.aliyuncs.com')
83
+ request.set_method('POST')
84
+ request.set_protocol_type('https') # https | http
85
+ request.set_version('2014-05-26')
86
+ request.set_action_name('RevokeSecurityGroup')
87
+ request.add_query_param('RegionId', region_id)
88
+ for index, value in enumerate(security_group_rule_ids):
89
+ request.add_query_param(f'SecurityGroupRuleId.{index + 1}', value)
90
+ request.add_query_param('SecurityGroupId', resource_id)
91
+ request.add_query_param('SecurityToken', creds.security_token)
92
+
93
+ response = client.do_action_with_exception(request)
94
+ logger.info(f"删除结果: {str(response, encoding='utf-8')}")
95
+
96
+
97
+ # 获取资源详情
98
+ def get_discovered_resource(context, resource_id, resource_type, region_id):
99
+ """
100
+ 调用API获取资源配置详情
101
+ :param context:函数计算上下文
102
+ :param resource_id:资源ID
103
+ :param resource_type:资源类型
104
+ :param region_id:资源所属地域ID
105
+ :return: 资源详情
106
+ """
107
+ # 需具备权限AliyunConfigFullAccess的函数计算FC的服务角色。
108
+ creds = context.credentials
109
+ client = AcsClient(creds.access_key_id, creds.access_key_secret, region_id='cn-shanghai')
110
+
111
+ request = CommonRequest()
112
+ request.set_domain('config.cn-shanghai.aliyuncs.com')
113
+ request.set_version('2020-09-07')
114
+ request.set_action_name('GetDiscoveredResource')
115
+ request.add_query_param('ResourceId', resource_id)
116
+ request.add_query_param('ResourceType', resource_type)
117
+ request.add_query_param('Region', region_id)
118
+ request.add_query_param('SecurityToken', creds.security_token)
119
+ request.set_method('GET')
120
+
121
+ try:
122
+ response = client.do_action_with_exception(request)
123
+ resource_result = str(response, encoding='utf-8')
124
+ return resource_result
125
+ except Exception as e:
126
+ logger.error('GetDiscoveredResource error: %s' % e)
127
+ EOF
128
+ filename = " ${ path . module } /python/index.py"
129
+ }
130
+
131
+ resource "local_file" "requirements_txt" {
132
+ content = << EOF
133
+ aliyun-python-sdk-core==2.15.2
134
+ jmespath>=0.10.0
135
+ EOF
136
+ filename = " ${ path . module } /python/requests/requirements.txt"
137
+ }
138
+
139
+ locals {
140
+ code_dir = " ${ path . module } /python/"
141
+ archive_output = " ${ path . module } /code.zip"
142
+ base64_output = " ${ path . module } /code_base64.txt"
143
+ }
144
+
145
+ data "archive_file" "code_package" {
146
+ type = " zip"
147
+ source_dir = local. code_dir
148
+ output_path = local. archive_output
149
+
150
+ depends_on = [
151
+ local_file . python_script ,
152
+ local_file . requirements_txt ,
153
+ ]
154
+ }
155
+
156
+ resource "null_resource" "upload_code" {
157
+ provisioner "local-exec" {
158
+ command = << EOT
159
+ base64 -w 0 ${ local . archive_output } > ${ local . base64_output }
160
+ EOT
161
+
162
+ interpreter = [" sh" , " -c" ]
163
+ }
164
+
165
+ depends_on = [data . archive_file . code_package ]
166
+ }
167
+
168
+ data "local_file" "base64_encoded_code" {
169
+ filename = local. base64_output
170
+ depends_on = [null_resource. upload_code ]
171
+ }
172
+
173
+ resource "alicloud_fcv3_function" "fc_function" {
174
+ runtime = " python3.10"
175
+ handler = " index.handler"
176
+ function_name = " HHM-FC-TEST"
177
+ role = alicloud_ram_role. role . arn
178
+ code {
179
+ zip_file = data. local_file . base64_encoded_code . content
180
+ }
181
+
182
+ depends_on = [data . local_file . base64_encoded_code ]
183
+ }
184
+
185
+ resource "alicloud_config_rule" "default" {
186
+ rule_name = " SPM0014安全组不允许对全部网段开启风险端口"
187
+ description = " 禁止安全组对所有网段开放风险端口22, 3389"
188
+ source_owner = " ALIYUN"
189
+ source_identifier = " sg-risky-ports-check"
190
+ resource_types_scope = [" ACS::ECS::SecurityGroup" ]
191
+ config_rule_trigger_types = " ConfigurationItemChangeNotification,ScheduledNotification"
192
+ maximum_execution_frequency = " One_Hour"
193
+ risk_level = 1
194
+
195
+ input_parameters = {
196
+ " ports" : " 22,3389"
197
+ }
198
+ }
199
+
200
+ resource "alicloud_config_remediation" "default" {
201
+ config_rule_id = alicloud_config_rule. default . id
202
+ remediation_template_id = alicloud_fcv3_function. fc_function . function_arn
203
+ remediation_source_type = " CUSTOM"
204
+ invoke_type = " AUTO_EXECUTION"
205
+ params = " {}"
206
+ remediation_type = " FC"
207
+ }
208
+
209
+ resource "random_integer" "default" {
210
+ min = 10000
211
+ max = 99999
212
+ }
213
+
214
+ resource "alicloud_ram_role" "role" {
215
+ name = " tf-example-role-${ random_integer . default . result } "
216
+ document = << EOF
217
+ {
218
+ "Statement": [
219
+ {
220
+ "Action": "sts:AssumeRole",
221
+ "Effect": "Allow",
222
+ "Principal": {
223
+ "Service": [
224
+ "fc.aliyuncs.com"
225
+ ]
226
+ }
227
+ }
228
+ ],
229
+ "Version": "1"
230
+ }
231
+ EOF
232
+ description = " Ecs ram role."
233
+ force = true
234
+ }
235
+
236
+ resource "alicloud_ram_policy" "policy" {
237
+ policy_name = " tf-example-ram-policy-${ random_integer . default . result } "
238
+ policy_document = << EOF
239
+ {
240
+ "Statement": [
241
+ {
242
+ "Action": [
243
+ "config:GetDiscoveredResource",
244
+ "ecs:RevokeSecurityGroup"
245
+ ],
246
+ "Effect": "Allow",
247
+ "Resource": ["*"]
248
+ }
249
+ ],
250
+ "Version": "1"
251
+ }
252
+ EOF
253
+ description = " this is a policy test"
254
+ force = true
255
+ }
256
+
257
+ resource "alicloud_ram_role_policy_attachment" "attach" {
258
+ policy_name = alicloud_ram_policy. policy . policy_name
259
+ policy_type = " Custom"
260
+ role_name = alicloud_ram_role. role . name
261
+ }
0 commit comments