Manage Environment Variables with Azure Key Vault
Azure Key Vault, serves as a valuable solution for securely storing and managing a wide range of sensitive information. This includes not only fundamental key-value pairs but also digital certificates and private keys. It ensures the continuous availability of these resources for our deployments and applications, enhancing security and accessibility.
The current version of the Console can only acquire key-value pairs (aka secrets) from Key Vault.
You can directly manage the secrets stored in Key Vault using the web interface of your Key Vault instance. The exclusive role of the Console is to retrieve the secrets keys from Key Vault and then create the respective Kubernetes configuration files to enable the external secrets operator to deploy the associated Kubernetes Secrets on the cluster.
To correctly configure a Key Vault in your project follow these steps:
- Install the
external-secrets
operator in the Kubernetes cluster where your project will be deployed - Setup the Key Vault instance for the operator authentication
- Setup the project to use the Azure Key Vault provider as a secret manager
Setup the Key Vault instance
There are several ways to enable the operator authentication against the Key Vault instance, the one we support at the moment is the Workload Identity authentication. This authentication method does not require sharing any secret between the cluster and Key Vault.
Workload Identity setup
The Workload Identity authentication works by establishing a trust relationship between a service account from the namespace of the Kubernetes cluster where your project will be deployed and the Azure Active Directory service that is responsible for the authentication and authorization against the Key Vault instance.
1. Create an Azure Active Directory application
First off, you need to create an Azure application aka Service Principal. This application will be used as a conduit to Azure Key Vault and will set up all the required permissions and credentials. Follow the steps reported here.
2. Authorize the AAD application
Once the AAD Application has been created you need to authorize it to read the secrets stored in Key Vault. This process depends on your organization's policies and the authorization method chosen, if you are using the RBAC authorization model follow these steps.
3. Enable your cluster as an Open ID Connect provider
In this step, we are going to enable the cluster to act as an Open ID Connect provider. This step allows the verification of the token signed by the operator by Key Vault.
The actions to be performed in this step depend on the nature of your cluster:
- Managed clusters (i.e. AKS, GCP, ...) are usually easier to configure as an OIDC provider. In fact, GCP clusters usually are by default OIDC providers. While AKS clusters can be configured in this way.
- Self-managed clusters require a bit more work but here there is a well-explained tutorial.
4. Add the federated credentials to the application
In this last step, we are ready to associate the service account that will be automatically deployed in the cluster namespace associated to the environment of the project with the AAD Application created before.
On the Application main page, click on the Certificates & secrets
menu voice on the left, then switch to the Federated credential
tab and click Add credential
, you will be prompted with a form. Inside the form fill in the Subject identifier
field in the following way:
system:serviceaccount:<namespace>:akv-accessor
Where:
<namespace>
is the namespace where your project will be deployed. it depends on the environment of the project, its value can be retrieved from the environments page in the Console.
The other fields of the form can be filled in as you wish.
This configuration can also be done from the Azure CLI program az
, as explained here.
Setup the Console project
Once the Key Vault instance is configured, we are now ready to set up the Console project. The project set up can be split into three steps:
- Azure Key Vault provider creation
- Project configuration
- Microservices configuration
Azure Key Vault provider
In order to connect to the Azure Key Vault instance you have to create a provider. In the provider creation modal, select the Azure Key Vault
type when prompted, then fill the fields as described in the providers management page
Please notice that each provider is linked to an Azure Key Vault store, we advice to setup at least two providers for each project, one for production data and another for noprod data, each associated with the respective environment of the project.
Project configuration
Connect the provider to the project or environment through the CMS. Retrieve the previously generated provider's _id
(you can find it inside the Providers
section of the CMS) and use it to modify the Environments variables
section in the CMS as follows:
{
"type": "azure-key-vault",
"providerId": <providerId>,
"azureClientId": <azureClientId>,
"azureTenantId": <azureTenantId>,
"serviceAccountName": <serviceAccountName>,
}
Where:
<providerId>
(required) is the_id
of the provider created before<azureClientId>
(required) is the client id of the Azure Active Directory application that will fetch the secrets from the cluster<azureTenantId>
(required) the tenant identifier for your company on Azure<serviceAccountName>
an optional name for the service account to use in the authentication process. Defaults toakv-accessor
If serviceAccountName
is defined the Console will not deploy the service account automatically but is your responsibility to provision it.
You also have the option to distinguish between providers for specific environments. This enables you to establish various Azure Key Vault providers for different environments. To achieve this, you need to create an environmentsVariables
object with the same structure as the one demonstrated above within the target environment object found in the Environments
section of the project's page in the CMS. Any environment that doesn't specify its own environmentsVariables
configuration will automatically inherit it from the project.
Use Azure Key Vault secrets inside the Console
Secrets stored within an Azure Key Vault provider cannot be directly utilized as interpolations in the project's configuration. However, you can access these variables by creating a new microservice environment variable with the value type set to from secret
linking a secret with name akv-secret
and the secret key specified as the desired secret name. Detailed instructions for this process can be found in the microservice configuration section.
By design, the akv-secret
in the cluster is not automatically synchronized with its corresponding secrets on Azure Key Vault. Instead, when a new variable is added or removed in Key Vault, it is necessary to regenerate the Design configuration of the project to properly reconfigure the Kubernetes secret. Conversely, if a variable is edited, a new deploy of the target environment is required to update the variables on the cluster.
Examples - AKV Integration on a GKE cluster
This example guides you, step by step, configuring AKV in your Company, linked to a Google Kubernetes Engine cluster. The starting environment of this example is a green field, neither the External Secret Operator has been installed.
1. Installing the External Secrets Operator
The first step in order to let your AKV integration work is to install the External Secret Operator.
In this example we will use Helm to install it, but you can find the complete installation guide at this page.
Before installing the External Secret Operator, be sure to be connected to the right k8s cluster.
With the following simple commands you can install the External Secret Operator:
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace
The commands above will install the External Secret Operator in a dedicated namespace, automatically created by Helm during the installation process.
After the installation is complete, you should have 3 services up and running inside the external-secrets
namespace:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
external-secrets-operator-5db95c68b8-nn27p 1/1 Running 0 6d
external-secrets-operator-cert-controller-568bd5d5cc-258j2 1/1 Running 0 6d
external-secrets-operator-webhook-85695d9f88-7mxbp 1/1 Running 0 6d
2. Azure setup
Azure needs different operations to let you complete the integration with the Mia-Platform Console and the External Secret Operator:
- Create an Azure App Registration (aka Service Principal);
- Create the Service Principal credentials or certificate, to allow the login using it;
- Add the "Federated Credentials" to the Service Principal, in order to let AKV authenticate with it through the k8s Cluster;
- Authorize the Service Principal reading data from the Azure Key Vault you need to access.
In this example we used the Azure Portal to perform the operations above. If you prefer you can use the az
client or the Azure REST APIs too.
1. Create the Service Principal
You have different ways to create a Service Principal. Following you will find two ways:
- Azure Client → using the
az
cli you can create it directly from your terminal. This is the preferred way; - Azure Portal → using the Azure Portal UI directly.
- Azure Client
- Azure Portal
To create the service principal through the az
client follow these instructions.
Login on azure with the method you prefer:
az login --tenant {{TENANT_ID}}
Set the subscription where you want to create the service principal:
az account set --subscription {{SUBSCRIPTION_ID}}
Create the service principal. In this example, we will create a Service Principal that can authenticate itself with a "Client Credentials" authentication:
az ad sp create-for-rbac --name {{SERVICE_PRINCIPAL_NAME}}
Save the result of the previous command, that will be similar to the following one:
{
"appId": "{{SERVICE_PRINCIPAL_CLIENT_ID_GENERATED_BY_AZURE}}",
"displayName": "{{SERVICE_PRINCIPAL_NAME}}",
"password": "{{SERVICE_PRINCIPAL_CLIENT_SECRET}}",
"tenant": "{{TENANT_ID}}"
}
The information that you will use for the authentication are:
- appId → the username, or clientId;
- password → the password, or clientSecret.
The following instructions highly depends on the Azure Portal and could be changed in future.
To create the Service Principal through the Azure Portal you just need to:
- open the Azure Portal App Registrations page on your browser (usually the page is at this link, but it can be different based on your Azure subscription);
- click on the "New registration" button;
- insert the name you prefer;
- select the account types → usually the "Accounts in this organizational directory only" is the used option;
- leave the "Redirect URI" empty;
- click on the "Register" button.
Save the clientId
generated by Azure, the Application (client) ID
field content, because you will need it later.
2. Create the Service Principal credentials or certificate
If you created the service principal through the az client
and you already have its credentials, you can go on with the next section.
In order to authenticate using the Service Principal you just created, you need to create credentials or certificate:
- client credentials: with Client Credentials approach you will get a Bearer Token calling the Azure
/oauth
API using aclientId
and aclientSecret
; - client credentials certificate: with the Certificate approach you will generate a private-public certificates pair and you will get a Bearer Token calling the Azure
/oauth
API without exchanging credentials, so it's a more safer way.
Read more on the official Microsoft documentation.
In order to create the credentials or certificate to authenticate with Azure, once you created your app registration, follow these steps:
- Client Credentials Certificate
- Client Credentials
First of all, you need to generate a certificate with its private key. The suggested way is to generate a certificate signed by a trusted certificate authority.
Otherwise, for testing purpose only, you can also generate a self-signed certificate.
Following an example on how to generate a self-signed certificate valid for 1 year with openssl, just for test purposes:
# Interactive command, that will ask you for certificate data
openssl req -x509 -newkey rsa:4096 -keyout private-key-encrypted.pem -out certificate.pem -sha256 -days 365
# Now you should have a certificate and a private key, both in PEM format
ls -l
total 40
-rw-r--r-- 1 nb196 staff 2094 Aug 1 18:26 certificate.pem
-rw------- 1 nb196 staff 3422 Aug 1 18:25 private-key-encrypted.pem
# Now you need to decrypt the private key with the following command, using the passphrase you typed with the previous openssl command
openssl rsa -in private-key-encrypted.pem -out private-key-decrypted.pem
ls -l
total 48
-rw-r--r-- 1 nb196 staff 2094 Aug 1 18:26 certificate.pem
-rw------- 1 nb196 staff 3272 Aug 1 18:28 private-key-decrypted.pem
-rw------- 1 nb196 staff 3422 Aug 1 18:25 private-key-encrypted.pem
Read more on the official Microsoft documentation.
After generatign the certificates pair:
- access your App page;
- on the menu on the left, click on "Manage" → "Certificates & secrets";
- select the "Certificate" tab;
- click on the "Upload certificate" button;
- upload the certificate, in one of the supported formats (in the example below, you should upload the
certificate.pem
file); - (recommended) give the certificate a description.
Save the Thumbprint
generated by Azure, because you will need it later.
Remember to store the certificate, the private-key and the thumbprint in a secure store.
- access your App page;
- on the menu on the left, click on "Manage" → "Certificates & secrets";
- select the "Client secrets" tab;
- click on the "New client secret" button;
- set an expiration date;
- (recommended) give the certificate a description.
Azure will generate a "clientId
- clientSecret
" pair that you can use to authenticate.
Save the secret value generated by Azure, because you will need it later.
Remember to copy the generated clientId
and clientSecret
. If you lose the clientSecret
value you will not be able to get it anymore and you will need to create a new one.
Remember to store the "clientId
- clientSecret
" pair in a secure store.
3. Add the Federated Credentials
The "Federated Credentials" are needed to let your kubernetes cluster, and the External Secret Operator, able to authenticate with Azure using the Service Principal you previously created.
Before doing the steps below, you need to get the URL of the cluster issuer, that depends on the Cluster you are using. This example is based on a Google Kubernetes Engine cluster, that is enabled as Open ID Connect provider by default.
The "Cluster issuer URL", that you will need to setup the "Federated Credentials", is dynamic and depends on your GKE cluster. The URL format is the following one:
Remember to change the {{gcpProjectId}}
, the {{location}}
and the {{clusterId}}
placeholders with the real values.
You will need to add a "Federated Credential" **for each runtime environment" you have on your project. To do that:
- access your App page;
- on the menu on the left, click on "Manage" → "Certificates & secrets";
- select the "Federated credentials" tab;
- for each runtime environment:
- click on the "Add credential" button;
- select the "Kubernetes accessing Azure resources" scenario;
- insert the "cluster issuer URL" you got before;
- insert the k8s namespace;
- insert the k8s service account name. The default one is
akv-accessor
; - give the Federated credential a name;
- (recommended) give the Federated credential a description;
- leave the default "Audience";
- click on the "Add" button.
4. Authorize the Service Principal accessing the Azure Key Vault
To do that, you just need to modify the access settings of the Azure Key Vaults you want the Service Principal access to.
For each AKV you want to access:
- access the AKV page;
- on the menu on the left, click on "Access control (IAM)";
- click on the "Role assignments" tab;
- click on the "Add" → "Add role assignment" button;
- select the "Key Vault Secrets User" role, then press the "Next" button → with this role, you will only be able to read secret values, not write;
- select "Assign access to User, group, or service principal" then press on the "+Select members" button;
- look for the Service Principal using its name.
For the last step, only privileged users will be able to search for app registration. If you didn't find the Service Principal, probably you don't have enough permissions on the Azure Key Vault instance.
3. Console setup
In order to connect to the Azure Key Vault instance you have to create a provider. In the provider creation modal, select the Azure Key Vault type when prompted, then fill the fields as described in the providers management page.
Usually the AKV base URL has the following format:
https://{{akv-id}}.vault.azure.net/
Anyway, you can get it accessing the AKV "Overview" page, Azure will show you it:
Based on the Service Principal authorization access you setup above, you must choose the right authentication when configuring the AKV provider on the console.
- Client Credentials Certificate
- Client Credentials
Insert the following information:
Access Token URL: the Azure URL the Console will call to get the token. It has the following format:
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Client ID: the ID of the Service Principal you created above. You can find it in the "Overview" page of the App Registration on the Azure Portal;
Private Key: the private key in PEM format. In the example above, it should be the content of the
private-key-decrypted.pem
file;Certificate Thumbprint: a thumbprint generated by Azure when you added the Certificate inside the Service Principal;
Scope: the Bearer Token scope. To interact with AKV, it must be the following one:
https://vault.azure.net/.default
Insert the following information:
Access Token URL: the Azure URL the Console will call to get the token. It has the following format:
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Client ID: the ID of the Service Principal you created above. You can find it in the "Overview" page of the App Registration on the Azure Portal;
Client secret: the secret generated by Azure when you created the "Client Credentials" on the App Registration;
Scope: the Bearer Token scope. To interact with AKV, it must be the following one:
https://vault.azure.net/.default
Now that you created the AKV provider, you need to setup the projects you want to use it on. To do that, you need to modify the project configurations on the Console CMS.
If you want to use a single AKV for all your runtime environments, you can just modify the Environments variables
JSON, inserting the following information, as reported above:
{
"type": "azure-key-vault",
"providerId": <providerId>,
"azureClientId": <azureClientId>,
"azureTenantId": <azureTenantId>,
"serviceAccountName": <serviceAccountName>,
}
In this example we integrated the Console with just one AKV, but you can also setup different AKV for each runtime environment, as reported above.
Secrets usage
To use the secrets from the AKV, you just need to referencing it from a microservice on the Console. Let's use "Core Business" as name of the project you want to use the AKV secrets.
- open the "Core Business" project design page;
- select the microservice you need to the secrets;
- select the tab "Environment Variables";
- create a new one;
- insert the key you want for your environment variable;
- select "from secret" as a value type;
- insert
akv-secret
as a secret name; - insert the secret key, that must be the same of the secret on AKV.
Now if you save, the console will generate the files needed by the External Secret Operator in order to generate the akv-secret
k8s Secret, containing the AKV secrets.
Deploying your project, if the setup process went well, you should find the following resources on the k8s namespace of your project:
$ kubectl get externalsecret
NAME STORE REFRESH INTERVAL STATUS READY
akv-external-secret akv-store 0 SecretSynced True
$ kubectl get secretstore
NAME AGE STATUS CAPABILITIES READY
akv-store 6d Valid Read True
$ kubectl get sa
NAME SECRETS AGE
akv-accessor 0 6d
$ kubectl get secret
NAME TYPE DATA AGE
akv-secret Opaque 1 6d