Azure Active Directory with OIDC auth method and external groups
Before a client can interact with Vault, it must authenticate with an auth method to acquire a token. This token has policies attached so that the behavior of the client can be governed.
Note
To learn the basics of Vault tokens, go through the Tokens tutorial.
Auth methods perform authentication to verify the user or machine-supplied information. Some auth methods are targeted towards users while others are targeted toward machines or apps.
Challenge
Vault supports a number of auth methods for users or system to prove their identity so that a token with appropriate policies can be obtained. Delegated authorization methods based on OAuth 2.0 are convenient for users and have become increasingly common.
Solution
If you use Azure Active Directory (AD), you can use Microsoft's identity platform and its implementation of OpenID Connect to verify the identity of a Vault user. By registering a Vault application in Azure, configuring Vault's OIDC auth method, and connecting the AD group with an external group in Vault, your Vault users can log into Vault by web browser. They will be redirected to Azure to complete login and then be routed back to Vault with a newly-created token.
Note
To learn how to configure authentication for system-assigned or user-assigned managed identities in Azure, go through documentation on the Azure Auth Method.
This tutorial uses the current user's email to authenticate to Azure AD. You can optionally edit the claims and Vault configuration to use Azure AD UserPrincipalName (UPN).
Prerequisites
To perform the tasks described in this tutorial, you need to have a Vault 1.6 or later. Refer to the Getting Started tutorial to install Vault. Make sure that your Vault server has been initialized and unsealed.
In this tutorial, make sure that Azure can access your Vault server to successfully redirect the authentication request.
Azure Active Directory
This tutorial uses Azure Active Directory. Make sure you have:
Configured an Azure AD tenant.
Permissions to configure application registrations and read group information.
Signed into Azure from the CLI with the correct tenant ID.
An Azure AD group you can use to connect to a Vault external group.
Policy requirements
Note
For the purpose of this tutorial, you can use the root
token to work
with Vault. However, it is recommended that root tokens are only used for just
enough initial setup or in emergencies. As a best practice, use tokens with
an appropriate set of policies based on your role in the organization.
To perform all tasks demonstrated in this tutorial, your policy must include the following permissions:
# Mount the OIDC auth methodpath "sys/auth/oidc" { capabilities = [ "create", "read", "update", "delete", "sudo" ]} # Configure the OIDC auth methodpath "auth/oidc/*" { capabilities = [ "create", "read", "update", "delete", "list" ]} # Write ACL policiespath "sys/policies/acl/*" { capabilities = [ "create", "read", "update", "delete", "list" ]} # List available secrets engines to retrieve accessor IDpath "sys/mounts" { capabilities = [ "read" ]} # Manage secrets enginespath "sys/mounts/*"{ capabilities = ["create", "read", "update", "delete", "list", "sudo"]} # List, create, update, and delete key/value secretspath "secret/*"{ capabilities = ["create", "read", "update", "delete", "list", "sudo"]}
If you are not familiar with policies, complete the policies tutorial.
Lab setup
In another terminal, start a Vault dev server with
root
as the root token.$ vault server -dev -dev-root-token-id root
The Vault dev server defaults to running at
127.0.0.1:8200
. The server is initialized and unsealed.Insecure operation
Do not run a Vault dev server in production. This approach starts a Vault server with an in-memory database and runs in an insecure way.
Export an environment variable for the
vault
CLI to address the Vault server.$ export VAULT_ADDR=http://127.0.0.1:8200
Export an environment variable for the
vault
CLI to address the Vault server through the OIDC interface.$ export VAULT_OIDC_ADDR=http://127.0.0.1:8250
Export an environment variable for the
vault
CLI to authenticate with the Vault server.$ export VAULT_TOKEN=root
Note
For these tasks, you can use Vault's root token. However, it is recommended that root tokens are only used for enough initial setup or in emergencies. As a best practice, use an authentication method or token that meets the policy requirements.
The Vault server is ready.
Register Vault as a web app
An app registration allows Azure AD to identify Vault and the user.
Set the
AD_AZURE_DISPLAY_NAME
environment variable to a unique display name for Vault's app registration.$ export AD_AZURE_DISPLAY_NAME=vault-$(xxd -l 4 -p < /dev/random)
Note
The example above uses
xxd
and/dev/random
to generate a short unique string to use for the app name.Register a web app for Vault with two redirect URIs (also called
reply-urls
). One URI is for Vault CLI access and the second is for UI access. Save the application ID to theAD_VAULT_APP_ID
environment variable.$ export AD_VAULT_APP_ID=$(az ad app create \ --display-name ${AD_AZURE_DISPLAY_NAME} \ --web-redirect-uris "http://localhost:8250/oidc/callback" \ "${VAULT_ADDR}/ui/vault/auth/oidc/oidc/callback" | \ jq -r '.appId')
Retrieve the application ID of the Microsoft Graph API, which allows you to access Azure service resources. This ID will be used to attach API permissions to the app registration.
$ export AD_MICROSOFT_GRAPH_API_ID=$(az ad sp list \ --filter "displayName eq 'Microsoft Graph'" \ --query '[].appId' -o tsv)
Using the Microsoft Graph API ID, retrieve the ID of the permission for
GroupMember.Read.All
.$ export AD_PERMISSION_GROUP_MEMBER_READ_ALL_ID=$(az ad sp show \ --id ${AD_MICROSOFT_GRAPH_API_ID} \ --query "oauth2PermissionScopes[?value=='GroupMember.Read.All'].id" -o tsv)
Add the
GroupMember.Read.All
permission to the application. This allows the application to read an Active Directory group and its users.$ az ad app permission add \ --id ${AD_VAULT_APP_ID} \ --api ${AD_MICROSOFT_GRAPH_API_ID} \ --api-permissions ${AD_PERMISSION_GROUP_MEMBER_READ_ALL_ID}=Scope
NOTE: If you would want to use UPN instead of email, you may need to add permissions such as
User.Read
andprofile
.Create a service principal to attach to the application. The service principal allows you to grant administrative consent from the Azure CLI.
$ az ad sp create --id ${AD_VAULT_APP_ID}
Grant administrative consent for the application to access the Microsoft Graph API.
$ az ad app permission grant --id ${AD_VAULT_APP_ID} \ --api ${AD_MICROSOFT_GRAPH_API_ID} \ --scope ${AD_PERMISSION_GROUP_MEMBER_READ_ALL_ID}
Retrieve the Azure tenant ID for the application and set it to the
AD_TENANT_ID
environment variable.$ export AD_TENANT_ID=$(az ad sp show --id ${AD_VAULT_APP_ID} \ --query 'appOwnerOrganizationId' -o tsv)
Reset the client secret for the application and set the password to the
AD_CLIENT_SECRET
environment variable. You will need the secret to configure the OIDC auth method in Vault.$ export AD_CLIENT_SECRET=$(az ad app credential reset \ --id ${AD_VAULT_APP_ID} | jq -r '.password')
Update application group claims and ID tokens
To use AD groups to authenticate to Vault, you need to update the Vault application in Azure with a claim for group membership information.
Create a file named
manifest.json
with the specification for an ID token for an AD group.$ cat > manifest.json << EOF{ "idToken": [ { "name": "groups", "additionalProperties": [] }, { "name": "email", "additionalProperties": [] } ]}EOF
Update the application with the claims manifest in
manifest.json
and setgroupMembershipClaims
toSecurityGroup
. You can expand the group type to additional groups.$ az ad app update --id ${AD_VAULT_APP_ID} \ --set groupMembershipClaims=SecurityGroup \ --optional-claims @manifest.json
Create Vault policies for an example group
Every client token has policies attached to it to control its secret access. You must create the policies before defining them in the OIDC configuration.
Create an example Vault policy that allows an application development team to read and write secrets mounted at
secrets/
.$ cat > kv-reader-policy.hcl << EOFpath "secret/*" { capabilities = ["read", "list"]}EOF
Write the policy named
kv-reader
to Vault.$ vault policy write kv-reader kv-reader-policy.hcl
Enable the key-value secrets engine at
secret/
.$ vault secrets enable -path=secret -version=2 kv
Create a sample entry in the KV secrets engine.
$ vault kv put secret/azure hello=world
Configure Vault with the OIDC auth method
OIDC must be enabled and configured before it can be used. In this section, you
will configure OIDC for a role named app-dev
, which application development
teams can use to log in and access secrets.
Set the
VAULT_LOGIN_ROLE
environment variable toapp-dev
. In your own configuration, you can change this role name.$ export VAULT_LOGIN_ROLE=app-dev
Enable the OIDC auth method on the Vault server.
$ vault auth enable oidc
Configure the OIDC auth method with the application ID, client secret, and tenant ID of your Vault application in Azure AD.
$ vault write auth/oidc/config \ oidc_client_id="${AD_VAULT_APP_ID}" \ oidc_client_secret="${AD_CLIENT_SECRET}" \ default_role="${VAULT_LOGIN_ROLE}" \ oidc_discovery_url="https://login.microsoftonline.com/${AD_TENANT_ID}/v2.0"
Tip
Further information for configuring the OIDC auth method for use with Azure AD is available in the Azure Active Directory (AAD) section of the OIDC Provider Configuration documentation.
Add a role to Vault called
app-dev
that uses the Vault policy to read secrets (kv-reader
). It authenticates to Azure by a user's email. In addition, it passes thegroup_claim
ofgroups
that were configured as part of the claims manifest. Theoidc_scopes
should be set to thehttps://graph.microsoft.com/.default
, which is the Microsoft Graph API.$ vault write auth/oidc/role/${VAULT_LOGIN_ROLE} \ user_claim="email" \ allowed_redirect_uris="http://localhost:8250/oidc/callback" \ allowed_redirect_uris="${VAULT_ADDR}/ui/vault/auth/oidc/oidc/callback" \ policies="kv-reader" \ oidc_scopes="https://graph.microsoft.com/.default"
Note
If you want to use UPN instead of user email, change the
user_claim
field toupn
.Record the current Vault token.
$ echo $VAULT_TOKEN VAULT_TOKEN=hvs.REDACTED
You will use this to re-authenticate with Vault to add additional OIDC configuration for external groups.
Unset the
VAULT_TOKEN
environment variable. When you authenticate with Azure you will receive a new token based on the OIDC configuration.$ unset VAULT_TOKEN
Try to log into the server with the OIDC auth method. If it is successful, the command launches a browser to Azure for you to log in and return a Vault token.
$ vault login -method=oidc role="app-dev" Complete the login via your OIDC provider. Launching browser to: https://login.microsoftonline.com/... Success! You are now authenticated. The token information displayed belowis already stored in the token helper. You do NOT need to run "vault login"again. Future Vault requests will automatically use this token. Key Value--- -----token hvs.REDACTEDtoken_accessor u58XsOYz2I5T1GmqwsaaOpsP.WEwzytoken_duration 1htoken_renewable truetoken_policies ["default" "kv-reader"]identity_policies []policies ["default" "kv-reader"]token_meta_role app-dev
You successful authenticated to Vault using Azure credentials. The
kv-reader
policy was applied because this was configured as the default policy for theapp-dev
role.As part of the
app-dev
role, you should be able to accesssecret/
.$ vault kv list secret Keys----azure
The secret created earlier is listed.
Set up Vault external group and AD group
With OIDC setup correctly, you will now create an Active Directory group for the security team to write secrets. Connect this Azure AD group to a Vault policy, which will allow any users in the Azure AD group to log into Vault by email and write secrets.
Export the token that was unset prior to testing the OIDC configuration.
$ export VAULT_TOKEN=<actual-token-value>
Create a policy file named
secops.hcl
.$ tee secops.hcl <<EOF# Manage k/v secretspath "/secret/*" { capabilities = ["create", "read", "update", "delete", "list"]}EOF
Create a policy named
secops
with the policy defined insecops.hcl
.$ vault policy write secops secops.hcl
Create an Azure AD group.
$ az ad group create \ --display-name hashicorp-secops-$AD_AZURE_DISPLAY_NAME \ --mail-nickname hashicorp-secops-$AD_AZURE_DISPLAY_NAME
Add the user authenticated with the Azure CLI to the new AD group.
$ az ad group member add --group hashicorp-secops-$AD_AZURE_DISPLAY_NAME \ --member-id $(az ad signed-in-user show | jq -r .id)
Create a role named
secops
.$ vault write auth/oidc/role/secops \user_claim="email" \allowed_redirect_uris="http://localhost:8250/oidc/callback" \allowed_redirect_uris="${VAULT_ADDR}/ui/vault/auth/oidc/oidc/callback" \groups_claim="groups" \policies="kv-reader" \oidc_scopes="https://graph.microsoft.com/.default"
Create an external group named
secops
in the Vault identity secrets engine that references thesecops
policy and set the group ID in theVAULT_GROUP_ID
environment variable.$ export VAULT_GROUP_ID=$(vault write \ -field=id -format=table \ identity/group \ name="secops" \ type="external" \ policies="secops")
Retrieve Vault's OIDC accessor ID and set it to the
VAULT_OIDC_ACCESSOR_ID
environment variable.$ export VAULT_OIDC_ACCESSOR_ID=$(vault auth list -format=json | \ jq -r '."oidc/".accessor')
Retrieve the
objectId
Active Directory group you previously create and save it as an environment variable.$ AZ_GROUP_ID=$(az ad group show --group hashicorp-secops-$AD_AZURE_DISPLAY_NAME | jq .id -r)
Create a group alias using the ID of the AD security group.
$ vault write identity/group-alias name="$AZ_GROUP_ID" \ mount_accessor="$VAULT_OIDC_ACCESSOR_ID" \ canonical_id="$VAULT_GROUP_ID"
Unset the
VAULT_TOKEN
environment variable. When you authenticate with Azure you will receive a new token based on the OIDC configuration.$ unset VAULT_TOKEN
Try to log into the server with the OIDC auth method as a member of the AD group you configured with Vault. If it is successful, the command launches a browser to Azure for you to log in and return a Vault token.
$ vault login -method=oidc role="secops" Complete the login via your OIDC provider. Launching browser to: https://login.microsoftonline.com/...snip... Waiting for OIDC authentication to complete...Success! You are now authenticated. The token information displayed belowis already stored in the token helper. You do NOT need to run "vault login"again. Future Vault requests will automatically use this token. Key Value--- -----token hvs.REDACTEDtoken_accessor 6OACh6sPly1ogpRV5RY5zmos.CGhuZtoken_duration 1htoken_renewable truetoken_policies ["default" "kv-reader"]identity_policies ["secops"]policies ["default" "kv-reader" "secops"]token_meta_role secops
The
secops
policy is assigned through the AD group membership.As part of the
secops
role that is connected to the AD group, you should be able to write secrets to thesecret/
path.$ vault kv put secret/groups oidc=ftw === Secret Path ===secret/data/groups ======= Metadata =======Key Value--- -----created_time 2023-01-09T15:22:21.854306825Zcustom_metadata <nil>deletion_time n/adestroyed falseversion 1
You are now able to write secrets based on the
secops
policy assigned to the user.
Cleanup
To avoid unnecessary charges and having unused security resources in your Azure account, remove the following:
Delete the Vault Azure app.
$ az ad app delete --id $AD_VAULT_APP_ID
Delete the Azure AD group
$ az ad group delete --group hashicorp-secops-$AD_AZURE_DISPLAY_NAME
Create an array of the local environment variables.
$ learnVariables=( \AD_AZURE_DISPLAY_NAME \AD_VAULT_APP_ID \AD_MICROSOFT_GRAPH_API_ID \AD_PERMISSION_GROUP_MEMBER_READ_ALL_ID \AD_TENANT_ID \AD_CLIENT_SECRET \VAULT_LOGIN_ROLE \VAULT_GROUP_ID \VAULT_OIDC_ACCESSOR_ID \)
Unset the environment variables.
for v in ${learnVariables[@]}; dounset $vdone
Summary
In this tutorial, you configured Vault's OIDC auth method to authenticate a user by using a group in Azure Active Directory. This allowed the user to read and list secrets from Vault.