1. 背景介绍
某海外企业在阿里云上有多个云账号,客户安全团队比较关注各云账号内部分资源的变更情况。如RAM角色的变更需要统一投递到共享存储(如tableStore或RDS)便于快速查看多账号资源变更情况。
2. 方案架构
Config可以将几十款云产品的变更保存到外部存储(如SLS、OSS等),另外也会默认投递变更数据投递到事件总线,每个账号内都会默认投递到各自的事件总线中。由于客户是多个云账号需要统一处理,所以在各自云账号的事件总线中通过配置事件目标,投递到其他云账号的事件总线。
在成员账号配置EB的时候,通过配置事件模式可以过滤特定的资源。满足客户过滤指定资源变更的需求。
成员账号事件总线-事件目标配置
在单个成员账号内需要在事件总线中配置事件规则,将事件目标投递到资源管理账号(MA)的事件总线。
事件模式配置:
{
"source": [
"acs.ram"
],
"data": {
"resourceName": [
{
"prefix": "sg-"
}
]
},
"type": [
"ram:Config:ConfigurationItemChangeNotification"
]
}
当成员账号里面有许多个RAM角色,以上规则只会过滤出前缀为sg- 打头的RAM角色资源。
资源管理账号(MA)事件总线-事件目标配置
演示环境
本次演示只演示各账号内RAM Role变更。
演示账号说明
账号名称 |
功能 |
yf_04 |
1、开通EB,用于接收另外2个云账号内EB事件 2、开通FC,用于处理EB事件入库及展示事件 3、开通RDS,用于保存EB事件 |
config_eb_1 |
1、开通EB,用于接收同账号内Config变更 2、修改RAM 角色信任策略管理(trust policy)触发变更 |
config_eb_2 |
1、开通EB,用于接收同账号内Config变更 2、修改RAM角色信任策略管理(trust policy)触发变更 |
测试变更
在config_eb_1里面创建2个RAM ROLE 。同样的操作在config_eb_2里面再同样进行一次。
1、先在config_eb_1中创建1个RAM role。
sg-001
2、再在config_eb_2中创建1个RAM role。
ug-001
3、在config_eb_1中修改sg-001的trust policy。
变更前:
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"RAM": [
"acs:ram::1546****2513:root"
]
}
}
],
"Version": "1"
}
将Principal属性做变更,变更后:
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"RAM": [
"acs:ram::1062****9476:root"
]
}
}
],
"Version": "1"
}
4、在config_eb_1 查看Config资源变更
操作日志
5、在yf_04 账号查看EB事件(统一事件中心)
{
"datacontenttype": "application/json;charset=utf-8",
"aliyunaccountid": "1062****9476",
"aliyunpublishtime": "2022-05-20T23:56:16.188Z",
"data": {
"resourceEventType": "MODIFY",
"resourceCreateTime": "1652416551000",
"resourceId": "343433500315236591",
"captureTime": "1653090910000", # 事件接收时间
"configuration": "{"UpdateDate":"2022-05-20T23:53:11Z","MaxSessionDuration":3600,"RoleName":"sg-001","Description":"sg-001","AssumeRolePolicyDocument":"{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1062516667359476:root\\"]}}],\\n \\"Version\\": \\"1\\"}","Arn":"acs:ram::1177528403585585:role/sg-001","RoleId":"343433500315236591","CreateDate":"2022-05-13T04:35:51Z"}",
"dataType": "ConfigurationItemChangeNotification",
"resourceName": "sg-001",
"availabilityZone": "",
"tags": "",
"accountId": "1177****5585",
"relationshipDiff": "",
"resourceStatus": "",
"regionId": "cn-beijing",
"requestId": "d63f5ae7-8c9a-4bcd-958b-bf86c94dd327",
"configAggregators": "1062516667359476:ca-d1ef7086a0f4009fc283",
"resourceGroupId": "",
"arn": "acs:sls:global:1177528403585585:eventbridge",
"relationship": "",
"configurationDiff": "{"UpdateDate":["2022-05-20T13:33:38Z","2022-05-20T23:53:11Z"],"AssumeRolePolicyDocument":["{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1546227542332513:root\\"]}}],\\n \\"Version\\": \\"1\\"}","{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1062516667359476:root\\"]}}],\\n \\"Version\\": \\"1\\"}"]}",
"resourceType": "ACS::RAM::Role"
},
"aliyunoriginalaccountid": "1177****5585",
"specversion": "1.0",
"aliyuneventbusname": "default",
"id": "d63f5ae7-8c9a-4bcd-958b-bf86c94dd327",
"source": "acs.ram",
"time": "2022-05-20T23:55:10Z",
"aliyunregionid": "cn-beijing",
"type": "ram:Config:ConfigurationItemChangeNotification"
}
6、在config_eb_2 执行相同的配置变更操作
修改 Ram Role: ug-001 的 trust policy值
变更前:
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"RAM": [
"acs:ram::1177****5585:root"
]
}
}
],
"Version": "1"
}
修改Principal属性,变更后:
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"RAM": [
"acs:ram::1062****9476:root"
]
}
}
],
"Version": "1"
}
7、在yf_04 账号查看EB事件
{
"datacontenttype": "application/json;charset=utf-8",
"aliyunaccountid": "1062****9476",
"aliyunpublishtime": "2022-05-21T00:15:37.308Z",
"data": {
"resourceEventType": "MODIFY",
"resourceCreateTime": "1652416692000",
"resourceId": "388886671837864637",
"captureTime": "1653092130000",
"configuration": "{"UpdateDate":"2022-05-21T00:13:44Z","MaxSessionDuration":3600,"RoleName":"ug-001","Description":"ug-001","AssumeRolePolicyDocument":"{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1062516667359476:root\\"]}}],\\n \\"Version\\": \\"1\\"}","Arn":"acs:ram::1526528402803627:role/ug-001","RoleId":"388886671837864637","CreateDate":"2022-05-13T04:38:12Z"}",
"dataType": "ConfigurationItemChangeNotification",
"resourceName": "ug-001",
"availabilityZone": "",
"tags": "",
"accountId": "1526****3627",
"relationshipDiff": "",
"resourceStatus": "",
"regionId": "cn-beijing",
"requestId": "6ee47ee9-55d0-470e-b5e0-7c8859ee7fbc",
"configAggregators": "1062516667359476:ca-d1ef7086a0f4009fc283",
"resourceGroupId": "",
"arn": "acs:sls:global:1526528402803627:eventbridge",
"relationship": "",
"configurationDiff": "{"UpdateDate":["2022-05-20T14:15:14Z","2022-05-21T00:13:44Z"],"AssumeRolePolicyDocument":["{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1177528403585585:root\\"]}}],\\n \\"Version\\": \\"1\\"}","{\\n \\"Statement\\": [{\\n \\"Action\\": \\"sts:AssumeRole\\",\\n \\"Effect\\": \\"Allow\\",\\n \\"Principal\\": {\\"RAM\\": [\\"acs:ram::1062516667359476:root\\"]}}],\\n \\"Version\\": \\"1\\"}"]}",
"resourceType": "ACS::RAM::Role"
},
"aliyunoriginalaccountid": "1526****3627",
"specversion": "1.0",
"aliyuneventbusname": "default",
"id": "6ee47ee9-55d0-470e-b5e0-7c8859ee7fbc",
"source": "acs.ram",
"time": "2022-05-21T00:15:30Z",
"aliyunregionid": "cn-beijing",
"type": "ram:Config:ConfigurationItemChangeNotification"
}
8、在yf_04账号中开启函数计算服务,将事件解析并保存到RDS
在FC中配置一个触发器函数,触发规则
注意:
1、这里配置的触发器是选择哪个?
在EB那边数据,需要选择访问控制。
事件触发流程(EB官方产品手册)
函数计算代码
import pymysql
import json,logging
import os
connection = None
logger = logging.getLogger()
def initialize(context):
global connection
try:
connection = pymysql.connect(
host=os.environ['MYSQL_ENDPOING'], # 替换为您的HOST名称。
port=int(os.environ['MYSQL_PORT']), # 替换为您的端口号。
user=os.environ['MYSQL_USER'], # 替换为您的用户名。
passwd=os.environ['MYSQL_PASSWORD'], # 替换为您的用户名对应的密码。
db=os.environ['MYSQL_DBNAME'], # 替换为您的数据库名称。
connect_timeout=5)
logger.info('eb job connect mysql success!!!')
except Exception as e:
logger.error(e)
logger.error(
"ERROR: Unexpected error: Could not connect to MySql instance.")
raise Exception(str(e))
def pre_stop(context):
logger.info("pre_stop hook start.")
if connection != None:
connection.close()
# 保存变更表及任务表
def save_transactional(sql, params):
try:
cursor=connection.cursor()#初始化游标
cursor.execute(sql , params)
connection.commit()
except Exception as e:
logger.error(e)
def handler(event, context):
eb = json.loads(event).get("data")
eb_action,eb_time,resource_name,req_id = eb.get("resourceEventType"),eb.get("captureTime"),eb.get("resourceName"),eb.get("requestId")
account_id, region, config_diff, resourse_type = eb.get("accountId"),eb.get("regionId"),eb.get("configurationDiff"),eb.get("resourceType")
logger.info(eb_action+eb_time+resource_name+req_id+account_id+region+config_diff+resourse_type)
change_sql = "insert into event_list(req_id,type,time,resource,account,region,configdiff,resourcetype) values(%s,%s,%s,%s,%s,%s,%s,%s)"
params = (req_id,eb_action,eb_time,resource_name,account_id, region, config_diff, resourse_type)
save_transactional(change_sql, params)
return 'success'
RDS里面的数据记录
重要
函数计算配置时,访问RDS需要配置函数计算的网络选项。否则会出现网络不通。
3. 本文小结
通过以上方案,当企业有多个云账号,并且只想对特定某些资源的变更需要及时监测,那可以通过这套解决方案有效过滤。把变更的数据保存到数据库中。