Azure

Bad Practice: Client Secrets

Even when stored securely in environment variables or secret management systems, long-lived service principal credentials (such as Client Secrets or Certificates) remain valid indefinitely unless manually rotated, which introduces risk. And so even though the credentials are securely retrieved, they are long-lived, meaning if they are compromised, attackers will have persistent access until the credentials are rotated or revoked.

from azure.identity import ClientSecretCredential
from azure.keyvault.secrets import SecretClient
import os

# Long-lived service principal key retrieved securely
client_secret = os.getenv('AZURE_CLIENT_SECRET')
tenant_id = os.getenv('AZURE_TENANT_ID')
client_id = os.getenv('AZURE_CLIENT_ID')

credential = ClientSecretCredential(tenant_id, client_id, client_secret)

# Access Azure Key Vault using long-lived credentials
secret_client = SecretClient(vault_url="https://<your-key-vault>.vault.azure.net/", credential=credential)
secret = secret_client.get_secret("your-secret-name")
print(f"Secret value: {secret.value}")

Good Practice: Managed Identities

Managed Identities provide a more secure alternative to using the standard IAM credentials in Azure, by eliminating the need for long-lived credentials. Managed Identities are automatically managed by Azure and are short-lived, reducing the attack surface.

How to Use Managed Identities

To convert an Azure service principal key to role-based authentication, you can either use Managed Identities or Azure AD App Role Assignments.

Managed Identities allow Azure resources like Virtual Machines or App Services to authenticate to other Azure services securely without needing credentials, while Azure AD App Role Assignments enable secure, role-based access for external or non-Azure services.

Once the application is updated to use these methods, the old client secret (key) can be deleted, improving security by eliminating long-lived credentials and replacing them with automatically managed, short-lived tokens.

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

# Use Managed Identity to get ephemeral credentials
credential = DefaultAzureCredential()

# Access Azure Key Vault using Managed Identity
secret_client = SecretClient(vault_url="https://<your-key-vault>.vault.azure.net/", credential=credential)
secret = secret_client.get_secret("your-secret-name")
print(f"Secret value: {secret.value}")

How it Works

When an Azure resource (e.g., a VM or Azure Function) with a managed identity needs to access another Azure service (such as a Key Vault, Storage Account, or Azure SQL Database), it authenticates using Azure AD. This process does not require any manual management of credentials, as Azure manages the lifecycle of the identity and authentication behind the scenes.

Source: Marczak.IO

When an Azure resource (e.g., a VM or Azure Function) with a managed identity needs to access another Azure service (such as a Key Vault, Storage Account, or Azure SQL Database), it authenticates using Azure AD. This process does not require any manual management of credentials, as Azure manages the lifecycle of the identity and authentication behind the scenes.

The key steps involved in the process are:

  1. Request a Token:
    • The Azure resource (with the managed identity) sends a request tothe Azure Instance Metadata Service (IMDS) to obtain an OAuth 2.0 access token. The request is typically sent to an endpoint like:
    • http://169.254.169.254/metadata/identity/oauth2/token
    • This is a local, non-routable IP address that provides access to Azure’s metadata service, allowing the resource to authenticate without needing external credentials.
  2. STS Token Issuance:
    • Azure’s STS (Security Token Service), much like AWS, plays a key role here. When the request is made, Azure AD acts as the identity provider andissues a time-limited OAuth 2.0 token on behalf of the managed identity.
    • This token is scoped for a particularresource or service. For instance, if the VM is requesting access to a Key Vault, the token would be specific to that Key Vault
  3. STS Token Issuance:
    • Once the token is issued, the resource (e.g., the VM or Function) uses the OAuth 2.0 token to authenticate to the target Azure service. The token is passed in the request’s Authorization header as aBearer token.
    • Example of a REST request to access Key Vault with a token:
    • GET https://myvault.vault.azure.net/secrets/mysecret?api-version=7.0
    • Authorization: Bearer <OAuth-Token>
  4. Role-Based Access Control (RBAC) via Azure AD:
    • For the access request to succeed, the target resource (e.g., Key Vault or Storage Account) must have an appropriateRole-Based Access Control (RBAC) policy configured in Azure AD.
    • This policy defines who (i.e., the managed identity) is allowed to access what (specific Azure resources) and how (permissions such asread, write, list, etc.).
    • Unlike AWS’s trust policy, Azure uses RBAC to determine what the managed identity can do. For example, an identity can be assigned the Reader role to a Storage Account, or it can be given Key Vault Reader access.
  5. Time-Limited Credentials
    • The token received by the managed identity istime-limited (typically valid for an hour). Once it expires, the resource must request a new token from Azure AD to continue accessing the service.
    • This is similar to AWS’s temporary credentials issued by STS when assuming a role, though Azure uses OAuth 2.0 tokens rather than access keys.

Example in Pictures