{"record":{"id":"fa1c24d655d9704b","repo":"kubernetes/kops","slug":"failed-to-get-bootstrap-data-secret-w","errorCode":null,"errorMessage":"failed to get bootstrap data secret: %w","messagePattern":"failed to get bootstrap data secret: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/controllers/clusterapi/kopsconfig_controller.go","lineNumber":161,"sourceCode":"\tparentAPIVersion, parentKind := parent.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind()\n\tsecret.OwnerReferences = []metav1.OwnerReference{\n\t\t{\n\t\t\tAPIVersion: parentAPIVersion,\n\t\t\tKind:       parentKind,\n\t\t\tName:       parent.GetName(),\n\t\t\tUID:        parent.GetUID(),\n\t\t\tController: pointer.Bool(true),\n\t\t},\n\t}\n\n\tvar existing corev1.Secret\n\tif err := r.client.Get(ctx, secretName, &existing); err != nil {\n\t\tif apierrors.IsNotFound(err) {\n\t\t\tif err := r.client.Create(ctx, secret); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create bootstrap data secret for KopsConfig %s/%s: %w\", parent.GetNamespace(), parent.GetName(), err)\n\t\t\t}\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"failed to get bootstrap data secret: %w\", err)\n\t\t}\n\t} else {\n\t\t// TODO: Verify that the existing secret \"matches\"\n\t\tklog.Warningf(\"TODO: verify that the existing secret matches our expected value\")\n\t}\n\n\tparent.Status.DataSecretName = pointer.String(secret.Name)\n\tparent.Status.Ready = true\n\t// conditions.MarkTrue(scope.Config, bootstrapv1.DataSecretAvailableCondition)\n\treturn nil\n}\n\nfunc (r *KopsConfigReconciler) buildBootstrapData(ctx context.Context, cluster *kopsapi.Cluster, kopsControlPlane *capikops.KopsControlPlane) ([]byte, error) {\n\twellKnownAddresses := model.WellKnownAddresses{}\n\tfor _, systemEndpoint := range kopsControlPlane.Status.SystemEndpoints {\n\t\tswitch systemEndpoint.Type {\n\t\tcase capikops.SystemEndpointTypeKopsController:\n\t\t\twellKnownAddresses[wellknownservices.KopsController] = append(wellKnownAddresses[wellknownservices.KopsController], systemEndpoint.Endpoint)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/controllers/clusterapi/kopsconfig_controller.go#L143-L179","documentation":"This error wraps any failure from the controller-runtime client Get when reading the bootstrap-data Secret named after the KopsConfig object (pkg/controllers/clusterapi/kopsconfig_controller.go:155-161). It is thrown only when the Get fails for a reason OTHER than NotFound (NotFound is handled by creating the secret instead), so it indicates the API server rejected or failed the read. The controller cannot proceed to store bootstrap data, and Reconcile returns the error to trigger a retry with backoff.","triggerScenarios":"The Get of Secret <namespace>/<kopsconfig-name> fails with a non-NotFound error: RBAC denial (no get permission on secrets), API server connection errors/timeouts, the secret exists but cannot be read (e.g. too large, corrupted), context cancellation during reconcile, or webhook/authorizer failures.","commonSituations":"Operators deploying the kops cluster-api controllers without the kubebuilder-generated RBAC for secrets; an API server outage or network partition in the management cluster; reconcile running with an expired or revoked service-account token; a security policy (e.g. PSA restricted, admission webhook) blocking secret reads.","solutions":["Check RBAC: ensure the controller's ServiceAccount has get/list on secrets in the KopsConfig namespace (see the +kubebuilder:rbac markers; verify with kubectl auth can-i get secrets --as=system:serviceaccount:<ns>:<sa>).","Check API server health and connectivity from the controller pod (kubectl get --raw /healthz from an exec, or inspect controller logs for connection refused/timeout).","Inspect the wrapped error text after 'failed to get bootstrap data secret:' to identify the exact cause (forbidden vs timeout vs context canceled).","If errors are transient (timeouts), they will be retried by controller-runtime; verify the error clears rather than modifying data.","If a mutating admission webhook intercepts Secrets, verify it is not rejecting or delaying GET-related operations and is reachable."],"exampleFix":"// before: controller RBAC missing secrets read\n// (manifest omits ClusterRole rule)\n// after\nrules:\n- apiGroups: [\"\"]\n  resources: [\"secrets\"]\n  verbs: [\"create\", \"get\", \"list\", \"watch\", \"patch\", \"update\"]","handlingStrategy":"try-catch","validationCode":"// Go: pre-check secret read access before relying on the controller\nerr := r.client.Get(ctx, secretName, &existing)\nif err != nil && !apierrors.IsNotFound(err) {\n\t// surface wrapped cause early\n}\n// CLI RBAC pre-check:\n// kubectl auth can-i get secret <name> -n <ns> --as=system:serviceaccount:<ns>:<sa>","typeGuard":"// Go: classify the error before reacting\nfunc isRealSecretError(err error) bool {\n\treturn err != nil && !apierrors.IsNotFound(err) // NotFound is handled by Create path\n}","tryCatchPattern":"if err := r.storeBootstrapData(ctx, obj, data); err != nil {\n\tif apierrors.IsForbidden(err) {\n\t\t// fix RBAC (RoleBinding) rather than retrying\n\t\treturn ctrl.Result{}, fmt.Errorf(\"fix secrets RBAC: %w\", err)\n\t}\n\t// transient API server errors: let controller-runtime retry with backoff\n\treturn ctrl.Result{}, err // requeue\n}","preventionTips":["Ship the kubebuilder-generated ClusterRole with secrets get/create/update permissions and keep it in sync with code markers.","Monitor controller logs for 'failed to get bootstrap data secret' and alert on non-NotFound variants.","Verify API server health and network policy between controller pod and API server before deploying.","Run the controller with a dedicated ServiceAccount and validate its permissions in CI (kubectl auth can-i).","Avoid admission webhooks on Secret GET paths that could block controller reads."],"tags":["kubernetes","rbac","secret","controller-runtime","bootstrap-data"],"backgroundTag":"kubernetes-api-forbidden","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}