feat: add enable/disable support for user secrets (#27537)

Users can now disable a secret to stop it from being injected into
workspaces without deleting it, and re-enable it later. Disabled secrets
stay visible and editable everywhere they already appear.

An enabled secret must have at least one injection target; a secret with
no target can be stored only while disabled. Existing target-less secrets
are migrated to disabled to preserve current behavior.

Support spans the REST API, SDK, CLI, dashboard, and audit log.
This commit is contained in:
Zach
2026-07-28 09:58:33 -06:00
committed by GitHub
parent 3c61a9a939
commit 85984ff142
56 changed files with 1391 additions and 186 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ We track the following resources:
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>disable_module_cache</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_autostop_notify</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_service_account</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>enabled</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
| UserSkill<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>content</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_name</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>notified_autostop_deadline</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>template_version_preset_id</td><td>false</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
+2 -1
View File
@@ -49,7 +49,8 @@ Users can view their public key in their account settings:
User secrets are developer-managed values that Coder injects at workspace start.
If a user secret targets the same environment variable name or file path as a
template-provided variable or file, Coder injects the user secret into that
workspace. User secret values are covered by
workspace. A secret can be disabled, in which case it is stored but not injected
until it is re-enabled. User secret values are covered by
[Database Encryption](./database-encryption.md) when it is enabled. See the
[User secrets guide](../../user-guides/user-secrets.md).
+28 -22
View File
@@ -5117,6 +5117,7 @@ This is required on creation to enable a user-flow of validating a template work
```json
{
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"name": "string",
@@ -5126,13 +5127,14 @@ This is required on creation to enable a user-flow of validating a template work
### Properties
| Name | Type | Required | Restrictions | Description |
|---------------|--------|----------|--------------|-------------|
| `description` | string | false | | |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `name` | string | false | | |
| `value` | string | false | | |
| Name | Type | Required | Restrictions | Description |
|---------------|---------|----------|--------------|-------------|
| `description` | string | false | | |
| `enabled` | boolean | false | | |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `name` | string | false | | |
| `value` | string | false | | |
## codersdk.CreateUserSkillRequest
@@ -13833,6 +13835,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
```json
{
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"value": "string"
@@ -13841,12 +13844,13 @@ If the schedule is empty, the user will be updated to use the default schedule.|
### Properties
| Name | Type | Required | Restrictions | Description |
|---------------|--------|----------|--------------|-------------|
| `description` | string | false | | |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `value` | string | false | | |
| Name | Type | Required | Restrictions | Description |
|---------------|---------|----------|--------------|-------------|
| `description` | string | false | | |
| `enabled` | boolean | false | | |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `value` | string | false | | |
## codersdk.UpdateUserSkillRequest
@@ -14532,6 +14536,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@@ -14542,15 +14547,16 @@ If the schedule is empty, the user will be updated to use the default schedule.|
### Properties
| Name | Type | Required | Restrictions | Description |
|---------------|--------|----------|--------------|-------------|
| `created_at` | string | false | | |
| `description` | string | false | | |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `id` | string | false | | |
| `name` | string | false | | |
| `updated_at` | string | false | | |
| Name | Type | Required | Restrictions | Description |
|---------------|---------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `created_at` | string | false | | |
| `description` | string | false | | |
| `enabled` | boolean | false | | Enabled controls whether the secret is injected into workspaces. Disabled secrets remain visible and editable, but are not added to the agent manifest, so they are not exposed as environment variables or written to secret files. |
| `env_name` | string | false | | |
| `file_path` | string | false | | |
| `id` | string | false | | |
| `name` | string | false | | |
| `updated_at` | string | false | | |
## codersdk.UserSkill
+29 -20
View File
@@ -28,6 +28,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/secrets \
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@@ -47,16 +48,17 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/secrets \
Status Code **200**
| Name | Type | Required | Restrictions | Description |
|-----------------|-------------------|----------|--------------|-------------|
| `[array item]` | array | false | | |
| `» created_at` | string(date-time) | false | | |
| `» description` | string | false | | |
| `» env_name` | string | false | | |
| `» file_path` | string | false | | |
| `» id` | string(uuid) | false | | |
| `» name` | string | false | | |
| `» updated_at` | string(date-time) | false | | |
| Name | Type | Required | Restrictions | Description |
|-----------------|-------------------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `[array item]` | array | false | | |
| `» created_at` | string(date-time) | false | | |
| `» description` | string | false | | |
| `» enabled` | boolean | false | | Enabled controls whether the secret is injected into workspaces. Disabled secrets remain visible and editable, but are not added to the agent manifest, so they are not exposed as environment variables or written to secret files. |
| `» env_name` | string | false | | |
| `» file_path` | string | false | | |
| `» id` | string(uuid) | false | | |
| `» name` | string | false | | |
| `» updated_at` | string(date-time) | false | | |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
@@ -79,6 +81,7 @@ curl -X POST http://coder-server:8080/api/v2/users/{user}/secrets \
```json
{
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"name": "string",
@@ -101,6 +104,7 @@ curl -X POST http://coder-server:8080/api/v2/users/{user}/secrets \
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@@ -156,6 +160,7 @@ curl -X POST http://coder-server:8080/api/v2/users/{user}/secrets/batch \
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@@ -178,16 +183,17 @@ curl -X POST http://coder-server:8080/api/v2/users/{user}/secrets/batch \
Status Code **201**
| Name | Type | Required | Restrictions | Description |
|-----------------|-------------------|----------|--------------|-------------|
| `[array item]` | array | false | | |
| `» created_at` | string(date-time) | false | | |
| `» description` | string | false | | |
| `» env_name` | string | false | | |
| `» file_path` | string | false | | |
| `» id` | string(uuid) | false | | |
| `» name` | string | false | | |
| `» updated_at` | string(date-time) | false | | |
| Name | Type | Required | Restrictions | Description |
|-----------------|-------------------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `[array item]` | array | false | | |
| `» created_at` | string(date-time) | false | | |
| `» description` | string | false | | |
| `» enabled` | boolean | false | | Enabled controls whether the secret is injected into workspaces. Disabled secrets remain visible and editable, but are not added to the agent manifest, so they are not exposed as environment variables or written to secret files. |
| `» env_name` | string | false | | |
| `» file_path` | string | false | | |
| `» id` | string(uuid) | false | | |
| `» name` | string | false | | |
| `» updated_at` | string(date-time) | false | | |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
@@ -219,6 +225,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/secrets/{name} \
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@@ -281,6 +288,7 @@ curl -X PATCH http://coder-server:8080/api/v2/users/{user}/secrets/{name} \
```json
{
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"value": "string"
@@ -303,6 +311,7 @@ curl -X PATCH http://coder-server:8080/api/v2/users/{user}/secrets/{name} \
{
"created_at": "2019-08-24T14:15:22Z",
"description": "string",
"enabled": true,
"env_name": "string",
"file_path": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+8 -6
View File
@@ -39,9 +39,11 @@ coder secret
## Subcommands
| Name | Purpose |
|-------------------------------------------|-----------------------------------|
| [<code>create</code>](./secret_create.md) | Create a secret |
| [<code>update</code>](./secret_update.md) | Update a secret |
| [<code>list</code>](./secret_list.md) | List secrets, or show one by name |
| [<code>delete</code>](./secret_delete.md) | Delete a secret |
| Name | Purpose |
|---------------------------------------------|---------------------------------------------------|
| [<code>create</code>](./secret_create.md) | Create a secret |
| [<code>update</code>](./secret_update.md) | Update a secret |
| [<code>enable</code>](./secret_enable.md) | Enable a secret so it is injected into workspaces |
| [<code>disable</code>](./secret_disable.md) | Disable a secret without removing it |
| [<code>list</code>](./secret_list.md) | List secrets, or show one by name |
| [<code>delete</code>](./secret_delete.md) | Delete a secret |
+9
View File
@@ -48,3 +48,12 @@ Name of the workspace environment variable that this secret will set.
| Type | <code>string</code> |
Workspace file path where this secret will be written. Must start with ~/ or /.
### --enabled
| | |
|---------|-------------------|
| Type | <code>bool</code> |
| Default | <code>true</code> |
Whether the secret is injected into workspaces. An enabled secret must set --env or --file; pass --enabled=false to store a secret without injecting it.
+10
View File
@@ -0,0 +1,10 @@
<!-- DO NOT EDIT | GENERATED CONTENT -->
# secret disable
Disable a secret without removing it
## Usage
```console
coder secret disable <name>
```
+10
View File
@@ -0,0 +1,10 @@
<!-- DO NOT EDIT | GENERATED CONTENT -->
# secret enable
Enable a secret so it is injected into workspaces
## Usage
```console
coder secret enable <name>
```
+4 -4
View File
@@ -23,10 +23,10 @@ Secret values are omitted from the output.
### -c, --column
| | |
|---------|---------------------------------------------------------------|
| Type | <code>[created\|name\|updated\|env\|file\|description]</code> |
| Default | <code>name,created,updated,env,file,description</code> |
| | |
|---------|------------------------------------------------------------------------|
| Type | <code>[created\|name\|updated\|env\|file\|enabled\|description]</code> |
| Default | <code>name,created,updated,env,file,enabled,description</code> |
Columns to display in table output.
+9 -1
View File
@@ -12,7 +12,7 @@ coder secret update [flags] <name>
## Description
```console
At least one of --value, --description, --env, or --file must be specified. Provide the secret value by at most one of --value or non-interactive stdin (pipe or redirect).
At least one of --value, --description, --env, --file, or --enabled must be specified. Provide the secret value by at most one of --value or non-interactive stdin (pipe or redirect).
```
## Options
@@ -48,3 +48,11 @@ Name of the workspace environment variable that this secret will set. Pass an em
| Type | <code>string</code> |
Workspace file path where this secret will be written. Must start with ~/ or /. Pass an empty string to clear it.
### --enabled
| | |
|------|-------------------|
| Type | <code>bool</code> |
Whether the secret is injected into workspaces. An enabled secret must keep at least one of --env or --file; pass --enabled=false to stop injecting it without deleting it.
+66 -16
View File
@@ -11,9 +11,19 @@ Each user secret has:
- A value, which contains the sensitive content.
- An optional description.
- An optional environment variable target, file target, or both.
- An enabled flag that controls whether Coder injects the secret into your
workspaces.
A secret without an environment variable target or file target is stored, but is
not injected into workspaces.
An enabled secret must have at least one of an environment variable target or a
file target. To keep a secret stored without injecting it, disable it
(`enabled = false`) instead of clearing both targets. A create or update that
would leave an enabled secret with no target is rejected with a 400 and
directs you to disable the secret instead.
Disabled secrets stay visible and editable in the CLI, REST API, and dashboard,
but are not injected into workspaces. Secrets that predate the enabled flag and
had no target were migrated to disabled, so they show as disabled and need a
target before you can enable them.
User secrets apply to all workspaces that you own.
@@ -39,6 +49,12 @@ time the workspace agent reconnects to Coder, for example after the workspace
or the agent restarts. To pick up a change to a secret while a workspace is
running, restart the workspace.
Disabling a secret (`coder secret disable`) stops it from being injected from
the next workspace start onward. Running sessions keep values that were already
injected until the agent manifest is refetched, which happens on workspace
restart. Disabling does not remove a file that was already written; the same
"Coder never deletes secret files" rule below applies.
### Environment variable secrets
Coder injects environment variable secrets into every new shell, terminal,
@@ -46,11 +62,13 @@ app, SSH session, and startup script that you start in your workspace.
Existing shells and processes keep the environment they were given when they
started.
| If you... | ...then in your workspace |
|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| Create or update an env secret | The change applies after the next workspace start. Until then, your running workspace continues to use the secrets it had when it last started. |
| Rename the env var (`--env NEW_NAME`) | After the next workspace start, new shells get `NEW_NAME` and the old name is no longer set. |
| Clear the env target (`--env ""`) or delete the secret | After the next workspace start, the variable is no longer injected. |
| If you... | ...then in your workspace |
|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Create or update an env secret | The change applies after the next workspace start. Until then, your running workspace continues to use the secrets it had when it last started. |
| Rename the env var (`--env NEW_NAME`) | After the next workspace start, new shells get `NEW_NAME` and the old name is no longer set. |
| Clear the env target (`--env ""`) | Only succeeds if the secret keeps its file target or is disabled in the same request; otherwise the request is rejected with a 400. After the next workspace start, the variable is no longer injected. |
| Disable the secret (`coder secret disable`) | After the next workspace start, the variable is no longer injected. Running sessions keep the value until the agent manifest is refetched (workspace restart). |
| Delete the secret | After the next workspace start, the variable is no longer injected. |
To pick up a change in a long-running shell or app started after a restart,
restart that shell or app.
@@ -62,11 +80,13 @@ starts, before any startup scripts run. New parent directories are created as
needed. If the file already exists, Coder overwrites the contents and leaves
the existing permissions alone.
| If you... | ...then in your workspace |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| Create or update a file secret | The file is written or overwritten at the next workspace start. |
| Change the file path (`--file NEW_PATH`) | At the next workspace start, a file is written at `NEW_PATH`. **The file at the previous path stays on disk with its old value.** |
| Clear the file target (`--file ""`) or delete the secret | **The previously-written file stays on disk with its last value.** |
| If you... | ...then in your workspace |
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Create or update a file secret | The file is written or overwritten at the next workspace start. |
| Change the file path (`--file NEW_PATH`) | At the next workspace start, a file is written at `NEW_PATH`. **The file at the previous path stays on disk with its old value.** |
| Clear the file target (`--file ""`) | Only succeeds if the secret keeps its env target or is disabled in the same request; otherwise the request is rejected with a 400. **The previously-written file stays on disk with its last value.** |
| Disable the secret (`coder secret disable`) | The file is no longer written at the next workspace start. **The previously-written file stays on disk with its last value.** |
| Delete the secret | **The previously-written file stays on disk with its last value.** |
> [!IMPORTANT]
> Coder never deletes secret files it has written for you. If you remove a
@@ -120,7 +140,10 @@ You can create, edit, and delete user secrets from the Coder dashboard:
From this page you can add a new secret, update an existing secret's value,
description, or environment variable and file targets, and delete secrets you
no longer need.
no longer need. Each row has an enable/disable toggle that controls whether
Coder injects the secret. A secret with no environment variable or file target
cannot be enabled from the dashboard; the toggle is disabled with a tooltip,
mirroring the API invariant that an enabled secret must have a target.
The rest of this guide shows the equivalent CLI commands. The same behaviors,
limits, and injection rules apply whether you manage secrets from the
@@ -194,11 +217,21 @@ want to store a trailing newline:
echo -n "$API_KEY" | coder secret create api-key --env API_KEY
```
### Create a disabled secret
An enabled secret must set `--env`, `--file`, or both. To store a secret
without injecting it, pass `--enabled=false`. You can add a target and enable
it later with `coder secret enable`.
```sh
echo -n "$API_KEY" | coder secret create api-key --enabled=false
```
## Update a secret
Use `coder secret update` to update a secret value, description, environment
variable target, or file target. At least one of `--value`, `--description`,
`--env`, or `--file` must be specified.
`--env`, `--file`, or `--enabled` must be specified.
```sh
# Update a secret value.
@@ -207,10 +240,26 @@ echo -n "$NEW_API_KEY" | coder secret update api-key
# Change the environment variable target.
coder secret update api-key --env NEW_API_KEY
# Clear the file injection target while keeping the secret.
# Clear the file injection target while keeping the secret. This only
# succeeds because api-key still has an environment variable target; a
# request that clears the last target of an enabled secret is rejected.
coder secret update api-key --file ""
```
### Enable and disable a secret
Disable a secret to stop injecting it without deleting it, then enable it again
to resume. Enabling a secret that has no target is rejected; add a target
first.
```sh
# Stop injecting a secret without deleting it.
coder secret disable api-key
# Resume injection.
coder secret enable api-key
```
## List and delete secrets
List, show, and delete your secrets with the `coder secret` CLI:
@@ -227,7 +276,8 @@ coder secret delete api-key
```
The list and show commands return secret metadata only. They never return the
secret value.
secret value. The `coder secret list` table includes an `enabled` column so you
can see which secrets are currently injected.
See [How your secrets reach a workspace](#how-your-secrets-reach-a-workspace)
for what happens to running workspaces when you delete a secret.