Skip to content

Latest commit

 

History

History
184 lines (158 loc) · 5.98 KB

README.md

File metadata and controls

184 lines (158 loc) · 5.98 KB
display_name description icon maintainer_github partner_github verified tags
Hashicorp Vault Integration (JWT)
Authenticates with Vault using a JWT from Coder's OIDC provider
../.icons/vault.svg
coder
hashicorp
true
helper
integration
vault
jwt
oidc

Hashicorp Vault Integration (JWT)

This module lets you authenticate with Hashicorp Vault in your Coder workspaces by reusing the OIDC access token from Coder's OIDC authentication method or another source of jwt token. This requires configuring the Vault JWT/OIDC auth method.

module "vault" {
  count           = data.coder_workspace.me.start_count
  source          = "registry.coder.com/modules/vault-jwt/coder"
  version         = "1.0.21"
  agent_id        = coder_agent.example.id
  vault_addr      = "https://vault.example.com"
  vault_jwt_role  = "coder"                # The Vault role to use for authentication
  vault_jwt_token = "eyJhbGciOiJIUzI1N..." # optional, if not present, defaults to user's oidc authentication token
}

Then you can use the Vault CLI in your workspaces to fetch secrets from Vault:

vault kv get -namespace=coder -mount=secrets coder

or using the Vault API:

curl -H "X-Vault-Token: ${VAULT_TOKEN}" -X GET "${VAULT_ADDR}/v1/coder/secrets/data/coder"

Examples

Configure Vault integration with a non standard auth path (default is "jwt")

module "vault" {
  count               = data.coder_workspace.me.start_count
  source              = "registry.coder.com/modules/vault-jwt/coder"
  version             = "1.0.21"
  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
}

Map workspace owner's group to a Vault role

data "coder_workspace_owner" "me" {}

module "vault" {
  count          = data.coder_workspace.me.start_count
  source         = "registry.coder.com/modules/vault-jwt/coder"
  version        = "1.0.21"
  agent_id       = coder_agent.example.id
  vault_addr     = "https://vault.example.com"
  vault_jwt_role = data.coder_workspace_owner.me.groups[0]
}

Install a specific version of the Vault CLI

module "vault" {
  count             = data.coder_workspace.me.start_count
  source            = "registry.coder.com/modules/vault-jwt/coder"
  version           = "1.0.21"
  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"
}

use a custom jwt token

terraform {
  required_providers {
    jwt = {
      source  = "geektheripper/jwt"
      version = "1.1.4"
    }
    time = {
      source  = "hashicorp/time"
      version = "0.11.1"
    }
  }
}


resource "jwt_signed_token" "vault" {
  count     = data.coder_workspace.me.start_count
  algorithm = "RS256"
  # `openssl genrsa -out key.pem 4096` and `openssl rsa -in key.pem -pubout > pub.pem` to generate keys
  key = file("key.pem")
  claims_json = jsonencode({
    iss = "https://code.example.com"
    sub = "${data.coder_workspace.me.id}"
    aud = "https://vault.example.com"
    iat = provider::time::rfc3339_parse(plantimestamp()).unix
    # exp = timeadd(timestamp(), 3600)
    agent            = coder_agent.main.id
    provisioner      = data.coder_provisioner.main.id
    provisioner_arch = data.coder_provisioner.main.arch
    provisioner_os   = data.coder_provisioner.main.os

    workspace        = data.coder_workspace.me.id
    workspace_url    = data.coder_workspace.me.access_url
    workspace_port   = data.coder_workspace.me.access_port
    workspace_name   = data.coder_workspace.me.name
    template         = data.coder_workspace.me.template_id
    template_name    = data.coder_workspace.me.template_name
    template_version = data.coder_workspace.me.template_version
    owner            = data.coder_workspace_owner.me.id
    owner_name       = data.coder_workspace_owner.me.name
    owner_email      = data.coder_workspace_owner.me.email
    owner_login_type = data.coder_workspace_owner.me.login_type
    owner_groups     = data.coder_workspace_owner.me.groups
  })
}

module "vault" {
  count           = data.coder_workspace.me.start_count
  source          = "registry.coder.com/modules/vault-jwt/coder"
  version         = "1.0.20"
  agent_id        = coder_agent.example.id
  vault_addr      = "https://vault.example.com"
  vault_jwt_role  = "coder" # The Vault role to use for authentication
  vault_jwt_token = jwt_signed_token.vault[0].token
}

example vault jwt role

vault write auth/<JWT_MOUNT>/role/workspace -<<EOF
{
  "user_claim": "sub",
  "bound_audiences": "https://vault.example.com",
  "role_type": "jwt",
  "ttl": "1h",
  "claim_mappings": {
    "owner": "owner",
    "owner_email": "owner_email",
    "owner_login_type": "owner_login_type",
    "owner_name": "owner_name",
    "provisioner": "provisioner",
    "provisioner_arch": "provisioner_arch",
    "provisioner_os": "provisioner_os",
    "sub": "sub",
    "template": "template",
    "template_name": "template_name",
    "template_version": "template_version",
    "workspace": "workspace",
    "workspace_name": "workspace_name",
    "workspace_id": "workspace_id"
}
}
EOF

example workspace access vault policy

path "kv/data/app/coder/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.owner_name}}/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.workspace_name}}" {
  capabilities = ["create", "read", "update", "delete", "list", "subscribe"]
  subscribe_event_types = ["*"]
}
path "kv/metadata/app/coder/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.owner_name}}/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.workspace_name}}" {
  capabilities = ["create", "read", "update", "delete", "list", "subscribe"]
  subscribe_event_types = ["*"]
}