open-vault/website/content/docs/auth/azure.mdx
Yoko Hyakuna f374938d31
Fix broken links referencing to API docs (#14565)
* Fix all '/api/' to '/api-docs/'

* Minor fixes

* Undo some of the unintentional changes
2022-03-17 18:14:48 -07:00

393 lines
13 KiB
Plaintext

---
layout: docs
page_title: Azure - Auth Methods
description: |-
The azure auth method plugin allows automated authentication of Azure Active
Directory.
---
# Azure Auth Method
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 [Azure Managed Service Identity (MSI)](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) for more information about these resources.
~> System-assigned identities are unique to every virtual machine in Azure. If the
virtual machines using Azure auth are recreated frequently, using system-assigned
identities could result in a lot of Vault entities. For environments with high ephemeral
workloads, user-assigned identities are recommended.
## Prerequisites:
The following documentation assumes that the method has been
[mounted](/docs/plugin) at `auth/azure`.
- 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) for accessing the Azure Resource Manager with read access to compute endpoints. 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)
Required Azure API permissions to be granted to Vault user:
- `Microsoft.Compute/virtualMachines/*/read`
- `Microsoft.Compute/virtualMachineScaleSets/*/read`
_NOTE:_ The above permissions are only required when the associated vm\* parameters are used on login. Please see the [API doc](https://www.vaultproject.io/api-docs/auth/azure#login) for more details.
If Vault is hosted on Azure, Vault can use MSI to access Azure instead of a shared secret. MSI must be [enabled](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/qs-configure-portal-windows-vm) on the VMs hosting Vault.
The next sections review how the authN/Z workflows work. If you
have already reviewed these sections, here are some quick links to:
- [Usage](/docs/secrets/azure#usage)
- [API documentation](/api-docs/auth/azure) docs.
## 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_ and _vmss_name_). 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:
```text
$ vault auth enable azure
```
1. Configure the Azure auth method:
```text
$ 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.
1. Create a role:
```text
$ 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](/api-docs/auth/azure).
### Via the API
1. Enable Azure authentication in Vault:
```sh
$ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data '{"type": "azure"}' \
https://127.0.0.1:8200/v1/sys/auth/azure
```
1. Configure the Azure auth method:
```sh
$ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data '{"tenant_id": "...", "resource": "..."}' \
https://127.0.0.1:8200/v1/auth/azure/config
```
1. Create a role:
```sh
$ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data '{"policies": ["dev", "prod"], ...}' \
https://127.0.0.1:8200/v1/auth/azure/role/dev-role
```
### Plugin Setup
~> The following section is only relevant if you decide to enable the azure auth
method as an external plugin. The azure plugin method is integrated into Vault as
a builtin method by default.
Assuming you have saved the binary `vault-plugin-auth-azure` to some folder and
configured the [plugin directory](/docs/internals/plugins#plugin-directory)
for your server at `path/to/plugins`:
1. Enable the plugin in the catalog:
```text
$ vault write sys/plugins/catalog/auth/azure-auth \
command="vault-plugin-auth-azure" \
sha256="..."
```
1. Enable the azure auth method as a plugin:
```text
$ vault auth enable -path=azure azure-auth
```
## 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](/api-docs/auth/azure) for more details.
## Code Example
The following code snippet demonstrates the Azure auth method to authenticate
with Vault.
<CodeTabs heading="azure auth example">
<CodeBlockConfig lineNumbers>
```go
package main
import (
"context"
"fmt"
vault "github.com/hashicorp/vault/api"
auth "github.com/hashicorp/vault/api-docs/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.TODO(), 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
secret, err := client.Logical().Read("kv-v2/data/creds")
if err != nil {
return "", fmt.Errorf("unable to read secret: %w", err)
}
data, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("data type assertion failed: %T %#v", secret.Data["data"], secret.Data["data"])
}
// data map can contain more than one key-value pair,
// in this case we're just grabbing one of them
key := "password"
value, ok := data[key].(string)
if !ok {
return "", fmt.Errorf("value type assertion failed: %T %#v", data[key], data[key])
}
return value, nil
}
```
</CodeBlockConfig>
<CodeBlockConfig lineNumbers>
```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"];
}
}
}
```
</CodeBlockConfig>
</CodeTabs>