This repository was archived by the owner on May 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 62
feat(vault-jwt): Add Vault JWT/OIDC module #297
Merged
Merged
Changes from 5 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
2dfce27
feat: add Hashicorp Vault JWT integration module
matifali c9b1651
Clarify role mapping in Vault integration docs
matifali b02c4de
docs: update OIDC link in Vault JWT README
matifali bf24358
Update module in tsconfig to 'nodenext'
matifali d3a796e
Fix variable names in Vault JWT module scripts
matifali a94fda9
Update vault-jwt/run.sh
matifali 37bf439
Merge branch 'main' into maa/vault-okta-jwt
matifali 1dc0256
Clarify Hashicorp Vault Integration setup instructions
matifali 864ff24
Bump Vault JWT module version to 1.0.19 in README
matifali File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| --- | ||
| display_name: Hashicorp Vault Integration (JWT) | ||
| description: Authenticates with Vault using a JWT from Coder's OIDC provider | ||
| icon: ../.icons/vault.svg | ||
| maintainer_github: coder | ||
| partner_github: hashicorp | ||
| verified: true | ||
| tags: [helper, integration, vault, jwt, oidc] | ||
| --- | ||
|
|
||
| # Hashicorp Vault Integration (JWT) | ||
|
|
||
| This module lets you authenticate with [Hashicorp Vault](https://www.vaultproject.io/) in your Coder workspaces using a [JWT](https://developer.hashicorp.com/vault/docs/auth/jwt#jwt-authentication) from Coder's [OIDC authentication method](https://coder.com/docs/admin/auth#openid-connect). | ||
|
|
||
| ```tf | ||
| module "vault" { | ||
| source = "registry.coder.com/modules/vault-jwt/coder" | ||
| version = "1.0.17" | ||
| agent_id = coder_agent.example.id | ||
| vault_addr = "https://vault.example.com" | ||
| vault_jwt_role = "coder" # The Vault role to use for authentication | ||
| } | ||
| ``` | ||
|
|
||
| Then you can use the Vault CLI in your workspaces to fetch secrets from Vault: | ||
|
|
||
| ```shell | ||
| vault kv get -namespace=coder -mount=secrets coder | ||
| ``` | ||
|
|
||
| or using the Vault API: | ||
|
|
||
| ```shell | ||
| curl -H "X-Vault-Token: ${VAULT_TOKEN}" -X GET "${VAULT_ADDR}/v1/coder/secrets/data/coder" | ||
| ``` | ||
|
|
||
|  | ||
|
|
||
| ## Configuration | ||
|
|
||
| To configure the Vault module, you must set up a Vault JWT auth method. See the [Vault documentation](https://developer.hashicorp.com/vault/docs/auth/jwt#configuration) for more information. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Configure Vault integration with a non standard auth path | ||
|
|
||
| ```tf | ||
| module "vault" { | ||
| source = "registry.coder.com/modules/vault-jwt/coder" | ||
| version = "1.0.17" | ||
| agent_id = coder_agent.example.id | ||
| vault_addr = "https://vault.example.com" | ||
| vault_jwt_auth_path = "oidc" | ||
| vault_jwt_role = "coder" # The Vault role to use for authentication | ||
| } | ||
| ``` | ||
|
|
||
| ### Configure Vault integration with a role from your OIDC provider by mapping the workspace owner's group to a Vault role | ||
|
|
||
| ```tf | ||
| data "coder_workspace_owner" "me" {} | ||
|
|
||
| module "vault" { | ||
| source = "registry.coder.com/modules/vault-jwt/coder" | ||
| version = "1.0.7" | ||
| agent_id = coder_agent.example.id | ||
| vault_addr = "https://vault.example.com" | ||
| vault_jwt_role = data.coder_workspace_owner.me.groups[0] | ||
| } | ||
| ``` | ||
|
|
||
| ### Configure Vault integration and install a specific version of the Vault CLI | ||
|
|
||
| ```tf | ||
| module "vault" { | ||
| source = "registry.coder.com/modules/vault-jwt/coder" | ||
| version = "1.0.17" | ||
| agent_id = coder_agent.example.id | ||
| vault_addr = "https://vault.example.com" | ||
| vault_jwt_role = "coder" # The Vault role to use for authentication | ||
| vault_cli_version = "1.17.5" | ||
| } | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { describe } from "bun:test"; | ||
| import { runTerraformInit, testRequiredVariables } from "../test"; | ||
|
|
||
| describe("vault-jwt", async () => { | ||
| await runTerraformInit(import.meta.dir); | ||
|
|
||
| testRequiredVariables(import.meta.dir, { | ||
| agent_id: "foo", | ||
| vault_addr: "foo", | ||
| vault_jwt_role: "foo", | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| terraform { | ||
| required_version = ">= 1.0" | ||
|
|
||
| required_providers { | ||
| coder = { | ||
| source = "coder/coder" | ||
| version = ">= 0.12.4" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| # Add required variables for your modules and remove any unneeded variables | ||
| variable "agent_id" { | ||
| type = string | ||
| description = "The ID of a Coder agent." | ||
| } | ||
|
|
||
| variable "vault_addr" { | ||
| type = string | ||
| description = "The address of the Vault server." | ||
| } | ||
|
|
||
| variable "vault_jwt_auth_path" { | ||
| type = string | ||
| description = "The path to the Vault JWT auth method." | ||
| default = "jwt" | ||
| } | ||
|
|
||
| variable "vault_jwt_role" { | ||
| type = string | ||
| description = "The name of the Vault role to use for authentication." | ||
| } | ||
|
|
||
| variable "vault_cli_version" { | ||
| type = string | ||
| description = "The version of Vault to install." | ||
| default = "latest" | ||
| validation { | ||
| condition = can(regex("^(latest|[0-9]+\\.[0-9]+\\.[0-9]+)$", var.vault_cli_version)) | ||
| error_message = "Vault version must be in the format 0.0.0 or latest" | ||
| } | ||
| } | ||
|
|
||
| resource "coder_script" "vault" { | ||
| agent_id = var.agent_id | ||
| display_name = "Vault (GitHub)" | ||
| icon = "/icon/vault.svg" | ||
| script = templatefile("${path.module}/run.sh", { | ||
| CODER_OIDC_ACCESS_TOKEN : data.coder_workspace_owner.me.oidc_access_token, | ||
| VAULT_JWT_AUTH_PATH : var.vault_jwt_auth_path, | ||
| VAULT_JWT_ROLE : var.vault_jwt_role, | ||
| VAULT_CLI_VERSION : var.vault_cli_version, | ||
| }) | ||
| run_on_start = true | ||
| start_blocks_login = true | ||
| } | ||
|
|
||
| resource "coder_env" "vault_addr" { | ||
| agent_id = var.agent_id | ||
| name = "VAULT_ADDR" | ||
| value = var.vault_addr | ||
| } | ||
|
|
||
| data "coder_workspace_owner" "me" {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| # Convert all templated variables to shell variables | ||
| VAULT_CLI_VERSION=${VAULT_CLI_VERSION} | ||
| VAULT_JWT_AUTH_PATH=${VAULT_JWT_AUTH_PATH} | ||
| VAULT_JWT_ROLE=${VAULT_JWT_ROLE} | ||
| CODER_OIDC_ACCESS_TOKEN=${CODER_OIDC_ACCESS_TOKEN} | ||
|
|
||
| fetch() { | ||
| dest="$1" | ||
| url="$2" | ||
| if command -v curl > /dev/null 2>&1; then | ||
| curl -sSL --fail "$${url}" -o "$${dest}" | ||
| elif command -v wget > /dev/null 2>&1; then | ||
| wget -O "$${dest}" "$${url}" | ||
| elif command -v busybox > /dev/null 2>&1; then | ||
| busybox wget -O "$${dest}" "$${url}" | ||
| else | ||
| printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n" | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| unzip_safe() { | ||
| if command -v unzip > /dev/null 2>&1; then | ||
| command unzip "$@" | ||
| elif command -v busybox > /dev/null 2>&1; then | ||
| busybox unzip "$@" | ||
| else | ||
| printf "unzip or busybox is not installed. Please install unzip in your image.\n" | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| install() { | ||
| # Get the architecture of the system | ||
| ARCH=$(uname -m) | ||
| if [ "$${ARCH}" = "x86_64" ]; then | ||
| ARCH="amd64" | ||
| elif [ "$${ARCH}" = "aarch64" ]; then | ||
| ARCH="arm64" | ||
| else | ||
| printf "Unsupported architecture: $${ARCH}\n" | ||
| return 1 | ||
| fi | ||
| # Fetch the latest version of Vault if VAULT_CLI_VERSION is 'latest' | ||
| if [ "$${VAULT_CLI_VERSION}" = "latest" ]; then | ||
| LATEST_VERSION=$(curl -s https://releases.hashicorp.com/vault/ | grep -v 'rc' | grep -oE 'vault/[0-9]+\.[0-9]+\.[0-9]+' | sed 's/vault\///' | sort -V | tail -n 1) | ||
| printf "Latest version of Vault is %s.\n\n" "$${LATEST_VERSION}" | ||
| if [ -z "$${LATEST_VERSION}" ]; then | ||
| printf "Failed to determine the latest Vault version.\n" | ||
| return 1 | ||
| fi | ||
| VAULT_CLI_VERSION=$${VAULT_CLI_VERSION} | ||
| fi | ||
|
|
||
| # Check if the vault CLI is installed and has the correct version | ||
| installation_needed=1 | ||
| if command -v vault > /dev/null 2>&1; then | ||
| CURRENT_VERSION=$(vault version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') | ||
| if [ "$${CURRENT_VERSION}" = "$${VAULT_CLI_VERSION}" ]; then | ||
| printf "Vault version %s is already installed and up-to-date.\n\n" "$${CURRENT_VERSION}" | ||
| installation_needed=0 | ||
| fi | ||
| fi | ||
|
|
||
| if [ $${installation_needed} -eq 1 ]; then | ||
| # Download and install Vault | ||
| if [ -z "$${CURRENT_VERSION}" ]; then | ||
| printf "Installing Vault CLI ...\n\n" | ||
| else | ||
| printf "Upgrading Vault CLI from version %s to %s ...\n\n" "$${CURRENT_VERSION}" "${VAULT_CLI_VERSION}" | ||
| fi | ||
| fetch vault.zip "https://releases.hashicorp.com/vault/$${VAULT_CLI_VERSION}/vault_$${VAULT_CLI_VERSION}_linux_$${ARCH}.zip" | ||
| if [ $? -ne 0 ]; then | ||
| printf "Failed to download Vault.\n" | ||
| return 1 | ||
| fi | ||
| if ! unzip_safe vault.zip; then | ||
| printf "Failed to unzip Vault.\n" | ||
| return 1 | ||
| fi | ||
| rm vault.zip | ||
| if sudo mv vault /usr/local/bin/vault 2> /dev/null; then | ||
| printf "Vault installed successfully!\n\n" | ||
| else | ||
| mkdir -p ~/.local/bin | ||
| if ! mv vault ~/.local/bin/vault; then | ||
| printf "Failed to move Vault to local bin.\n" | ||
| return 1 | ||
| fi | ||
| printf "Please add ~/.local/bin to your PATH to use vault CLI.\n" | ||
| fi | ||
| fi | ||
| return 0 | ||
| } | ||
|
|
||
| TMP=$(mktemp -d) | ||
| if ! ( | ||
| cd "$TMP" | ||
| install | ||
| ); then | ||
| echo "Failed to install Vault CLI." | ||
| exit 1 | ||
| fi | ||
| rm -rf "$TMP" | ||
|
|
||
| # Authenticate with Vault | ||
| printf "🔑 Authenticating with Vault ...\n\n" | ||
| echo "$${CODER_OIDC_ACCESS_TOKEN}" | vault write auth/$${VAULT_JWT_AUTH_PATH}/login role=$${VAULT_JWT_ROLE} jwt=- | ||
matifali marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| printf "🥳 Vault authentication complete!\n\n" | ||
| printf "You can now use Vault CLI to access secrets.\n" | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this supposed to be an image URL?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I will take care of this.