Vault Associate Certification (Part 1): Compare authentication methods
Tags: hashicorp, vault, security, learning
Published: 2023-08-27 14:48:43

In this post I will go through what you need to know about **authentication methods**, or **auth methods**, in order to pass the Vault Associate certification exam. Well, I say that, but in reality you will need to work with a few different auth methods in a real Vault cluster to actually learn what you need because there are many auth methods and each auth method has its own quirks that you might need to know.

Authentication methods make up the first objective in the Vault certification journey. This objective covers the following sub-objectives:

- [Describe authentication methods](#describe-authentication-methods)
- [Choose an authentication method based on use case](#choose-an-authentication-method-based-on-use-case)
- [Differentiate human vs. system auth methods](#differentiate-human-vs-system-auth-methods)

Apart from discussing these three points I will also get hands-on with a few of the common auth methods available, that could likely come up at the exam. Once again, practicing enabling and using auth methods in a real Vault cluster is a must so make sure you do some hands-on experimentation after reading this post.

## Describe authentication methods

An authentication method is a way for a user or system to authenticate to Vault to prove who the user or system is. If successful, Vault will respond with a **Vault token** (among other things!). A Vault token, or just token, is in turn used to authenticate subsequent calls to Vault.

This can be a bit confusing at first. Just remember that in the end you always need a Vault token to authenticate to Vault. You use some other authentication method in order to obtain a token, which you then use with the _token authentication method_ to actually interact with Vault.

What authentication methods are available to you? The official documentation[^auth] lists 18 different auth methods. One of them, the _JWT/OIDC_ auth method, in turn consists of 10 different OIDC[^oidc] providers. Some examples of the available auth methods are the following:

- AppRole
- AWS
- Azure
- GitHub
- Google Cloud
- JWT/OIDC
- Kubernetes
- LDAP
- Okta
- TLS Certificates
- Tokens
- Username and Password

I have included _tokens_ in the list since it is so central to using Vault.

In the last part of this post I will go through how to use a few of the common auth methods. The general workflow and usage of an auth methods follow a few common steps:

1. Enable the auth method.
1. Configure the auth method.
1. Use the auth method.
1. Possibly disable the auth method if it is no longer needed.

The specifics of what each step entails varies from auth method to auth method, except the first step of enabling an auth method which is identical for each method. 

The token auth method is special, it is always enabled and you can't disable it. This is because Vault depends on the token authentication method, if it didn't exist Vault would not work.

When you set up a Vault cluster for the first time you need to decide what auth methods you want to use. You can, and most likely should, enable several auth methods in the same cluster. You could enable all of them if there was a need for it. You can enable the same auth method multiple times in the same cluster. This is another point that can be somewhat confusing at first. Why would you want to enable the same auth method several times in the same cluster? Two possible reasons are:

- You have multiple GitHub organizations and you want users from each organization be able to authenticate to Vault using their respective GitHub organization. Then you need to enable the GitHub auth method twice, and configure one auth method for each GitHub organization. Apart from configuring the auth methods differently you would also need to mount the auth methods at different paths in Vault. If you remember from the previous post, _everything in Vault exists at a path_. This will become clear later in this post.
- You want to delegate administration of an auth method to two or more people and have them configured differently by responsibility. You could then mount the auth method at different paths and create policies that gives permissions to each method separately.

To summarize this part:

1. We use auth methods to prove our identities to Vault in order to obtain a token which we can then use to further interact with Vault
1. There are many auth methods available. We can add any number of auth methods to our Vault cluster depending on our needs.
1. The token auth method is required. It is enabled by default. It can't be disabled.

## Choose an authentication method based on use case

This second objective point is closely related to the third point that comes below. This is because when we discuss use cases for Vault we will make an early selection based on who will use the auth method, a human or a system. Some of the parts discussed in this section will be repeated in the next section.

Without any evidence to back up this claim I will say that the most common use case for Vault is _to store application secrets_.

We have applications, or systems, that require access to secrets that we have stored in Vault. This could be passwords to third-party systems, connection-strings to Azure services, OIDC client secrets, certificates, or any other type of secret. Our application, or system, must authenticate to Vault in order to gain access to these secrets. With that in mind, what authentication method should we use? We could use a whole bunch of auth methods, but some are not created for the use of systems without the intervention of a human user.

So the first question we should ask ourselves when we pick an authentication method is: are my users real humans or non-human applications?

Our human users can use things like MFA when authenticating. This is in general not possible for applications.

A second question we should ask ourselves is: where are my applications running? If I have all my applications running in a Kubernetes cluster, then the kubernetes auth method should come in handy. This auth method allows us to specify that a given service accounts in Kubernetes should be able to access certain secrets. This is a use-case where the auth method is used by an application, and not a human user.

A third question we should ask ourselves is: do I have any organizational requirements on what authentication solution I should use? Maybe you have a central OIDC/OAuth2 system you must use due to some reason, then the OIDC auth method is probably what you want to use.

It is important to remember that you can enable multiple auth methods and use the one that fits the best for a given scenario.

## Differentiate human vs. system auth methods

There is not much more to add to this point than what was said in the last section. Let me just make a few bullet points as a summary:

- Some auth methods are geared towards human users. This is suitable if we store secrets in Vault that a human user must access through the Vault CLI or UI. An example could be authenticating with the GitHub auth method where a user signs in using his or her GitHub Personal Access Token (PAT). Note that a human user could utilize MFA during sign-in, which system users could not.
- Some auth methods are geared towards systems. These are generally auth methods where an application requires access to secrets and no human is involved in the process of obtaining these secrets. An example could be the Kubernetes auth method where a pod running in a Kubernetes cluster has a service account that reads secrets at pod start-up and provides the values to the pod as environment variables.
- Some auth methods works for both humans and systems, and there is nothing that stops you from using an auth method in an unintended way - but if it feels wrong it probably is wrong!

## Common authentication methods

To make the concept of auth methods clear I will show how to use the _AppRole_, _GitHub_, and _Username and Password_ authentication methods. I pick these three to demonstrate because they are relatively simple so the usage won't get lost in the technical details. 

There are similarities between how these (and other) auth methods are used, but also many differences. The differences mainly show up in how the auth method is configured. To enable an auth method using the Vault CLI you run the following command:

```console
$ vault auth enable <auth method>
```

Replace `<auth method>` with the auth method you want to enable. When you do this the auth method is enabled at a path that corresponds to the name of the auth method. However, all auth methods are in fact mounted at a path starting with `auth/` followed by the path you specify when you enable the auth method. This is a bit confusing at first. To make this easier to grasp we will look at an example. If I want to enable the `github` auth method I run:

```console
$ vault auth enable github
```

Now the GitHub auth method is available at `auth/github`. I could mount it at a different path (however, still under `auth/`) with the following command:

```console
$ vault auth enable -path=gitsystem github
```

Now the GitHub auth method would instead be available at `auth/gitsystem`. Note that if you want to enable the same auth method two or more times you will have to provide different paths for each instance of the auth method, except for one which you can mount at `auth/<auth method>` if you wish.

### AppRole

The `approle` auth method is geared towards automated processes, systems, or _apps_ as the name suggests. With this auth method we configure _roles_ and allow apps to use these roles to retrieve Vault tokens with associated policies.

As with any auth method we need to enable it to use it:

```console
$ vault auth enable approle

Success! Enabled approle auth method at: approle/
```

Next we create and configure a new _role_ named `administrator`:

```console
$ vault write auth/approle/role/administrator \
    token_ttl=5m \
    token_max_ttl=60m \
    token_policies=custom-admin-policy

Success! Data written to: auth/approle/role/administrator
```

In the previous command it is clear that I interact with the auth method at the path `auth/approle/...` and not `approle/`. I believe this is a bit confusing at first. There are a number of parameters we can specify[^approle] when configuring the `approle` auth method, in the previous command I restricted myself to the following settings:

- `token_ttl`: when we authenticate to Vault using this role we will receive a token that we can use for further interaction with Vault, this token will have a time-to-live (TTL) of five minutes (`5m`).
- `token_max_ttl`: during authentication using this role we can ask for a longer TTL than the default of five minutes, but this parameter restricts the maximum TTL to one hour (`60m`).
- `token_policies`: after authentication using this role the resulting Vault token will have a custom Vault policy named `custom-admin-policy`. This policy does not have to exist when we run this command. More on policies in a future post.

Now that we have a role there are two things we need to be able to use it. The first is the _role ID_:

```console
$ vault read auth/approle/role/administrator/role-id

Key        Value
---        -----
role_id    5146a9e5-92c2-f7d2-22cc-2649540f6cf4
```

Each role we create has a static role ID. The second thing we need is a _secret ID_, which by default does not exist, and it can also be configured to expire with its own TTL. To create a new secret ID:

```console
$ vault write -f auth/approle/role/administrator/secret-id

Key                   Value
---                   -----
secret_id             b24c49b0-150e-b414-9ce1-78b0502c8dbf
secret_id_accessor    ecfe8a7f-23fb-93fc-eced-f1b9db943e37
secret_id_num_uses    0
secret_id_ttl         0s
```

This generated secret ID has a TTL of 0s, which means it never expires. Since this auth method is intended to be used by apps we do not run a `vault login` command to obtain a token, instead we can do the following:

```console
$ vault write auth/approle/login \
    role_id=5146a9e5-92c2-f7d2-22cc-2649540f6cf4 \
    secret_id=b24c49b0-150e-b414-9ce1-78b0502c8dbf

Key                     Value
---                     -----
token                   hvs.CAESILp9x<truncated>QTYwR1pOYTNjU1E
token_accessor          y2nj2lw36DMJsmBdyotuSYGC
token_duration          5m
token_renewable         true
token_policies          ["custom-admin-policy" "default"]
identity_policies       []
policies                ["custom-admin-policy" "default"]
token_meta_role_name    administrator
```

We successfully authenticated to Vault and we obtained a Vault token. We can see that the token is associated with our custom policy `custom-admin-policy` and that the token duration is set to five minutes as expected.

The way I illustrated the `approle` auth method above is not how you are supposed to use it. You might have wondered what was the point of a role ID and secret ID? They are basically just renamed username and password. There is a recommended workflow for how to use this auth method, and it involves providing the role ID and secret ID to an application using two different paths. The role ID is not considered a secret, and could be baked into a VM or Docker image at build time. The secret ID, however, is a secret and should not be known to anyone other than the application. Instead of me rehashing the story of how to provide the secret ID to the application I recommend reading the following blog post by HashiCorp: [How (and Why) to Use AppRole Correctly in HashiCorp Vault](https://www.hashicorp.com/blog/how-and-why-to-use-approle-correctly-in-hashicorp-vault).

### GitHub

Are you a part of a GitHub organization? If so, you could authenticate to Vault using a GitHub Personal Access Token (PAT). Note that you must be a part of an organization and that organization must allow you to use your PAT to read information about that organization. When I tried setting this up I was not able to use the new fine-grained GitHub PAT to do it, instead I had to use the classic PAT. The important part is that you need to add the `read:org` scope to the PAT for it to work.

You enable the GitHub authentication method like any other auth method:

```console
$ vault auth enable github

Success! Enabled github auth method at: github/
```

To configure the GitHub auth method for an organization named `acme-corp`:

```console
$ vault write auth/github/config organization=acme-corp

Success! Data written to: auth/github/config
```

You can specify what policies should be attached to a given user when that user authenticates with the GitHub auth method. A better way is to specify policies based on what team in the GitHub organization the user belongs to. To do this for a team named `team-a`:

```console
$ vault write auth/github/map/teams/team-a value=my-custom-policy

Success! Data written to: auth/github/map/teams/team-a
```

If a member of `team-a` runs the login command the following token is generated:

```console
$ vault login -method=github

GitHub Personal Access Token (will be hidden): ***

Success! You are now authenticated.

Key                    Value
---                    -----
token                  hvs.CAES<truncated>nBHMUI
token_accessor         yzMuNumPVnmRqRQANVv9HKYg
token_duration         768h
token_renewable        true
token_policies         ["default" "my-custom-policy"]
identity_policies      []
policies               ["default" "my-custom-policy"]
token_meta_org         acme-corp
token_meta_username    user-a
```

Now the `token` can be used to run further Vault commands that are allowed by the `default` and `my-custom-policy` policies.

### Username and Password

The username and password, or `userpass`, auth method is a basic authentication method that uses (not surprisingly) usernames and passwords for authentication. There is no connection to a third-party system for this auth method, all the users we define live inside of Vault only. This is similar to the `approle` auth method in a way, but this auth method is geared towards human users. 

To use this auth method we first enable it:

```console
$ vault auth enable userpass

Success! Enabled userpass auth method at: userpass/
```

The next step is to configure users. To configure a user with username `bob` and password `S3cr3t123` we run:

```console
$ vault write auth/userpass/users/bob \
    password=S3cr3t123 \
    policies=custom-policy

Success! Data written to: auth/userpass/users/bob
```

That was easy! No additional configuration is required. Note once again that we interact with the auth method at `auth/userpass/...` and not `userpass/...`. Now `bob` can sign in to Vault using the following command:

```console
$ vault login -method=userpass username=bob
Password (will be hidden): ***

Success! You are now authenticated.

Key                    Value
---                    -----
token                  hvs.CAESIDpIKM<truncated>hEdkpNd3RwZWI
token_accessor         bX44F1oGm146W8e38pkrhEUx
token_duration         768h
token_renewable        true
token_policies         ["custom-policy" "default"]
identity_policies      []
policies               ["custom-policy" "default"]
token_meta_username    bob
```

`bob` provided his username directly in the `vault login` command. It is also possible to directly enter the password with `password=S3cr3t123`, but if it is omitted you will be asked for the password in a prompt. It is generally a good idea not to enter the password in the command directly since it might get stored in your terminal history.

Note that this authentication method should be considered less secure than other methods and I would avoid using it in a production cluster. But it is simple to work with and might fit some use-cases where the security restrictions are less important[^security].

[^auth]: Available at https://developer.hashicorp.com/vault/docs/auth
[^approle]: See the full list at https://developer.hashicorp.com/vault/api-docs/auth/approle#parameters
[^oidc]: OpenID Connect, the identity layer built on top of the OAuth 2.0 framework.
[^security]: Not sure what use-case that is!