• HashiCorp Developer

  • HashiCorp Cloud Platform
  • Terraform
  • Packer
  • Consul
  • Vault
  • Boundary
  • Nomad
  • Waypoint
  • Vagrant
Vault
  • Install
  • Tutorials
  • Documentation
  • API
  • Try Cloud(opens in new tab)
  • Sign up
Authentication

Skip to main content
14 tutorials
  • Tokens
  • OIDC Auth Method
  • Azure Active Directory with OIDC Auth Method and External Groups
  • OIDC Authentication with Okta
  • Vault as an OIDC Identity Provider
  • AppRole Usage Best Practices
  • AppRole Pull Authentication
  • AppRole With Terraform & Chef
  • Enable Login Multi Factor Authentication (MFA)
  • Active Directory Auth Method with TOTP Login MFA
  • Vault Agent with AWS
  • Vault Agent with Kubernetes
  • Identity: Entities and Groups
  • Build Your Own Plugins

  • Resources

  • Tutorial Library
  • Certifications
  • Community Forum
    (opens in new tab)
  • Support
    (opens in new tab)
  • GitHub
    (opens in new tab)
  1. Developer
  2. Vault
  3. Tutorials
  4. Authentication
  5. AppRole Pull Authentication

AppRole Pull Authentication

  • 22min

  • VaultVault
  • InteractiveInteractive

Before a client can interact with Vault, it must authenticate against an auth method to acquire a token. This token has policies attached so that the behavior of the client can be governed.

Authentication Workflow

Since tokens are the core method for authentication within Vault, there is a token auth method (often referred to as token store). This is a special auth method responsible for creating and storing tokens.

Auth Methods

Auth methods perform authentication to verify the user or machine-supplied information. Some of the supported auth methods are targeted towards users while others are targeted toward machines or apps. For example, LDAP auth method enables user authentication using an existing LDAP server while AppRole auth method is recommended for machines or apps.

The Getting Started tutorial walks you through how to enable the GitHub auth method for user authentication.

This introductory tutorial focuses on generating tokens for machines or apps by enabling the AppRole auth method.

Personas

The end-to-end scenario described in this tutorial involves two personas:

  • admin with privileged permissions to configure an auth method
  • app is the consumer of secrets stored in Vault

Challenge

Think of a scenario where a DevOps team wants to configure Jenkins to read secrets from Vault so that it can inject the secrets to an app's environment variables (e.g. MYSQL_DB_HOST) at deployment time.

Instead of hardcoding secrets in each build script as plain text, Jenkins retrieves secrets from Vault.

As a user, you can authenticate with Vault using your LDAP credentials, and Vault generates a token. This token has policies granting you permission to perform the appropriate operations.

How can a Jenkins server programmatically request a token so that it can read secrets from Vault?

Solution

Enable AppRole auth method so that the Jenkins server can obtain a Vault token with appropriate policies attached. Since each AppRole has attached policies, you can write fine-grained policies limiting which app can access which path.

Prerequisites

To perform the tasks described in this tutorial, you need to have a Vault environment. Refer to the Getting Started tutorial to install Vault. Make sure that your Vault server has been initialized and unsealed.

Launch Terminal

This tutorial includes a free interactive command-line lab that lets you follow along on actual cloud infrastructure.

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 AppRole auth method
path "sys/auth/approle" {
  capabilities = [ "create", "read", "update", "delete", "sudo" ]
}

# Configure the AppRole auth method
path "sys/auth/approle/*" {
  capabilities = [ "create", "read", "update", "delete" ]
}

# Create and manage roles
path "auth/approle/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

# Write ACL policies
path "sys/policies/acl/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

# Write test data
# Set the path to "secret/data/mysql/*" if you are running `kv-v2`
path "secret/mysql/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

If you are not familiar with policies, complete the policies tutorial.

Scenario Introduction

AppRole is an authentication mechanism within Vault to allow machines or apps to acquire a token to interact with Vault. It uses RoleID and SecretID for login.

AppRole auth method workflow

For the purpose of introducing the basics of AppRole, this tutorial walks you through a very simple scenario involving only two personas (admin and app). Please refer to the Advanced Features section for further discussions after completing the following steps.

In this tutorial, you are going to perform the following steps:

  1. Enable AppRole auth method
  2. Create a role with policy attached
  3. Get RoleID and SecretID
  4. Login with RoleID & SecretID
  5. Read secrets using the AppRole token

Step 1 through 3 need to be performed by an admin user. Step 4 and 5 describe the commands that an app runs to get a token and read secrets from Vault.

Lab setup

  1. In a 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.

  2. Open a new terminal and export an environment variable for the vault CLI to address the Vault server.

    $ export VAULT_ADDR=http://127.0.0.1:8200
    
  3. Export an environment variable for the vault CLI to authenticate with the Vault server.

    $ export VAULT_TOKEN=root
    
  4. Create some test data.

    $ vault kv put secret/mysql/webapp db_name="users" username="admin" password="passw0rd"
    

    Example output:

    Key              Value
    ---              -----
    created_time     2021-06-08T02:34:23.182299Z
    deletion_time    n/a
    destroyed        false
    version          1
    

The Vault server is ready.

Note: If you do not have access to an HCP Vault cluster, visit the Create a Vault Cluster on HCP tutorial.

  1. Launch the HCP Portal and login.

  2. Click Vault in the left navigation pane.

  3. In the Vault clusters pane, click vault-cluster.

  4. Under Cluster URLs, click Public Cluster URL. Public Cluster URL

  5. In a terminal, set the VAULT_ADDR environment variable to the copied address.

    $ export VAULT_ADDR=<Public_Cluster_URL>
    
  6. Return to the Overview page and click Generate token. Generate a Token

    Within a few moments, a new token will be generated.

  7. Copy the Admin Token. Generated Token

  8. Return to the terminal and set the VAULT_TOKEN environment variable.

    $ export VAULT_TOKEN=<token>
    
  9. Set the VAULT_NAMESPACE environment variable to admin.

    $ export VAULT_NAMESPACE=admin
    

    The admin namespace is the top-level namespace automatically created by HCP Vault. All CLI operations default to use the namespace defined in this environment variable.

  10. Type vault status to verify your connectivity to the Vault cluster.

    $ vault status
    
    Key                      Value
    ---                      -----
    Recovery Seal Type       shamir
    Initialized              true
    Sealed                   false
    Total Recovery Shares    1
    Threshold                1
    Version                  1.9.2+ent
    Storage Type             raft
    ...snipped...
    
  11. Enable the K/V secret engine

    $ vault secrets enable --version=2 --path=secret kv
    
  12. Create some test data.

    $ vault kv put secret/mysql/webapp db_name="users" username="admin" password="passw0rd"
    

    Example output:

    Key              Value
    ---              -----
    created_time     2021-06-08T02:34:23.182299Z
    deletion_time    n/a
    destroyed        false
    version          1
    

The HCP Vault server is ready.

Step 1: Enable AppRole auth method

(Persona: admin)

The AppRole auth method must be enabled before it can be used.

Enable approle auth method by executing the following command.

$ vault auth enable approle
Success! Enabled approle auth method at: approle/

Enable approle auth method by mounting its endpoint at /sys/auth/approle.

$ curl --header "X-Vault-Token: $VAULT_TOKEN" \
    --request POST \
    --data '{"type": "approle"}' \
    $VAULT_ADDR/v1/sys/auth/approle

The above example passes the type (approle) in the request payload at the sys/auth/approle endpoint.

Enable approle auth method by mounting its endpoint at /sys/auth/approle.

$ curl --header "X-Vault-Token: $VAULT_TOKEN" \
    --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    --request POST \
    --data '{"type": "approle"}' \
    $VAULT_ADDR/v1/sys/auth/approle

The above example passes the type (approle) in the request payload at the sys/auth/approle endpoint.

  1. Enter http://127.0.0.1:8200/ui in a browser to launch the Vault UI.

  2. Enter root in the Token field and click Sign In.

  3. Select the Access tab on top.

  4. Select Enable new method. Enable AppRole

  5. Select the AppRole radio button and click Next.

  6. Leave the path as the defaulted path and click Enable Method.

  7. Select approle without making any update. Enable AppRole

Step 2: Create a role with policy attached

(Persona: admin)

When you enabled the AppRole auth method, it gets mounted at the /auth/approle path. In this example, you are going to create a role for the app persona (jenkins in our scenario).

First, create a policy named jenkins with following definition.

# Read-only permission on secrets stored at 'secret/data/mysql/webapp'
path "secret/data/mysql/webapp" {
  capabilities = [ "read" ]
}
  1. Before creating a role, create a jenkins policy.

    $ vault policy write jenkins -<<EOF
    # Read-only permission on secrets stored at 'secret/data/mysql/webapp'
    path "secret/data/mysql/webapp" {
      capabilities = [ "read" ]
    }
    EOF
    

    Output:

    Success! Uploaded policy: jenkins
    
  2. Creates a role named jenkins with jenkins policy attached. The generated token's time-to-live (TTL) is set to 1 hour and can be renewed for up to 4 hours of its first creation. (NOTE: This example creates a role which operates in pull mode.)

    $ vault write auth/approle/role/jenkins token_policies="jenkins" \
        token_ttl=1h token_max_ttl=4h
    

    Output:

    Success! Data written to: auth/approle/role/jenkins
    

    To attach multiple policies, pass the policy names as a comma separated string: token_policies="jenkins,anotherpolicy".

    The command to create a new AppRole is:

    $ vault write auth/approle/role/<ROLE_NAME> [parameters]
    

    There are a number of parameters that you can set on a role. If you want to limit the use of the generated secret ID, set secret_id_num_uses or secret_id_ttl parameter values. Similarly, you can specify token_num_uses and token_ttl. You may never want the app token to expire. In such a case, specify the period so that the token generated by this AppRole is a periodic token. To learn more about periodic tokens, refer to the Tokens tutorial.

  3. Read the jenkins role you created to verify.

    $ vault read auth/approle/role/jenkins
    

    Example output:

    Key                        Value
    ---                        -----
    bind_secret_id             true
    local_secret_ids           false
    secret_id_bound_cidrs      <nil>
    secret_id_num_uses         0
    secret_id_ttl              0s
    token_bound_cidrs          []
    token_explicit_max_ttl     0s
    token_max_ttl              4h
    token_no_default_policy    false
    token_num_uses             0
    token_period               0s
    token_policies             [jenkins]
    token_ttl                  1h
    token_type                 default
    
  1. Before creating a role, create jenkins policy.

    Create an API request payload containing the policy definition.

    $ tee payload.json <<"EOF"
    {
      "policy": "# Read-only permission on secrets stored at 'secret/data/mysql/webapp'\npath \"secret/data/mysql/webapp\" {\n  capabilities = [ \"read\" ]\n}"
    }
    EOF
    

    Create an policy named jenkins.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" --request PUT --data @payload.json \
          $VAULT_ADDR/v1/sys/policies/acl/jenkins
    
  2. Creates a role named jenkins with a jenkins policy attached. The token's time-to-live (TTL) is set to 1 hour and can be renewed for up to 4 hours of its first creation. (NOTE: This example creates a role which operates in pull mode.)

    First, create the API request payload.

    $ tee payload.json <<EOF
    {
      "token_policies": "jenkins",
      "token_ttl": "1h",
      "token_max_ttl": "4h"
    }
    EOF
    

    Create a new role named jenkins.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
        --request POST \
        --data @payload.json \
        $VAULT_ADDR/v1/auth/approle/role/jenkins
    

    There are a number of parameters that you can set on a role. If you want to limit the use of the generated secret ID, set secret_id_num_uses or secret_id_ttl parameter values. Similarly, you can specify token_num_uses and token_ttl. You may never want the app token to expire. In such a case, specify the period so that the token generated by this AppRole is a periodic token. To learn more about periodic tokens, refer to the Tokens tutorial.

  3. Review the Jenkins role you just created.

    NOTE: This example uses jq to process the JSON output for readability.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" --request GET \
            $VAULT_ADDR/v1/auth/approle/role/jenkins | jq -r ".data"
    

    Example output:

    {
      "bind_secret_id": true,
      "local_secret_ids": false,
      "secret_id_bound_cidrs": null,
      "secret_id_num_uses": 0,
      "secret_id_ttl": 0,
      "token_bound_cidrs": [],
      "token_explicit_max_ttl": 0,
      "token_max_ttl": 14400,
      "token_no_default_policy": false,
      "token_num_uses": 0,
      "token_period": 0,
      "token_policies": ["jenkins"],
      "token_ttl": 3600,
      "token_type": "default"
    }
    
  1. Before creating a role, create jenkins policy.

    Create an API request payload containing the policy definition.

    $ tee payload.json <<"EOF"
    {
      "policy": "# Read-only permission on secrets stored at 'secret/data/mysql/webapp'\npath \"secret/data/mysql/webapp\" {\n  capabilities = [ \"read\" ]\n}"
    }
    EOF
    

    Create an policy named jenkins.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
        --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
        --request PUT --data @payload.json \
        $VAULT_ADDR/v1/sys/policies/acl/jenkins
    
  2. Creates a role named jenkins with a jenkins policy attached. The token's time-to-live (TTL) is set to 1 hour and can be renewed for up to 4 hours of its first creation. (NOTE: This example creates a role which operates in pull mode.)

    First, create the API request payload.

    $ tee payload.json <<EOF
    {
      "token_policies": "jenkins",
      "token_ttl": "1h",
      "token_max_ttl": "4h"
    }
    EOF
    

    Create a new role named jenkins.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
        --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
        --request POST \
        --data @payload.json \
        $VAULT_ADDR/v1/auth/approle/role/jenkins
    

    There are a number of parameters that you can set on a role. If you want to limit the use of the generated secret ID, set secret_id_num_uses or secret_id_ttl parameter values. Similarly, you can specify token_num_uses and token_ttl. You may never want the app token to expire. In such a case, specify the period so that the token generated by this AppRole is a periodic token. To learn more about periodic tokens, refer to the Tokens tutorial.

  3. Review the Jenkins role you just created.

    NOTE: This example uses jq to process the JSON output for readability.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
        --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
        --request GET \
        $VAULT_ADDR/v1/auth/approle/role/jenkins | jq -r ".data"
    

    Example output:

    {
      "bind_secret_id": true,
      "local_secret_ids": false,
      "secret_id_bound_cidrs": null,
      "secret_id_num_uses": 0,
      "secret_id_ttl": 0,
      "token_bound_cidrs": [],
      "token_explicit_max_ttl": 0,
      "token_max_ttl": 14400,
      "token_no_default_policy": false,
      "token_num_uses": 0,
      "token_period": 0,
      "token_policies": ["jenkins"],
      "token_ttl": 3600,
      "token_type": "default"
    }
    
  1. Select the Policies tab, and then select Create ACL policy.

  2. Enter jenkins in the Name text field.

  3. Enter the following policy in the Policy field.

    # Read-only permission on secrets stored at 'secret/data/mysql/webapp'
    path "secret/data/mysql/webapp" {
      capabilities = [ "read" ]
    }
    
  4. Click Create Policy to complete.

  5. Click the Vault CLI shell icon (>_) to open a command shell. Execute the following command to create a new jenkins role:

    vault write auth/approle/role/jenkins token_policies="jenkins" token_ttl=1h token_max_ttl=4h
    

    Create a role

Step 3: Get RoleID and SecretID

The RoleID and SecretID are like a username and password that a machine or app uses to authenticate.

Since the example created a jenkins role which operates in pull mode, Vault will generate the SecretID. You can set properties such as usage-limit, TTLs, and expirations on the SecretIDs to control its lifecycle.

To retrieve the RoleID, invoke the auth/approle/role/<ROLE_NAME>/role-id endpoint. To generate a new SecretID, invoke the auth/approle/role/<ROLE_NAME>/secret-id endpoint.

Now, you need to fetch the RoleID and SecretID of a role.

  1. Execute the following command to retrieve the RoleID for the jenkins role.

    $ vault read auth/approle/role/jenkins/role-id
    
    Key     Value
    ---     -----
    role_id 675a50e7-cfe0-be76-e35f-49ec009731ea
    
  2. Execute the following command to generate a SecretID for the jenkins role.

    $ vault write -force auth/approle/role/jenkins/secret-id
    
    Key                 Value
    ---                 -----
    secret_id           ed0a642f-2acf-c2da-232f-1b21300d5f29
    secret_id_accessor  a240a31f-270a-4765-64bd-94ba1f65703c
    

    The -force (or -f) flag forces the write operation to continue without any data values specified. Or you can set parameters such as cidr_list.

    If you specified secret_id_ttl, secret_id_num_uses, or bound_cidr_list on the role in Step 2, the generated SecretID carries out the conditions.

  1. To read the RoleID for the jenkins role.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
          $VAULT_ADDR/v1/auth/approle/role/jenkins/role-id | jq -r ".data"
    

    Example output:

    {
      "role_id": "5b5817f5-7db1-31ea-1943-1dbecf797ab3"
    }
    
  2. To generate a new SecretID for the jenkins role.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
          --request POST \
          $VAULT_ADDR/v1/auth/approle/role/jenkins/secret-id | jq -r ".data"
    

    Example output:

    {
      "secret_id": "4e692046-914a-e2d4-0cc7-08de52401b07",
      "secret_id_accessor": "8003b5f6-b42a-bf27-429c-4b09f67544e4",
      "secret_id_ttl": 0
    }
    

You can pass parameters in the request payload, or invoke the API with an empty payload.

If you specified secret_id_ttl, secret_id_num_uses, or bound_cidr_list on the role in Step 2, the generated SecretID carries out the conditions.

  1. To read the RoleID for the jenkins role.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
         --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
         $VAULT_ADDR/v1/auth/approle/role/jenkins/role-id | jq -r ".data"
    

    Example output:

    {
      "role_id": "5b5817f5-7db1-31ea-1943-1dbecf797ab3"
    }
    
  2. To generate a new SecretID for the jenkins role.

    $ curl --header "X-Vault-Token: $VAULT_TOKEN" \
          --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
          --request POST \
          $VAULT_ADDR/v1/auth/approle/role/jenkins/secret-id | jq -r ".data"
    

    Example output:

    {
      "secret_id": "4e692046-914a-e2d4-0cc7-08de52401b07",
      "secret_id_accessor": "8003b5f6-b42a-bf27-429c-4b09f67544e4",
      "secret_id_ttl": 0
    }
    

You can pass parameters in the request payload, or invoke the API with an empty payload.

If you specified secret_id_ttl, secret_id_num_uses, or bound_cidr_list on the role in Step 2, the generated SecretID carries out the conditions.

  1. In the Web UI, click the Vault CLI shell icon (>_) to open a command shell if it's not already opened.

  2. Execute the following command to read the RoleID.

    $ vault read auth/approle/role/jenkins/role-id
    
  3. Execute the following command to generate a new SecretID.

    $ vault write -force auth/approle/role/jenkins/secret-id
    

    NOTE: The -force flag forces the write operation to continue without any data values specified.

    Credentials

    The acquired role-id and secret-id are the credentials that your trusted application uses to authenticate with Vault.

The RoleID is similar to a username; therefore, you will get the same value for a given role. In this case, the jenkins role has a fixed RoleID. While SecretID is similar to a password that Vault will generate a new value every time you request it.

Step 4: Login with RoleID & SecretID

(Persona: app)

The client (in this case, Jenkins) uses the RoleID and SecretID passed by the admin to authenticate with Vault. If Jenkins did not receive the RoleID and/or SecretID, the admin needs to investigate.

Refer to the Advanced Features section for further discussion on distributing the RoleID and SecretID to the client app securely.

To login, use the auth/approle/login endpoint by passing the RoleID and SecretID.

Example:

$ vault write auth/approle/login role_id="675a50e7-cfe0-be76-e35f-49ec009731ea" \
    secret_id="ed0a642f-2acf-c2da-232f-1b21300d5f29"

Example output:

Key                     Value
---                     -----
token                   s.ncEw5bAZJqvGJgl8pBDM0C5h
token_accessor          gIQFfVhUd8fDsZjC7gLBMnQu
token_duration          1h
token_renewable         true
token_policies          ["default" "jenkins"]
identity_policies       []
policies                ["default" "jenkins"]
token_meta_role_name    jenkins

Vault returns a client token with default and jenkins policies attached.

Store the generated token value in an environment variable named, APP_TOKEN.

Example:

$ export APP_TOKEN="s.ncEw5bAZJqvGJgl8pBDM0C5h"

To login, use the auth/approle/login endpoint by passing the RoleID and SecretID in the request payload.

Example:

Create an API request payload containing the RoleID and SecretID.

$ tee payload.json <<"EOF"
{
  "role_id": "5b5817f5-7db1-31ea-1943-1dbecf797ab3",
  "secret_id": "4e692046-914a-e2d4-0cc7-08de52401b07"
}
EOF

Authenticate with Vault using the AppRole auth method.

$ curl --request POST --data @payload.json $VAULT_ADDR/v1/auth/approle/login \
    | jq -r ".auth"

Example output:

{
  "client_token": "s.d1D1l86gypL6qu1zJPdUjRtu",
  "accessor": "8hGdxs6NR0eazshp1TA0Pveb",
  "policies": ["default", "jenkins"],
  "token_policies": ["default", "jenkins"],
  "metadata": {
    "role_name": "jenkins"
  },
  "lease_duration": 3600,
  "renewable": true,
  "entity_id": "5a70b980-59f1-9f88-5ac9-5aad3f1c6594",
  "token_type": "service",
  "orphan": true
}

Vault returns a client token with default and jenkins policies attached.

Store the generated client_token value in an environment variable named, APP_TOKEN.

Example:

$ export APP_TOKEN="s.d1D1l86gypL6qu1zJPdUjRtu"

To login, use the auth/approle/login endpoint by passing the RoleID and SecretID in the request payload.

Example:

Create an API request payload containing the RoleID and SecretID.

$ tee payload.json <<"EOF"
{
  "role_id": "5b5817f5-7db1-31ea-1943-1dbecf797ab3",
  "secret_id": "4e692046-914a-e2d4-0cc7-08de52401b07"
}
EOF

Authenticate with Vault using the AppRole auth method.

$ curl --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    --request POST --data @payload.json $VAULT_ADDR/v1/auth/approle/login \
    | jq -r ".auth"

Example output:

{
  "client_token": "s.d1D1l86gypL6qu1zJPdUjRtu",
  "accessor": "8hGdxs6NR0eazshp1TA0Pveb",
  "policies": ["default", "jenkins"],
  "token_policies": ["default", "jenkins"],
  "metadata": {
    "role_name": "jenkins"
  },
  "lease_duration": 3600,
  "renewable": true,
  "entity_id": "5a70b980-59f1-9f88-5ac9-5aad3f1c6594",
  "token_type": "service",
  "orphan": true
}

Vault returns a client token with default and jenkins policies attached.

Store the generated client_token value in an environment variable named, APP_TOKEN.

Example:

$ export APP_TOKEN="s.d1D1l86gypL6qu1zJPdUjRtu"

To learn more about the Key/Value v2 secrets engine, read the Versioned Key/Value Secrets Engine tutorial.

Step 5: Read secrets using the AppRole token

(Persona: app)

Once receiving a token from Vault, the client can make future requests using this token.

Verify that you can access the secrets at secret/mysql/webapp.

$ VAULT_TOKEN=$APP_TOKEN vault kv get secret/mysql/webapp

====== Metadata ======
Key              Value
---              -----
created_time     2021-06-08T02:34:23.182299Z
deletion_time    n/a
destroyed        false
version          1

====== Data ======
Key         Value
---         -----
db_name     users
password    passw0rd
username    admin

The app has a read-only access; therefore, the following delete command will fail.

$ VAULT_TOKEN=$APP_TOKEN vault kv delete secret/mysql/webapp

The error message indicates permission error.

Error deleting secret/mysql/webapp: Error making API request.

URL: DELETE http://127.0.0.1:8200/v1/secret/data/mysql/webapp
Code: 403. Errors:

* 1 error occurred:
    * permission denied

Verify that you can access the secrets at secret/mysql/webapp.

$ curl --header "X-Vault-Token: $APP_TOKEN" \
    $VAULT_ADDR/v1/secret/data/mysql/webapp | jq -r ".data"

Example output:

{
  "data": {
    "db_name": "users",
    "password": "passw0rd",
    "username": "admin"
  },
  "metadata": {
    "created_time": "2021-06-08T02:34:23.182299Z",
    "deletion_time": "",
    "destroyed": false,
    "version": 1
  }
}

The app has read-only access; therefore, the following delete command will fail.

$ curl --header "X-Vault-Token: $APP_TOKEN" \
   --request DELETE \
   $VAULT_ADDR/v1/secret/data/mysql/webapp | jq

The error message indicates permission error.

{
  "errors": ["1 error occurred:\n\t* permission denied\n\n"]
}

Verify that you can access the secrets at secret/mysql/webapp.

$ curl --header "X-Vault-Token: $APP_TOKEN" \
    --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    $VAULT_ADDR/v1/secret/data/mysql/webapp | jq -r ".data"

Example output:

{
  "data": {
    "db_name": "users",
    "password": "passw0rd",
    "username": "admin"
  },
  "metadata": {
    "created_time": "2021-06-08T02:34:23.182299Z",
    "deletion_time": "",
    "destroyed": false,
    "version": 1
  }
}

The app has read-only access; therefore, the following delete command will fail.

$ curl --header "X-Vault-Token: $APP_TOKEN" \
   --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
   --request DELETE \
   $VAULT_ADDR/v1/secret/data/mysql/webapp | jq

The error message indicates permission error.

{
  "errors": ["1 error occurred:\n\t* permission denied\n\n"]
}

Response Wrap the SecretID

The RoleID is equivalent to a username, and SecretID is the corresponding password. The app needs both to log in with Vault. Naturally, the next question becomes how to deliver those values to the client securely.

A common solution involves three personas instead of two: admin, app, and trusted entity. The trusted entity delivers the RoleID and SecretID to the client by separate means.

For example, Terraform as a trusted entity can deliver the RoleID onto the virtual machine. When the app runs on the virtual machine, the RoleID already exists on the virtual machine.

AppRole auth method workflow

SecretID is like a password. To keep the SecretID confidential, use response wrapping so that only the expecting client can unwrap the SecretID.

In Step 3, you executed the following command to retrieve the Secret ID.

$ vault write -force auth/approle/role/jenkins/secret-id

Instead, use response wrapping by passing the -wrap-ttl parameter.

$ vault write -wrap-ttl=60s -force auth/approle/role/jenkins/secret-id

Key                              Value
---                              -----
wrapping_token:                  s.yzbznr9NlZNzsgEtz3SI56pX
wrapping_accessor:               Smi4CO0Sdhn8FJvL8XvOT30y
wrapping_token_ttl:              1m
wrapping_token_creation_time:    2021-06-07 20:02:01.019838 -0700 PDT
wrapping_token_creation_path:    auth/approle/role/jenkins/secret-id

Send this wrapping_token to the client so that the response can be unwrapped and obtain the SecretID.

$ VAULT_TOKEN="s.yzbznr9NlZNzsgEtz3SI56pX" vault unwrap

Key                   Value
---                   -----
secret_id             c4086c73-4569-90c9-fd73-72c879e3b7b4
secret_id_accessor    3a2e9483-a7d2-dc19-7480-b1a025daeccc
secret_id_ttl         0s

To learn more about the wrapping token, read the Cubbyhole Response Wrapping tutorial.

Limit the SecretID Usages

Treat the SecretID like a password and force it to be regenerated after a number of use.

To do so, update the role definition with secret_id_num_uses set.

$ vault write auth/approle/role/jenkins token_policies="jenkins" \
     token_ttl=1h token_max_ttl=4h \
     secret_id_num_uses=10

First, create an API request payload containing the configuration parameters for jenkins role. Notice that the secret_id_num_uses value is set.

$ tee payload.json <<EOF
{
  "token_policies": "jenkins",
  "token_ttl": "1h",
  "token_max_ttl": "4h",
  "secret_id_num_uses": 10
}
EOF

Update the role definition with secret_id_num_uses set.

$ curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST \
       --data @payload.json \
       $VAULT_ADDR/v1/auth/approle/role/jenkins

First, create an API request payload containing the configuration parameters for jenkins role. Notice that the secret_id_num_uses value is set.

$ tee payload.json <<EOF
{
  "token_policies": "jenkins",
  "token_ttl": "1h",
  "token_max_ttl": "4h",
  "secret_id_num_uses": 10
}
EOF

Update the role definition with secret_id_num_uses set.

$ curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST \
       --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
       --data @payload.json \
       $VAULT_ADDR/v1/auth/approle/role/jenkins

In this example, a SecretID of the jenkins role can be used for up to 10 times to authenticate and fetch a client token. After the number of uses is reached, the SecretID expires and you would need to generate a new one. This is similar to forcing a password rotation.

Help and Reference

  • How (and Why) to Use AppRole Correctly in HashiCorp Vault
  • AppRole Auth Method
  • AppRole Auth Method (API)
  • Authenticating Applications with HashiCorp Vault AppRole
 Previous
 Next

On this page

  1. AppRole Pull Authentication
  2. Personas
  3. Challenge
  4. Solution
  5. Prerequisites
  6. Scenario Introduction
  7. Lab setup
  8. Step 1: Enable AppRole auth method
  9. Step 2: Create a role with policy attached
  10. Step 3: Get RoleID and SecretID
  11. Step 4: Login with RoleID & SecretID
  12. Step 5: Read secrets using the AppRole token
  13. Response Wrap the SecretID
  14. Limit the SecretID Usages
  15. Help and Reference
Give Feedback(opens in new tab)
  • Certifications
  • System Status
  • Terms of Use
  • Security
  • Privacy
  • Trademark Policy
  • Trade Controls
  • Give Feedback(opens in new tab)