b93d6e44e0
* Add fields 'ttl' and 'num_uses' to SecretID generation. Add fields 'ttl' and 'num_uses' when generating/obtaining a SecretID. Rather than just being able to use the Role's SecretID ttl and num uses. #14390 * Add secret_id_num_uses response field to generating SecretID Add the response field secret_id_num_uses to the endpoints for generating SecretIDs. Used in testing but also to supply the vendor with this variable. * Add tests for new ttl and num_uses SecretID generation fields Add tests to assert the new TTL and NumUses option in the SecretID entry. Separate test for testing with just parameters vs a -force example. * Patch up test for ttl and num_uses fields * Add changelog entry for auth/approle 'ttl' and 'num_uses' fields * Add fields to API Docs and AppRole Auth Docs example * Correct error message for failing test on missing field. Change the error message produced when a test fails due to a missing field. Previous values did not map to correct fields. * Remove unnecessary int cast to int "secret_id_num_uses" field. Unnecessary cast to int where type already is int. * Move numUses field check to after assignment. * Remove metadata entry in sample payload to limit change to changes made. Remove metadata entry in sample payload for custom-secret-id. The metadata was not changed in the features pull request. * Bind fields 'ttl' and 'num_uses' to role's configuration. Rather than implicitly overriding, error when the ttl is lower than and the num uses higher than the role's configuration. #14390 * Update changelog 14474 with a more detailed description. More elaborate description for the changelog. Specifying the per-request based fields. * Elaborate more on the bounds of the 'ttl' and 'num_uses' field. Specify in both the api-docs and the CLI the limits of the fields. Specify that the role's configuration is still the leading factor. * Upper bound ttl with role secret id ttl Upper bound ttl with role secret id ttl when creating a secret id Adding test cases for infinite ttl and num uses Adding test cases for negative ttl and num uses Validation on infinite ttl and num uses * Formatting issues. Removed unnecessary newline * Update documentation for AppRole Secret ID and Role Changed that TTL is not allowed to be shorter to longer * Cleanup approle secret ID test and impl * Define ttl and num_uses in every test Define ttl and num_uses in every test despite them not being tested. This is to ensure that no unexpected behaviour comes to mind. * Rename test RoleSecretID -> RoleSecretIDWithoutFields * Test secret id generation defaults to Role's config Test secret id generation defaults to Role's configuration entries. * Change finit -> finite Co-authored-by: Josh Black <raskchanky@users.noreply.github.com> * Rephrase comments to the correct validation check * Rephrase role-secret-id option description * Remove "default" incorrect statement about ttl * Remove "default" incorrect statement about ttl for custom secret id * Touch up approle.mdx to align more with path_role documentation Co-authored-by: Remco Buddelmeijer <r.buddelmeijer@fullstaq.com> Co-authored-by: Josh Black <raskchanky@users.noreply.github.com>
406 lines
14 KiB
Plaintext
406 lines
14 KiB
Plaintext
---
|
|
layout: docs
|
|
page_title: AppRole - Auth Methods
|
|
description: |-
|
|
The AppRole auth method allows machines and services to authenticate with
|
|
Vault.
|
|
---
|
|
|
|
# AppRole Auth Method
|
|
|
|
The `approle` auth method allows machines or _apps_ to authenticate with
|
|
Vault-defined _roles_. The open design of `AppRole` enables a varied set of
|
|
workflows and configurations to handle large numbers of apps. This auth method
|
|
is oriented to automated workflows (machines and services), and is less useful
|
|
for human operators.
|
|
|
|
An "AppRole" represents a set of Vault policies and login constraints that must
|
|
be met to receive a token with those policies. The scope can be as narrow or
|
|
broad as desired. An AppRole can be created for a particular machine, or even
|
|
a particular user on that machine, or a service spread across machines. The
|
|
credentials required for successful login depend upon the constraints set on
|
|
the AppRole associated with the credentials.
|
|
|
|
## Authentication
|
|
|
|
### Via the CLI
|
|
|
|
The default path is `/approle`. If this auth method was enabled at a different
|
|
path, specify `auth/my-path/login` instead.
|
|
|
|
```shell-session
|
|
$ vault write auth/approle/login \
|
|
role_id=db02de05-fa39-4855-059b-67221c5c2f63 \
|
|
secret_id=6a174c20-f6de-a53c-74d2-6018fcceff64
|
|
|
|
Key Value
|
|
--- -----
|
|
token 65b74ffd-842c-fd43-1386-f7d7006e520a
|
|
token_accessor 3c29bc22-5c72-11a6-f778-2bc8f48cea0e
|
|
token_duration 20m0s
|
|
token_renewable true
|
|
token_policies [default]
|
|
```
|
|
|
|
### Via the API
|
|
|
|
The default endpoint is `auth/approle/login`. If this auth method was enabled
|
|
at a different path, use that value instead of `approle`.
|
|
|
|
```shell-session
|
|
$ curl \
|
|
--request POST \
|
|
--data '{"role_id":"988a9df-...","secret_id":"37b74931..."}' \
|
|
http://127.0.0.1:8200/v1/auth/approle/login
|
|
```
|
|
|
|
The response will contain the token at `auth.client_token`:
|
|
|
|
```json
|
|
{
|
|
"auth": {
|
|
"renewable": true,
|
|
"lease_duration": 2764800,
|
|
"metadata": {},
|
|
"policies": ["default", "dev-policy", "test-policy"],
|
|
"accessor": "5d7fb475-07cb-4060-c2de-1ca3fcbf0c56",
|
|
"client_token": "98a4c7ab-b1fe-361b-ba0b-e307aacfd587"
|
|
}
|
|
}
|
|
```
|
|
|
|
-> **Application Integration:** See the [Code Example](#code-example) section
|
|
for a code snippet demonstrating the authentication with Vault using the
|
|
AppRole auth method.
|
|
|
|
## Configuration
|
|
|
|
Auth methods must be configured in advance before users or machines can
|
|
authenticate. These steps are usually completed by an operator or configuration
|
|
management tool.
|
|
|
|
### Via the CLI
|
|
|
|
1. Enable the AppRole auth method:
|
|
|
|
```shell-session
|
|
$ vault auth enable approle
|
|
```
|
|
|
|
1. Create a named role:
|
|
|
|
```shell-session
|
|
$ vault write auth/approle/role/my-role \
|
|
secret_id_ttl=10m \
|
|
token_num_uses=10 \
|
|
token_ttl=20m \
|
|
token_max_ttl=30m \
|
|
secret_id_num_uses=40
|
|
```
|
|
|
|
~> **Note:** If the token issued by your approle needs the ability to create child tokens, you will need to set token_num_uses to 0.
|
|
|
|
For the complete list of configuration options, please see the API
|
|
documentation.
|
|
|
|
1. Fetch the RoleID of the AppRole:
|
|
|
|
```shell-session
|
|
$ vault read auth/approle/role/my-role/role-id
|
|
role_id db02de05-fa39-4855-059b-67221c5c2f63
|
|
```
|
|
|
|
1. Get a SecretID issued against the AppRole:
|
|
|
|
```shell-session
|
|
$ vault write -f auth/approle/role/my-role/secret-id
|
|
secret_id 6a174c20-f6de-a53c-74d2-6018fcceff64
|
|
secret_id_accessor c454f7e5-996e-7230-6074-6ef26b7bcf86
|
|
secret_id_ttl 10m
|
|
secret_id_num_uses 40
|
|
```
|
|
|
|
### Via the API
|
|
|
|
1. Enable the AppRole auth method:
|
|
|
|
```shell-session
|
|
$ curl \
|
|
--header "X-Vault-Token: ..." \
|
|
--request POST \
|
|
--data '{"type": "approle"}' \
|
|
http://127.0.0.1:8200/v1/sys/auth/approle
|
|
```
|
|
|
|
1. Create an AppRole with desired set of policies:
|
|
|
|
```shell-session
|
|
$ curl \
|
|
--header "X-Vault-Token: ..." \
|
|
--request POST \
|
|
--data '{"policies": "dev-policy,test-policy"}' \
|
|
http://127.0.0.1:8200/v1/auth/approle/role/my-role
|
|
```
|
|
|
|
1. Fetch the identifier of the role:
|
|
|
|
```shell-session
|
|
$ curl \
|
|
--header "X-Vault-Token: ..." \
|
|
http://127.0.0.1:8200/v1/auth/approle/role/my-role/role-id
|
|
```
|
|
|
|
The response will look like:
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"role_id": "988a9dfd-ea69-4a53-6cb6-9d6b86474bba"
|
|
}
|
|
}
|
|
```
|
|
|
|
1. Create a new secret identifier under the role:
|
|
|
|
```shell-session
|
|
$ curl \
|
|
--header "X-Vault-Token: ..." \
|
|
--request POST \
|
|
http://127.0.0.1:8200/v1/auth/approle/role/my-role/secret-id
|
|
```
|
|
|
|
The response will look like:
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"secret_id_accessor": "45946873-1d96-a9d4-678c-9229f74386a5",
|
|
"secret_id": "37b74931-c4cd-d49a-9246-ccc62d682a25",
|
|
"secret_id_ttl": 600,
|
|
"secret_id_num_uses": 40
|
|
}
|
|
}
|
|
```
|
|
|
|
## Credentials/Constraints
|
|
|
|
### RoleID
|
|
|
|
RoleID is an identifier that selects the AppRole against which the other
|
|
credentials are evaluated. When authenticating against this auth method's login
|
|
endpoint, the RoleID is a required argument (via `role_id`) at all times. By
|
|
default, RoleIDs are unique UUIDs, which allow them to serve as secondary
|
|
secrets to the other credential information. However, they can be set to
|
|
particular values to match introspected information by the client (for
|
|
instance, the client's domain name).
|
|
|
|
### SecretID
|
|
|
|
SecretID is a credential that is required by default for any login (via
|
|
`secret_id`) and is intended to always be secret. (For advanced usage,
|
|
requiring a SecretID can be disabled via an AppRole's `bind_secret_id`
|
|
parameter, allowing machines with only knowledge of the RoleID, or matching
|
|
other set constraints, to fetch a token). SecretIDs can be created against an
|
|
AppRole either via generation of a 128-bit purely random UUID by the role
|
|
itself (`Pull` mode) or via specific, custom values (`Push` mode). Similarly to
|
|
tokens, SecretIDs have properties like usage-limit, TTLs and expirations.
|
|
|
|
#### Pull And Push SecretID Modes
|
|
|
|
If the SecretID used for login is fetched from an AppRole, this is operating in
|
|
Pull mode. If a "custom" SecretID is set against an AppRole by the client, it
|
|
is referred to as a Push mode. Push mode mimics the behavior of the deprecated
|
|
App-ID auth method; however, in most cases Pull mode is the better approach. The
|
|
reason is that Push mode requires some other system to have knowledge of the
|
|
full set of client credentials (RoleID and SecretID) in order to create the
|
|
entry, even if these are then distributed via different paths. However, in Pull
|
|
mode, even though the RoleID must be known in order to distribute it to the
|
|
client, the SecretID can be kept confidential from all parties except for the
|
|
final authenticating client by using [Response Wrapping](/docs/concepts/response-wrapping).
|
|
|
|
Push mode is available for App-ID workflow compatibility, which in some
|
|
specific cases is preferable, but in most cases Pull mode is more secure and
|
|
should be preferred.
|
|
|
|
### Further Constraints
|
|
|
|
`role_id` is a required credential at the login endpoint. AppRole pointed to by
|
|
the `role_id` will have constraints set on it. This dictates other `required`
|
|
credentials for login. The `bind_secret_id` constraint requires `secret_id` to
|
|
be presented at the login endpoint. Going forward, this auth method can support
|
|
more constraint parameters to support varied set of Apps. Some constraints will
|
|
not require a credential, but still enforce constraints for login. For
|
|
example, `secret_id_bound_cidrs` will only allow logins coming from IP addresses
|
|
belonging to configured CIDR blocks on the AppRole.
|
|
|
|
## Tutorial
|
|
|
|
Refer to the [AppRole Pull
|
|
Authentication](https://learn.hashicorp.com/vault/identity-access-management/iam-authentication)
|
|
tutorial to learn how to use the AppRole method to generate tokens for machines or apps.
|
|
|
|
## API
|
|
|
|
The AppRole auth method has a full HTTP API. Please see the
|
|
[AppRole API](/api-docs/auth/approle) for more
|
|
details.
|
|
|
|
## Code Example
|
|
|
|
The following example demonstrates AppRole authentication with response
|
|
wrapping.
|
|
|
|
<CodeTabs>
|
|
|
|
<CodeBlockConfig>
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
vault "github.com/hashicorp/vault/api"
|
|
auth "github.com/hashicorp/vault/api/auth/approle"
|
|
)
|
|
|
|
// Fetches a key-value secret (kv-v2) after authenticating via AppRole.
|
|
func getSecretWithAppRole() (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)
|
|
}
|
|
|
|
// A combination of a Role ID and Secret ID is required to log in to Vault
|
|
// with an AppRole.
|
|
// First, let's get the role ID given to us by our Vault administrator.
|
|
roleID := os.Getenv("APPROLE_ROLE_ID")
|
|
if roleID == "" {
|
|
return "", fmt.Errorf("no role ID was provided in APPROLE_ROLE_ID env var")
|
|
}
|
|
|
|
// The Secret ID is a value that needs to be protected, so instead of the
|
|
// app having knowledge of the secret ID directly, we have a trusted orchestrator (https://learn.hashicorp.com/tutorials/vault/secure-introduction?in=vault/app-integration#trusted-orchestrator)
|
|
// give the app access to a short-lived response-wrapping token (https://www.vaultproject.io/docs/concepts/response-wrapping).
|
|
// Read more at: https://learn.hashicorp.com/tutorials/vault/approle-best-practices?in=vault/auth-methods#secretid-delivery-best-practices
|
|
secretID := &auth.SecretID{FromFile: "path/to/wrapping-token"}
|
|
|
|
appRoleAuth, err := auth.NewAppRoleAuth(
|
|
roleID,
|
|
secretID,
|
|
auth.WithWrappingToken(), // Only required if the secret ID is response-wrapped.
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("unable to initialize AppRole auth method: %w", err)
|
|
}
|
|
|
|
authInfo, err := client.Auth().Login(context.Background(), appRoleAuth)
|
|
if err != nil {
|
|
return "", fmt.Errorf("unable to login to AppRole auth method: %w", err)
|
|
}
|
|
if authInfo == nil {
|
|
return "", fmt.Errorf("no auth info was returned after login")
|
|
}
|
|
|
|
// get secret from the default mount path for KV v2 in dev mode, "secret"
|
|
secret, err := client.KVv2("secret").Get(context.Background(), "creds")
|
|
if err != nil {
|
|
return "", fmt.Errorf("unable to read secret: %w", err)
|
|
}
|
|
|
|
// data map can contain more than one key-value pair,
|
|
// in this case we're just grabbing one of them
|
|
value, ok := secret.Data["password"].(string)
|
|
if !ok {
|
|
return "", fmt.Errorf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
```
|
|
|
|
</CodeBlockConfig>
|
|
|
|
<CodeBlockConfig>
|
|
|
|
```cs
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using VaultSharp;
|
|
using VaultSharp.V1.AuthMethods;
|
|
using VaultSharp.V1.AuthMethods.AppRole;
|
|
using VaultSharp.V1.AuthMethods.Token;
|
|
using VaultSharp.V1.Commons;
|
|
|
|
namespace Examples
|
|
{
|
|
public class ApproleAuthExample
|
|
{
|
|
const string DefaultTokenPath = "../../../path/to/wrapping-token";
|
|
|
|
/// <summary>
|
|
/// Fetches a key-value secret (kv-v2) after authenticating to Vault via AppRole authentication
|
|
/// </summary>
|
|
public string GetSecretWithAppRole()
|
|
{
|
|
// A combination of a Role ID and Secret ID is required to log in to Vault with an AppRole.
|
|
// The Secret ID is a value that needs to be protected, so instead of the app having knowledge of the secret ID directly,
|
|
// we have a trusted orchestrator (https://learn.hashicorp.com/tutorials/vault/secure-introduction?in=vault/app-integration#trusted-orchestrator)
|
|
// give the app access to a short-lived response-wrapping token (https://www.vaultproject.io/docs/concepts/response-wrapping).
|
|
// Read more at: https://learn.hashicorp.com/tutorials/vault/approle-best-practices?in=vault/auth-methods#secretid-delivery-best-practices
|
|
var vaultAddr = Environment.GetEnvironmentVariable("VAULT_ADDR");
|
|
if(String.IsNullOrEmpty(vaultAddr))
|
|
{
|
|
throw new System.ArgumentNullException("Vault Address");
|
|
}
|
|
|
|
var roleId = Environment.GetEnvironmentVariable("APPROLE_ROLE_ID");
|
|
if(String.IsNullOrEmpty(roleId))
|
|
{
|
|
throw new System.ArgumentNullException("AppRole Role Id");
|
|
}
|
|
// Get the path to wrapping token or fall back on default path
|
|
string pathToToken = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("WRAPPING_TOKEN_PATH")) ? Environment.GetEnvironmentVariable("WRAPPING_TOKEN_PATH") : DefaultTokenPath;
|
|
string wrappingToken = File.ReadAllText(pathToToken); // placed here by a trusted orchestrator
|
|
|
|
// We need to create two VaultClient objects for authenticating via AppRole. The first is for
|
|
// using the unwrap utility. We need to initialize the client with the wrapping token.
|
|
IAuthMethodInfo wrappedTokenAuthMethod = new TokenAuthMethodInfo(wrappingToken);
|
|
var vaultClientSettingsForUnwrapping = new VaultClientSettings(vaultAddr, wrappedTokenAuthMethod);
|
|
|
|
IVaultClient vaultClientForUnwrapping = new VaultClient(vaultClientSettingsForUnwrapping);
|
|
|
|
// We pass null here instead of the wrapping token to avoid depleting its single usage
|
|
// given that we already initialized our client with the wrapping token
|
|
Secret<Dictionary<string, object>> secretIdData = vaultClientForUnwrapping.V1.System
|
|
.UnwrapWrappedResponseDataAsync<Dictionary<string, object>>(null).Result;
|
|
|
|
var secretId = secretIdData.Data["secret_id"]; // Grab the secret_id
|
|
|
|
// We create a second VaultClient and initialize it with the AppRole auth method and our new credentials.
|
|
IAuthMethodInfo authMethod = new AppRoleAuthMethodInfo(roleId, secretId.ToString());
|
|
var vaultClientSettings = new VaultClientSettings(vaultAddr, authMethod);
|
|
|
|
IVaultClient vaultClient = new VaultClient(vaultClientSettings);
|
|
|
|
// We can retrieve the secret from VaultClient
|
|
Secret<SecretData> kv2Secret = null;
|
|
kv2Secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(path: "/creds").Result;
|
|
|
|
var password = kv2Secret.Data.Data["password"];
|
|
|
|
return password.ToString();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
</CodeBlockConfig>
|
|
|
|
</CodeTabs>
|