When a custom function rule is triggered, Cloud Config invokes the associated function in Function Compute to evaluate your resources and return a compliance result. This page explains the function code structure and input parameters with a Python example.
Custom function rule
A custom function rule uses a Function Compute function to define and run its evaluation logic.
Scenarios
If managed rules and condition rules do not meet your compliance requirements, write custom functions for complex evaluations. Additional scenarios and code examples are available in the Custom function rule sample library.
Mechanism
The following figure shows the execution flow of a custom function rule.

Execution steps:
-
Create a function in Function Compute.
-
Create a custom rule based on the function in Cloud Config. An evaluation is automatically triggered.
NoteCloud Config automatically triggers an evaluation after rule creation.
-
Cloud Config uses its service-linked role (AliyunServiceRoleForConfig) to obtain permissions for the GetFunction and InvokeFunction API operations.
-
Cloud Config calls the InvokeFunction API operation to run the function and passes the configuration item and rule information.
-
The function evaluates the resource.
-
The function calls the PutEvaluations API operation to return the compliance evaluation result to Cloud Config.
Cloud Config saves and displays the result in the console. You can then remediate non-compliant resources or deliver data to other Alibaba Cloud services.
Function code
A rule is evaluation logic stored in a function. Cloud Config invokes this function during auditing. The function code has two parts:
-
handlerThe
handleris the entry function invoked when the rule triggers. You must specify the handler when creating a function in the Function Compute console. Handlers.NoteCloud Config supports only event handlers.
-
put_evaluationsThis function calls the PutEvaluations API operation to submit the compliance evaluation result to Cloud Config.
The following code provides a Python example:
# #!/usr/bin/env python
# # -*- encoding: utf-8 -*-
import json
import logging
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
logger = logging.getLogger()
# The compliance type of a resource.
COMPLIANCE_TYPE_COMPLIANT = 'COMPLIANT'
COMPLIANCE_TYPE_NON_COMPLIANT = 'NON_COMPLIANT'
COMPLIANCE_TYPE_NOT_APPLICABLE = 'NOT_APPLICABLE'
# The delivery type of a resource configuration.
CONFIGURATION_TYPE_COMMON = 'COMMON'
CONFIGURATION_TYPE_OVERSIZE = 'OVERSIZE'
CONFIGURATION_TYPE_NONE = 'NONE'
# The entry function that orchestrates and processes the business logic.
def handler(event, context):
"""
The handler function.
:param event: The event.
:param context: The context.
:return: The evaluation result.
"""
# Validate the event. You can copy this code block.
evt = validate_event(event)
if not evt:
return None
creds = context.credentials
rule_parameters = evt.get('ruleParameters')
result_token = evt.get('resultToken')
invoking_event = evt.get('invokingEvent')
ordering_timestamp = evt.get('orderingTimestamp')
# The configuration of the resource. The trigger of the rule must be set to Configuration Change. When you create or manually run a rule, Cloud Config invokes the function to evaluate all resources one by one. If the configuration of a resource changes, Cloud Config automatically invokes the function to evaluate the resource based on the change information.
configuration_item = invoking_event.get('configurationItem')
account_id = configuration_item.get('accountId')
resource_id = configuration_item.get('resourceId')
resource_type = configuration_item.get('resourceType')
region_id = configuration_item.get('regionId')
# Check whether the size of the delivered resource configuration is greater than or equal to 100 KB. If it is, you must call the GetDiscoveredResource operation to query the resource details.
configuration_type = invoking_event.get('configurationType')
if configuration_type and configuration_type == CONFIGURATION_TYPE_OVERSIZE:
resource_result = get_discovered_resource(creds, resource_id, resource_type, region_id)
resource_json = json.loads(resource_result)
configuration_item["configuration"] = resource_json["DiscoveredResourceDetail"]["Configuration"]
# Evaluate the resource. You must implement the evaluation logic based on your business requirements. The following code is for reference only.
compliance_type, annotation = evaluate_configuration_item(
rule_parameters, configuration_item)
# Set the evaluation result. The format must comply with the following example.
evaluations = [
{
'accountId': account_id,
'complianceResourceId': resource_id,
'complianceResourceType': resource_type,
'complianceRegionId': region_id,
'orderingTimestamp': ordering_timestamp,
'complianceType': compliance_type,
'annotation': annotation
}
]
# Submit the evaluation result to Cloud Config. You can copy this code block.
put_evaluations(creds, result_token, evaluations)
return evaluations
# Evaluate the resource based on the rule information and resource configuration. You must implement the evaluation logic based on your business requirements. The following code is for reference only.
def evaluate_configuration_item(rule_parameters, configuration_item):
"""
The evaluation logic.
:param rule_parameters: The rule information.
:param configuration_item: The resource configuration.
:return: The compliance type.
"""
# Initialize the return value.
compliance_type = COMPLIANCE_TYPE_NON_COMPLIANT
annotation = None
# Obtain the full resource configuration.
full_configuration = configuration_item['configuration']
if not full_configuration:
annotation = 'Configuration is empty.'
return compliance_type, annotation
# Convert the configuration to the JSON format.
configuration = parse_json(full_configuration)
if not configuration:
annotation = 'Configuration:{} is invalid.'.format(full_configuration)
return compliance_type, annotation
return compliance_type, annotation
def validate_event(event):
"""
Validate the event.
:param event: The event.
:return: A JSON object.
"""
if not event:
logger.error('Event is empty.')
evt = parse_json(event)
logger.info('Loading event: %s .' % evt)
if 'resultToken' not in evt:
logger.error('ResultToken is empty.')
return None
if 'ruleParameters' not in evt:
logger.error('RuleParameters is empty.')
return None
if 'invokingEvent' not in evt:
logger.error('InvokingEvent is empty.')
return None
return evt
def parse_json(content):
"""
Convert data to the JSON format.
:param content: A JSON string.
:return: A JSON object.
"""
try:
return json.loads(content)
except Exception as e:
logger.error('Parse content:{} to json error:{}.'.format(content, e))
return None
# Submit the evaluation result to Cloud Config. You can copy this code block.
def put_evaluations(creds, result_token, evaluations):
"""
Call an API operation to return and write the evaluation result.
:param creds: The credentials of the function.
:param result_token: The result token.
:param evaluations: The evaluation results.
:return: None
"""
# The service-linked role for Function Compute must have the AliyunConfigFullAccess policy attached.
client = AcsClient(creds.access_key_id, creds.access_key_secret, region_id='ap-southeast-1')
# Create a request and set its parameters. The domain name is config.ap-southeast-1.aliyuncs.com.
request = CommonRequest()
request.set_domain('config.ap-southeast-1.aliyuncs.com')
request.set_version('2019-01-08')
request.set_action_name('PutEvaluations')
request.add_body_params('ResultToken', result_token)
request.add_body_params('Evaluations', evaluations)
request.add_body_params('SecurityToken', creds.security_token)
request.set_method('POST')
try:
response = client.do_action_with_exception(request)
logger.info('PutEvaluations with request: {}, response: {}.'.format(request, response))
except Exception as e:
logger.error('PutEvaluations error: %s' % e)
# Retrieve the full resource details. You can copy this code block.
def get_discovered_resource(creds, resource_id, resource_type, region_id):
"""
Call an API operation to obtain the resource configuration details.
:param creds: The credentials of the function.
:param resource_id: The resource ID.
:param resource_type: The resource type.
:param region_id: The ID of the region in which the resource resides.
:return: The resource details.
"""
# The service-linked role for Function Compute must have the AliyunConfigFullAccess policy attached.
client = AcsClient(creds.access_key_id, creds.access_key_secret, region_id='ap-southeast-1')
request = CommonRequest()
request.set_domain('config.ap-southeast-1.aliyuncs.com')
request.set_version('2020-09-07')
request.set_action_name('GetDiscoveredResource')
request.add_query_param('ResourceId', resource_id)
request.add_query_param('ResourceType', resource_type)
request.add_query_param('Region', region_id)
request.add_query_param('SecurityToken', creds.security_token)
request.set_method('GET')
try:
response = client.do_action_with_exception(request)
resource_result = str(response, encoding='utf-8')
return resource_result
except Exception as e:
logger.error('GetDiscoveredResource error: %s' % e)
View the configuration field in the configuration item in the Cloud Config console to identify parameter names for your rule. See Step 6 in View resource information.
Function inputs
Function input parameters consist of a configuration item and rule information. The content sent to Function Compute varies based on the Trigger of the rule.
To obtain function input parameters in Function Compute, View invocation logs.
-
If the Trigger of the rule is set to Periodic only, Cloud Config does not send configuration items to Function Compute.
When a rule runs for the first time, on a schedule, or manually, Cloud Config sends a single record without a configuration item. Example:
{ "orderingTimestamp": 1716365226714, "invokingEvent": { "accountId": 120886317861****, "messageType": "ScheduledNotification", "notificationCreationTimestamp": 1716365226714, "configurationType": "NONE" }, "ruleParameters": { "CpuCount": "2" }, "resultToken": "HLQr3BZx/C+DLjwudFcYdXxZFPF2HnGqlg1uHceZ5kDEFeQF2K5LZGofyhn+GE4NP5VgkwANUH3qcdeSjWwODk1ymtmLWLzFV4JForVWYIKdbwwhbDBOgVwF7Ov9c3uVCNz/KpxNElwhTzMkZB95U1vmLs4vUYXuB/Txw4jiCYBYZZnVumhwXWswTLvAhIe5Y451FckObyM3I47AaB+4KtDW3I5q8O+Kx7eSYkqqGTawmJEYjvWXz9CHHMLFtNYyJX54a35mpVdxFSvgeXYDJTStxqb+d9UH/162fZh7T78OHxpQZgl8bcXzZhml****" } -
If the Trigger of the rule includes Configuration Changes, Cloud Config sends the configuration item to Function Compute.
On first run, scheduled run, or manual run, Cloud Config sends configuration items one by one. When a resource is created or changed, Cloud Config sends only the affected configuration item. Example:
{ "orderingTimestamp":1695786337959, "invokingEvent":{ "accountId":120886317861****, "messageType":"Manual", "notificationCreationTimestamp":1695786337959, "configurationType":"COMMON", "configurationItem":{ "accountId":120886317861****, "arn":"acs:ecs:ap-southeast-1:120886317861****:instance/i-t4n0vr6x7v54jdbu****", "availabilityZone":"ap-southeast-1a", "regionId":"ap-southeast-1", "configuration":"{\\"ResourceGroupId\\":\\"\\",\\"Memory\\":4096,\\"InstanceChargeType\\":\\"PostPaid\\",\\"Cpu\\":2,\\"OSName\\":\\"Alibaba Cloud Linux 3.2104 LTS 64\xe4\xbd\x8d\\",\\"InstanceNetworkType\\":\\"vpc\\",\\"InnerIpAddress\\":{\\"IpAddress\\":[]},\\"ExpiredTime\\":\\"2099-12-31T15:59Z\\",\\"ImageId\\":\\"aliyun_3_x64_20G_alibase_20230727.vhd\\",\\"EipAddress\\":{\\"AllocationId\\":\\"\\",\\"IpAddress\\":\\"\\",\\"InternetChargeType\\":\\"\\"},\\"ImageOptions\\":{},\\"VlanId\\":\\"\\",\\"HostName\\":\\"iZt4n0vr6x7v54jdbuk****\\",\\"Status\\":\\"Running\\",\\"HibernationOptions\\":{\\"Configured\\":false},\\"MetadataOptions\\":{\\"HttpTokens\\":\\"\\",\\"HttpEndpoint\\":\\"\\"},\\"InstanceId\\":\\"i-t4n0vr6x7v54jdbu****\\",\\"StoppedMode\\":\\"Not-applicable\\",\\"CpuOptions\\":{\\"ThreadsPerCore\\":2,\\"Numa\\":\\"ON\\",\\"CoreCount\\":1},\\"StartTime\\":\\"2023-08-18T09:02Z\\",\\"DeletionProtection\\":false,\\"VpcAttributes\\":{\\"PrivateIpAddress\\":{\\"IpAddress\\":[\\"192.168.XX.XX\\"]},\\"VpcId\\":\\"vpc-t4nmwd0l9a7aj09yr****\\",\\"VSwitchId\\":\\"vsw-t4njclm0dlz2szayi****\\",\\"NatIpAddress\\":\\"\\"},\\"SecurityGroupIds\\":{\\"SecurityGroupId\\":[\\"sg-t4n5pulxj2lvechw****\\"]},\\"InternetChargeType\\":\\"PayByTraffic\\",\\"InstanceName\\":\\"zs-test-peer****\\",\\"DeploymentSetId\\":\\"\\",\\"InternetMaxBandwidthOut\\":0,\\"SerialNumber\\":\\"8c3fadf7-2ea1-4486-84ce-7784aeb7****\\",\\"OSType\\":\\"linux\\",\\"CreationTime\\":\\"2023-08-18T09:02Z\\",\\"AutoReleaseTime\\":\\"\\",\\"Description\\":\\"\\",\\"InstanceTypeFamily\\":\\"ecs.c7\\",\\"DedicatedInstanceAttribute\\":{\\"Tenancy\\":\\"\\",\\"Affinity\\":\\"\\"},\\"PublicIpAddress\\":{\\"IpAddress\\":[]},\\"GPUSpec\\":\\"\\",\\"NetworkInterfaces\\":{\\"NetworkInterface\\":[{\\"Type\\":\\"Primary\\",\\"PrimaryIpAddress\\":\\"192.168.XX.XX\\",\\"MacAddress\\":\\"00:16:3e:04:XX:XX\\",\\"NetworkInterfaceId\\":\\"eni-t4n16tmnpp794y1o****\\",\\"PrivateIpSets\\":{\\"PrivateIpSet\\":[{\\"PrivateIpAddress\\":\\"192.168.XX.XX\\",\\"Primary\\":true}]}}]},\\"SpotPriceLimit\\":0.0,\\"SaleCycle\\":\\"\\",\\"DeviceAvailable\\":true,\\"InstanceType\\":\\"ecs.c7.large\\",\\"OSNameEn\\":\\"Alibaba Cloud Linux 3.2104 LTS 64 bit\\",\\"SpotStrategy\\":\\"NoSpot\\",\\"IoOptimized\\":true,\\"ZoneId\\":\\"ap-southeast-1a\\",\\"ClusterId\\":\\"\\",\\"EcsCapacityReservationAttr\\":{\\"CapacityReservationPreference\\":\\"\\",\\"CapacityReservationId\\":\\"\\"},\\"DedicatedHostAttribute\\":{\\"DedicatedHostId\\":\\"\\",\\"DedicatedHostName\\":\\"\\",\\"DedicatedHostClusterId\\":\\"\\"},\\"GPUAmount\\":0,\\"OperationLocks\\":{\\"LockReason\\":[]},\\"InternetMaxBandwidthIn\\":-1,\\"Recyclable\\":false,\\"RegionId\\":\\"ap-southeast-1\\",\\"CreditSpecification\\":\\"\\"}", "captureTime":1695786337959, "resourceCreateTime":1692349320000, "resourceId":"i-t4n0vr6x7v54jdbu****", "resourceName":"zs-test-peer****", "resourceGroupId":"rg-acfmw3ty5y7****", "resourceType":"ACS::ECS::Instance", "tags":"{}" } }, "ruleParameters":{ "CpuCount":"2" }, "resultToken":"HLQr3BZx/C+DLjwudFcYdXxZFPF2HnGqlg1uHceZ5kDEFeQF2K5LZGofyhn+GE4NP5VgkwANUH3qcdeSjWwODk1ymtmLWLzFV4JForVWYIKdbwwhbDBOgVwF7Ov9c3uVCNz/KpxNElwhTzMkZB95U1vmLs4vUYXuB/Txw4jiCYBYZZnVumhwXWswTLvAhIe5Y451FckObyM3I47AaB+4KtDW3I5q8O+Kx7eSYkqqGTawmJEYjvWXz9CHHMLFtNYyJX54a35mpVdxFSvgeXYDJTStxqb+d9UH/162fZh7T78OHxpQZgl8bcXzZhml****" }If a configuration item is 100 KB or larger, Cloud Config sends only a resource summary without the
configurationfield. Example:NoteTo obtain the full resource configuration, you can call the GetDiscoveredResource API operation.
{ "orderingTimestamp":1695786337959, "invokingEvent":{ "accountId":120886317861****, "messageType":"Manual", "notificationCreationTimestamp":1695786337959, "configurationType":"OVERSIZE", "configurationItem":{ "accountId":120886317861****, "arn":"acs:ecs:ap-southeast-1:120886317861****:instance/i-t4n0vr6x7v54jdbu****", "availabilityZone":"ap-southeast-1a", "regionId":"ap-southeast-1", "captureTime":1695786337959, "resourceCreateTime":1692349320000, "resourceId":"i-t4n0vr6x7v54jdbu****", "resourceName":"zs-test-peer****", "resourceGroupId":"rg-acfmw3ty5y7****", "resourceType":"ACS::ECS::Instance", "tags":"{}" } }, "ruleParameters":{ "CpuCount":"2" }, "resultToken":"HLQr3BZx/C+DLjwudFcYdXxZFPF2HnGqlg1uHceZ5kDEFeQF2K5LZGofyhn+GE4NP5VgkwANUH3qcdeSjWwODk1ymtmLWLzFV4JForVWYIKdbwwhbDBOgVwF7Ov9c3uVCNz/KpxNElwhTzMkZB95U1vmLs4vUYXuB/Txw4jiCYBYZZnVumhwXWswTLvAhIe5Y451FckObyM3I47AaB+4KtDW3I5q8O+Kx7eSYkqqGTawmJEYjvWXz9CHHMLFtNYyJX54a35mpVdxFSvgeXYDJTStxqb+d9UH/162fZh7T78OHxpQZgl8bcXzZhml****" }
The following table lists key function input parameters by category.
|
Category |
Parameter |
Description |
|
Configuration item |
configurationItem |
A JSON object representing the resource configuration state at a specific time, including resource ID, type, region, creation timestamp, tags, and full configuration. |
|
configurationType |
The delivery type of the configuration item. Valid values:
|
|
|
Rule information |
orderingTimestamp |
The timestamp when the evaluation started. |
|
invokingEvent |
The invocation event. |
|
|
accountId |
The account ID associated with the invocation event. |
|
|
messageType |
The message type. Valid values:
|
|
|
notificationCreationTimestamp |
The timestamp when the rule was triggered. |
|
|
ruleParameters |
The input parameters for the custom rule, including parameter names and expected values. |
|
|
resultToken |
A token required when submitting evaluation results through the PutEvaluations API operation. |