Hashicorp Vault has the flexibility to use more than one Authentication Method, one of the options is JWT. this repo contains a series of examples to help automate automate their config.
from RFC7519 :
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
my take: JWT is a standard way to provide AuthN across different SaaS services like Okta, Gitlab, Github, Azure, AD e etc.
The dificulty then comes on how do we configure Vault JWT auth for each of the providers. more specifically, what configuration is needed from the provider side and what configuration is needed from Vault's side.
to start answering this question we must first look at how Vault's Auth Methods work.
Most Vault Auth Methods are set up in a Multiplex pattern, which allows reuse of a mount for different identities.
the Mount config itself is the link to JWT provider and then the different roles are the Identity checks.
this is where we tell Vault how to reach the Identity Provider. usually this comes in the form of: a connection URL, credentials, who our issuers are and are there any default roles to use if none are provided.
this will either be an oidc_discovery_url or jwks_url.
oidc_discovery_url="https://token.actions.githubusercontent.com"
jwks_url = "https://gitlab.com/-/jwks"
depending on the Identity Provider, it might be necessary to authenticate , this is done at the mount config level.
oidc_client_id = okta_app_oauth.vault.client_id
oidc_client_secret = okta_app_oauth.vault.client_secret
The value against which to match the iss claim in a JWT
bound_issuer = "gitlab.com"
Any default role you want the used if the Vault Client doesnt specify their own. this requires thought before implemented because it might be a security risk but if you dont define a default role, troubleshooting might be dificult.
default_role="demo"
The Roles are where the magic happens. this is how Vault decides if the JWT token it received is valid or not and what it does with it.
allowed_redirect_uris = [
"${var.vault_addr}/ui/vault/auth/${vault_jwt_auth_backend.okta_oidc.path}/oidc/callback",
# This is for logging in with the CLI if you want.
"http://localhost:${var.cli_port}/oidc/callback",
]
User Claim is what defines a Vault Client (Entity) in some scenarios it might be useful to control this.
user_claim="sub"
user_claim = "environment"
Bound claims/ bound audiences is where the specificities of the authentication are configured. TL:DR this is where you say what metadata this access must have to be valid.
bound_claims = {
project_id = data.gitlab_project.vault.id
ref = "main"
ref_type = "branch"
}
bound_claims = {
groups = join(",", each.value.bound_groups)
}
bound_claims = {
"sub" = "repo:${data.github_repository.vault_actions.full_name}:ref:refs/*"
}
Claim Mappings are the JWT metadata you want to save on the Vault Entity
claim_mappings = {
dysplayname=dysplayname,
surname=surname,
givenname=givenname,
preferred_username=preferred_username,
unique_name=unique_name,
email=email,
name=name
}
Policies are how you provide AuthZ to the auth method, least priviledge should apply and each role should only have access to the secrets they need.
token_policies = ["default", "hcp-root"]