{"record":{"id":"14aa1813abc89fa7","repo":"tailscale/tailscale","slug":"failed-to-list-config-secrets-w","errorCode":null,"errorMessage":"failed to list config Secrets: %w","messagePattern":"failed to list config Secrets: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/k8s-operator/api-server-proxy-pg.go","lineNumber":346,"sourceCode":"\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to create or update Role %s: %w\", role.Name, err)\n\t}\n\trolebinding := certSecretRoleBinding(pg, r.tsNamespace, domain)\n\tif _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, rolebinding, func(rb *rbacv1.RoleBinding) {\n\t\trb.Labels = rolebinding.Labels\n\t\trb.Subjects = rolebinding.Subjects\n\t\trb.RoleRef = rolebinding.RoleRef\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to create or update RoleBinding %s: %w\", rolebinding.Name, err)\n\t}\n\treturn nil\n}\n\nfunc (r *KubeAPIServerTSServiceReconciler) maybeAdvertiseServices(ctx context.Context, pg *tsapi.ProxyGroup, serviceName tailcfg.ServiceName, logger *zap.SugaredLogger) error {\n\t// Get all config Secrets for this ProxyGroup\n\tcfgSecrets := &corev1.SecretList{}\n\tif err := r.List(ctx, cfgSecrets, client.InNamespace(r.tsNamespace), client.MatchingLabels(pgSecretLabels(pg.Name, kubetypes.LabelSecretTypeConfig))); err != nil {\n\t\treturn fmt.Errorf(\"failed to list config Secrets: %w\", err)\n\t}\n\n\t// Only advertise a Tailscale Service once the TLS certs required for\n\t// serving it are available.\n\tshouldBeAdvertised, err := hasCerts(ctx, r.Client, r.tsNamespace, serviceName, pg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error checking TLS credentials provisioned for Tailscale Service %q: %w\", serviceName, err)\n\t}\n\tvar advertiseServices []string\n\tif shouldBeAdvertised {\n\t\tadvertiseServices = []string{serviceName.String()}\n\t}\n\n\tfor _, s := range cfgSecrets.Items {\n\t\tif len(s.Data[kubetypes.KubeAPIServerConfigFile]) == 0 {\n\t\t\tcontinue\n\t\t}\n","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/k8s-operator/api-server-proxy-pg.go#L328-L364","documentation":"Thrown by maybeAdvertiseServices when the controller-runtime client's List call fails while fetching all ProxyGroup config Secrets (label selector built by pgSecretLabels(pg.Name, kubetypes.LabelSecretTypeConfig)) in the operator namespace. The reconciler needs these Secrets to patch the advertise-services list in each proxy's config. The %w is the API server's List error.","triggerScenarios":"r.List(ctx, cfgSecrets, client.InNamespace(r.tsNamespace), client.MatchingLabels(...)) fails when the operator ServiceAccount cannot list secrets with that label selector in the namespace, the namespace was deleted/renamed (operator installed with a different --namespace than its RBAC covers), or the API server errors on the watch-backed list.","commonSituations":"Operator deployed to a non-default namespace but its Role granting secrets list only exists in the old namespace; least-privilege RBAC tuned down to get-only (no list verb); label-selector optimizations requiring the secrets resource name in RBAC (list secrets with fieldSelector/labelSelector needs 'list' on 'secrets'); transient API server or etcd issues.","solutions":["Check the wrapped error verb/URL; test with kubectl auth can-i list secrets -n <operator-namespace> --as=system:serviceaccount:<ns>:operator.","Ensure the operator's namespaced Role in its installation namespace includes verbs [list, get, watch] on secrets.","Confirm the operator Pod's ACTAILSCALE_OPERATOR_NAMESPACE / install namespace matches where the ProxyGroup resources are created by the operator.","Retry after API server recovery; the reconciler requeues on error automatically.","Look for network policies blocking the operator Pod's egress to the Kubernetes API."],"exampleFix":"# before: Role allows only reading named secrets\n- apiGroups: [\"\"]\n  resources: [\"secrets\"]\n  resourceNames: [\"proxygroup-foo-0\"]\n  verbs: [\"get\"]\n\n# after: allow listing operator-managed config secrets\n- apiGroups: [\"\"]\n  resources: [\"secrets\"]\n  verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]","handlingStrategy":"retry","validationCode":"// kubectl auth can-i list secrets -n <operator-ns> \\\n//   --as=system:serviceaccount:<operator-ns>:operator\n// expected output: yes","typeGuard":"func isListDenied(err error) bool {\n\tvar status *apierrors.StatusError\n\tif errors.As(err, &status) {\n\t\treturn status.ErrStatus.Reason == metav1.StatusReasonForbidden\n\t}\n\treturn false\n}","tryCatchPattern":"if err := r.List(ctx, cfgSecrets, client.InNamespace(r.tsNamespace), client.MatchingLabels(sel)); err != nil {\n\tif isListDenied(err) {\n\t\tlogger.Error(\"cannot list config Secrets — fix operator Role (verbs: list,watch on secrets)\")\n\t}\n\treturn ctrl.Result{}, err // transient API errors retried with backoff\n}","preventionTips":["Keep list+watch on secrets in the operator's namespaced Role even under least-privilege reviews.","Pin the operator install namespace and never move it without re-applying RBAC.","Label all operator-owned Secrets and never rely on external writers for them.","Monitor operator events; repeated list failures indicate RBAC drift before user-facing breakage."],"tags":["kubernetes","rbac","secrets","operator","api-server-proxy"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}