Skip to content

AppRole (Machine Authentication)#

While all individuals use SAML to authenticate to Vault with their own named permissions, there are various ways for machines/apps/services to authenticate to Vault. AppRole is a popular machine authentication method that can be used for certain use cases. See the integration examples for more options.

In essence, an AppRole is a static username (role_id) and dynamic/rotatable password (secret_id) for a machine to authenticate to Vault to retrieve other secrets. AppRoles differ from traditional usernames and passwords in that you can have multiple secret_id's associated with a single role_id.

Choosing Your AppRole Strategy#

Single AppRole Mount Setup#

Use the standard single AppRole mount (auth/approle) if your application meets one or more of the following criteria:

  • Runs in only one environment
  • Does not need environment-specific policies
  • Your team only needs a small number of approles and would like to use the pre-created approle mount

Continue to Creating an AppRole below.

Use environment-specific AppRole mounts if your application:

  • Runs across multiple environments (dev, staging, production, test, qa)
  • Needs different policies per environment
  • Wants to reduce Vault licensing costs

Skip to Multi-Environment AppRole Setup below.

Creating an AppRole#

AppRoles can only be created via the Vault CLI or API. They are not available for creation/configuration from the GUI. See this example for how terraform can also be used to create AppRoles.

  1. Log in to Vault with the CLI. See this article for more information

    Bash
    export VAULT_ADDR=https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/
    vault login --method=saml --namespace=admin
    export VAULT_NAMESPACE=admin/CESI
    
  2. Create a policy to associate with the AppRole. This is what gives the machine connecting to Vault permissions to perform operations in Vault. This example policy gives the approle permissions to create, read, update, patch, and delete any secrets in the secret/example/* path. This policy and its name should be customized for your use case.

    Note

    Most policies require /data/ after the mount (i.e. secret/data/...) to read from a Vault KV v2 secrets engine. A few integrations require the data to be omitted from the policy so it is important to look at the specific integration or include both.

    Bash
    vault policy write approle_example_access_policy - <<EOF
    path "secret/data/example/*" {
        capabilities = ["create", "read", "update", "patch", "delete"]
    }
    
    path "secret/example/*" {
        capabilities = ["create", "read", "update", "patch", "delete"]
    }
    EOF
    
  3. Create the AppRole itself. The maximum life of a secret_id or password is 365 days and will need to be change at least yearly (or more often).

    Bash
    vault write auth/approle/role/example \
    token_policies="default,approle_example_access_policy" \
    secret_id_ttl="365d"
    

Reading the AppRole role_id (username)#

Bash
export VAULT_ADDR=https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/
vault login --method=saml --namespace=admin

vault read --namespace=admin/CESI auth/approle/role/example/role-id

Creating a new AppRole secret_id (password)#

Note

The output will include both a secret_id and secret_id_accessor. The secret_id is the password itself, whereas the secret_id_accessor is a record of that password that can later be used to revoke it. It may be good to record the secret_id_accessor as that makes revoking the secret_id easier.

Bash
export VAULT_ADDR=https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/
vault login --method=saml --namespace=admin
export VAULT_NAMESPACE=admin/CESI

vault write --namespace=admin/CESI -f auth/approle/role/example/secret-id 

Revoking an AppRole secret_id#

Bash
export VAULT_ADDR=https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/
vault login --method=saml --namespace=admin

# List the secret_id_accessors of all current secret_ids for example role
vault list --namespace=admin/CESI auth/approle/role/example/secret-id

# Revoke secret-id's no longer needed
vault write --namespace=admin/CESI auth/approle/role/example/secret-id-accessor/destroy secret_id_accessor=<SECRET ID ACCESSOR TO BE REVOKED>

# Confirm only expected remaining secret-id's exist
vault list --namespace=admin/CESI auth/approle/role/example/secret-id

Rotating an AppRole secret_id#

  1. Create a new secret_id using the steps in Creating a new AppRole secret_id.

  2. Update the application or service to use the new secret_id.

  3. Revoke the old secret_id using the steps in Revoking an AppRole secret_id.

For secret IDs that have a TTL longer than 30 days, users will be notified at 30 days, 7 days, 3 days, and 1 day before a Secret ID expires. While you do not technically need to revoke the old secret_id (as it will likely expire if a secret_id_ttl has been set), it is good best practice for security purposes to revoke unused secret_id's.

For applications that run across multiple environments (development, staging, production, test, qa), you can reduce Vault client licensing costs by using environment-specific AppRole mounts with entity aliasing.

Benefits#

  • Lower licensing costs: Multiple environments count as 1 client instead of 1 client per environment
  • Policy isolation: Each AppRole for an environment maintains separate policies
  • Standard naming: Choose from 5 pre-approved mount names

Reference: HashiCorp Vault Identity Entities and Groups Tutorial

Standard Mount Names (Required)#

You must use these exact 3-character environment suffixes:

  • approle-dev - Development
  • approle-stg - Staging
  • approle-prd - Production
  • approle-tst - Test
  • approle-qat - QA/Testing

Do NOT Use

  • approle (base mount - only use for non environment specific approles)
  • approle-staging, approle-prod, approle-production (non-standard names)
  • Any other custom names

Step-by-Step Setup#

1. Enable Environment-Specific AppRole Mounts#

Bash
export VAULT_ADDR=https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/
vault login --method=saml --namespace=admin
export VAULT_NAMESPACE=admin/CESI

# Enable only the environments you need
vault auth enable -path=approle-dev approle
vault auth enable -path=approle-prd approle

2. Create Environment-Specific Policies#

Create separate policies for each environment with appropriate access levels.

Development policy (dev-policy.hcl):

Bash
vault policy write myapp-dev-policy - <<EOF
# Full access for development
path "secret/data/myapp/dev/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

path "secret/metadata/myapp/dev/*" {
  capabilities = ["list"]
}
EOF

Production policy (prd-policy.hcl):

Bash
vault policy write myapp-prd-policy - <<EOF
# Read-only for production
path "secret/data/myapp/prd/*" {
  capabilities = ["read", "list"]
}

path "secret/metadata/myapp/prd/*" {
  capabilities = ["list"]
}
EOF

3. Create AppRole Roles in Each Mount#

TTL Limits

Maximum secret_id_ttl is 1 year (365 days). This is enforced by Sentinel policy.

Bash
# Create development AppRole
vault write auth/approle-dev/role/myapp \
  token_policies="default,myapp-dev-policy" \
  secret_id_ttl="365d"

# Create production AppRole  
vault write auth/approle-prd/role/myapp \
  token_policies="default,myapp-prd-policy" \
  secret_id_ttl="365d"

4. Create Single Entity (For Licensing Benefit)#

Bash
vault write identity/entity \
  name="myapp-entity" \
  metadata=app="myapp" 
Save the returned id value - this is your ENTITY_ID.

5. Get Mount Accessors and Role IDs#

Bash
# Get mount accessors
DEV_ACCESSOR=$(vault auth list -format=json | jq -r '.["approle-dev/"].accessor')
PRD_ACCESSOR=$(vault auth list -format=json | jq -r '.["approle-prd/"].accessor')

# Get Role IDs
DEV_ROLE_ID=$(vault read -field=role_id auth/approle-dev/role/myapp/role-id)
PRD_ROLE_ID=$(vault read -field=role_id auth/approle-prd/role/myapp/role-id)
Bash
ENTITY_ID="<paste-entity-id-from-step-4>"

# Link dev AppRole to entity
vault write identity/entity-alias \
  name="$DEV_ROLE_ID" \
  canonical_id="$ENTITY_ID" \
  mount_accessor="$DEV_ACCESSOR"

# Link prd AppRole to entity
vault write identity/entity-alias \
  name="$PRD_ROLE_ID" \
  canonical_id="$ENTITY_ID" \
  mount_accessor="$PRD_ACCESSOR"

7. Generate and Distribute Credentials#

Bash
# Generate Secret IDs
vault write -f auth/approle-dev/role/myapp/secret-id
vault write -f auth/approle-prd/role/myapp/secret-id

Securely distribute:

  • Development: DEV_ROLE_ID + generated Secret ID
  • Production: PRD_ROLE_ID + generated Secret ID

Verification#

Check if entity has multiple aliases:

Bash
vault read identity/entity/name/myapp-entity

Look for the aliases array showing multiple entries with different mount_path values.

Managing Multi-Environment AppRoles#

Reading role_id:

Bash
vault read auth/approle-dev/role/myapp/role-id
vault read auth/approle-prd/role/myapp/role-id

Creating new secret_id:

Bash
vault write -f auth/approle-dev/role/myapp/secret-id
vault write -f auth/approle-prd/role/myapp/secret-id

Revoking secret_id:

Bash
# List current secret IDs
vault list auth/approle-dev/role/myapp/secret-id

# Revoke specific secret ID
vault write auth/approle-dev/role/myapp/secret-id-accessor/destroy \
  secret_id_accessor=<ACCESSOR_TO_REVOKE>

Rotating credentials: Follow the same Rotating an AppRole secret_id process, but perform for each environment AppRole mount separately.

Troubleshooting Multi-Environment Setup#

Authentication fails:

  • Verify correct mount_path in Vault Agent config
  • Check you're using correct Role ID for that environment
  • Confirm Secret ID has not expired

Cannot create mount:

  • Verify using approved names: approle-dev, approle-stg, approle-prd, approle-tst, approle-qat
  • Do not use approle (base approle mount is pre-created by DevEx)
  • Contact DevEx Team at devex@umn.edu if you need non-standard name