mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: plumb user secrets through provisioner chain to terraform (#24542)
This change passes user secrets from coderd to the Terraform process at workspace build time so the `data.coder_secret` data source in terraform-provider-coder can resolve values at plan time. Secrets traverse two proto hops: `provisionerdserver` fetches them via`ListUserSecretsWithValues`, attaches them to `AcquiredJob.WorkspaceBuild.user_secrets` on `provisionerd.proto`; `runner.go` forwards into `PlanRequest.user_secrets` on `provisioner.proto`; the Terraform provisioner encodes each as `CODER_SECRET_ENV_<name>` or `CODER_SECRET_FILE_<hex(path)>` before invoking `terraform plan`. Only plan requests carry secrets; apply runs with `nil` because values are baked into plan state. Fetch is gated on a workspace transitioning to start. stop and delete transitions never carry secrets, so revoking or deleting a stored secret cannot make a workspace unstoppable. DB errors on the fetch fail the job outright rather than silently continuing with an empty secret set. Note that user secrets will be stored in the workspace_builds table in provisioner_state with other Terraform state (including other sensitive data).
This commit is contained in:
@@ -591,6 +591,26 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch user secrets for build-time injection, but only on start
|
||||
// transitions where the workspace actually needs them.
|
||||
var userSecrets []*sdkproto.UserSecretValue
|
||||
if workspaceBuild.Transition == database.WorkspaceTransitionStart {
|
||||
dbSecrets, err := s.Database.ListUserSecretsWithValues(ctx, owner.ID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get user secrets: %s", err))
|
||||
}
|
||||
for _, secret := range dbSecrets {
|
||||
if secret.EnvName == "" && secret.FilePath == "" {
|
||||
continue
|
||||
}
|
||||
userSecrets = append(userSecrets, &sdkproto.UserSecretValue{
|
||||
EnvName: secret.EnvName,
|
||||
FilePath: secret.FilePath,
|
||||
Value: []byte(secret.Value),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
transition, err := convertWorkspaceTransition(workspaceBuild.Transition)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("convert workspace transition: %s", err))
|
||||
@@ -773,7 +793,8 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
|
||||
TaskPrompt: task.Prompt,
|
||||
TemplateVersionModulesFile: versionModulesFile,
|
||||
},
|
||||
LogLevel: input.LogLevel,
|
||||
LogLevel: input.LogLevel,
|
||||
UserSecrets: userSecrets,
|
||||
},
|
||||
}
|
||||
case database.ProvisionerJobTypeTemplateVersionDryRun:
|
||||
|
||||
Reference in New Issue
Block a user