AppRole is intended for applications and scripts that need access to secrets without a human. The application presents a pair of identifiers: role_id (changes rarely and is not a secret) and secret_id (issued for a limited time and number of uses), and receives a token with the role’s policies.

Goal

Configure a role for the myapp application, obtain its role_id and secret_id, log in with them, and read a secret, while limiting the token lifetime, the number of secret_id uses, and the networks from which login is allowed.

Prerequisites

Before you start, prepare the following:

  • A Stronghold token with permission to enable authentication methods and write policies and roles.
  • The KV version 2 secrets engine mounted at secret/ (it is enabled by default in development mode).

Step 1. Create a secret and a policy

Write a test secret and restrict access to it with a policy.

  1. Write the secret that the application will read:

    d8 stronghold kv put -mount=secret myapp/config db_password=s3cr3t
  2. Create a policy that allows only reading this path:

    d8 stronghold policy write myapp - <<'POLICY'
    path "secret/data/myapp/*" {
      capabilities = ["read"]
    }
    POLICY

Step 2. Enable the method and create a role

Enable the AppRole auth method and create the myapp role:

d8 stronghold auth enable approle

d8 stronghold write auth/approle/role/myapp token_policies=myapp token_ttl=15m token_max_ttl=1h secret_id_ttl=24h secret_id_num_uses=1 token_bound_cidrs="127.0.0.1/32,10.0.0.0/8" secret_id_bound_cidrs="127.0.0.1/32,10.0.0.0/8"

Role parameters:

ParameterPurpose
token_policiesPolicies of the token that the application receives
token_ttl, token_max_ttlToken lifetime and the limit of its renewal
secret_id_ttlThe period during which an issued secret_id can be used
secret_id_num_usesHow many times a single secret_id can be used to log in. 1 makes secret_id single-use
token_bound_cidrsNetworks from which the issued token can be used
secret_id_bound_cidrsNetworks from which login with secret_id is allowed

Specify the actual networks of the application servers in token_bound_cidrs and secret_id_bound_cidrs. The example adds 127.0.0.1/32 so that it can be checked on a single machine.

Step 3. Get the identifiers

Read the role_id of the role and issue a secret_id:

ROLE_ID=$(d8 stronghold read -field=role_id auth/approle/role/myapp/role-id)
SECRET_ID=$(d8 stronghold write -f -field=secret_id auth/approle/role/myapp/secret-id)

You can put role_id into the application configuration. Deliver secret_id over a secure channel. A wrapped secret_id can be retrieved only once, so its interception is detected.

Step 4. Log in and read the secret

Log in as the application and read the secret with the issued token.

  1. Log in with role_id and secret_id:

    APP_TOKEN=$(d8 stronghold write -field=token auth/approle/login role_id="$ROLE_ID" secret_id="$SECRET_ID")
  2. Read the secret with the application token:

    STRONGHOLD_TOKEN="$APP_TOKEN" d8 stronghold kv get -mount=secret myapp/config

Verification

Check the restrictions of the role and the token.

  1. Make sure the token received only the role’s policies:

    STRONGHOLD_TOKEN="$APP_TOKEN" d8 stronghold token lookup

    The policies field must contain default and myapp.

  2. Make sure secret_id is single-use: a second login must fail:

    # Log in again with the same secret_id.
    d8 stronghold write auth/approle/login role_id="$ROLE_ID" secret_id="$SECRET_ID"
  3. Make sure the application cannot read other secrets:

    # Read a path outside the policy.
    STRONGHOLD_TOKEN="$APP_TOKEN" d8 stronghold kv get -mount=secret other/config

    The request must fail with permission denied.

Cleanup

Revoke the token and delete the role, the policy, and the secret:

d8 stronghold token revoke "$APP_TOKEN"
d8 stronghold delete auth/approle/role/myapp
d8 stronghold policy delete myapp
d8 stronghold kv metadata delete -mount=secret myapp/config

Additional resources