@@ -10,16 +10,17 @@ tags: [helper, integration, vault, jwt, oidc]
1010
1111# Hashicorp Vault Integration (JWT)
1212
13- This module lets you authenticate with [ Hashicorp Vault] ( https://www.vaultproject.io/ ) in your Coder workspaces by reusing the [ OIDC] ( https://coder.com/docs/admin/users/oidc-auth ) access token from Coder's OIDC authentication method. This requires configuring the Vault [ JWT/OIDC] ( https://developer.hashicorp.com/vault/docs/auth/jwt#configuration ) auth method.
13+ This module lets you authenticate with [ Hashicorp Vault] ( https://www.vaultproject.io/ ) in your Coder workspaces by reusing the [ OIDC] ( https://coder.com/docs/admin/users/oidc-auth ) access token from Coder's OIDC authentication method or another source of jwt token . This requires configuring the Vault [ JWT/OIDC] ( https://developer.hashicorp.com/vault/docs/auth/jwt#configuration ) auth method.
1414
1515``` tf
1616module "vault" {
17- count = data.coder_workspace.me.start_count
18- source = "registry.coder.com/modules/vault-jwt/coder"
19- version = "1.0.31"
20- agent_id = coder_agent.example.id
21- vault_addr = "https://vault.example.com"
22- vault_jwt_role = "coder" # The Vault role to use for authentication
17+ count = data.coder_workspace.me.start_count
18+ source = "registry.coder.com/modules/vault-jwt/coder"
19+ version = "1.1.0"
20+ agent_id = coder_agent.example.id
21+ vault_addr = "https://vault.example.com"
22+ vault_jwt_role = "coder" # The Vault role to use for authentication
23+ vault_jwt_token = "eyJhbGciOiJIUzI1N..." # optional, if not present, defaults to user's oidc authentication token
2324}
2425```
2526
@@ -79,3 +80,106 @@ module "vault" {
7980 vault_cli_version = "1.17.5"
8081}
8182```
83+
84+ ### Use a custom JWT token
85+
86+ ``` tf
87+
88+ terraform {
89+ required_providers {
90+ jwt = {
91+ source = "geektheripper/jwt"
92+ version = "1.1.4"
93+ }
94+ time = {
95+ source = "hashicorp/time"
96+ version = "0.11.1"
97+ }
98+ }
99+ }
100+
101+
102+ resource "jwt_signed_token" "vault" {
103+ count = data.coder_workspace.me.start_count
104+ algorithm = "RS256"
105+ # `openssl genrsa -out key.pem 4096` and `openssl rsa -in key.pem -pubout > pub.pem` to generate keys
106+ key = file("key.pem")
107+ claims_json = jsonencode({
108+ iss = "https://code.example.com"
109+ sub = "${data.coder_workspace.me.id}"
110+ aud = "https://vault.example.com"
111+ iat = provider::time::rfc3339_parse(plantimestamp()).unix
112+ # Uncomment to set an expiry on the JWT token(default 3600 seconds).
113+ # workspace will need to be restarted to generate a new token if it expires
114+ #exp = provider::time::rfc3339_parse(timeadd(timestamp(), 3600)).unix agent = coder_agent.main.id
115+ provisioner = data.coder_provisioner.main.id
116+ provisioner_arch = data.coder_provisioner.main.arch
117+ provisioner_os = data.coder_provisioner.main.os
118+
119+ workspace = data.coder_workspace.me.id
120+ workspace_url = data.coder_workspace.me.access_url
121+ workspace_port = data.coder_workspace.me.access_port
122+ workspace_name = data.coder_workspace.me.name
123+ template = data.coder_workspace.me.template_id
124+ template_name = data.coder_workspace.me.template_name
125+ template_version = data.coder_workspace.me.template_version
126+ owner = data.coder_workspace_owner.me.id
127+ owner_name = data.coder_workspace_owner.me.name
128+ owner_email = data.coder_workspace_owner.me.email
129+ owner_login_type = data.coder_workspace_owner.me.login_type
130+ owner_groups = data.coder_workspace_owner.me.groups
131+ })
132+ }
133+
134+ module "vault" {
135+ count = data.coder_workspace.me.start_count
136+ source = "registry.coder.com/modules/vault-jwt/coder"
137+ version = "1.1.0"
138+ agent_id = coder_agent.example.id
139+ vault_addr = "https://vault.example.com"
140+ vault_jwt_role = "coder" # The Vault role to use for authentication
141+ vault_jwt_token = jwt_signed_token.vault[0].token
142+ }
143+ ```
144+
145+ #### Example Vault JWT role
146+
147+ ``` shell
148+ vault write auth/JWT_MOUNT/role/workspace - << EOF
149+ {
150+ "user_claim": "sub",
151+ "bound_audiences": "https://vault.example.com",
152+ "role_type": "jwt",
153+ "ttl": "1h",
154+ "claim_mappings": {
155+ "owner": "owner",
156+ "owner_email": "owner_email",
157+ "owner_login_type": "owner_login_type",
158+ "owner_name": "owner_name",
159+ "provisioner": "provisioner",
160+ "provisioner_arch": "provisioner_arch",
161+ "provisioner_os": "provisioner_os",
162+ "sub": "sub",
163+ "template": "template",
164+ "template_name": "template_name",
165+ "template_version": "template_version",
166+ "workspace": "workspace",
167+ "workspace_name": "workspace_name",
168+ "workspace_id": "workspace_id"
169+ }
170+ }
171+ EOF
172+ ```
173+
174+ #### Example workspace access Vault policy
175+
176+ ``` tf
177+ path "kv/data/app/coder/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.owner_name}}/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.workspace_name}}" {
178+ capabilities = ["create", "read", "update", "delete", "list", "subscribe"]
179+ subscribe_event_types = ["*"]
180+ }
181+ path "kv/metadata/app/coder/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.owner_name}}/{{identity.entity.aliases.<MOUNT_ACCESSOR>.metadata.workspace_name}}" {
182+ capabilities = ["create", "read", "update", "delete", "list", "subscribe"]
183+ subscribe_event_types = ["*"]
184+ }
185+ ```
0 commit comments