# Azure

The `azure` auth method allows authentication against Vault using Azure Active Directory credentials. It treats Azure as a Trusted Third Party and expects a [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) signed by Azure Active Directory for the configured tenant.

This method supports authentication for system-assigned and user-assigned managed identities. See [Managed identities for Azure resources](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) for more information about these resources.

This documentation assumes the Azure method is mounted at the `/auth/azure` path in Vault. Since it is possible to enable auth methods at any location, please update your API calls accordingly.

### Prerequisites:

The Azure auth method requires client credentials to access Azure APIs. The following are required to configure the auth method:

* A configured [Azure AD application](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) which is used as the resource for generating MSI access tokens.
* Client credentials (shared secret) with read access to particular Azure Resource Manager resources. See [Azure AD Service to Service Client Credentials](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service).

If Vault is hosted on Azure, Vault can use MSI to access Azure instead of a shared secret. A managed identity must be [enabled](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/) on the resource that acquires the access token.

The following Azure [role assignments](https://learn.microsoft.com/en-us/azure/role-based-access-control/overview#role-assignments) must be granted to the Azure AD application in order for the auth method to access Azure APIs during authentication.

#### Role assignments

\~> **Note:** The role assignments are only required when the `vm_name`, `vmss_name`, or `resource_id` parameters are used on login.

| Azure Environment                                                                                                                                                                                              | Login Parameter | Azure API Permission                                                                                         |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------ |
| Virtual Machine                                                                                                                                                                                                | `vm_name`       | `Microsoft.Compute/virtualMachines/*/read`                                                                   |
| Virtual Machine Scale Set ([Uniform Orchestration](https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-orchestration-modes#scale-sets-with-uniform-orchestration))   | `vmss_name`     | `Microsoft.Compute/virtualMachineScaleSets/*/read`                                                           |
| Virtual Machine Scale Set ([Flexible Orchestration](https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-orchestration-modes#scale-sets-with-flexible-orchestration)) | `vmss_name`     | `Microsoft.Compute/virtualMachineScaleSets/*/read` `Microsoft.ManagedIdentity/userAssignedIdentities/*/read` |
| Services that ([support managed identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/managed-identities-status)) for Azure resources                        | `resource_id`   | `read` on the resource used to obtain the JWT                                                                |

#### API permissions

The following [API permissions](https://learn.microsoft.com/en-us/azure/active-directory/develop/permissions-consent-overview#types-of-permissions) must be assigned to the service principal provided to Vault for managing the root rotation in Azure:

| Permission Name           | Type        |
| ------------------------- | ----------- |
| Application.ReadWrite.All | Application |

### Authentication

#### Via the CLI

The default path is `/auth/azure`. If this auth method was enabled at a different path, specify `auth/my-path/login` instead.

```shell-session
$ vault write auth/azure/login \
    role="dev-role" \
    jwt="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
    subscription_id="12345-..." \
    resource_group_name="test-group" \
    vm_name="test-vm"
```

The `role` and `jwt` parameters are required. When using `bound_service_principal_ids` and `bound_group_ids` in the token roles, all the information is required in the JWT (except for `vm_name`, `vmss_name`, `resource_id`). When using other `bound_*` parameters, calls to Azure APIs will be made and `subscription_id`, `resource_group_name`, and `vm_name`/`vmss_name` are all required and can be obtained through instance metadata.

For example:

```shell-session
$ vault write auth/azure/login role="dev-role" \
     jwt="$(curl -s 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true | jq -r '.access_token')" \
     subscription_id=$(curl -s -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2017-08-01" | jq -r '.compute | .subscriptionId')  \
     resource_group_name=$(curl -s -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2017-08-01" | jq -r '.compute | .resourceGroupName') \
     vm_name=$(curl -s -H Metadata:true "http://169.254.169.254/metadata/instance?api-version=2017-08-01" | jq -r '.compute | .name')
```

#### Via the API

The default endpoint is `auth/azure/login`. If this auth method was enabled at a different path, use that value instead of `azure`.

```shell-session
$ curl \
    --request POST \
    --data '{"role": "dev-role", "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}' \
    https://127.0.0.1:8200/v1/auth/azure/login
```

The response will contain the token at `auth.client_token`:

```json
{
  "auth": {
    "client_token": "f33f8c72-924e-11f8-cb43-ac59d697597c",
    "accessor": "0e9e354a-520f-df04-6867-ee81cae3d42d",
    "policies": ["default", "dev", "prod"],
    "lease_duration": 2764800,
    "renewable": true
  }
}
```

### Configuration

Auth methods must be configured in advance before machines can authenticate. These steps are usually completed by an operator or configuration management tool.

#### Via the CLI

1. Enable Azure authentication in Vault:

   ```shell-session
   $ vault auth enable azure
   ```
2. Configure the Azure auth method:

   ```shell-session
   $ vault write auth/azure/config \
       tenant_id=7cd1f227-ca67-4fc6-a1a4-9888ea7f388c \
       resource=https://management.azure.com/ \
       client_id=dd794de4-4c6c-40b3-a930-d84cd32e9699 \
       client_secret=IT3B2XfZvWnfB98s1cie8EMe7zWg483Xy8zY004=
   ```

   For the complete list of configuration options, please see the API documentation.
3. Create a role:

   ```shell-session
   $ vault write auth/azure/role/dev-role \
       policies="prod,dev" \
       bound_subscription_ids=6a1d5988-5917-4221-b224-904cd7e24a25 \
       bound_resource_groups=vault
   ```

   Roles are associated with an authentication type/entity and a set of Vault policies. Roles are configured with constraints specific to the authentication type, as well as overall constraints and configuration for the generated auth tokens.

   For the complete list of role options, please see the API documentation.

#### Via the API

1. Enable Azure authentication in Vault:

   ```shell-session
   $ curl \
       --header "X-Vault-Token: ..." \
       --request POST \
       --data '{"type": "azure"}' \
       https://127.0.0.1:8200/v1/sys/auth/azure
   ```
2. Configure the Azure auth method:

   ```shell-session
   $ curl \
       --header "X-Vault-Token: ..." \
       --request POST \
       --data '{"tenant_id": "...", "resource": "..."}' \
       https://127.0.0.1:8200/v1/auth/azure/config
   ```
3. Create a role:

   ```shell-session
   $ curl \
       --header "X-Vault-Token: ..." \
       --request POST \
       --data '{"policies": ["dev", "prod"], ...}' \
       https://127.0.0.1:8200/v1/auth/azure/role/dev-role
   ```

### Azure managed identities

There are two types of [managed identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview#managed-identity-types) in Azure: System-assigned and User-assigned. System-assigned identities are unique to every virtual machine in Azure. If the resources using Azure auth are recreated frequently, using system-assigned identities could result in many Vault entities being created. For environments with high ephemeral workloads, user-assigned identities are recommended.

#### Limitations

The TTL of the access token returned by Azure AD for a managed identity is 24hrs and is not configurable. See ([limitations of using managed identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/managed-identity-best-practice-recommendations#limitation-of-using-managed-identities-for-authorization)) for more info.

### Azure debug logs

The Azure auth plugin supports debug logging which includes additional information about requests and responses from the Azure API.

To enable the Azure debug logs, set the following environment variable on the Vault server:

```shell
AZURE_GO_SDK_LOG_LEVEL=DEBUG
```

### API

The Azure Auth Plugin has a full HTTP API. Please see the API documentation for more details.

### Code example

The following example demonstrates the Azure auth method to authenticate with Vault.

```go
package main

import (
	"context"
	"fmt"

	vault "github.com/hashicorp/vault/api"
	auth "github.com/hashicorp/vault/api/auth/azure"
)

// Fetches a key-value secret (kv-v2) after authenticating to Vault via Azure authentication.
// This example assumes you have a configured Azure AD Application.
func getSecretWithAzureAuth() (string, error) {
	config := vault.DefaultConfig() // modify for more granular configuration

	client, err := vault.NewClient(config)
	if err != nil {
		return "", fmt.Errorf("unable to initialize Vault client: %w", err)
	}

	azureAuth, err := auth.NewAzureAuth(
		"dev-role-azure",
	)
	if err != nil {
		return "", fmt.Errorf("unable to initialize Azure auth method: %w", err)
	}

	authInfo, err := client.Auth().Login(context.Background(), azureAuth)
	if err != nil {
		return "", fmt.Errorf("unable to login to Azure auth method: %w", err)
	}
	if authInfo == nil {
		return "", fmt.Errorf("no auth info was returned after login")
	}

	// get secret from the default mount path for KV v2 in dev mode, "secret"
	secret, err := client.KVv2("secret").Get(context.Background(), "creds")
	if err != nil {
		return "", fmt.Errorf("unable to read secret: %w", err)
	}

	// data map can contain more than one key-value pair,
	// in this case we're just grabbing one of them
	value, ok := secret.Data["password"].(string)
	if !ok {
		return "", fmt.Errorf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])
	}

	return value, nil
}

```

```cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using VaultSharp;
using VaultSharp.V1.AuthMethods;
using VaultSharp.V1.AuthMethods.Azure;
using VaultSharp.V1.Commons;

namespace Examples
{
    public class AzureAuthExample
    {
        public class InstanceMetadata
        {
            public string name { get; set; }
            public string resourceGroupName { get; set; }
            public string subscriptionId { get; set; }
        }

        const string MetadataEndPoint = "http://169.254.169.254/metadata/instance?api-version=2017-08-01";
        const string AccessTokenEndPoint = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/";

        /// <summary>
        /// Fetches a key-value secret (kv-v2) after authenticating to Vault via Azure authentication.
        /// This example assumes you have a configured Azure AD Application.
        /// </summary>
        public string GetSecretWithAzureAuth()
        {
            string vaultAddr = Environment.GetEnvironmentVariable("VAULT_ADDR");
            if(String.IsNullOrEmpty(vaultAddr))
            {
                throw new System.ArgumentNullException("Vault Address");
            }

            string roleName = Environment.GetEnvironmentVariable("VAULT_ROLE");
            if(String.IsNullOrEmpty(roleName))
            {
                throw new System.ArgumentNullException("Vault Role Name");
            }

            string jwt = GetJWT();
            InstanceMetadata metadata = GetMetadata();

            IAuthMethodInfo authMethod = new AzureAuthMethodInfo(roleName: roleName, jwt: jwt, subscriptionId: metadata.subscriptionId, resourceGroupName: metadata.resourceGroupName, virtualMachineName: metadata.name);
            var vaultClientSettings = new VaultClientSettings(vaultAddr, authMethod);

            IVaultClient vaultClient = new VaultClient(vaultClientSettings);

            // We can retrieve the secret from the VaultClient object
            Secret<SecretData> kv2Secret = null;
            kv2Secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(path: "/creds").Result;

            var password = kv2Secret.Data.Data["password"];

            return password.ToString();
        }

        /// <summary>
        /// Query Azure Resource Manage for metadata about the Azure instance
        /// </summary>
        private InstanceMetadata GetMetadata()
        {
            HttpWebRequest metadataRequest = (HttpWebRequest)WebRequest.Create(MetadataEndPoint);
            metadataRequest.Headers["Metadata"] = "true";
            metadataRequest.Method = "GET";

            HttpWebResponse metadataResponse = (HttpWebResponse)metadataRequest.GetResponse();

            StreamReader streamResponse = new StreamReader(metadataResponse.GetResponseStream());
            string stringResponse = streamResponse.ReadToEnd();
            var resultsDict = JsonConvert.DeserializeObject<Dictionary<string, InstanceMetadata>>(stringResponse);

            return resultsDict["compute"];
        }

        /// <summary>
        /// Query Azure Resource Manager (ARM) for an access token
        /// </summary>
        private string GetJWT()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AccessTokenEndPoint);
            request.Headers["Metadata"] = "true";
            request.Method = "GET";

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Pipe response Stream to a StreamReader and extract access token
            StreamReader streamResponse = new StreamReader(response.GetResponseStream());
            string stringResponse = streamResponse.ReadToEnd();
            var resultsDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);

            return resultsDict["access_token"];
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.enclaive.cloud/vault/tutorials/cli/authentication/aws-azure-gcp-and-external-auth-methods/azure.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
