In part 3, we worked on the infrastructure part of our custom action. This involved updating our ARM template with our function code and then configuring Azure to proxy requests to that endpoint (provided by Azure Functions). In this part, we can test our custom action, and wrap things up.
Testing the custom action is pretty easy. With the az cli installed one can make arbitrary rest calls against Azure Resource Manager using the az rest command. Your command will look something like this:
az resource invoke-action --action Restart --ids /subscriptions/<<your_sub_id>>/resourceGroups/<<your_resource_group>>/providers/Microsoft.CustomProviders/resourceproviders/public
Our function doesn’t really output anything, so you should see a blank JSON object returned. In order to confirm that it worked, you can head to the activity log on the web apps, and check there for a restart operation.
In order to wrap things up, simply delete the resource group that hosts all the components. You’ll also want to delete the storage account you used to store the function code.
I really like the idea of custom actions. I like the idea that I, as an application developer / devops guy, can extend the Azure management plane to include operations that are specific to my application. While the example we showed here simply restarts all components in a particular deployment, the possibilities here are endless. You can even configure Azure Dashboards to call custom ARM actions.
From a security perspective, I’m fairly happy with the layout. From the end user perspective, calling the action depends on the appropriate rights to the resource group that contains the proxy definition. This provides an effective way to provide access to these actions to only those authorized users. Further, you could place the management functions in a separate resource group.
I would have preferred if the link between the proxy definition and the function app was a bit stronger. While I understand that the entropy in an Azure Function key is pretty high, it leaves a bit to be desired. First off, there is no automatic way to rotate that key. Automation would have to be built to both rotate the function key and update the proxy. Secondly, a leak of the Azure Function key (even because of user error, for example) would provide a way for non-authorized people to affect the application. Further, it would be quite difficult to investigate, since there is no identity attached to the function call. A potential idea here is to have an Azure Function trigger that is specific to the Azure Resource Manager and has some guarantees that it can only be called from a specific resource group.
Lastly, the experience of having to create/populate/deploy the function app could feel better. It definitely requires some pre-planning, and requires resources to be built outside of the main application. Further, it provides another attack vector that one needs to consider. Someone replacing the zip of the managed application (let’s say, in storage) could drastically affect what the function app actually does. Since we are granting the managed identity of that management app a lot of permissions, a breach here could really hurt.
For the above example, I almost feel like Azure should also allow us to create “compound actions”. All I’m doing when I call
restart (in our sample case anyways), is calling
restart on the resources within the resource group. Maybe we could do that by simply defining a compound action in JSON format (using another resource provider). Extending this a bit further, it would be cool if an action could also trigger an incremental ARM template update (say in the case we want to update secrets, or other). This way, all the “code” for this action could be self-contained within the template definition, and not rely on my code to function correctly.
In any event, I enjoy the concept of Azure custom actions and hope to use it more in future deployments, particularly as the infrastructure I am deploying gets more complex. I hope you enjoyed this series!
Shamir Charania, a seasoned cloud expert, possesses in-depth expertise in Amazon Web Services (AWS) and Microsoft Azure, complemented by his six-year tenure as a Microsoft MVP in Azure. At Keep Secure, Shamir provides strategic cloud guidance, with senior architecture-level decision-making to having the technical chops to back it all up. With a strong emphasis on cybersecurity, he develops robust global cloud strategies prioritizing data protection and resilience. Leveraging complexity theory, Shamir delivers innovative and elegant solutions to address complex requirements while driving business growth, positioning himself as a driving force in cloud transformation for organizations in the digital age.