All Products
Search
Document Center

Cloud Config:Definition and execution of custom function rules

Last Updated:Jan 18, 2024

Cloud Config allows you to create custom rules based on Function Compute to audit associated resources. If a rule is triggered, Cloud Config invokes the corresponding rule function to evaluate the associated resources and then returns the compliance evaluation results for the resources. This topic describes the input parameters of a custom function rule and provides relevant sample Python code.

What is a custom function rule?

A custom function rule is a custom rule that Cloud Config uses a function of Function Compute to carry the rule code.

Scenarios

If the preset rule templates and condition rules of Cloud Config cannot meet the requirements for resource compliance detection, you can write function code to audit resources in complex scenarios or automatically remediate non-compliant resources. For example, in multi-account scenarios, a custom function rule is used to automatically remediate the Elastic Compute Service (ECS) instances on which the CloudMonitor agent is not installed. For more information, see Automatically remediate non-compliant resources across accounts in an enterprise by using a resource directory.

How it works

  1. A function is created in Function Compute.

  2. A custom rule is created based on Function Compute in Cloud Config, and Cloud Config automatically triggers an evaluation.

    Note

    After you create a rule, Cloud Config automatically triggers an evaluation.

  3. Cloud Config obtains the permissions to call the GetFunction and InvokeFunction operations by using the service-linked role AliyunServiceRoleForConfig.

  4. Cloud Config calls the InvokeFunction operation to execute the function to obtain resource configurations and rule information.

  5. The function evaluates the resources.

  6. Function Compute returns the resource evaluation result to Cloud Config by calling the PutEvaluations operation.

    Cloud Config saves the resource evaluation result and displays the result in the Cloud Config console. You can view the result in the Cloud Config console. You can also remediate non-compliant resources or perform settings to deliver resource data to the corresponding cloud service.

Function code

A rule is a snippet of logical judgment code that is stored in a rule function. Cloud Config audits resources based on rules. When a rule is triggered, Cloud Config invokes the corresponding rule function to evaluate the associated resources. In this example, the code of the custom rule function contains the following key functions:

  • handler

    The handler function is the entry function that is invoked when the rule is triggered. When you create a function in the Function Compute console, you must configure the handler function. For more information about the handler function, see Handlers.

    Note

    Cloud Config supports only event handlers. For more information, see Event handlers.

  • put_evaluations

    The resource evaluation result is returned to Cloud Config by calling the PutEvaluations operation.

You can use the following sample Python code to create a rule:

# # !/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 evaluation types of resources. 
COMPLIANCE_TYPE_COMPLIANT = 'COMPLIANT'
COMPLIANCE_TYPE_NON_COMPLIANT = 'NON_COMPLIANT'
COMPLIANCE_TYPE_NOT_APPLICABLE = 'NOT_APPLICABLE'
# The types of pushed resource configurations. 
CONFIGURATION_TYPE_COMMON = 'COMMON'
CONFIGURATION_TYPE_OVERSIZE = 'OVERSIZE'
CONFIGURATION_TYPE_NONE = 'NONE'


# The entry function that orchestrates and processes business logic. 
def handler(event, context):
    """
    Process an event.
    :param event: the event.
    :param context: the context.
    :return: the compliance evaluation result.
    """
    # Check whether the event is valid. You can copy the following sample code based on your business scenario. 
    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')

    # Obtain the resource configurations. A rule must be set to be triggered upon configuration changes. After a rule that you create is triggered or you manually trigger a rule, Cloud Config invokes the rule function to evaluate associated resources one by one. If the configurations of a resource change, Cloud Config automatically invokes the corresponding rule function to evaluate the resource. 
    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 resource configurations that you want to push is greater than or equal to 100 KB. If yes, the GetDiscoveredResource operation is called 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 resources. You must implement the evaluation logic based on your business scenario. The following code is only for reference: 
    compliance_type, annotation = evaluate_configuration_item(
        rule_parameters, configuration_item)

    # Set the compliance evaluation result. The result must use the syntax shown in the following sample: 
    evaluations = [
        {
            'accountId': account_id,
            'complianceResourceId': resource_id,
            'complianceResourceType': resource_type,
            'complianceRegionId': region_id,
            'orderingTimestamp': ordering_timestamp,
            'complianceType': compliance_type,
            'annotation': annotation
        }
    ]

    # Return the compliance evaluation result and write it to Cloud Config. You can copy the following sample code based on your business scenario. 
    put_evaluations(creds, result_token, evaluations)
    return evaluations


# Evaluate a resource based on the rule information and resource configurations. You must implement the evaluation logic based on your business scenario. The following code is only for reference: 
def evaluate_configuration_item(rule_parameters, configuration_item):
    """
    Evaluate a resource.
    :param rule_parameters: the rule information.
    :param configuration_item: the resource configurations.
    :return: the compliance evaluation result.
    """
    # Initialize the return values.
    compliance_type = COMPLIANCE_TYPE_NON_COMPLIANT
    annotation = None

    # Obtain the complete resource configurations.
    full_configuration = configuration_item['configuration']
    if not full_configuration:
        annotation = 'Configuration is empty.'
        return compliance_type, annotation

    # Convert the configurations to a JSON object.
    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):
    """
    Check whether an event is valid.
    :param event: the event.
    :return: the 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 a JSON string into a JSON object.
    :param content: the JSON string.
    :return: the JSON object.
    """
    try:
        return json.loads(content)
    except Exception as e:
        logger.error('Parse content:{} to json error:{}.'.format(content, e))
        return None


# Return the compliance evaluation result and write it to Cloud Config. You can copy the following sample code based on your business scenario. 
def put_evaluations(creds, result_token, evaluations):
    """
    Call the Cloud Config API to return the compliance evaluation result and write the result to Cloud Config. 
    :param context: the Function Compute context.
    :param result_token: the result token.
    :param evaluations: the compliance evaluation result.
    :return: None
    """
    # Your account must be assigned a service role of Function Compute to which the AliyunConfigFullAccess policy is attached. 
    client = AcsClient(creds.access_key_id, creds.access_key_secret, region_id='ap-southeast-1')

    # Create a request and set the parameters. In this example, the domain parameter is set to 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)


# Obtain the details of a resource. You can copy the following sample code based on your business scenario. 
def get_discovered_resource(creds, resource_id, resource_type, region_id):
    """
    Call an API operation to obtain the details of a resource.
    :param context: the Function Compute context.
    :param resource_id: the resource ID.
    :param resource_type: the resource type.
    :param region_id: the ID of the region where the resource resides.
    :return: the resource details.
    """
    # Your account must be assigned a service role of Function Compute to which the AliyunConfigFullAccess policy is 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)
Important

To obtain the parameter names of the rules that you want to configure, we recommend that you view the core parameters of the resource configurations that are specified by the configuration parameter in the code in the Cloud Config console. For more information, see Step 6 in View the information about a resource.

Input parameters

The input parameters of a rule function of Function Compute has two categories: resource configurations and rule information. In an event message, the ruleParameters field stores the input parameters of a rule function. The following code shows the fields in an event message in the JSON format:

For more information about how to obtain the input parameters of a rule function from Function Compute, see View function invocation logs.

{
    "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****"
}

Category

Field

Description

Resource configurations

configurationItem

The configurations of a resource. The following configurations are included: the ID of the Alibaba Cloud account to which the resource belongs, the Alibaba Cloud Resource Name (ARN) of the resource, the ID of the zone where the resource resides, the ID of the region where the resource resides, the detailed configuration of the resource, the timestamp when Cloud Config detected a resource change event and generated a log, the timestamp when the resource was created, the resource status, the resource ID, the resource name, the resource type, and tags.

configurationType

The type of pushed configurations. Valid values:

  • COMMON: If the size of configurationItem is less than 100 KB, the resource configurations are pushed normally.

  • OVERSIZE: If the size of configurationItem is greater than or equal to 100 KB, the GetDiscoveredResource operation is called to query the resource details.

Rule information

orderingTimestamp

The start timestamp of the evaluation execution.

invokingEvent

The invocation event.

accountId

The account ID of the invocation event.

messageType

The message type. Valid values:

  • Manual: manual execution.

  • ConfigurationItemChangeNotification: configuration change.

notificationCreationTimestamp

The timestamp when the rule was triggered.

ruleParameters

The input parameters of the custom rule. The names and expected values of the input parameters of the custom rule must be specified.

resultToken

The result token in Function Compute.