Deploying Azure Container Instance via ARM Template with CMK in a Private Key Vault

I mean… Some of us already gave Amazon access to our house, right?

Background Overview

I have a Logic App workflow where when triggered, it will deploy an Azure Container Instance based off of the latest image in Container Registry using action Create or update a resource group under Azure Resource Manager connector. The container is a one-time ETL run that gets destroyed once done. It was all working fine, but then I got a new requirement that the container instance must be CMK (Customer Managed Key) enabled.

Failed Attempts

I checked the ARM template for ACI group Microsoft Learn – Microsoft.ContainerInstance containerGroups and added the following properties to my ARM template:

"properties": {
  "encryptionProperties": {
    "vaultBaseUrl": "https://mykeyvault.vault.azure.net",
    "keyName": "acikey",
    "keyVersion": "xxxxxxxxxxxxxxxx"
},

under resources. I created this ACI key as RSA-HSM 4096 key in my private key vault. I triggered my workflow to run, but during the ARM template deployment, it gave the following error:

The key vault key is not found to unwrap the encryption key. (Code: MasterKeyNotAccessibleException)

I googled this error, and only one relevant result came up, which was a thread in terraform github repository Github – Support for Container Group private Key Vault #19741.

Based on this comment, I gathered that it might be the HSM key that is not working, so I changed that to RSA. Still the same error when reran.

The error message seemed to imply that it is some kind of permission issue, so I made sure that the Logic App that is calling the Azure Resource Manager has Key Vault Crypto User role in the private key vault. Still no luck.

Resolution

Then I saw this Microsoft documentation, where it illustrates exactly what I needed Microsoft Learn – Encrypt data with a customer-managed key in a network protected Azure Key Vault with Trusted Services enabled. I had to create User Assigned Managed Identity to be assigned to the to-be-deployed ACI. Referring to the above documentation, I performed the following steps:

  1. Create user managed identity in the same resource group
  2. Assign Key Vault Crypto Service Encryption User to the user managed ID above
  3. Modify ARM template’s apiVersion, identity property under container group properties, and identity object under resources Microsoft Learn – Modify Your JSON Deployment Template

I ran again and now I got a different error message:

The client '<logic app id>' with object id '<logic app id>' has permission to perform action 'Microsoft.ContainerInstance/containerGroups/write' on scope '<to-be-deployed aci>'; however, it does not have permission to perform action(s) 'Microsoft.ManagedIdentity/userAssignedIdentities/assign/action' on the linked scope(s) '<user assigned managed id>' … (Code: LinkedAuthorizationFailed).

Now we made a progress! It sounds like my Logic App needs permission to assign Managed Identity to the to-be-deployed ACI. I added Managed Identity Operator role to my Logic App under IAM blade in the created User Assigned Managed Identity.

I reran the workflow and voila, the ACI successfully got deployed!

Clean Up

  • Because the key was not the real issue, I changed the key back to RSA-HSM and verified that it still worked
  • I also removed Logic App’s Crypto User role in the Key Vault because it doesn’t need it
  • Todo: Update logic inside the ACI to use the new user assigned managed identity (currently it is using Service Principal and Client Secret to access other resources such as storage account)

Conclusion

I had to create a user assigned managed identity so that that can be assigned to ACI and be used to access the encryption key. It can’t be done with system assigned managed identity because system managed identity is created during the ACI resource creation, and we can’t give the necessary crypto role to it prior to deployment when it needs the key vault key.

So that’s it! Looking back at it, I spent too much time assuming that it was the Logic App workflow that needed the Key Vault Crypto access since it is the one initiating the deployment. Once I know the answer, it is fairly obvious that the ACI is the one that needs Crypto access so that it can encrypt itself.

I hope this helps someone or myself in the future.

HTML Data Attributes: Don’t Overuse It



The other day when I was code reviewing my colleague’s UI update, I saw this:

<span className={styles.userRating} data-status={liked}>
    <!--Thumbsup icon goes in here-->
</span>

And the following in the CSS:

.userRating {
    opacity: 0.5;
}
.userRating[data-status="true"]{
    opacity: 1;
}


When I saw this it made me cringe, but I couldn’t explain why at that moment. First thing that came up in my mind was, sure it works, but why do it this way?

Raises Questions

It is a valid HTML/CSS, but it seems to be doing what classes should be doing. Hmm…a code smell. As someone who looked at this CSS for the first time, you would think “What does data-status even mean when set to true? What does this data attribute control?”.

Just changing the attribute name to data-selected instead of data-status would clear up some confusion, but there still lies another issue – Separation of Concerns.

Separation of Concerns

We all want to keep things tidy and make sure that the boundaries are properly set between different components and layers. But sometimes this is challenging, especially in the web development world because HTML/CSS/JS to me has always had fragile boundaries where each realm easily trespasses another’s boundary (for example, Javascript updating DOM elements, which is a totally valid thing to do).

Ideally, Javascript should control the behavior, HTML the representation, and CSS the styling. Framework helps strengthen the boundary, but it is not perfect.
Data attributes reside more so on HTML/JS side, as its name suggests. It may make sense to use data attributes inside CSS in some occasion, but definitely not justified with a simple true/false value.

In the code snippet above, you don’t know what data-status does or where it is used in, unless you do a find-all in your IDE. There is just no way of telling what effect(s) this attribute has.

But can’t you say the same thing about classes? Can’t you use classes elsewhere too like in jQuery selector? Yes but it is general consensus that classes are mostly used for styling, and because the code above uses CSS Modules, it is very clear from the syntax that the class gives a style to the element:

styles.userRating

There Are Pros and Cons To Everything

There is one benefit of doing it using data attribute though, which is the HTML is a lot cleaner than conditionally applying CSS classes in className. But that is all I can come up with, and I am not sure if that outweighs all the other benefits.

The Looks

Also, .userRating[data-status="true"] is just plain ugly. It is long, has brackets, and it hurts my eyes if there are dozens of these in HTML and CSS files (and there indeed was dozen of them found during the code review. I removed all of them later for cleanup :p). I would much rather see .userRating.selected; it is concise and shows the intention clearly.

I agree that the aesthetics is somewhat subjective, but if it could directly impact the readability of the code, then you should not dismiss it.
Note that selecting data attributes are said to be slower than classes too, but I have not verified this myself.

Conclusion

You should use data attributes only when it makes sense, like passing data between script and the element. If it is just a styling thing, use classes!

Web development is hard because there is so much to learn from the beginning. Backend is hard too, but from my experience backend has somewhat solid path that you can follow. Frontend, not so much; learning path diverges the moment you step into it, and each path leads to its own deep rabbit hole.

But principle of software engineering is still applicable to web dev; keep things separate as much as possible, and let each component do what it’s designed to do.