Repository navigation
Releases: coder/coder-k8s
Release list
v0.1.5
This release turns on two kinds: CoderAIGatewayKey and CoderMCPServer. The operator now creates, rotates and deletes Coder AI Gateway keys, and it manages MCP server configs that Coder chats use. It also cleans up better. A CoderControlPlane now waits for the keys, AI providers and MCP servers that use it while you delete them, so their deletes reach Coder. A cleanup record is a ConfigMap that the operator writes before each AI provider or key create. It lets the operator delete what a namespace deletion left in Coder, when a control plane on the same Coder database comes back. Read the upgrade notes before you upgrade. The first step needs an action from you.
Upgrade notes
-
Apply the CRDs and RBAC before or together with the new image (#346, #374, #381). This release adds the
CoderAIGatewayKeyandCoderMCPServerCRDs, new ClusterRole rules, and two new objects incoder-system: the Rolemanager-roleand the RoleBindingcoder-k8s-cleanup-records. From a clone of v0.1.5, run:kubectl apply -f config/crd/bases/ -f config/rbac/
Or apply
dist/install.yamlfrom v0.1.5. The operator watches every kind that it reconciles, so the manager does not start without the two new CRDs. Without the Role and the RoleBinding, the operator cannot write cleanup records. Then it creates no AI provider and no key, and existingCoderAIProviderobjects stop syncing. Check both objects:kubectl -n coder-system get role manager-role kubectl -n coder-system get rolebinding coder-k8s-cleanup-records
If you run the operator in another namespace, change the namespace of both objects.
-
Delete the AI providers that v0.1.4 left in Coder by hand (#374, #375). In v0.1.4, a namespace deletion or a provider deleted after its control plane left the provider in Coder in some cases. v0.1.4 wrote no cleanup records, so this release cannot find those providers. Search the v0.1.4 operator logs for
Releasing the finalizer without a delete in Coder: the provider can stay in the Coder database, which names the provider ID. Then open AI settings > Providers (/ai/settings/providers) as an owner, and delete each provider that noCoderAIProviderobject uses. ACoderAIProviderthat still exists gets its record at its first reconcile that reaches Coder. -
Do not give other users write access to ConfigMaps in
coder-system(#374). A cleanup record names the Coder provider ID or the key name prefix that a sweep deletes. A user who can write these ConfigMaps can point a sweep at other Coder resources. Find the records withkubectl -n coder-system get configmaps -l coder.com/cleanup-record. -
Expect slower control plane deletes (#362, #384). A
CoderControlPlanedelete can now take up to about 15 minutes while its keys, providers and MCP servers delete. Before, it went at once. See "Changed behavior". -
Delete keys, providers and MCP servers before their namespace. This advice does not change. A namespace deletion removes Coder's pods at once, so the operator cannot delete these objects in Coder at that time.
New
CoderAIGatewayKey(#341, #346, #370). This is the first release that runs this kind. One object keeps one Coder AI Gateway key in a Secret that the object owns. The operator creates the key, rotates it (every 30 days by default), deletes replaced keys after a grace period (1 hour by default), and deletes every key of the object when you delete the object. The control plane must opt in withspec.aiGateway.allowKeys: true. Without it, the object stalls withNotAllowed. An object that never created a key makes no Coder call. You need a Coder Premium license with the AI Gateway enabled, and the operator user must be a site owner. A gateway key is a full-trust credential. Grant write access tocoderaigatewaykeys, and read access to the output Secrets, only to principals that can hold that power. The guide is Manage AI Gateway keys.- Key names. The operator names its keys
ck8s-<UID>-<serial>, where<UID>is the object'smetadata.uidwithout dashes. The operator and the sweep delete keys with this prefix. Do not give your own keys names that start this way. - Only Coder's own
404proves that a key is gone. A404from a proxy makes the operator retry (#341).
- Key names. The operator names its keys
CoderMCPServer(#330, #356, #360, #363, #366, #368, #381). This is the first release that runs this kind. One object manages one MCP server config in a Coder organization (AI settings > MCP servers). Coder chats then offer its tools to the model. The control plane must list the organizations inspec.mcpServers.organizations. Without it, the object stalls withMCPServersNotAllowed. You need Coder v2.37.2 or later, and the operator user must be a site owner. The guide is Manage MCP servers.- Kill switches. The operator disables the server in Coder when the credential Secret withdraws consent, or when the control plane withdraws its opt-in. A disable in the dashboard stalls the object with
DisabledExternally. A spec edit enables the server again. - Access.
spec.accesslists groups. When a listed group does not exist in Coder, the operator removes the access of unlisted groups and of users, and adds no group. - Deletion. Deleting the object deletes the config in Coder.
- Kill switches. The operator disables the server in Coder when the credential Secret withdraws consent, or when the control plane withdraws its opt-in. A disable in the dashboard stalls the object with
- Opt-in status admission policy for
CoderMCPServer(#377).config/admission/status-operator-only.yamlholds aValidatingAdmissionPolicyand its binding. Only the operator ServiceAccount can then writecodermcpservers/status, and cluster admins are denied too. The install bundle does not apply it. Apply it withkubectl apply -f config/admission/. It needs Kubernetes v1.30 or later, whereValidatingAdmissionPolicyis GA. It hard-codes the usersystem:serviceaccount:coder-system:coder-k8s. If the operator runs as another ServiceAccount or in another namespace, edit the expression first, or the operator cannot write status. - GitOps health rules for
CoderMCPServer(#383).config/gitops/argocd-health-codermcpserver.luais for Argo CD.config/gitops/flux-healthcheck-codermcpserver.yamlis for a Flux v2.5+ Kustomization withspec.wait: true. - Cleanup records and the sweep (#374, #375, #385, #386). Before each AI provider or key create, the operator writes a ConfigMap
ck8s-cleanup-<object UID>in its own namespace (coder-system). The labelcoder.com/cleanup-recordholds the kind (CoderAIProviderorCoderAIGatewayKey). The record holds no secret. It names the object, the Coder deployment ID from/api/v2/buildinfo, and the provider ID or the key name prefix. If the operator cannot write the record, it sends no create.- When an object goes without a delete in Coder, for example in a namespace deletion, the record stays. The leftovers stay valid in Coder until the sweep deletes them.
- The sweep runs when a ready
CoderControlPlanein the same namespace reaches the same Coder deployment again, which means the same Coder database. It matches by deployment ID, never by URL or name. The operator user of that control plane must be a site owner. - A new Coder database behind the same URL is never swept. A control plane in another namespace never sweeps a record either.
- The counter
coder_k8s_cleanup_records_swept_total{kind}counts swept records. When no ready control plane reaches a record's deployment, the gaugecoder_k8s_cleanup_records_unmatched{kind}counts the record. The operator also writes aNoMatchingDeploymentWarning Event on the ConfigMap every 10 minutes.
- New metric
coder_k8s_cleanup_released_without_delete_total{kind}(#362). It counts eachCoderAIGatewayKeyorCoderAIProviderfinalizer that went without a delete in Coder.
Changed behavior
- A deleted
CoderControlPlanewaits for the objects that use it (#362, #384, #385). This applies whileCoderAIGatewayKey,CoderAIProviderorCoderMCPServerobjects that reference the control plane are being deleted.- The control plane keeps its finalizer for up to 10 minutes, so Coder keeps running. The objects delete in Coder as usual, with retries.
- After the 10 minutes, the remaining objects get at most 5 more minutes for one last delete attempt. So a control plane delete can take up to about 15 minutes. Before, it went at once.
- A key or MCP server delete attempt that runs during the wait stops at the end of the wait.
- T...
v0.1.4
This release turns on the CoderAIProvider kind. The operator now creates, syncs, disables and deletes AI providers in Coder from Kubernetes objects. It also hardens how the operator handles credentials. The operator no longer follows redirects to another origin with the operator token. It refuses more Secrets as credentials, and it uses the operator token Secret only when the control plane owns it. Aggregated API errors no longer show the Coder URL. CoderTemplateTest no longer gets stuck after two no-effect create answers, and no longer gives up too early on an uncertain create. Read the upgrade notes before you upgrade. Several items need an action from you.
Security
- No cross-origin redirects with the operator token (#230, #293, #297, #306). The bootstrap client, the license and entitlements client and the aggregated API server's Coder client now follow a redirect only to the same scheme, host and port. A redirect to another origin fails the call, so the operator never sends
Coder-Session-Tokenthere. This also covers the websocket that streams workspace build logs (coderworkspaces/log?follow=true). Same-origin redirects still work. The log line saysrefusing redirect to a different origin than the coder URL, orrefusing request to a different origin than the coder URLfor a refused websocket request. - More Secrets are refused as credentials (#258, #271, #282).
CoderWorkspaceProxy,CoderProvisionerandCoderAIProvidernow refuse every Secret that the spec of aCoderControlPlanein the same namespace references. This coversspec.licenseSecretRef,spec.database.connectionSecretRef,spec.extraEnvsecretKeyRefs,spec.envFromsecretRefs,spec.imagePullSecrets,spec.tls.secretNames,spec.expose.ingress.tls,spec.certs.secretsand the Secret sources ofspec.volumes. Before, of a control plane's Secrets, the operator refused only its operator token Secret. - The operator token Secret must be owned (#238). A
CoderControlPlanenow uses its operator token Secret only when the control plane is the Secret's controller owner. It no longer takes over an existing Secret with that name. - Aggregated API errors hide Coder details (#281, #291). Error messages no longer show the Coder URL, the request path, Coder's IP address or Coder's internal error text. This covers
403,409,5xx, unexpected statuses and network errors. Status codes do not change. The full Coder error stays in the server log (coder-errorslogger). - Provider IDs are checked before every Coder call (#325). The
CoderAIProvidercontroller sends no request whenstatus.providerIDis not a canonical, lowercase, non-nil UUID. It logs anassertion failed:error instead.
Upgrade notes
- Apply the CRDs and RBAC before or together with the new image (#315). This release adds the
CoderAIProviderCRD, new RBAC rules and newCoderControlPlanefields. Applyconfig/crd/bases/andconfig/rbac/from v0.1.4, or applydist/install.yamlfrom v0.1.4. The operator watches every kind it reconciles, so the manager fails to start if theCoderAIProviderCRD is missing. - Check your operator token Secrets before you upgrade (#238). A control plane whose operator token Secret (
spec.operatorAccess.generatedTokenSecretName, default<name>-operator-token) has another owner, or no owner, stops using operator access. Provisioners, template tests,CoderAIProviderobjects and the aggregated API server then stop working for that control plane. The conditionOperatorTokenSecretOwned=Falsewith the reasonTokenSecretNotOwnedreports it. Secrets that an earlier version used already have the right owner. The usual cause is a control plane that was deleted with--cascade=orphanand created again. Operator token Secret has a command that lists unowned Secrets. To fix one, delete the leftover Secret so the controller creates a new one, or setgeneratedTokenSecretNameto a free name. - Move proxy and provisioner credentials out of control plane Secrets (#258, #271). A
CoderWorkspaceProxyorCoderProvisionerthat references a Secret that a control plane spec also references now reportsCredentialsReady=Falsewith the reasonCredentialRefused. It keeps its last applied Deployment, but the operator does not apply its spec changes. Store the credential in its own labeled and annotatedOpaqueSecret, and point the reference at that Secret. Configure credential Secrets has a command that lists the affected resources. - Turn off
CODER_REDIRECT_TO_ACCESS_URLon control planes (#293). WithCODER_REDIRECT_TO_ACCESS_URL=true(or--redirect-to-access-url) on aCoderControlPlane, every operator call to Coder fails withrefusing redirect to a different origin than the coder URL: the license, provisioner key, aggregated API,CoderTemplateTestandCoderAIProvidercalls. These calls also failed before, because the redirect drops the API path. To send browsers from HTTP to HTTPS, set the redirect in your Ingress, Gateway or load balancer instead. Withspec.bootstrapon a proxy,spec.bootstrap.coderURLmust be the final origin that answers without a redirect (#230). - Expect plain HTTP inside the cluster when built-in TLS is on (#273). With
spec.tls.secretNames, the provisioner key calls and the aggregated API server now call the control plane Service athttp://<control plane>.<namespace>.svc.cluster.local:<port>, not atstatus.url. The control-plane controller andCoderTemplateTestalready did this. The operator token crosses the cluster network without TLS. Use a service mesh if you need encryption inside the cluster. Use aNetworkPolicyto limit which pods can reach the control plane Service. Allow the operator and aggregated API server pods to reach the control plane Service HTTP port. Provisioner pods still connect tostatus.url. - Remove unsupported list options from
codertemplatesrequests (#234). AcodertemplatesLIST now applies label and field selectors. AcodertemplatesLIST now returns400forcontinue, forresourceVersionMatch, and for a field selector on any field other thanmetadata.nameandmetadata.namespace. Templates have no labels, so a label selector that requires a label returns no templates. Before, the server ignored them and returned every template.limitis still ignored, and anyresourceVersionis accepted. Akubectl apply --prune -l ...overcodertemplatesnow sees only the matching templates. - Check provisioner key cleanup (#248). When you delete a
CoderProvisioner, the operator now deletes only the Coder key recorded instatus.organizationIDandstatus.provisionerKeyID. When the status has no key, the operator removes the finalizer without a call to Coder. If the status lost its key IDs, delete the key in Coder by hand (coder provisioner keys list --org <organization>). - Grant write access to
CoderAIProvideronly to Coder owners (#315). The operator calls Coder as a site owner. Givecreate,update,patchanddeleteoncoderaiprovidersonly to principals that can act as a Coder owner for AI providers in the whole deployment. Such a principal can use any opted-in credential Secret in the namespace, toward the origins that the Secret lists. A delete deletes the provider in Coder for every user. - Check your Coder version (#315, #345).
CoderAIProviderneeds Coder v2.37.2 or later. The CI E2E tests of coder-k8s v0.1.4 run against Coder v2.37.2. coder-k8s still uses the Coder SDK v2.37.3.
Added
CoderAIProvider(#235, #245, #253, #265, #276, #283, #298, #302, #303, #310, #312, #315). This newcoder.com/v1alpha1kind manages one AI provider in Coder. The object name is the Coder provider name, and it cannot be a UUID.spec.type(openai,anthropic,azure,google,openai-compat,openrouterorvercel) andspec.controlPlaneRefcannot change. The operator creates the provider and keeps its settings and API key equal to the spec. It reads the key fromspec.apiKeySecretRef, a credential Secret that lists the origin o...
v0.1.3
This release adds template versions, workspace build logs, workspace start and stop, template promotion and rollback, and the new CoderTemplateTest kind. It also adds credential consent checks for CoderWorkspaceProxy and CoderProvisioner, and kube-apiserver now verifies the certificate of the aggregated API server. Read the upgrade notes before you upgrade. Several items need an action from you.
Security
-
Credential consent checks for
CoderWorkspaceProxyandCoderProvisioner(GHSA-v37g-f2wp-qqg4, #225). The operator now uses a Kubernetes Secret only when the Secret is marked as a credential for the destination that receives it:- The Secret has the label
coder.com/credential: "true". - Its annotation
coder.com/credential-destinationslists the origin (scheme://host[:port]) that receives the value. - It has type
Opaque. The value is not empty, is at most 8 KiB, and has no leading or trailing whitespace.
The operator refuses Secrets that it generates itself, and it reads and updates a generated proxy token Secret or provisioner key Secret only when the resource owns it. It refuses
extraEnvandextraArgsentries that set the URL or token that it sets itself. Proxy pods no longer get a Kubernetes service account token. The new conditionCredentialsReadyreports the result. When a check fails, the operator sends nothing to Coder and keeps the last applied Deployment. - The Secret has the label
-
Go 1.26.9 and
golang.org/x/netv0.60.0 (#222). This fixes 12 Go advisories thatgovulncheckreported as called by coder-k8s code. They are in the HTTP/1 and HTTP/2 code,crypto/tls,html/templateand MIME header parsing. -
Server-side dry-run is rejected (#171). Coder has no dry-run mode.
codertemplatesandcoderworkspacesnow answer everydryRun=Allwrite (create, update, patch, server-side apply, delete) with400 BadRequest, before any request goes to Coder. -
Verified serving certificate (#140, #141). kube-apiserver now verifies the aggregated API server's certificate through the APIService
caBundle. The APIService manifest no longer setsinsecureSkipTLSVerify: true. -
Least-privilege standalone ServiceAccount (#146, #147). A standalone aggregated API server now runs as
coder-k8s-apiserver, withoutmanager-role.
Upgrade notes
-
Label and annotate the Secrets that proxies and provisioners use (#225). Before you upgrade, follow Configure credential Secrets for proxies and provisioners (
docs/how-to/workspace-proxy-credentials.md). The page hasjqand shell checks that list every Secret and setting that needs a change. In short:-
Label and annotate every referenced Secret. This covers
spec.proxySessionTokenSecretRef,spec.bootstrap.credentialsSecretRefandspec.extraEnv[].valueFrom.secretKeyRefonCoderWorkspaceProxy, andspec.extraEnv[].valueFrom.secretKeyRefonCoderProvisioner:kubectl -n <ns> label secret <name> coder.com/credential=true kubectl -n <ns> annotate secret <name> coder.com/credential-destinations=https://coder.example.com
-
A proxy that uses the operator token Secret as
spec.bootstrap.credentialsSecretRefneeds a dedicated Coder token in its own Secret. -
With
spec.bootstrap, the bootstrap credentials Secret must exist on every reconcile. Recreate it if you deleted it after the first registration. -
A generated proxy token Secret (default
<proxy>-proxy-token) or provisioner key Secret (default<provisioner>-provisioner-key) must not exist yet, or the resource must own it. Otherwise delete it, or set a new name. For a provisioner, the operator then creates a new provisioner key. A Secret that an earlier version already adopted has the resource as its owner and stays in use. -
Remove
extraEnvandextraArgsentries that the operator sets itself. ForCoderWorkspaceProxythese areCODER_PRIMARY_ACCESS_URL,CODER_PROXY_SESSION_TOKEN,--primary-access-urland--proxy-session-token. ForCoderProvisionerthese areCODER_URL,CODER_PROVISIONER_DAEMON_KEY,--urland--key. -
Proxy pods no longer get a service account token. A custom proxy image that reads the Kubernetes API needs a change. Each proxy that passes the checks rolls out one time after the upgrade.
-
After the upgrade, check that every proxy and provisioner reports
CredentialsReady=True. A resource that fails a check keeps running with its last applied Deployment, but the operator does not apply its spec changes until you fix the cause.CredentialsReady=Falseuses one of these reasons:CredentialSecretNotFound,CredentialKeyMissing,CredentialNotOptedIn,CredentialDestinationNotAllowed,CredentialRefused,CredentialMalformed,TokenSecretNotOwned,KeySecretNotOwnedandReservedSettingOverride. The messages name Secrets, keys, fields and origins, and never contain values.
-
-
Grant write access to
CoderWorkspaceProxy,CoderProvisionerandCoderControlPlaneonly to admins (#225). Givecreate,updateandpatchoncoderworkspaceproxies,coderprovisionersandcodercontrolplanesonly to principals that can already read Secrets and create Pods in that namespace. A customspec.imageruns with everything the pod receives, including the proxy token or provisioner key and everyextraEnvvalue. The checks in this release do not restrict the image. -
Apply the CRDs and RBAC before or together with the new image (#210, #213). This release adds the
CoderTemplateTestCRD and newCoderControlPlanefields (spec.templateTests). Applyconfig/crd/bases/andconfig/rbac/from v0.1.3, or applydist/install.yamlfrom v0.1.3. The operator watches every kind it reconciles, so the manager does not start if theCoderTemplateTestCRD is missing. -
Move the aggregated API server to the managed serving CA (#140, #141, #146). In a Pod, the server now serves a certificate signed by its own CA. It keeps the CA in the Secret
coder-system/coder-k8s-apiserver-tlsand puts the CA into the APIServicecaBundle. Apply the changes in this order:kubectl apply -f config/rbac/. This includesconfig/rbac/apiservice-cabundle-role.yaml, which lets the server patch its own APIService.- Deploy the new image. It sets
caBundleand turnsinsecureSkipTLSVerifyoff in one step. kubectl apply -f deploy/apiserver-apiservice.yaml. The file no longer setsinsecureSkipTLSVerify.
If you apply step 3 before the new image runs, requests through kube-apiserver fail with
503until the new image starts. Do not apply an old copy ofdeploy/apiserver-apiservice.yamlafter that. If cert-manager or a GitOps tool ownscaBundle, annotate the APIService withcoder.com/manage-ca-bundle=falsefirst. Anyone who can read thecoder-k8s-apiserver-tlsSecret can issue certificates that this CA vouches for. See Deploy the aggregated API server for rollback and CA replacement. -
Move a standalone aggregated API server to its own ServiceAccount (#146, #147). This applies only to
--app=aggregated-apiserver.--app=allanddist/install.yamldo not change. Apply the RBAC and the empty placeholder Secret, then switch the Deployment tocoder-k8s-apiserver:kubectl apply -f config/apiserver-standalone/ -f config/rbac/apiservice-cabundle-role.yaml kubectl -n coder-system patch deployment coder-k8s --type=json \ -p '[{"op": "replace", "path": "/spec/template/spec/serviceAccountName", "value": "coder-k8s-apiserver"}]'The new ServiceAccount cannot create Secrets, so the placeholder must exist before the pod starts. The server fills the placeholder. When you apply it over an existing Secret, the Secret keeps its CA.
-
Stop using server-side dry-run on
codertemplatesandcoderworkspaces(#171).kubectl diff,kubectl apply --dry-run=server,kubectl delete --dry-run=serverand the opt-in server-side diff of Argo CD now get400 BadRequestfor these resources. The default Argo CD diff and sync send no server-side dry-run. The newstart,stopandpromotesubresources support?dryRun=Allas a read-only preview. -
Check your Coder version (#163). coder-k8s now uses the Coder SDK v2.37.3. Coder v2.37 is a release on Coder's mainline channel, not the stable channel. The CI E2E tests of coder-k8s v0.1.3 run against Coder v2.37.2.
-
Grant the new permissions to the users who need them (#178, #179, #185, #187). Each new resource and subresource has its own grant. Access to
codertemplatesdoes not includecodertemplateversions. No verb oncoderworkspacesorcodertemplatesgrants the subresources, and no default role ...
v0.1.2
This release contains the security fix from v0.1.1 plus a packaging repair. The v0.1.1 release build failed before publishing, so v0.1.1 has no binaries or images; use this release.
Security
- Authentication for the aggregated API server and the MCP HTTP server (GHSA-c3vp-pjh2-7gv4, #136). In v0.1.0, both servers accepted unauthenticated requests and acted with the operator's authority, and the default
--app=allran both. The aggregated API server now authenticates and authorizes every request through Kubernetes (front-proxy certificates, TokenReview, SubjectAccessReview); anonymous callers reach only/healthz,/livezand/readyz. The MCP server no longer runs in--app=all;--app=mcp-httplistens on127.0.0.1:8090and requires a bearer token from--mcp-token-file. - Dependency updates for published advisories (#92, #101, #104, #118), and code and image security scanning in CI (#88).
Upgrade notes
- The aggregated API server needs
config/rbac/auth-delegator-binding.yamlandconfig/rbac/authentication-reader-binding.yamlfor the operator ServiceAccount (both are applied bykubectl apply -f config/rbac/). Without read access tokube-system/extension-apiserver-authenticationit does not start; without permission to create SubjectAccessReviews it denies requests. - Clients that called port
6443directly must send a Kubernetes bearer token with RBAC onaggregation.coder.com, or go through kube-apiserver (kubectl). - RBAC on
codertemplatesandcoderworkspacesis owner-equivalent inside Coder: the server calls Coder with the control plane's operator token. Grant it only to subjects you would trust as Coder owners. --app=allno longer runs MCP anddeploy/mcp-service.yamlis removed; delete the old Service. To use MCP, run--app=mcp-http --mcp-token-file=<file>and connect throughkubectl port-forward.- Outside a cluster, the aggregated API server needs
KUBECONFIG(exactly one file) or~/.kube/config.
Added
dist/install.yaml, a generated one-file install bundle for the operator in controller mode, kept fresh by CI (#89).CoderControlPlanecan reference an external PostgreSQL connection Secret (#122).- Kind E2E coverage for the
CoderWorkspacelifecycle (#114).
Fixed
CoderTemplateUpdate applies metadata only after the new source is active, and returns409 Conflictif the template changed during the import (#129).spec.filestemplate Create waits for the import before creating the template (#116).- Canonical organization, owner, template and workspace names are enforced so repeated
kubectl applyconverges (#106, #111). - Aggregated API delete preconditions are honored, and workspace
resourceVersionreflects the returned representation (#110, #115). kubectl rollout restartworks on operator-managed Deployments (#121).- Release and
:mainimage builds are unified and repaired, and tag releases no longer fail on an unsetGORELEASER_CHANNEL(#86, #87, #99, #131, #138).
Documentation
v0.1.1
Warning
The release build for this tag failed before publishing, so v0.1.1 has no binaries, archives or container images. Use v0.1.2, which contains the same fix plus the packaging repair (#138). The v0.1.1 source and Go module already include the security fix (#136).
Security
- Authentication for the aggregated API server and the MCP HTTP server (GHSA-c3vp-pjh2-7gv4, #136). In v0.1.0, both servers accepted unauthenticated requests and acted with the operator's authority, and the default
--app=allran both. The aggregated API server now authenticates and authorizes every request through Kubernetes (front-proxy certificates, TokenReview, SubjectAccessReview); anonymous callers reach only/healthz,/livezand/readyz. The MCP server no longer runs in--app=all;--app=mcp-httplistens on127.0.0.1:8090and requires a bearer token from--mcp-token-file. - Dependency updates for published advisories (#92, #101, #104, #118), and code and image security scanning in CI (#88).
Upgrade notes
- The aggregated API server needs
config/rbac/auth-delegator-binding.yamlandconfig/rbac/authentication-reader-binding.yamlfor the operator ServiceAccount (both are applied bykubectl apply -f config/rbac/). Without read access tokube-system/extension-apiserver-authenticationit does not start; without permission to create SubjectAccessReviews it denies requests. - Clients that called port
6443directly must send a Kubernetes bearer token with RBAC onaggregation.coder.com, or go through kube-apiserver (kubectl). - RBAC on
codertemplatesandcoderworkspacesis owner-equivalent inside Coder: the server calls Coder with the control plane's operator token. Grant it only to subjects you would trust as Coder owners. --app=allno longer runs MCP anddeploy/mcp-service.yamlis removed; delete the old Service. To use MCP, run--app=mcp-http --mcp-token-file=<file>and connect throughkubectl port-forward.- Outside a cluster, the aggregated API server needs
KUBECONFIG(exactly one file) or~/.kube/config.
Added
dist/install.yaml, a generated one-file install bundle for the operator in controller mode, kept fresh by CI (#89).CoderControlPlanecan reference an external PostgreSQL connection Secret (#122).- Kind E2E coverage for the
CoderWorkspacelifecycle (#114).
Fixed
CoderTemplateUpdate applies metadata only after the new source is active, and returns409 Conflictif the template changed during the import (#129).spec.filestemplate Create waits for the import before creating the template (#116).- Canonical organization, owner, template and workspace names are enforced so repeated
kubectl applyconverges (#106, #111). - Aggregated API delete preconditions are honored, and workspace
resourceVersionreflects the returned representation (#110, #115). kubectl rollout restartworks on operator-managed Deployments (#121).- Release and
:mainimage builds are unified and repaired (#86, #87, #99, #131).
Documentation
v0.1.0: Hello, coder-k8s
Added
- Initial release of
coder-k8s, a Kubernetes operator and aggregated API server for managing Coder with native Kubernetes APIs. CoderControlPlaneCRD and reconciler that deploys and manages a Coder control plane, including readiness, leader election, license reconciliation from a Secret, entitlements reporting, and bootstrap of an operator API user/token (#2, #23, #41, #49, #66, #67, #77).CoderProvisionerCRD and controller for external provisioner daemons, with rate-limit-aware backoff and entitlement gating (#43, #65, #73, #79).CoderWorkspaceProxyCRD and controller (renamed fromWorkspaceProxy) for declarative workspace proxy management (#23, #61).- Aggregated API server (
aggregation.coder.com/v1alpha1) exposingCoderWorkspaceandCoderTemplatebacked by the Coder SDK, with all-namespaces LIST across multiple control planes, WATCH support, OpenAPI/SSA integration, template source files viaspec.files, and build-promotion gating (#11, #50, #69, #70, #72, #85). - MCP HTTP server with control-plane and aggregated MCP operations for AI/operational tooling (#35, #48).
- Single-binary
coder-k8swith--app=all|controller|aggregated-apiserver|mcp-httpmodes;allis the default (#11, #53). - Deployable manifests under
deploy/, generated CRDs/RBAC, an Argo CDApplicationSetexample, and a CloudNativePG-backedCoderControlPlaneexample (#38, #75, #80). - Documentation site published to GitHub Pages with tutorials, how-tos, and an auto-generated API reference (#19, #24, #71, #78).
- Apache-2.0 license and OCI image labels on the published
:mainimage (#3, #57).
Fixed
- Best-effort SSA create-on-update fallback and GVK-mapped OpenAPI schemas so server-side apply works against the aggregated API (#82, #83, #84).
- Reduced noisy reconcile errors and corrected the CloudNativePG access URL (#44).
- Prevent MCP schema panic in the control-plane status tool (#58).
- Removed duplicate
serverarg passed to the Coder control plane (#40). - Stop generating aggregation CRDs in manifests (the aggregated API server owns those types) (#68).
- Generated RBAC is now the single source of truth (#60).