亚马逊AWS官方博客

使用 GuardDuty 配合 Amazon Elasticsearch Service 实时监控安全态势

Original URL: https://aws.amazon.com/cn/blogs/database/monitoring-your-security-with-guardduty-in-real-time-with-amazon-elasticsearch-service/

 

在使用Amazon GuardDuty协助保护AWS账户与工作负载时,您的快速搜索与大量数据可视化能力将得到显著增强。在企业中,您可能需要分析来自数千个账户的活动,并在分析之后通知安全团队以采取纠正措施。在这一业务流程当中,时间将成为至关重要的决定性因素。

将GuardDuty同Amazon Ealsticsearch Service与数据可视化相结合,我们可以将数据转换为具备可行性的分析洞见。在本文中,我们将探讨如何使用Amazon ES帮助您分析GuardDuty发现的结果。此外,我们还将向您展示如何使用Kibana(Amazon ES的开源数据可视化插件)实现数据的搜索、浏览与可视化。

下面是概述以及创建所需资源的步骤。

解决方案概述与先决条件

首先来看宏观层面的设置流程,其中具体包含以下操作步骤:

  1. 使用Amazon CloudWatch Events与AWS Lambda收集GuardDuty的发现结果,而后将结果发送至Amazon S3存储桶。
  2. 将传递至S3存储桶的日志进一步发送至Amazon ES。
  3. 在Amazon ES中分析、搜索或聚合发现结果。
  4. 使用Kibana仪表板进行结果可视化。

在开始实际操作之前,请按照本AWS博文所述,在主账户中启用 GuardDuty。主账户用于汇总全部 GuardDuty 发现的结果,其通常由安全团队负责管理,并将显示所有成员账户的发现结果。

步骤1:使用AWS Lambda收集GuardDuty日志,并将其发送至Amazon S3

为了聚合各GuardDuty日志,请设置一项AWS Lambda函数,该函数将收集这些GuardDuty的发现并将其存储在Amazon S3当中。在以下列出的Lambda函数中,您还可以使用Amazon Simple Notification Service (Amazon SNS)将警报或通知发送给您的安全团队。

创建一个S3存储桶,如下图所示,用于存储GuardDuty日志,具体请参阅Amazon S3用户指南。在执行此项操作时,请注意存储桶的Amazon资源名称(ARN),我们将在稍后使用此名称。ARN的基本格式为:

arn:aws:s3:::guarddutylogs

添加一个Lambda函数

    1. 登录至AWS管理控制台。
    2. 在Compute服务部分中,选择 Lambda
    3. 选择Create a Function
    4. 选择Author from Scratch

      5.Author from scratch 部分(如下图所示),分别添加:

      • Name。为此函数输入名称。
      • 将Node.js 6.10选定为运行时环境。
      • Role。从以下选项中做出选择:
        • 选择一个现有角色。如果您已经拥有现成的适用角色,也可以直接选择。
        • 通过模板创建新角色。如果您使用此选项,则无需选择任何策略模板即可继续操作——在默认情况下,此选项将创建具有基本Lambda执行权限的角色。
      • Role Name。为角色输入名称。
      • Policy templates。如果您创建了一个新角色,则可直接将这部分留空。

6. 选择Create Function

7.Function Code部分,使用以下代码:

'use strict'

const aws = require('aws-sdk');
const s3 = new aws.S3();

// Environment variables for S3 Bucket
var BucketNAME = process.env.GUARDDUTY_LOGS_BUCKET;

function postToS3(message, context) {

    console.log("Entered postToS3");
    var key = message.id+".json";
    console.log("Save the object in S3 bucket with key: " + key)

    var params = {
        Body: JSON.stringify(message),
        Bucket: BucketNAME,
        Key: key
    };
    s3.putObject(params, function(err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data); // successful response
        /*
        data = {
         ETag: "\"6805f2cfc46c0f04559748bb039d69ae\"", 
         VersionId: "tpf3zF08nBplQK1XLOefGskR7mGDwcDk"
        }
        */
    });
}

exports.handler = function(event, context) {

    console.log('Received event: ', JSON.stringify(event, null, 2));
    
    var final_event;
    console.log(event + " : " + context.awsRequestId);
    if (event.source === "aws.guardduty") {
        final_event = event.detail;
    } else {
        final_event = event;
        return;
    }
	
	// Send the GuardDuty findings as a json object to S3
    postToS3(final_event, context);
};

 

8. 传递以下环境变量,具体如下图所示:

GUARDDUTY_LOGS_BUCKET: 作为日志传递目标的S3存储桶名称,请使用您之前为所创建存储桶指定的名称。

为Lambda函数创建一个角色

您的Lambda函数需要适当的权限才能将GuardDuty日志发送至S3存储桶。另外,它还需要权限才能将通知发送至SNS主题,并将日志发布到CloudWatch日志组。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:eu-west-1:xxxxxxxxxxxx:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:eu-west-1: xxxxxxxxxxxx:log-group:/aws/lambda/guardduty_to_s3:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::guarddutylogs/*"
        }
    ]
}

 

 

创建一项CloudWatch Events规则和为GuardDuty创建一个目标:

  1. 创建一项规则,允许CloudWatch为GuardDuty生成的所有发现发送事件。请运行以下CloudWatch CLI命令:
aws events put-rule --name Test --event-pattern 
"{\"source\":[\"aws.guardduty\"]}"

 

2.将Lambda函数添加为先前所创建规则的目标。请运行以下CloudWatch CLI命令:

aws events put-targets --rule Test --targets Id=1,Arn=arn:aws:lambda:us-east-1:111122223333:function:<your_function>

 

3.添加调用目标所需要的权限。请运行以下CloudWatch CLI命令:

aws lambda add-permission --function-name <your_function> --statement-id 1 --action 'lambda:InvokeFunction' --principal events.amazonaws.com

创建Amazon ES域

Amazon Elasticsearch Service (Amazon ES)是一项托管服务,可帮助我们轻松创建域,并在AWS云当中部署、操作并扩展Elasticsearch集群。Amazon ES是一套流行的开源搜索与分析引擎,适用于日志分析、实时应用程序监控以及点击流分析等诸多应用场景。您可以使用Amazon ES分析GuardDuty日志并过滤特定类型的发现结果。此外,您也可以构建仪表板,用于快速了解不同账户中发生的各项活动。

要创建Amazon ES域,您可以按照Amazon ES开发者指南中的创建Amazon ES域部分进行操作。Amazon ES集群启动并开始运行之后,请注意下图所示的端点。

步骤2:从S3向Amazon ES发送流式数据

在将数据放入S3存储桶之后,即可使用该存储桶作为所有当前及历史数据的存储库。您可以使用 Amazon Machine Learning构建模型,也可以将S3存储桶作为数据湖。

将数据从S3存储桶加载至Amazon ES域。流式数据将为分析及仪表板提供新的数据素材。要加载流式数据,请使用Lambda函数作为AWS云中的事件处理程序。每当将GuardDuty发现结果放入S3存储桶时,即会相应触发事件,由此事件调用Lambda函数,进而运行我们自定义的Java/Node.js/Python/C#代码。

在本次示例设置中,我们使用先前创建的Amazon S3存储桶,其中的所有GuardDuty发现结果均作为事件源提供。按照AWS博文中的说明进行设置,并在Node.js 6.10环境中使用以下代码。另外,请确保S3存储桶中的文件使用JSON文件后缀以正确触发Lambda函数。

Elasticsearch、http-aws-es以及其他库皆由第三方开发,而非AWS。AWS不对外部方案的功能或适用性负责。

Function Code部分,使用以下代码。

/* Imports */
var AWS = require('aws-sdk');
var connectionClass = require('http-aws-es');
var elasticsearch = require('elasticsearch');
var flatten = require('flat');

/* Globals */
var esDomain = {
    endpoint: 'xxxxxxx-guarddutylogsdemo-xxxxxxxxxxxxxxxxxxxxxxx.eu-west-1.es.amazonaws.com',
    region: 'eu-west-1',
    index: 'guarddutylogs',
    doctype: 'logs'
};
var s3 = new AWS.S3();
var elasticClient = new elasticsearch.Client({  
    host: esDomain.endpoint,
    log: 'error',
    connectionClass: connectionClass,
    amazonES: {
      credentials: new AWS.EnvironmentCredentials('AWS')
    }
});
/*
 * Add the given document to the ES domain.
 * If all records are successfully added, indicate success to lambda
 * (using the "context" parameter).
 */
function postDocumentToES(bucket, key, context) {
    
    console.log('Bucket : ' + bucket + '  Key: ' + key);
    //var req = new AWS.HttpRequest(endpoint);
	var logdata = "";
	var numDocsAdded = 0;   // Number of log lines added to ES so far
	
	var params = {
  		Bucket: bucket,
  		Key: key
	};	
	
	var getObjectPromise = s3.getObject(params).promise();
	getObjectPromise.then(function(data) {
  		logdata = JSON.parse(data.Body);
		console.log("logdata: " + JSON.stringify(logdata) + " id: " + logdata.id);
		var flattened_data = JSON.stringify(flatten(logdata, { maxDepth: 10 }));
		console.log("flattened data: " + flattened_data);
	
		elasticClient.create({
			index: esDomain.index,
			type: esDomain.doctype,
			id: logdata.id,
			body: flattened_data
		}, function (error, response) {		
			if(error)
				console.log("error : " + error); // Publish the error response
			else
				console.log("response: " + response);
		});
	}).catch(function(err) {
  		console.log(err);
	});	

}

/* Lambda "main": Execution starts here */
exports.handler = function(event, context) {
	
	console.log('Received event: ', JSON.stringify(event, null, 2));

    event.Records.forEach(function(record) {
        var bucket = record.s3.bucket.name;
        var objKey = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));
        postDocumentToES(bucket, objKey, context);
    });
}

 

步骤3:使用Amazon ES进行分析与搜索

将流式数据传输至Amazon ES之后,您可以将其用于分析,并在账户中搜索各类异常活动。为了能够在Amazon ES域中搜索文档,您可以使用Amazon ES搜索API或者使用Kibana搜索您的文档。Kibana是一款流行的可视化开源工具,能够与Amazon ES使用。Amazon ES提供具有Amazon ES域的Kibana默认安装选项,具体请完成以下操作:

    1. 要查看GuardDuty发现结果,我们可以选择Amazon ES服务直接提供的版本。但这就要求我们采取部分额外举措以保证安全性。为了快捷起见,我们将在个人笔记本电脑上运行Kibana并使用AWS SigV4签名代理,您可以通过GitHub获取。此签名代理由第三方——而非AWS开发。AWS不对内容的功能或适用性负责。此代理非常适合开发与测试类场景,但不适用于生产级工作负载。您可以参阅AWS博文以了解更多详细信息。
    2. 要使用Kibana,请配置至少一种索引模式。Kibana将使用这些索引模式以标识待分析的索引。在浏览器中打开Kibana之后,您将看到Get Started页面。创建索引模式以进行数据可视化。前往Management选项卡,而后选择Index Patterns。创建一个索引模式,在本示例中请选择 * 作为guarddutylogs的通配符,而后选择Next Step。具体如下图所示。

3.在Kibana流程的步骤2中,您也可以配置时间过滤器并选择一个字段,借此按时间范围缩小数据范围。这里我们选择eventLastSeen作为时间过滤器字段,而后选择Create Index Pattern,如下图所示。

4. Index Patterns索引模式屏幕中将显示您的文档字段,例如发现结果类型、攻击向量的来源和其他字段等。在本示例中,以上Lambda函数将对数据进行压平,借此实现搜索与分析。选择Discover选项卡以搜索您的数据。

5.到这里,我们从数据中收集到的最有用的一类信息为 type 。发现类型的目的在于为潜在的安全问题提供简洁且可读的描述。如果您选中表中文档条目左侧的Expand  标记以展开文档表中的文档,即可看到该文档的字段与数据。要显示或隐藏文档表中的字段列,请选择 Toggle column in table  。如果您将其指定为 type,则系统会将数据加载至包含type一列的表当中,如下图所示。

步骤4:使用Kibana仪表板实现数据可视化

在Kibana当中,您还可以对Amazon ES索引中的数据进行可视化。接下来,您可以构建显示相关可视化效果的仪表板。Kibana可视化基于运行在Amazon ES之上的查询。通过使用Amazon ES聚合以提取并处理数据,您可以创建图表与图形以显示您感兴趣的峰值、低谷与趋势。

要在Kibana当中设置仪表板,请执行以下操作:

在Kibana左侧导航栏中选择Visualize,而后选择Create a Visualization + 以创建一个新的可视化视图,而后在Maps下选择Region Map。在本示例中,我们假定需要查看攻击流量来自哪些国家。选择 * 索引模式。

在Options面板中的Layer Settings之下,保证在Join字段中选择Country Name。

在Data面板中,完成以下操作步骤:

1.在Metrics中,选择Count作为聚合类型。这意味着我们可以获取源自特定国家/地区的攻击向量总数。

2.在Buckets之下:

  • 在shape字段的Aggregation之下,选择Terms
  • 在Field部分,选择action.portProbeAction.portProbeDetails.0.remoteIpDetails.country.countryName.keyword作为字段内容,如下图所示。

 

  • 在Order By部分,选择指标:Count。
  • 在Order部分,选择Descending,并将大小设置为5。
  • 选择Apply Changes,如下图所示,以在地图上绘制出各值。


选择在绘制国家/地区值时需要考虑的日志时间范围。如下图所示,这将帮助我们更清晰地理解攻击活动的演变过程。

在应用各项更改之后,即可绘制地图。这时选择Save,以及Save the visualization as Attack By Country。

以类似的方式,您还可以根据攻击类型创建另一个可视化视图。具体示例如下所示。

创建GuardDuty发现结果仪表板

要在Kibana中创建仪表板,请执行以下操作:

  1. 在左侧导航栏中选择Dashboard,选择 + 号以创建新的仪表板。接下来,在顶端导航栏中选择Add,而后选择您刚刚创建完成的两个可视化视图。如此操作,即可将二者添加至当前仪表板。
  2. 在顶端导航栏中选择Save,并为其命名。而后,再次选择Save以进行保存。

在下图所示的仪表板中,我们添加了地图、饼状图与柱状图,借此快速了解账户中出现的威胁向量。

总结

在本篇博文中,我们了解了如何使用Amazon ES对GuardDuty的发现结果进行聚合、搜索与分析。这套解决方案有助于深入了解当前AWS环境中各类潜在的未授权与恶意活动。借助这些信息,您可以决定何时对所有账户中发生的事件采取措施。

如果您对本文还有其他建议与反馈,请在下方评论区中与我们交流。

本篇作者

Rohan Raizada

Amazon Web Services公司解决方案架构师。他与不同规模的企业一道,采用AWS云技术以构建起安全且可扩展的解决方案。在业余时间,他喜欢与家人共享时光以及享受户外自行车骑行。