本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
用于 AWS Config 规则 (Node.js) 的示例 AWS Lambda 函数
AWS Lambda 将执行函数来响应由 AWS 服务发布的事件。的函数AWS Config自定义 Lambda 规则接收由发布的事件AWS Config,然后该函数使用它从事件中接收到的数据以及从事件中检索的数据AWS Config用于评估规则合规性的 API。用于 Config 规则的函数的运作方式会因其执行的评估是由配置更改触发还是定期触发而有所不同。
有关其中的常见模式的信息AWS Lambda函数,请参阅编程模型在里面AWS Lambda开发人员指南.
评估由配置更改触发时的示例函数
AWS Config 检测到自定义规则范围内的资源发生配置更改时,会调用函数示例如下。
如果您使用 AWS Config 控制台创建与类似此示例的函数关联的规则,请选择 Configuration changes (配置更改) 作为触发器类型。如果您使用 AWS Config API 或 AWS CLI 创建规则,请将 MessageType
属性设置为 ConfigurationItemChangeNotification
和 OversizedConfigurationItemChangeNotification
。这些设置可使您的规则在每次 AWS Config 生成配置项或资源更改导致过大配置项时触发。
此示例评估您的资源并检查实例是否匹配资源类型 AWS::EC2::Instance
。此规则在 AWS Config 生成配置项或过大配置项通知时触发。
'use strict'; const aws = require('aws-sdk'); const config = new aws.ConfigService(); // Helper function used to validate input function checkDefined(reference, referenceName) { if (!reference) { throw new Error(`Error: ${referenceName} is not defined`); } return reference; } // Check whether the message type is OversizedConfigurationItemChangeNotification, function isOverSizedChangeNotification(messageType) { checkDefined(messageType, 'messageType'); return messageType === 'OversizedConfigurationItemChangeNotification'; } // Get the configurationItem for the resource using the getResourceConfigHistory API. function getConfiguration(resourceType, resourceId, configurationCaptureTime, callback) { config.getResourceConfigHistory({ resourceType, resourceId, laterTime: new Date(configurationCaptureTime), limit: 1 }, (err, data) => { if (err) { callback(err, null); } const configurationItem = data.configurationItems[0]; callback(null, configurationItem); }); } // Convert the oversized configuration item from the API model to the original invocation model. function convertApiConfiguration(apiConfiguration) { apiConfiguration.awsAccountId = apiConfiguration.accountId; apiConfiguration.ARN = apiConfiguration.arn; apiConfiguration.configurationStateMd5Hash = apiConfiguration.configurationItemMD5Hash; apiConfiguration.configurationItemVersion = apiConfiguration.version; apiConfiguration.configuration = JSON.parse(apiConfiguration.configuration); if ({}.hasOwnProperty.call(apiConfiguration, 'relationships')) { for (let i = 0; i < apiConfiguration.relationships.length; i++) { apiConfiguration.relationships[i].name = apiConfiguration.relationships[i].relationshipName; } } return apiConfiguration; } // Based on the message type, get the configuration item either from the configurationItem object in the invoking event or with the getResourceConfigHistory API in the getConfiguration function. function getConfigurationItem(invokingEvent, callback) { checkDefined(invokingEvent, 'invokingEvent'); if (isOverSizedChangeNotification(invokingEvent.messageType)) { const configurationItemSummary = checkDefined(invokingEvent.configurationItemSummary, 'configurationItemSummary'); getConfiguration(configurationItemSummary.resourceType, configurationItemSummary.resourceId, configurationItemSummary.configurationItemCaptureTime, (err, apiConfigurationItem) => { if (err) { callback(err); } const configurationItem = convertApiConfiguration(apiConfigurationItem); callback(null, configurationItem); }); } else { checkDefined(invokingEvent.configurationItem, 'configurationItem'); callback(null, invokingEvent.configurationItem); } } // Check whether the resource has been deleted. If the resource was deleted, then the evaluation returns not applicable. function isApplicable(configurationItem, event) { checkDefined(configurationItem, 'configurationItem'); checkDefined(event, 'event'); const status = configurationItem.configurationItemStatus; const eventLeftScope = event.eventLeftScope; return (status === 'OK' || status === 'ResourceDiscovered') && eventLeftScope === false; } // In this example, the resource is compliant if it is an instance and its type matches the type specified as the desired type. // If the resource is not an instance, then this resource is not applicable. function evaluateChangeNotificationCompliance(configurationItem, ruleParameters) { checkDefined(configurationItem, 'configurationItem'); checkDefined(configurationItem.configuration, 'configurationItem.configuration'); checkDefined(ruleParameters, 'ruleParameters'); if (configurationItem.resourceType !== 'AWS::EC2::Instance') { return 'NOT_APPLICABLE'; } else if (ruleParameters.desiredInstanceType === configurationItem.configuration.instanceType) { return 'COMPLIANT'; } return 'NON_COMPLIANT'; } // Receives the event and context from AWS Lambda. exports.handler = (event, context, callback) => { checkDefined(event, 'event'); const invokingEvent = JSON.parse(event.invokingEvent); const ruleParameters = JSON.parse(event.ruleParameters); getConfigurationItem(invokingEvent, (err, configurationItem) => { if (err) { callback(err); } let compliance = 'NOT_APPLICABLE'; const putEvaluationsRequest = {}; if (isApplicable(configurationItem, event)) { // Invoke the compliance checking function. compliance = evaluateChangeNotificationCompliance(configurationItem, ruleParameters); } // Initializes the request that contains the evaluation results. putEvaluationsRequest.Evaluations = [ { ComplianceResourceType: configurationItem.resourceType, ComplianceResourceId: configurationItem.resourceId, ComplianceType: compliance, OrderingTimestamp: configurationItem.configurationItemCaptureTime, }, ]; putEvaluationsRequest.ResultToken = event.resultToken; // Sends the evaluation results to AWS Config. config.putEvaluations(putEvaluationsRequest, (error, data) => { if (error) { callback(error, null); } else if (data.FailedEvaluations.length > 0) { // Ends the function if evaluation results are not successfully reported to AWS Config. callback(JSON.stringify(data), null); } else { callback(null, data); } }); }); };
函数运作
本函数在运行时执行以下操作:
-
该函数在以下情况下运行AWS Lambda传递
event
反对handler
函数。在此示例中,该函数接受可选的callback
参数,它使用它向调用者返回信息。AWS Lambda也通过了context
对象,它包含函数在运行时可以使用的信息和方法。请注意,在较新版本的 Lambda 中,不再使用上下文。 -
此函数检查事件的
messageType
是配置项还是过大配置项,然后返回配置项。 -
处理程序调用
isApplicable
函数来确定资源是否已删除。 -
处理程序调用
evaluateChangeNotificationCompliance
函数并传递 AWS Config 在事件中发布的configurationItem
和ruleParameters
对象。函数首先评估资源是否为 EC2 实例。如果资源不是 EC2 实例,函数会返回
NOT_APPLICABLE
这一合规性值。然后,函数评估配置项中的
instanceType
属性是否与desiredInstanceType
参数值一致。如果值相等,该函数将返回COMPLIANT
。如果值不相等,该函数将返回NON_COMPLIANT
。 -
处理程序通过初始化
putEvaluationsRequest
对象来做好向 AWS Config 发送评估结果的准备。该对象包含Evaluations
参数,这一参数用于识别受评估资源的合规性结果、资源类型和 ID。putEvaluationsRequest
对象还包含来自事件的结果令牌,该令牌可标识 AWS Config 的规则和事件。 -
处理程序通过向
config
客户端的putEvaluations
方法传递对象来向 AWS Config 发送评估结果。
定期评估时的示例函数
AWS Config 针对定期评估调用的函数示例如下。定期评估按您在 AWS Config 中定义规则时指定的频率进行。
如果您使用 AWS Config 控制台创建与类似此示例的函数关联的规则,请选择 Periodic (定期) 作为触发器类型。如果您使用 AWS Config API 或 AWS CLI 创建规则,请将 MessageType
属性设置为 ScheduledNotification
。
本示例会检查指定资源的总数是否超出指定的最大值。
var aws = require('aws-sdk'), // Loads the AWS SDK for JavaScript. config = new aws.ConfigService(), // Constructs a service object to use the aws.ConfigService class. COMPLIANCE_STATES = { COMPLIANT : 'COMPLIANT', NON_COMPLIANT : 'NON_COMPLIANT', NOT_APPLICABLE : 'NOT_APPLICABLE' }; // Receives the event and context from AWS Lambda. exports.handler = function(event, context, callback) { // Parses the invokingEvent and ruleParameters values, which contain JSON objects passed as strings. var invokingEvent = JSON.parse(event.invokingEvent), ruleParameters = JSON.parse(event.ruleParameters), noOfResources = 0; if (isScheduledNotification(invokingEvent)) { countResourceTypes(ruleParameters.applicableResourceType, "", noOfResources, function(err, count) { if (err === null) { var putEvaluationsRequest; // Initializes the request that contains the evaluation results. putEvaluationsRequest = { Evaluations : [ { // Applies the evaluation result to the AWS account published in the event. ComplianceResourceType : 'AWS::::Account', ComplianceResourceId : event.accountId, ComplianceType : evaluateCompliance(ruleParameters.maxCount, count), OrderingTimestamp : new Date() } ], ResultToken : event.resultToken }; // Sends the evaluation results to AWS Config. config.putEvaluations(putEvaluationsRequest, function(err, data) { if (err) { callback(err, null); } else { if (data.FailedEvaluations.length > 0) { // Ends the function execution if evaluation results are not successfully reported callback(JSON.stringify(data)); } callback(null, data); } }); } else { callback(err, null); } }); } else { console.log("Invoked for a notification other than Scheduled Notification... Ignoring."); } }; // Checks whether the invoking event is ScheduledNotification. function isScheduledNotification(invokingEvent) { return (invokingEvent.messageType === 'ScheduledNotification'); } // Checks whether the compliance conditions for the rule are violated. function evaluateCompliance(maxCount, actualCount) { if (actualCount > maxCount) { return COMPLIANCE_STATES.NON_COMPLIANT; } else { return COMPLIANCE_STATES.COMPLIANT; } } // Counts the applicable resources that belong to the AWS account. function countResourceTypes(applicableResourceType, nextToken, count, callback) { config.listDiscoveredResources({resourceType : applicableResourceType, nextToken : nextToken}, function(err, data) { if (err) { callback(err, null); } else { count = count + data.resourceIdentifiers.length; if (data.nextToken !== undefined && data.nextToken != null) { countResourceTypes(applicableResourceType, data.nextToken, count, callback); } callback(null, count); } }); return count; }
函数运作
本函数在运行时执行以下操作:
-
该函数在以下情况下运行AWS Lambda传递
event
反对handler
函数。在此示例中,该函数接受可选的callback
参数,它使用它向调用者返回信息。AWS Lambda也通过了context
对象,它包含函数在运行时可以使用的信息和方法。请注意,在较新版本的 Lambda 中,不再使用上下文。 -
为计数指定类型的资源,处理程序会调用
countResourceTypes
函数,而且它传递其从事件收到的applicableResourceType
参数。countResourceTypes
函数调用listDiscoveredResources
客户端的config
方法,该方法返回适用资源的标识符列表。该函数使用此列表的长度来确定适用资源的数量,而且它将此计数返回到处理程序。 -
处理程序通过初始化
putEvaluationsRequest
对象来做好向 AWS Config 发送评估结果的准备。此对象包括Evaluations
参数,用于标识合规性结果和AWS 账户那是在活动中发布的。您可以使用Evaluations
参数将结果应用于 AWS Config 支持的任何资源类型。putEvaluationsRequest
对象还包含来自事件的结果令牌,该令牌可标识 AWS Config 的规则和事件。 -
在
putEvaluationsRequest
对象中,处理程序调用evaluateCompliance
函数。此函数测试适用资源的数量是否超出分配给事件所提供的maxCount
参数的最大值。如果资源的数量超出最大值,函数将返回NON_COMPLIANT
。如果资源的数量没有超出最大值,函数将返回COMPLIANT
。 -
处理程序通过向
config
客户端的putEvaluations
方法传递对象来向 AWS Config 发送评估结果。