背景
近年来,随着云计算的广泛应用和企业上云的深度普及,许多企业或个人用户将各种日志托管在云上进行留存,从而进行查询、审计等操作。阿里云日志服务SLS除了支持用户业务日志采集存储、查询分析外,还支持几十种阿里云云产品日志的采集以及对用户日志数据进行更高级的消费、加工、可视化、告警等操作。
随着企业对网络安全和数据安全防护水平要求的逐步提升,为了更深入贯彻《网络安全法》《数据安全法》等法律法规的管理要求,企业管理对企业生产运维过程中所产生的日志数据,在留存处理、权限隔离、跨境合规、数据汇总等方面提出了更高阶的需求。
为了满足大客户及一些国际化客户安全合规、简单快速地接入日志、使用日志、操作日志,我们提出了一种新的解决方案——“云产品统一接入API”,以下简称“统一接入API”。
统一接入API主要针对阿里云云产品日志类型,以API的方式提供企业或组织用户快速上手,编排灵活的日志采集方案,对开发者非常友好,其主要具有以下几个特点:
(1)简单上手:统一接入API作为一个OpenAPI接口,除了会提供用户各种语言SDK外,还将会对接Terraform,使用户可以在多云场景下完成SLS资源的自动化配置和构建;
(2)自动化:开发者只需要关注基本的采集逻辑,统一接入API会自动、及时地发现被采集的实例对象,根据规则逻辑和采集策略自动完成日志采集;
(3)可编排:对于数据中心化汇总、数据实例粒度隔离、数据跨境合规等需求,统一接入API也提供简单的配置方式,开发者可以灵活编排,按照实际业务场景自定义其专属日志采集方案。
下面将具体展开对统一接入API的基本概况的介绍。
统一接入API概况
统一接入API提供四个OpenAPI的接口,用来创建更新、列举、删除、查看统一接入采集规则。
接口名 |
功能详情 |
UpsertCollectionPolicy |
创建、更新云产品日志采集的规则策略 |
ListCollectionPolicies |
列举云产品日志采集的规则策略 |
DeleteCollectionPolicy |
删除云产品日志采集的规则策略 |
GetCollectionPolicy |
查看云产品日志采集的规则策略 |
统一接入API在实现以实例粒度采集云产品日志基本功能的同时,还支持以下几个关键功能:
基本功能
实时发现云产品实例及属性变更,并基于规则策略为符合条件的实例建立配置采集链路:
(1)基于规则策略实现自动化采集云产品日志。比如用户新创建一些云产品实例时,无需用户单独配置,自动化规则将采集该新增实例的日志;当该实例属性发生变更时,也可以根据实例属性与规则匹配程度进行采集任务的动态调整。
(2)支持三种模式(全选模式、属性模式、实例模式)的采集策略,用户可以基于采集策略过滤规则实现精细化日志采集控制,从而控制采集存储的成本。
高级功能
基于数据加工实现日志转存,实现数据隔离、跨地域和跨账号同步:
(1)跨地域、多目标中心汇总的日志采集需求,跨地域采集日志是非常常见的业务场景,比如用户的业务部署在地域A,但是其安全监管却部署地域B,因此需要从地域B读取消费日志;多中心也是许多跨国公司的强烈需求,可以满足跨境合规的监管的规范,同时也满足异地容灾的高可用需求。另外中心化汇总也是在落实《数据安全法》的集中管控的倡议。
(2)支持实例粒度的数据采集隔离,比如某些云产品日志默认将同一个地域的实例都采集到同一个日志库下,但是这些实例可能属于不同的业务团队,而logstore已经是SLS的日志查看的最小访问控制RAM(Resource Access Management)权限单元,出于权限隔离或者业务隔离的需求,可以实现A业务团队仅看到A业务归属实例的日志,B业务团队仅看到B团队所归属的实例日志。
(3)跨账号日志管控需求,目前该功能还在开发中,未来将基于资源目录组织信任关系,帮助用户建立公司或组织内部的多账号日志采集集中管理。
目前统一接入API已经适配了OSS访问日志、CloudSIEM云产品和告警日志等云产品日志类型,未来将继续覆盖阿里云存储类、网络类、数据库类、安全类等多种云产品下的多种日志类型,从而为用户带来了更加灵活和高效的日志采集方案,让企业或组织可以更好地利用阿里云的云产品,提高企业或组织开发者在企业上云的运维管控、可观测性、安全合规等方面的数据应用水平。
下面我们将展开对统一接入API基本原理的详细介绍。
基本原理
用户可以通过对应的产品码和日志类型码配置具体规则名下的日志采集规则,如下:
参数名 |
说明 |
ProductCode |
指定云产品,如oss |
DataCode |
指定云产品对应产品类型,如access_log |
PolicyName |
指定规则策略名称,账号下全局唯一 |
Enabled |
true | false,规则是启动状态还是禁用状态 |
统一接入API按照流程可以拆分为以下三大模块,通过不同的属性入参控制采集规则:
自动化采集
当用户启用统一接入API开启云产品日志采集时,统一接入API后端服务会基于某些预设策略和一些定时任务,获取阿里云账号下在各个地域下的实例信息,从而当用户账号下的云产品实例有新增、或实例的属性发生变化时,统一接入API的实例同步服务会及时获取用户的实例信息,做到不需要用户手动开启即可管理对该实例的日志采集。
精细化采集
统一接入API维护运行自己的一套采集编排服务,支持三种采集模式,从而实现对用户实例的精细化采集:
参数名 |
二级参数 |
说明 |
PolicyConfig |
ResourceMode |
资源模式
|
|
||
|
||
InstanceIds |
定义一组实例Id,多个实例为或的关系 |
|
ResourceTags |
定义资源的tag标签对,可以有个tag标签对,多个tag为且的关系 |
|
Regions |
定义一组地域,多个地域为或的关系,支持通配符 |
(1)全选模式
只需要统一接入API的PolicyConfig.ResourceMode
设置为all,将会自动采集该阿里云账号下所有支持地域的所有云产品实例的日志。
(2)实例模式
实例模式(PolicyConfig.ResourceMode=instanceMode
)下,对于某一种单一云产品日志类型,开发者可以按照实例id来筛选需要采集的日志类型。开发者可以配置PolicyConfig.
InstanceIds
来指定特定需要采集的实例,如果用户有新增实例不在该实例列表,则不会被采集。
(3)属性模式
属性模式(PolicyConfig.ResourceMode=attributeMode
)是一种更通用的精细化采集策略, 目前支持两种属性,分别是地域属性(PolicyConfig.
Regions
)和标签属性(PolicyConfig.
ResourceTags
)。如果两种属性都配置,则采集同时能满足两种属性的实例的日志。地域属性和标签属性很多用户用来区分不同业务场景或者应用需求的常见属性,当实例的标签属性发生变更时,统一接入API也能够及时感知用户实例的属性变化,从而重新执行采集策略。
加工转存
如果用户有加工转存等高级需求,例如有中心化汇总各个区域的数据的需求,例如有按照具体实例粒度数据隔离的需求,可以调用统一接入API通过SLS数据加工实现高级转存投递功能,SLS数据加工是实现实例粒度采集隔离和跨地域、多中心等需求的进阶利器。统一接入API下,其具体参数设置如下:
参数名 |
二级参数 |
说明 |
centralizeEnabled |
是否开启中心化转存投递 |
|
centralizeConfig |
DestRegion |
自定义中心目标库地域 |
DestProject |
自定义中心目标项目project |
|
DestLogstore |
自定义中心目标库logstore |
|
DestTTL |
自定义目标库TTL,首次创建logstore时设置,如果目标库已经存在,设置不会影响原目标库TTL |
一种云产品日志类型下,用户可以基于统一接入API创建多条规则,用户实例是否会被采集,是多条统一接入API取"或"的关系决定的,多条规则,只要实例满足任意一条规则的采集策略,则该实例的日志就会被采集到对应地域的默认云产品目标日志库(例如regionA的OSS Buckect 会默认投递到oss-log-{uid}-regionA
)下。
如果用户规则开启了高级功能的转存投递,在同一种云产品的日志类型下,统一接入API同一个初级投递目标下只会创建创建一个加工job,在该加工job内部,基于不同的规则采集策略配置详情,定制化转存投递目标和投递粒度范围。
用户无需担心数据加工带来的额外成本,通过统一接入API进行数据加工投递,加工过程中产生的数据读取费用,数据网络传输费用,数据新写入费用都已经被SLS免除,用户可较轻负担地使用统一接入API从而实现各种日志采集的各种定制和组合功能。
场景实践
案例一:自动采集
小A是某家公司运维团队的工程师,该公司在阿里云OSS控制台下按照不同的业务单元(Business Unit)的需求创建了很多Bucket,这些Bucket分别放在不同的地域下,出于公司运维分析的要求,小A需要自动开启每个地域下所有Bucket实例的OSS访问日志并存入SLS。小A了解到SLS有提供云产品统一接入API,基于该API,小A快速实现自动化采集其公司账号下的Bucket实例的OSS访问日志,其具体方案如下:
案例二:转存汇总
小B是某家公司的安全团队负责人,出于数据集中化分析和安全运维的需要,他们需要将其账号下OSS访问日志都投递到远程SIEM端,帮助构建其内部SOC系统。小B除了希望满足:(1)可以自动开启其账号下所有地域下所有OSS Bucket的访问日志,无需手动点击开启;(2)当该账号业务下有新增OSS bucket时,可以及时自动开启,无需运维人员手动介入;同时小B还希望做到:(3)所有的OSS Bucket汇总到一个中心logstore下,安全团队只需单点消费该logstore数据就可以获取全地域下各个Bucket的访问日志。
小B只需通过调用SLS统一接入API,创建规则,并进行如下配置,即可满足上述(1)(2)(3)点需求,具体方案如下:
案例三:精准优选
小C是小B的同事,看到小B的日志自动化采集方案非常心动,出于降低成本的考虑,他对小B提出了两点需求建议,(1)公司账号下并不是所有的Bucket都需要自动化采集,可以只采集满足部分标签属性Bucket 实例(例如envTag="Online"
)的日志;(2)目前公司的核心业务部署在北京、上海、杭州(例如regions=${coreReg}
),虽然深圳、青岛、成都等地域都有业务相关的bucket,但是不是核心区域业务,所以可以不采集其访问日志。
小B只需通过调用SLS统一接入统一接入API,修改规则,并进行如下配置,即可满足上述两点需求。
案例四:跨境合规
小B使用统一接入API方案,节省了大量的运维成本和人员精力,在公司内获得了广泛的好评,也带动了公司业务如火如荼的发展,不久以后,公司除了国内业务,还拓展了海外业务,此时采集海外核心业务bucket访问日志的需求也提上了日程。小B的老板小D咨询了身边的安全行业从业者,深刻学习了网络安全和数据安全法、欧盟法等法律法规对跨境数据传输保护的处置方法和有关规定,对小A提出了新的要求:除了国内中心外,还需建立海外中心用于汇总海外核心业务Bucket的访问日志。
小B此时已经熟练掌握了统一接入API,基于统一接入API,他很快就提出了新的解决方案,创建两个统一接入API规则,分别采集国内和海外的oss bucket的访问日志,完美解决了小D的需求,获得从上到下的一致好评。
案例五:数据隔离
随着对统一接入API的深度使用,小B的日志采集方案获得了公司内外的广泛认可。有一天,隔壁公司的小E也听说了小B的解决方案,他对小B提出了当前他们公司遇到的问题,并咨询小B有没有什么方便的做法。
小E目前遇到的问题是:小E公司有两个业务团队分别是Team1和Team2,其中Team1所拥有的bucket实例访问日志和Team2团队所拥有的bucket实例访问日志会被采集到同一个日志库下,出于业务数据安全保密的设计以及权限使用最小够用的原则,(1)两个业务团队都不希望对方看到其业务团队的OSS访问日志;(2)审计团队出于安全审计的目的,需要看到所有业务团队的OSS访问日志;
小B领会了小E的需求,针对小E的切实需求场景和统一接入API,提出了实例粒度数据隔离的解决方案,方案如下:
通过数据加工流转,使得不同bucket的访问日志按照业务属性划分投递到不同的logstore下,对于不同的业务团队,给予不同logstore的RAM访问权限,从而实现了访问日志的权限隔离。小E采纳了小B的方案,快速完成了按照业务进行实例粒度隔离的日志采集。
其他功能
用户可以创建更新/查询/删除规则,除此之外,统一接入API还支持规则标签功能及实例反查匹配规则功能,以便于给开发者提供更方便的规则管理体验。
规则标签
用户在不同应用需求和业务场景下可能创建了多条业务规则,为了方便运维人员进行归纳统计,统一接入API提供规则标签属性的功能,支持app
和policyGroup
两种属性类型,用户可以在创建或修改规则时进行 Policy 的 attribute
设定,从而在列举查询时实现有组织的归纳管理。下面是一个设置规则属性的示例:
attribute.setApp("myApp") attribute.setPolicyGroup("myPolicyGroup") policy.setAttribute(attribute)
不同应用或业务场景也可设置其专属属性,用户在查询规则时,可根据规则属性信息进行筛选过滤。
实例匹配
用户某些场景下,需要判断当前被采集的实例是否已经满足当前的统一接入 API 规则的采集配置,这种场景下,用户可以通过调用ListCollectionPolicies
接口, 输入实例 ID 及该实例所属的云产品及日志类型,反查当前实例匹配的规则策略,如果当前实例已经匹配(即有至少一条 Policy 返回),则当前实例一定满足采集统一接入 API 的配置条件,其日志将会被采集到用户的日志库下。下面是一个设置通过实例反查匹配规则的示例:
policy.setProductCode("oss") policy.setDataCode("access_log") policy.setInstanceId("your-bucket-instance-id")
开始使用
相信在了解了统一接入API的基本原理和各种实践场景后,聪明的开发者们已经开始迫不及待要应用统一接入API进行各种业务场景下的日志高阶采集了。
统一接入 API 中心化部署,用户可以通过 OpenApi 门户平台,在上海和新加坡中心下开启使用:
权限准备
{ "Action": ["log:UpsertCollectionPolicy"], "Resource": [ "acs:log::${AccountId}:collectionpolicy/${PolicyName}" ], "Effect": "Allow" }
{ "Action": ["log:ListCollectionPolicies"], "Resource": [ "acs:log::${AccountId}:collectionpolicy/" ], "Effect": "Allow" }
{ "Action": ["log:DeleteCollectionPolicy"], "Resource": [ "acs:log::${AccountId}:collectionpolicy/${PolicyName}" ], "Effect": "Allow" }
{ "Action": ["log:GetCollectionPolicy"], "Resource": [ "acs:log::${AccountId}:collectionpolicy/${PolicyName}" ], "Effect": "Allow" }
用户可以快速上手应用编排统一接入API进行云产品日志采集,从而自动、灵活、安全、高效地完成云产品日志采集配置。
SDK 及使用示例
java
Github 链接: https://github.com/aliyun/alibabacloud-java-sdk/tree/master/sls-20201230
<dependency> <groupId>com.aliyun</groupId> <artifactId>sls20201230</artifactId> <version>3.1.0</version> </dependency>
代码示例
importcom.alibaba.fastjson.serializer.SerializerFeature; importcom.aliyun.sls20201230.models.*; importcom.aliyun.sls20201230.Client; importcom.aliyun.tea.TeaException; publicclassCollectionPolicyTest { StringpolicyName="oss-test"; //Globally unique under a single accountStringproductCode="oss"; StringdataCode="access_log"; Booleanenabled=true; BooleancentralizeEnabled=false; ClientNewTestClient() throwsException { StringsubAK=System.getenv("YOUR_RAM_AK_ID"); StringsubSK=System.getenv("YOUR_RAM_AK_KEY"); //generate clientcom.aliyun.teaopenapi.models.Configconfig=newcom.aliyun.teaopenapi.models.Config(); config.setEndpoint("cn-shanghai.log.aliyuncs.com"); //shanghai or ap-southeast-1config.setAccessKeyId(subAK); config.setAccessKeySecret(subSK); Clientclient=newClient(config); returnclient; } voidTestUpsert() { UpsertCollectionPolicyRequestrequest=newUpsertCollectionPolicyRequest(); Clientclient=NewTestClient(); try{ request.setPolicyName(policyName); request.setDataCode(dataCode); request.setProductCode(productCode); UpsertCollectionPolicyRequest.UpsertCollectionPolicyRequestPolicyConfigpolicyConfig=newUpsertCollectionPolicyRequest.UpsertCollectionPolicyRequestPolicyConfig(); //resourceModepolicyConfig.setResourceMode("all"); //set policy configrequest.setPolicyConfig(policyConfig); //set enabledrequest.setEnabled(enabled); UpsertCollectionPolicyResponseresp=client.upsertCollectionPolicy(request); System.out.println(resp.getBody().getMessage()); }catch (TeaExceptione) { System.out.println(e.getCode() +" "+e.getMessage()); } catch (Exceptione) { System.out.println(e.getCause() +" "+e.getMessage()); } } voidTestGet() { GetCollectionPolicyRequestrequest=newGetCollectionPolicyRequest(); Clientclient=NewTestClient(); try { GetCollectionPolicyResponseresp=client.getCollectionPolicy(policyName, request); System.out.println(JSONObject.toJSONString(resp.body.getCollectionPolicy(), SerializerFeature.PrettyFormat)); } catch (TeaExceptione) { System.out.println(e.getCode() +" "+e.getMessage()); } catch (Exceptione) { System.out.println(e.getCause() +" "+e.getMessage()); } } voidTestList() { ListCollectionPoliciesRequestrequest=newListCollectionPoliciesRequest(); Clientclient=NewTestClient(); try { ListCollectionPoliciesResponseresp=client.listCollectionPolicies(request); System.out.println(JSONObject.toJSONString(resp.body.getData(), SerializerFeature.PrettyFormat)); } catch (TeaExceptione) { System.out.println(e.getCode() +" "+e.getMessage()); } catch (Exceptione) { System.out.println(e.getCause() +" "+e.getMessage()); } } voidTestDelete() { DeleteCollectionPolicyRequestrequest=newDeleteCollectionPolicyRequest(); Clientclient=NewTestClient(); try { DeleteCollectionPolicyResponseresp=client.deleteCollectionPolicy(policyName, request); System.out.println(JSONObject.toJSONString(resp, SerializerFeature.PrettyFormat)); } catch (TeaExceptione) { System.out.println(e.getCode() +" "+e.getMessage()); } catch (Exceptione) { System.out.println(e.getCause() +" "+e.getMessage()); } } }
python
Github 链接:https://github.com/aliyun/alibabacloud-python-sdk/tree/master/sls-20201230
pip install alibabacloud_sls20201230
代码示例
importosfromalibabacloud_sls20201230.clientimportClientasSls20201230Clientfromalibabacloud_tea_openapiimportmodelsasopen_api_modelsfromalibabacloud_sls20201230importmodelsassls_20201230_modelsclassTestCollectionPolicy: def__init__(self, product_code, data_code, policy_name, resource_mode="all"): self.product_code=product_codeself.data_code=data_codeself.policy_name=policy_nameself.resource_mode=resource_modedefget_test_client(self): config=open_api_models.Config( access_key_id=os.environ.get("YOUR_RAM_AK_ID"), access_key_secret=os.environ.get("YOUR_RAM_AK_KEY"), ) config.endpoint='cn-shanghai.log.aliyuncs.com'client=Sls20201230Client(config) returnclientdeftest_get(self): client=self.get_test_client() req=sls_20201230_models.GetCollectionPolicyRequest() resp=client.get_collection_policy(self.policy_name, req) print("get", resp) deftest_upsert(self): client=self.get_test_client() req=sls_20201230_models.UpsertCollectionPolicyRequest() req.enabled=Truepolicy_config=sls_20201230_models.UpsertCollectionPolicyRequestPolicyConfig() policy_config.resource_mode=self.resource_modereq.policy_config=policy_configreq.product_code=self.product_codereq.data_code=self.data_codereq.policy_name=self.policy_nametry: resp=client.upsert_collection_policy(req) print("upsert", resp) exceptExceptionase: print(e) deftest_list(self): client=self.get_test_client() req=sls_20201230_models.ListCollectionPoliciesRequest() req.page_num=1req.page_size=100# req.instance_id = "xxx"; #if you want to filter by instance id, product code and data code is requiredtry: resp=client.list_collection_policies(req) print("resp", resp) exceptExceptionase: print(e) deftest_delete(self): client=self.get_test_client() product_code=self.product_codedata_code=self.data_codepolicy_name=self.policy_namereq=sls_20201230_models.DeleteCollectionPolicyRequest(data_code=data_code, product_code=product_code) try: resp=client.delete_collection_policy(policy_name, req) print("resp", resp) exceptExceptionase: print(e) if__name__=='__main__': policy_name="oss-test"product_code="oss"data_code="access_log"collection=TestCollectionPolicy(product_code=product_code, data_code=data_code, policy_name=policy_name) collection.test_list() collection.test_upsert() collection.test_get() collection.test_delete()
Golang
Github: https://github.com/alibabacloud-go/sls-20201230
go get github.com/alibabacloud-go/sls-20201230/v4/client@v4.1.0
示例代码
import ( "fmt"openapi"github.com/alibabacloud-go/darabonba-openapi/v2/client"sls20201230"github.com/alibabacloud-go/sls-20201230/v4/client""github.com/alibabacloud-go/tea/tea""os""testing") funcCreateClient(accessKeyId*string, accessKeySecret*string) (_result*sls20201230.Client, _errerror) { config :=&openapi.Config{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, } config.Endpoint=tea.String("cn-shanghai.log.aliyuncs.com") _result=&sls20201230.Client{} _result, _err=sls20201230.NewClient(config) return_result, _err} funcList(client*sls20201230.Client) { listCollectionPoliciesRequest :=&sls20201230.ListCollectionPoliciesRequest{} resp, _err :=client.ListCollectionPolicies(listCollectionPoliciesRequest) if_err!=nil { fmt.Println(_err) } else { fmt.Println(resp.Body) } } funcGet(client*sls20201230.Client, policyName*string) { getCollectionPolicyRequest :=&sls20201230.GetCollectionPolicyRequest{} resp, _err :=client.GetCollectionPolicy(policyName, getCollectionPolicyRequest) if_err!=nil { fmt.Println(_err) } else { fmt.Println(resp.Body) } } funcUpsert(client*sls20201230.Client, policyName, productCode, dataCodestring) { upsertCollectionPolicyRequest :=&sls20201230.UpsertCollectionPolicyRequest{} upsertCollectionPolicyRequest.SetPolicyName(policyName) upsertCollectionPolicyRequest.SetProductCode(productCode) upsertCollectionPolicyRequest.SetDataCode(dataCode) upsertCollectionPolicyRequest.SetEnabled(true) policyConfig :=&sls20201230.UpsertCollectionPolicyRequestPolicyConfig{} policyConfig.SetResourceMode("all") upsertCollectionPolicyRequest.SetPolicyConfig(policyConfig) resp, _err :=client.UpsertCollectionPolicy(upsertCollectionPolicyRequest) if_err!=nil { fmt.Println(_err) } else { fmt.Println(resp.Body) } } funcDelete(client*sls20201230.Client, policyName*string) { getCollectionPolicyRequest :=&sls20201230.GetCollectionPolicyRequest{} resp, _err :=client.GetCollectionPolicy(policyName, getCollectionPolicyRequest) if_err!=nil { fmt.Println(_err) } else { fmt.Println(resp.Body) } } funcTestCollectionPolicy(t*testing.T) { client, _err :=CreateClient(tea.String(os.Getenv("YOUR_RAM_AK_ID")), tea.String(os.Getenv("YOUR_RAM_AK_KEY"))) if_err!=nil { fmt.Println(_err) return } policyName :="oss-test"productCode :="oss"dataCode :="access_log"List(client) Upsert(client, policyName, productCode, dataCode) Get(client, tea.String(policyName)) Delete(client, tea.String(policyName)) }
其他
php
Github :https://github.com/alibabacloud-sdk-php/sls-20201230
composer require alibabacloud/sls-20201230
nodejs
Github: https://github.com/aliyun/alibabacloud-typescript-sdk/tree/master/sls-20201230
npm install @alicloud/sls20201230 -S
c++
Github: https://github.com/alibabacloud-sdk-cpp/sls-20201230
git clone https://github.com/aliyun/alibabacloud-cpp-sdk.git sh sls-20201230/scripts/install.sh
c#
Github: https://github.com/aliyun/alibabacloud-csharp-sdk/tree/master/sls-20201230
dotnet add package AlibabaCloud.SDK.Sls20201230