User Manual — Back to Service Discovery Back to User Manual
The Kubernetes discovery plugin helps you find DocumentDB-compatible targets running in Kubernetes clusters, including AKS, EKS, GKE, OpenShift, on-premises clusters, and local clusters such as kind, minikube, k3s, k3d, Docker Desktop, and Rancher Desktop.
You can use Kubernetes discovery from either:
For a step-by-step lab that creates a local or AKS DocumentDB cluster and tests this feature end to end, see Kubernetes Service Discovery: Getting Started and Test Lab.
The Kubernetes Clusters node lists one or more kubeconfig sources as siblings:
KUBECONFIG environment variable, or the Kubernetes default kubeconfig path in your user profile). It is created by default, but if you remove it explicitly, it stays removed until you add it again.Each source expands independently to its own contexts -> namespaces -> services subtree. Failures in one source do not affect the others.
Kubeconfig sources use one of two storage models, and the source’s hover tooltip states which one applies:
Most kubeconfigs for cloud clusters (AKS, EKS, GKE) do not embed a long-lived token; they reference an exec credential plugin that fetches a short-lived token on demand. For those, a linked source runs the plugin each time, so it always has fresh credentials, while a copy only carries the exec instructions and still depends on that helper program being installed wherever the editor runs.
The Kubernetes Clusters node has an inline + (Add Kubeconfig…) action that opens a quick pick:
$KUBECONFIG or the Kubernetes default kubeconfig path). Added as a linked source.Custom file and pasted-YAML sources are validated before they are saved. If the file or pasted YAML cannot be loaded or contains zero contexts, the source is not added and an error is shown. The Default source also validates the current default kubeconfig before it is added; if it is missing, invalid, or empty, fix the underlying KUBECONFIG value or default kubeconfig file and try again. Adding the same path twice or pasting identical YAML reuses the existing entry.
The Kubernetes default kubeconfig path is ~/.kube/config on macOS/Linux and %USERPROFILE%\.kube\config on Windows.
You can drag a kubeconfig file from your file manager (or from the VS Code Explorer) and drop it onto the Discovery view to add it as a linked file source, the same as picking it with Kubeconfig file…. You are asked to confirm, with an option to preview, before anything is imported.
When the editor runs in a remote context (WSL, SSH, Dev Containers, Codespaces), the extension can only read files on the machine where it runs. A file dropped from the Windows host into a WSL window is automatically located on the WSL drive mount (/mnt/<drive>) and linked from there when found. If the file is not reachable that way (for example a different remote host, a network share, or a web link), the drop is rejected with an explanation instead of guessing. In that case, copy the file into the editor’s filesystem (for example your WSL or remote home directory) and drop that, or use Paste kubeconfig YAML… to add its contents as a copy.
⚠️ Only add kubeconfig sources you trust. A kubeconfig is executable configuration: it can reference external credential helper programs through an
execcredential plugin (the standard mechanism used by AKS, EKS, and GKE — for examplekubelogin,aws, orgke-gcloud-auth-plugin). When you expand a source to list its contexts and namespaces, the Kubernetes client may run the command configured in that kubeconfig on your machine, with your privileges. This is the same trust model askubectl. Only add, paste, or drop a kubeconfig that comes from a source you trust; treat a kubeconfig pasted from the clipboard or dropped from disk with the same caution as any script you would run locally.
Manage each source from its right-click context menu in the discovery tree:
v Discovery
v Kubernetes Clusters
v Default kubeconfig
v aks-prod (AKS / eastus)
v app
> sample-documentdb port-forward
> Other namespaces
v team.yaml
v eks-staging
...
A context node has a view toggle that controls how the levels beneath every context are shown across the whole Kubernetes discovery (it is a global choice, surfaced on the context node so it is easy to find). The current choice is remembered between sessions.
Use the inline button on a context node, or its right-click context menu, to switch. Following the same convention as the VS Code Search view, the button’s icon reflects the current mode and its label states the action: in tree view it shows View as List, and in list view it shows View as Tree. Namespaces whose pre-scan failed stay visible in both modes so you can retry them.
Each discovered DocumentDB target appears as a cluster node using the DocumentDB icon, so it reads as a first-class cluster you can expand and connect to, just like a saved connection.
The grey text after the target name is a single connectivity word that tells you how the extension reaches the service, in other words how portable the resulting connection string is. The healthy, directly reachable case shows no word at all; a word is only shown when there is something to be aware of:
| Word | Service type / state | What it means |
|---|---|---|
| (none) | LoadBalancer with an external address | Reachable directly; the connection string is portable if that address is reachable from you. |
node-routed |
NodePort, or LoadBalancer via a node | Reached through a cluster node address; only works if that node is reachable from your machine. |
pending |
LoadBalancer awaiting an external IP | No external address assigned yet (mirrors kubectl’s EXTERNAL-IP: <pending>). |
port-forward |
ClusterIP | Reached through a local port-forward tunnel; the 127.0.0.1 string only works on this machine while the tunnel is active. |
unsupported |
ExternalName or unknown types | Not resolved automatically; connect manually using a reachable endpoint. |
Hover the target for a richer tooltip that leads with the reachability explanation and then lists the target identity, its source (a DocumentDB Kubernetes Operator resource or a generic service), the service type, port, and where it lives (provider, region, namespace, context).
Auto-generated context names from cloud CLIs (clusterUser_…, arn:aws:eks:…, gke_…) are often hard to scan. You can give a context a friendlier display name without modifying the kubeconfig file:
Prod AKS East) and press Enter. Submit an empty value to clear the alias.The alias is stored locally inside the extension. It changes only:
The kubeconfig file, the underlying Kubernetes context name, saved-connection metadata, and output-channel logs are never modified. Aliases are scoped per source, so the same context name in two different kubeconfig sources can have different aliases. If you delete a context from the kubeconfig (or remove the source), its aliases are cleaned up automatically.
The New Connection > Service Discovery > Kubernetes flow lists every context across every source in a single quick pick. Each item shows the source label in the description so colliding context names can be told apart.
After selecting a context and a target, the wizard:
ClusterIP services, prompting for a local port.If credentials cannot be read or are not configured, discovery still succeeds and the connection flow prompts you for credentials later.
Kubernetes discovery uses the following target selection order.
DocumentDB Kubernetes Operator (DKO) custom resources are discovered first. The plugin lists documentdb.io/preview dbs resources in the selected namespace and maps each resource to its backing Service.
DKO-backed Services are not duplicated by generic service fallback. DKO targets are displayed before generic targets.
If the DKO CRD is not installed in a cluster, Kubernetes discovery falls back to generic Service discovery. If the CRD exists but cannot be listed because of RBAC, authentication, or API errors, discovery surfaces the failure instead of silently showing only generic targets.
A generic Kubernetes Service can opt in to discovery with this annotation or label:
metadata:
annotations:
documentdb.vscode.extension/discovery: 'true'
or:
metadata:
labels:
documentdb.vscode.extension/discovery: 'true'
An opted-in Service is included when it has at least one TCP port. Ports with non-TCP protocols are ignored. If the Kubernetes port protocol is omitted, it is treated as TCP.
Without explicit opt-in, generic fallback includes TCP Services that expose a known DocumentDB API-compatible service or numeric target port:
27017270182701910260Services that are not DKO-backed, not explicitly opted in, and not on a known DocumentDB API-compatible port are ignored.
Credentials are passed to the extension as native username/password authentication. They are never embedded into Kubernetes-discovered connection strings and are not written to logs.
For DKO resources, the plugin reads the Secret named by:
spec:
documentDbCredentialSecret: <secretName>
If spec.documentDbCredentialSecret is not set, the plugin uses the default Secret name documentdb-credentials.
For generic Services, add a same-namespace Secret reference with this annotation:
metadata:
annotations:
documentdb.vscode.extension/credential-secret: 'my-documentdb-credentials'
The Secret name must be a valid Kubernetes DNS subdomain name. The Secret must contain username and password data keys.
apiVersion: v1
kind: Secret
metadata:
name: my-documentdb-credentials
namespace: app
stringData:
username: my-user
password: my-password
Missing, invalid, or unreadable credential Secrets do not block discovery. The extension prompts for credentials later when needed.
Kubernetes-discovered DocumentDB targets are connected to with TLS enabled but certificate validation disabled (tls=true&tlsAllowInvalidCertificates=true). The DocumentDB Kubernetes Operator (DKO) gateway commonly serves a self-signed certificate, so strict certificate verification would otherwise break the most common discovery path. With validation disabled, the connection is still encrypted in transit, but the server certificate is not verified, so it does not protect against an on-path (man-in-the-middle) attacker.
Discovered target nodes show a ⚠️ Security: TLS/SSL certificate validation disabled line in their hover tooltip so this is visible before you connect.
When you save a discovered target to the Connections view, the tlsAllowInvalidCertificates=true parameter is stored as part of the connection string. If your service presents a certificate that your machine trusts (for example, a CA-signed certificate rather than the DKO self-signed one), you can edit the saved connection and remove tlsAllowInvalidCertificates=true to re-enable certificate validation. As with local connections, it is worth investing a little time in proper certificates even outside production so security-related issues surface early.
| Kubernetes Service type | Behavior |
|---|---|
| LoadBalancer | Uses the first load balancer ingress hostname or IP. If ingress is not assigned yet, falls back to NodePort behavior when a NodePort is available. |
| NodePort | Uses node ExternalIP addresses first. If only InternalIP addresses are available, the extension warns that the endpoint may not be reachable from your machine. |
| ClusterIP | Starts a local port-forward tunnel to a ready backing pod and connects through 127.0.0.1:<localPort>. |
| ExternalName | Not resolved automatically. Use the external DNS name to connect manually. |
For ClusterIP targets the extension prompts for a local port when needed. By default, the suggested local port matches the remote service port. You can change this under DocumentDB > Service Discovery > Kubernetes > Port Forward in VS Code settings:
documentDB.serviceDiscovery.kubernetes.portForward.localPortStrategy):
documentDB.serviceDiscovery.kubernetes.portForward.localPortBase, default 27100): the starting port for the autoSelect strategy.If the final port is already in use, the extension can use an existing process on that port (such as a manually started kubectl port-forward) if you confirm.
Active tunnels are tracked and reused for the same source, context, namespace, Service, and local port. Tunnels stop automatically when the extension is disposed or when the underlying source is removed.
A connection string for a ClusterIP target points at 127.0.0.1:<localPort> and therefore only works on this machine while the tunnel is active. For sharing such a connection with a teammate, see Copy Connection String.
The current implementation uses the following Kubernetes API operations. services only requires list; service get and watch are not required.
| Purpose | API group | Resource | Verbs |
|---|---|---|---|
| List contexts’ namespaces | "" |
namespaces |
list |
| Discover Services in a selected namespace | "" |
services |
list |
| Resolve NodePort and LoadBalancer NodePort fallback addresses | "" |
nodes |
list |
| Resolve ClusterIP port-forward backend pods | "" |
endpoints |
get |
| Open ClusterIP port-forward streams | "" |
pods/portforward |
create |
| Read DKO or generic credential Secrets | "" |
secrets |
get |
| Discover DKO resources | documentdb.io |
dbs |
list |
A broad ClusterRole for all Kubernetes discovery features looks like this:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: documentdb-vscode-discovery
rules:
- apiGroups: ['']
resources: ['namespaces']
verbs: ['list']
- apiGroups: ['']
resources: ['services']
verbs: ['list']
- apiGroups: ['']
resources: ['nodes']
verbs: ['list']
- apiGroups: ['']
resources: ['endpoints']
verbs: ['get']
- apiGroups: ['']
resources: ['pods/portforward']
verbs: ['create']
- apiGroups: ['']
resources: ['secrets']
verbs: ['get']
- apiGroups: ['documentdb.io']
resources: ['dbs']
verbs: ['list']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: documentdb-vscode-discovery-binding
subjects:
- kind: User
name: <your-username>
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: documentdb-vscode-discovery
apiGroup: rbac.authorization.k8s.io
You can narrow permissions for production use. Because namespaces and nodes are cluster-scoped resources, a namespace-scoped setup usually combines a small ClusterRole for cluster-scoped reads with Roles in selected namespaces for services, endpoints, pods/portforward, secrets, and dbs.
If RBAC denies an operation, discovery surfaces the failure as a warning, retry node, or connection error instead of silently hiding the cluster.
| Symptom | What to check |
|---|---|
| A source shows a kubeconfig error | Verify the file exists or the YAML is still valid; use Refresh or remove the source and add it again. |
| No contexts under a source | Verify the kubeconfig contents; the source must declare at least one context. |
| Namespace shows no DocumentDB services | Verify a DKO dbs resource exists, add the explicit discovery annotation/label, or expose a TCP known-port service. |
| RBAC errors or retry nodes | Grant the relevant RBAC from the table above. Namespace and service list failures appear as retry/error nodes. |
| LoadBalancer target is pending | Wait for load balancer ingress, or ensure NodePort fallback is available and reachable. |
| NodePort uses an InternalIP | The address may only be reachable from inside the cluster network. Use a reachable node address or another service type if needed. |
| ClusterIP connection fails | Check that a ready backing pod appears in the Service Endpoints, that pods/portforward is allowed, and that the chosen local port is free or intentionally reused. |
| Credentials are not auto-filled | Verify the Secret name convention, namespace, RBAC secrets get, and username / password data keys. Discovery still works without auto-resolved credentials. |
The plugin identifies common cluster providers from the kubeconfig server URL, context name, or cluster name. The detected provider and region, when available, are shown in the tree description or tooltip.
| Provider | Detection method |
|---|---|
| AKS | *.azmk8s.io server URL, with region extracted when available. |
| EKS | *.eks.amazonaws.com server URL, with region extracted when available. |
| GKE | container.googleapis.com or *.gke.io server URL. |
| OpenShift | Server URL or context/cluster name contains openshift. |
| kind | Context or cluster name starts with kind-. |
| minikube | Context or cluster name contains minikube. |
| k3s / k3d | Context or cluster name contains k3s or k3d. |
| Docker Desktop | Context or cluster name contains docker-desktop or docker desktop. |
| Rancher | Context or cluster name contains rancher. |