Skip to content

Commit 046ac1e

Browse files
committed
201-use-case-automatically-audit-security-group-rules
1 parent eb4ed97 commit 046ac1e

File tree

3 files changed

+325
-0
lines changed

3 files changed

+325
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Introduction
2+
3+
<!-- DOCS_DESCRIPTION_CN -->
4+
本示例用于在阿里云上创建配置审计规则与函数计算3.0,实现对不合规安全组规则的自动修复。
5+
本示例来自[对安全组规则的合规性进行自动审计修复](https://help.aliyun.com/document_detail/389066.html)
6+
<!-- DOCS_DESCRIPTION_CN -->
7+
8+
<!-- DOCS_DESCRIPTION_EN -->
9+
This example is used to use Cloud Config and Function Compute to automatically audit the compliance of security group rules on Alibaba Cloud.
10+
This example is from [Automatically audit the compliance of security group rules](https://help.aliyun.com/document_detail/389066.html).
11+
<!-- DOCS_DESCRIPTION_EN -->
12+
13+
<!-- BEGIN_TF_DOCS -->
14+
## Providers
15+
16+
| Name | Version |
17+
|------|---------|
18+
| <a name="provider_alicloud"></a> [alicloud](#provider\_alicloud) | n/a |
19+
| <a name="provider_archive"></a> [archive](#provider\_archive) | n/a |
20+
| <a name="provider_local"></a> [local](#provider\_local) | n/a |
21+
| <a name="provider_null"></a> [null](#provider\_null) | n/a |
22+
| <a name="provider_random"></a> [random](#provider\_random) | n/a |
23+
24+
## Modules
25+
26+
No modules.
27+
28+
## Resources
29+
30+
| Name | Type |
31+
|------|------|
32+
| [alicloud_config_remediation.default](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/config_remediation) | resource |
33+
| [alicloud_config_rule.default](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/config_rule) | resource |
34+
| [alicloud_fcv3_function.fc_function](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/fcv3_function) | resource |
35+
| [alicloud_ram_policy.policy](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/ram_policy) | resource |
36+
| [alicloud_ram_role.role](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/ram_role) | resource |
37+
| [alicloud_ram_role_policy_attachment.attach](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/ram_role_policy_attachment) | resource |
38+
| [local_file.python_script](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
39+
| [local_file.requirements_txt](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
40+
| [null_resource.upload_code](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
41+
| [random_integer.default](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) | resource |
42+
| [archive_file.code_package](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
43+
| [local_file.base64_encoded_code](https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file) | data source |
44+
45+
## Inputs
46+
47+
| Name | Description | Type | Default | Required |
48+
|------|-------------|------|---------|:--------:|
49+
| <a name="input_region_id"></a> [region\_id](#input\_region\_id) | n/a | `string` | `"cn-shenzhen"` | no |
50+
<!-- END_TF_DOCS -->
51+
52+
## Documentation
53+
<!-- docs-link -->
54+
55+
The template is based on Aliyun document: [Automatically audit the compliance of security group rules](https://help.aliyun.com/document_detail/389066.html)
56+
57+
<!-- docs-link -->
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
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+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
terraform {
2+
required_providers {
3+
alicloud = {
4+
source = "aliyun/alicloud"
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)