Azure Functions Hosting

Overview

The Azure provider supports deploying policies into Azure Functions to run them inexpensively in your subscription. Currently, you can deploy timer triggered functions (azure-periodic) or Event Grid triggered functions (azure-event-grid).

The first deployment to an Azure Function will create the following resources in your Azure subscription:

  • Resource Group: Holds all the resources

  • Azure Storage: Serves as the backend data store for the Functions

  • Application Insights: Provides logging and metric tracking for the Functions

  • App Service Plan: A Linux based consumption plan using the V2 runtime to support Python Functions

  • Function App: The Function that executes the given policy

Successive policy deployments will only create a new Function App for the policy, because the rest of the infrastructure can be shared.

Note: Python 3.6 or higher is required to deploy a policy to an Azure Function.

Azure Modes

Custodian can run in numerous modes. The default mode is pull.

  • pull:

    Default mode, which executes the policy locally to where Custodian is run.

    properties:
      type:
        enum:
        - pull
    required:
    - type
    
  • azure-periodic:

    Creates a timer triggered Azure Function to run the policy in Custodian. The timing is executed based on a user defined cron interval , such as every 15 minutes or every hour on weekdays.

    properties:
      execution-options:
        type: object
      provision-options:
        appInsights:
          oneOf:
          - type: string
          - properties:
              location: string
              name: string
              resourceGroupName: string
            type: object
          type: object
        servicePlan:
          oneOf:
          - type: string
          - properties:
              autoScale:
                properties:
                  defaultCapacity:
                    type: string
                  enabled:
                    type: boolean
                  maxCapacity:
                    type: string
                  minCapacity:
                    type: string
                type: object
              location: string
              name: string
              resourceGroupName: string
              skuName: string
              skuTier: string
            type: object
          type: object
        storageAccount:
          oneOf:
          - type: string
          - properties:
              location: string
              name: string
              resourceGroupName: string
            type: object
          type: object
        type: object
      schedule:
        pattern: ^\s?([0-5]?[0-9]|\,|(\*\/)|\-)+ (\*|[0-5]?[0-9]|\,|\/|\-)+ (\*|[0-9]|(1[0-9])|(2[0-3])|\,|\/|\-)+
          (\*|[1-9]|([1-2][0-9])|(3[0-1])|\,|\*\/|\-)+ ([Jj](an|anuary)|[Ff](eb|ebruary)|[Mm](ar|arch)|[Aa](pr|pril)|[Mm]ay|[Jj](un|une)|[Jj](ul|uly)|[Aa](ug|ugust)|[Ss](ep|eptember)|[Oo](ct|ctober)|[Nn](ov|ovember)|[Dd](ec|ecember)|\,|\*\/|[1-9]|(1[0-2])|\*)+
          ([Mm](on|onday)|[Tt](u|ue|ues|uesday)|[Ww](ed|ednesday)|[Tt](hu|hursday)|[Ff](ri|riday)|[Ss](at|aturday)|[Ss](un|unday)|[0-6]|\,|\*|\-)+\s?$
        type: string
      type:
        enum:
        - azure-periodic
    required:
    - type
    
  • azure-event-grid:

    Creates Event Grid triggered Azure Functions to run the policy in Custodian. This mode allows you to apply your policies when events occur. See Azure Event Grid for more details.

    properties:
      events:
        items:
          oneOf:
          - type: string
          - properties:
              event:
                type: string
              resourceProvider:
                type: string
            required:
            - resourceProvider
            - event
            type: object
        maxItems: 5
        type: array
      execution-options:
        type: object
      provision-options:
        appInsights:
          oneOf:
          - type: string
          - properties:
              location: string
              name: string
              resourceGroupName: string
            type: object
          type: object
        servicePlan:
          oneOf:
          - type: string
          - properties:
              autoScale:
                properties:
                  defaultCapacity:
                    type: string
                  enabled:
                    type: boolean
                  maxCapacity:
                    type: string
                  minCapacity:
                    type: string
                type: object
              location: string
              name: string
              resourceGroupName: string
              skuName: string
              skuTier: string
            type: object
          type: object
        storageAccount:
          oneOf:
          - type: string
          - properties:
              location: string
              name: string
              resourceGroupName: string
            type: object
          type: object
        type: object
      type:
        enum:
        - azure-event-grid
    required:
    - events
    - type
    

Provision Options

The following Azure resources are required to support an Azure Function. If they do not exist, Custodian will create them as it creates the Azure Function for the policy.

  • Storage (shared across functions)

  • Application Insights (shared across functions)

  • Application Service Plan (shared across functions with optional default auto scale rule)

  • Application Service (per function)

Functions can be deployed in either a dedicated Application Service Plan (Basic, Standard or Premium) or in a Consumption plan. More details on the different hosting models offered by Azure Functions can be found in the Azure Functions documentation. By default, Custodian policies are run using the Consumption hosting model. (i.e. skuTier=dynamic)

Note: Linux Consumption plans are not available in all regions. You will get an error when applying the policy if you use an unsupported location.

You can enable auto scaling for your dedicated App Service Plan. The default auto scaling allows you to specify the minimum and maximum number of VMs underlying the Functions. The App Service Plan will be scaled up if the average RAM usage was more than 80% in the past 10 minutes. This option is disabled by default.

The same shared resources from above can be used to service multiple Functions. This is done by specifying the resources names in the policy deployment definition, or by using the default names every time. When deploying a new policy using existing infrastructure, only the new Function will be created.

The default set of parameters for Azure Storage, Application Insights, and Application Service Plan will deploy the function successfully. To customize the deployment, the defaults can be overwritten by setting the provision-options object on mode. The following keys are supported, with their default values shown:

  • servicePlan
    • name (default: cloud-custodian)

    • location (default: East US)

    • resourceGroupName (default: cloud-custodian)

    • skuTier (default: Dynamic) # consumption

    • skuName (default: Y1)

    • autoScale (optional):
      • enabled (default: False)

      • minCapacity (default: 1)

      • maxCapacity (default: 1)

      • defaultCapacity (default: 1)

  • storageAccount
    • name (default: custodian + sha256(resourceGroupName+subscription_id)[:8])

    • location (default: servicePlan location)

    • resourceGroupName (default: servicePlan resource group)

  • appInsights
    • name (default: servicePlan resource group)

    • location (default: servicePlan location)

    • resourceGroupName (default: servicePlan name)

The location allows you to choose the region to deploy the resource group and resources that will be provisioned. Application Insights has 20 available locations and thus may not always be in the same region as the other resources. For details, see Application Insights availability by region.

If the specified resources already exist in the subscription, discovered by resource group and resource name, Custodian will not change the existing resource regardless of the parameters set by the policy. If a resource does not exist, it will be provisioned using the provided configuration.

You can provide resource IDs to specify existing infrastructure, rather than matching resource group and resource name. Please see the third example below for the correct formatting. Custodian verifies that the resources defined by the given IDs exist before creating the Function. If the resource is missing, Custodian will return an error.

The following example shows how to deploy a policy to a timer-triggered Function that runs every hour. The defaults are accepted for Storage and Application Insights, and custom values are provided for the Service Plan. This policy deploys a dedicated Basic B1 App Service Plan with the default auto scaling turned on. Based on the RAM consumption in the underlying VMs, the App Service Plan will be backed by 1-3 VMs.

policies:
  - name: stopped-vm
    mode:
        type: azure-periodic
        schedule: '0 0 * * * *'
        provision-options:
          servicePlan:
            name: functionshost
            skuTier: Basic
            skuName: B1
            autoScale:
              enabled: true
              minCapacity: 1
              maxCapacity: 3
              defaultCapacity: 1
     resource: azure.vm
     filters:
      - type: instance-view
        key: statuses[].code
        op: not-in
        value_type: swap
        value: "PowerState/running"

The following example shows how to set the name, size and location of all three components of the supporting infrastructure:

policies:
  - name: stopped-vm
    mode:
        type: azure-periodic
        schedule: '0 0 * * * *'
        provision-options:
          servicePlan:
            name: functionshost
            location: East US
            skuTier: Standard
            skuName: S1
          appInsights:
            location: East US
          storageAccount:
            name: sampleaccount
            location: East US
     resource: azure.vm
     filters:
      - type: instance-view
        key: statuses[].code
        op: not-in
        value_type: swap
        value: "PowerState/running"

The final example shows how to use resource ids to specify existing infrastructure:

policies:
  - name: stopped-vm
    mode:
        type: azure-periodic
        schedule: '0 0 * * * *'
        provision-options:
          servicePlan: /subscriptions/<subscription_id>/resourceGroups/cloud-custodian/providers/Microsoft.Web/serverFarms/existingResource
          appInsights: /subscriptions/<subscription_id>/resourceGroups/cloud-custodian/providers/microsoft.insights/components/existingResource
          storageAccount: /subscriptions/<subscription_id>/resourceGroups/cloud-custodian/providers/Microsoft.Storage/storageAccounts/existingResource
     resource: azure.vm
     filters:
      - type: instance-view
        key: statuses[].code
        op: not-in
        value_type: swap
        value: "PowerState/running"

Execution Options

Execution options are not required, but allow you to override defaults that would normally be provided on the command line in non-serverless scenarios.

Common properties are:

  • output_dir

  • cache_period

  • dryrun

  • metrics

The default output directory for an Azure Function is /tmp/<random_uuid>. The following example shows how to save the output of the policy to an Azure Storage Account instead of in the default Function location.

policies:
  - name: stopped-vm
    mode:
        type: azure-periodic
        schedule: '0 0 * * * *'
        provision-options:
          servicePlan:
            name: functionshost
        execution-options:
          output_dir: azure://yourstorageaccount.blob.core.windows.net/custodian
          metrics: azure://<resource_group_name>/<app_insights_name>
     resource: azure.vm
     filters:
      - type: instance-view
        key: statuses[].code
        op: not-in
        value_type: swap
        value: "PowerState/running"

More details on Blob Storage output can be found at Writing Custodian Output to Azure Blob Storage

Event Grid Functions

Currently, Event Grid Functions are only supported at the subscription level. You can set the function to be triggered by write and/or delete events. When an Event Grid Function is deployed, Custodian creates an Event Grid Subscription to trigger the new Function when any event occurs in the Subscription. Once triggered, Custodian only executes the policy if the event was caused by the resource provider and event type specified in the policy.

In order to subscribe to an event, you need to provide the resource provider and the action, or provide the string of one of the shortcuts. For a list of all of the resource providers and their actions, see Azure Resource Manager resource provider options.

The following example shows an Event Grid Function that runs when a value is written to Key Vault.

policies:
  - name: tag-key-vault-creator
    resource: azure.keyvault
    mode:
      type: azure-event-grid
      events:
        - resourceProvider: Microsoft.KeyVault/vaults
          event: write
    filters:
      - "tag:CreatorEmail": null
    actions:
      - type: auto-tag-user
        tag: CreatorEmail

Advanced Authentication Options

By default, the Function is both deployed and executed using the credentials and subscription ID you have configured for the Custodian CLI. To target your policy toward a subscription ID different than the one that the Function is deployed in, you can provide environment variables to set the Service Principal that should be used when the function is executed.

The following variables are used to overwrite the Service Principal configuration used when the Function is executed:

AZURE_FUNCTION_TENANT_ID
AZURE_FUNCTION_CLIENT_ID
AZURE_FUNCTION_CLIENT_SECRET
AZURE_FUNCTION_SUBSCRIPTION_ID

These will be used for Function execution, but the normal Service Principal credentials will still be used for deployment.

You may provide the Service Principal credentials for the function but omit the subscription ID if you wish.

Management Groups Support

You can deploy Azure Functions targeting all subscriptions that are part of a specified Management Group.

The following variable allows you to specify Management Group name:

AZURE_FUNCTION_MANAGEMENT_GROUP_NAME

It can be used with Function specific Service Principal credentials described in the previous section. The Management Group environment variable has the highest priority, so AZURE_FUNCTION_SUBSCRIPTION_ID will be ignored.

Timer triggered functions

When the Management Groups option is used with periodic mode, Cloud Custodian deploys a single Azure Function App with multiple Azure Functions following the single-subscription-per-function rule.

Event triggered functions

When the Management Groups option is used with event mode, Cloud Custodian deploys a single Azure Function. It creates an Event Grid subscription for each Subscription in the Management Group delivering events to a single Azure Storage Queue.

Permissions

The Service Principal used at the Functions runtime is required to have an appropriate level of permissions in each target subscription.

The Service Principal used to provision Azure Functions is required to have an appropriate level of permissions to access Management Groups. If the Service Principal doesn’t have MG Reader permissions in any child subscription, these subscriptions won’t be a part of the Cloud Custodian Azure Function deployment process.