Skip to content

Commit 15f5937

Browse files
lsy1968shanye997
authored andcommitted
201-use-case-automatically-audit-security-group-rules
1 parent f4dfc16 commit 15f5937

File tree

3 files changed

+334
-0
lines changed

3 files changed

+334
-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: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
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+
locals {
139+
code_dir = "${path.module}/python/"
140+
archive_output = "${path.module}/code.zip"
141+
base64_output = "${path.module}/code_base64.txt"
142+
}
143+
144+
data "archive_file" "code_package" {
145+
type = "zip"
146+
source_dir = local.code_dir
147+
output_path = local.archive_output
148+
149+
depends_on = [
150+
local_file.python_script,
151+
local_file.requirements_txt,
152+
]
153+
}
154+
155+
resource "null_resource" "upload_code" {
156+
provisioner "local-exec" {
157+
command = <<EOT
158+
base64 -w 0 ${local.archive_output} > ${local.base64_output}
159+
EOT
160+
161+
interpreter = ["sh", "-c"]
162+
}
163+
164+
depends_on = [data.archive_file.code_package]
165+
}
166+
167+
data "local_file" "base64_encoded_code" {
168+
filename = local.base64_output
169+
depends_on = [null_resource.upload_code]
170+
}
171+
resource "alicloud_fcv3_function" "fc_function" {
172+
runtime = "python3.10"
173+
handler = "index.handler"
174+
function_name = "HHM-FC-TEST"
175+
role = alicloud_ram_role.role.arn
176+
177+
code {
178+
zip_file = data.local_file.base64_encoded_code.content
179+
}
180+
lifecycle {
181+
ignore_changes = [
182+
code
183+
]
184+
}
185+
186+
# 显式设置 log_config 为空
187+
log_config {}
188+
189+
depends_on = [data.local_file.base64_encoded_code]
190+
}
191+
192+
resource "alicloud_config_rule" "default" {
193+
rule_name = "SPM0014安全组不允许对全部网段开启风险端口"
194+
description = "禁止安全组对所有网段开放风险端口22, 3389"
195+
source_owner = "ALIYUN"
196+
# (必需,ForceNew)指定是您还是阿里云拥有并管理该规则。有效值: CUSTOM_FC: 该规则是自定义规则,您拥有该规则 ● ALIYUN: 该规则是托管规则,阿里云拥有该规则。
197+
source_identifier = "sg-risky-ports-check"
198+
#配置审计ARN(必需,ForceNew)规则的标识符。对于托管规则,值为托管规则的名称。对于自定义规则,值为自定义规则的ARN。
199+
resource_types_scope = ["ACS::ECS::SecurityGroup"]
200+
#规则监控被排除的资源ID,多个ID用逗号分隔,仅适用于基于托管规则创建的规则,定制规则此字段为空。
201+
config_rule_trigger_types = "ConfigurationItemChangeNotification" #规则在配置更改时被触发
202+
#有效值包括:One_Hour、Three_Hours、Six_Hours、Twelve_Hours、TwentyFour_Hours。
203+
risk_level = 1 # ● 1: 严重 ● 2: 警告● 3: 信息
204+
205+
input_parameters = {
206+
"ports" : "22,3389"
207+
}
208+
}
209+
210+
resource "alicloud_config_remediation" "default" {
211+
config_rule_id = alicloud_config_rule.default.id
212+
remediation_template_id = alicloud_fcv3_function.fc_function.function_arn
213+
remediation_source_type = "CUSTOM"
214+
invoke_type = "AUTO_EXECUTION"
215+
params = "{}"
216+
remediation_type = "FC"
217+
}
218+
219+
resource "random_integer" "default" {
220+
min = 10000
221+
max = 99999
222+
}
223+
224+
resource "alicloud_ram_role" "role" {
225+
name = "tf-example-role-${random_integer.default.result}"
226+
document = <<EOF
227+
{
228+
"Statement": [
229+
{
230+
"Action": "sts:AssumeRole",
231+
"Effect": "Allow",
232+
"Principal": {
233+
"Service": [
234+
"fc.aliyuncs.com"
235+
]
236+
}
237+
}
238+
],
239+
"Version": "1"
240+
}
241+
EOF
242+
description = "Ecs ram role."
243+
force = true
244+
}
245+
resource "alicloud_ram_policy" "policy" {
246+
policy_name = "tf-example-ram-policy-${random_integer.default.result}"
247+
policy_document = <<EOF
248+
{
249+
"Statement": [
250+
{
251+
"Action": [
252+
"config:GetDiscoveredResource",
253+
"ecs:RevokeSecurityGroup"
254+
],
255+
"Effect": "Allow",
256+
"Resource": ["*"]
257+
}
258+
],
259+
"Version": "1"
260+
}
261+
EOF
262+
description = "this is a policy test"
263+
force = true
264+
}
265+
266+
resource "alicloud_ram_role_policy_attachment" "attach" {
267+
policy_name = alicloud_ram_policy.policy.policy_name
268+
policy_type = "Custom"
269+
role_name = alicloud_ram_role.role.name
270+
}
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)