AEM as a Cloud Service offers a way to manage secrets by using environment variables. But Azure Key Vault offers a more robust way to store and access secrets. As well as keys and certificates.
Although the Cloud Manager's solution works, it is specific to the cloud service. In multitiered architectures, apps and developers will need access to the same secrets. Having to manage and update secrets in many places results in administrative overhead. And leads to developers keeping secrets on their local hosts. Instead, use Azure's Key Vault Service. Which supports role-based access control (RBAC). To control and audit access from one central location. This is an advantage that Key Vault has over Cloud Manager environment variables.
Lets start from the ground up by creating a Key Vault. Assigning myself some roles. And writing some Java code in AEM. We will end by creating a service principal. Assigning it some roles. And updating the Java code so it uses a certificate from the keystore to authenticate with Azure.
Create the Key Vault & Secrets
In my last blog post, I wrote about dev containers. For this exercise, I am using a dev container created with the AEM template. And then I added the Azure CLI feature. Easy peasy. So after doing an az login I run these commands to create the resource group and key vault.
And then I assign myself the Key Vault Certificates Officer role. And the Key Vault Secrets Officer role. These provide a lot more access than I will need in the end. But for now I need it to create the certificate and secrets later on.
Finally, I create a couple of secrets
Azure CLI Credentials
You will need to include the Azure Java SDK in your bundle. To do this follow the instructions in my previous post about Azure IAM integration. With the basic dependencies included, add the one for the Key Vault Secret Client library.
By using the AzureCliCredentialBuilder, the SecretClient will be able to get a token. Here is the Java code.
This will work because I installed the Azure CLI in the dev container. And logged in. The AEM instance is also in the same dev container. It will fail as soon as I run az logout.
Create a Service Principal
Outside of local development, you should not use the AzureCliCredential. There are tons of examples, given your needs. But for now I will use a client certificate.
First I will create a service principal. I will do so with the --create-cert parameter. This will generate a client certificate and secure it by placing it into in the key vault I already have. Once I have a service principal, I will grant it read only access only to secret-one. With the Key Vault Secrets User role.
Install the Client Certificate
A service principal can authenticate with a client certificate. Or a client secret. The latter being equal to a password. And so the recommendation is to use client certificates. Unless your AEM instance is running on an Azure VM. In which case you should use managed identities. But for now, lets do client certificates.
You will need to download and secure the PFX with a password. To do so run the following command. That will download and decode the PFX file. And set an alias and password. Which Azure does not do.
And finally, you are ready to install it into the keystore. For this example, I'll use the keystore. That belongs to the authentication-service account in AEM.
Client Certificate Credentials
We have created the service principal and client certificate. And installed that certificate into the AEM keystore that belongs to the authentication-service. Now we need to update the Java code. It will need to load the PFX certificate into memory from the keystore. And give it to the ClientCertificateCredentialBuilder.
We also need to replace the AzureCliCredential with a ChainedTokenCredential. This credential class will chain together the AzureCliCredential with the ClientCertificateCredential. So that when the SecretClient needs a token it will call on the credential chain. Which will run through the chain in order. And return the token form the first credential class that is able to produce one.
Conclusion
During development, individual contributors will authenticate with their own identities. By using the Azure CLI. While in upper environments, authentication will get done with a service principal. And a client certificate. This ensures that developers never need to save secrets on their local machine. And authorization gets done via RBAC instead. When secrets need to get updated, it gets done in a central location. So that all the tiers get the updated secrets. Without having to update each of their respective configurations. Like the Cloud Manager's environment variables.
And although the Cloud Manager environment variables work, it is a simple solution. It can not compete with the Key Vault features such as logging, alerts and data protection. To name a few. These an many more will be available once you make the integration.
Comments