From bcd6a7c93ca0927836d0f738d05e1746ab90a97b Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Tue, 6 May 2025 10:44:41 +0200 Subject: [PATCH] feat(agent): add api_key_scope to control agent token permissions Change-Id: I90dd87756b47b589bf0a363e22de70d2cffd44fa Signed-off-by: Thomas Kosiewski --- .gitignore | 3 + docs/resources/agent.md | 8 +- examples/resources/coder_agent/resource.tf | 7 +- flake.lock | 8 +- flake.nix | 6 +- provider/agent.go | 11 +++ provider/agent_test.go | 91 ++++++++++++++++++++++ 7 files changed, 121 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 4d5d5ad6..ff9f6a53 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ website/vendor # Binary terraform-provider-coder + +# direnv +.direnv diff --git a/docs/resources/agent.md b/docs/resources/agent.md index 7c28b1f4..7df11e34 100644 --- a/docs/resources/agent.md +++ b/docs/resources/agent.md @@ -17,9 +17,10 @@ data "coder_workspace" "me" { } resource "coder_agent" "dev" { - os = "linux" - arch = "amd64" - dir = "/workspace" + os = "linux" + arch = "amd64" + dir = "/workspace" + api_key_scope = "all" display_apps { vscode = true vscode_insiders = false @@ -71,6 +72,7 @@ resource "kubernetes_pod" "dev" { ### Optional +- `api_key_scope` (String) Controls what API routes the agent token can access. Options: 'all' (full access) or 'no_user_data' (blocks /external-auth, /gitsshkey, and /gitauth routes) - `auth` (String) The authentication type the agent will use. Must be one of: `"token"`, `"google-instance-identity"`, `"aws-instance-identity"`, `"azure-instance-identity"`. - `connection_timeout` (Number) Time in seconds until the agent is marked as timed out when a connection with the server cannot be established. A value of zero never marks the agent as timed out. - `dir` (String) The starting directory when a user creates a shell session. Defaults to `"$HOME"`. diff --git a/examples/resources/coder_agent/resource.tf b/examples/resources/coder_agent/resource.tf index 6ccb07bf..7c219604 100644 --- a/examples/resources/coder_agent/resource.tf +++ b/examples/resources/coder_agent/resource.tf @@ -2,9 +2,10 @@ data "coder_workspace" "me" { } resource "coder_agent" "dev" { - os = "linux" - arch = "amd64" - dir = "/workspace" + os = "linux" + arch = "amd64" + dir = "/workspace" + api_key_scope = "all" display_apps { vscode = true vscode_insiders = false diff --git a/flake.lock b/flake.lock index d8033e14..ecf99d98 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714272655, - "narHash": "sha256-3/ghIWCve93ngkx5eNPdHIKJP/pMzSr5Wc4rNKE1wOc=", + "lastModified": 1746422338, + "narHash": "sha256-NTtKOTLQv6dPfRe00OGSywg37A1FYqldS6xiNmqBUYc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12430e43bd9b81a6b4e79e64f87c624ade701eaf", + "rev": "5b35d248e9206c1f3baf8de6a7683fee126364aa", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 87719bf4..40ceb861 100644 --- a/flake.nix +++ b/flake.nix @@ -2,11 +2,11 @@ description = "Terraform provider for Coder"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils, ... }: + outputs = { nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { @@ -21,7 +21,7 @@ name = "devShell"; buildInputs = with pkgs; [ terraform - go_1_20 + go_1_24 ]; }; } diff --git a/provider/agent.go b/provider/agent.go index ad264030..ebd8fff5 100644 --- a/provider/agent.go +++ b/provider/agent.go @@ -80,6 +80,17 @@ func agentResource() *schema.Resource { return nil }, Schema: map[string]*schema.Schema{ + "api_key_scope": { + Type: schema.TypeString, + Optional: true, + Default: "all", + ForceNew: true, + Description: "Controls what API routes the agent token can access. Options: 'all' (full access) or 'no_user_data' (blocks /external-auth, /gitsshkey, and /gitauth routes)", + ValidateFunc: validation.StringInSlice([]string{ + "all", + "no_user_data", + }, false), + }, "init_script": { Type: schema.TypeString, Computed: true, diff --git a/provider/agent_test.go b/provider/agent_test.go index a45ac86a..82e8691f 100644 --- a/provider/agent_test.go +++ b/provider/agent_test.go @@ -709,5 +709,96 @@ func TestAgent_DisplayApps(t *testing.T) { }}, }) }) +} + +// TestAgent_APIKeyScope tests valid states/transitions and invalid values for api_key_scope. +func TestAgent_APIKeyScope(t *testing.T) { + t.Parallel() + + t.Run("ValidTransitions", func(t *testing.T) { + t.Parallel() + + resourceName := "coder_agent.test_scope_valid" + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{ + // Step 1: Default value + { + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "test_scope_valid" { + os = "linux" + arch = "amd64" + # api_key_scope is omitted, should default to "default" + } + `, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "api_key_scope", "all"), + ), + }, + // Step 2: Explicit "default" + { + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "test_scope_valid" { + os = "linux" + arch = "amd64" + api_key_scope = "all" + } + `, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "api_key_scope", "all"), + ), + }, + // Step 3: Explicit "no_user_data" + { + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "test_scope_valid" { + os = "linux" + arch = "amd64" + api_key_scope = "no_user_data" + } + `, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "api_key_scope", "no_user_data"), + ), + }, + }, + }) + }) + + t.Run("InvalidValue", func(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{ + // Step 1: Invalid value check + { + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "test_scope_invalid" { // Use unique name + os = "linux" + arch = "amd64" + api_key_scope = "invalid-scope" + } + `, + ExpectError: regexp.MustCompile(`expected api_key_scope to be one of \["all" "no_user_data"\], got invalid-scope`), + PlanOnly: true, + }, + }, + }) + }) } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy