diff --git a/lib/services/access_request.go b/lib/services/access_request.go index e48ba7b657358..ddb6f3c6f1968 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -58,6 +58,8 @@ const ( // requestTTL is the TTL for an access request, i.e. the amount of time that // the access request can be reviewed. Defaults to 1 week. requestTTL = 7 * day + + InvalidKubernetesKindAccessRequest = "Not allowed to request Kubernetes resource kind" ) // ValidateAccessRequest validates the AccessRequest and sets default values @@ -1297,12 +1299,12 @@ func enforceKubernetesRequestModes(requestedResourceIDs []types.ResourceID, requ for _, id := range requestedResourceIDs { if id.Kind == types.KindKubernetesCluster { - return trace.BadParameter("Not allowed to request Kubernetes resource kind %q. Allowed kinds: %v.", types.KindKubernetesCluster, slices.Collect(maps.Keys(allowedKindsLookup))) + return trace.BadParameter("%s %q. Allowed kinds: %v.", InvalidKubernetesKindAccessRequest, types.KindKubernetesCluster, slices.Collect(maps.Keys(allowedKindsLookup))) } // Filter for kube resources. if slices.Contains(types.KubernetesResourcesKinds, id.Kind) { if _, found := allowedKindsLookup[id.Kind]; !found { - return trace.BadParameter("Not allowed to request Kubernetes resource kind %q. Allowed kinds: %v.", id.Kind, slices.Collect(maps.Keys(allowedKindsLookup))) + return trace.BadParameter("%s %q. Allowed kinds: %v.", InvalidKubernetesKindAccessRequest, id.Kind, slices.Collect(maps.Keys(allowedKindsLookup))) } } } diff --git a/lib/services/access_request_test.go b/lib/services/access_request_test.go index 7ce3f59802874..72f74c2ad42be 100644 --- a/lib/services/access_request_test.go +++ b/lib/services/access_request_test.go @@ -2571,7 +2571,7 @@ func TestValidate_WithKubernetesRequestMode(t *testing.T) { "request-mode-namespace": { Options: types.RoleOptions{ RequestMode: &types.AccessRequestMode{ - KubernetesResources: []types.KubernetesResource{ + KubernetesResources: []types.RequestModeKubernetesResource{ {Kind: types.KindKubeNamespace}, }, }, @@ -2581,7 +2581,7 @@ func TestValidate_WithKubernetesRequestMode(t *testing.T) { "request-mode-wildcard": { Options: types.RoleOptions{ RequestMode: &types.AccessRequestMode{ - KubernetesResources: []types.KubernetesResource{ + KubernetesResources: []types.RequestModeKubernetesResource{ {Kind: types.Wildcard}, }, }, @@ -2591,7 +2591,7 @@ func TestValidate_WithKubernetesRequestMode(t *testing.T) { "request-mode-pods": { Options: types.RoleOptions{ RequestMode: &types.AccessRequestMode{ - KubernetesResources: []types.KubernetesResource{ + KubernetesResources: []types.RequestModeKubernetesResource{ {Kind: types.KindKubePod}, }, }, @@ -2720,7 +2720,7 @@ func TestValidate_WithKubernetesRequestMode(t *testing.T) { err = validator.Validate(context.Background(), req, identity) if tc.wantErr { require.Error(t, err) - require.Contains(t, err.Error(), "Not allowed to request Kubernetes resource") + require.Contains(t, err.Error(), InvalidKubernetesKindAccessRequest) } else { require.NoError(t, err) } diff --git a/tool/tsh/common/tsh.go b/tool/tsh/common/tsh.go index c91b333784541..1b3ca1e5589fb 100644 --- a/tool/tsh/common/tsh.go +++ b/tool/tsh/common/tsh.go @@ -2625,6 +2625,10 @@ func executeAccessRequest(cf *CLIConf, tc *client.TeleportClient) error { req, err = clt.CreateAccessRequestV2(cf.Context, req) return trace.Wrap(err) }); err != nil { + if strings.Contains(err.Error(), services.InvalidKubernetesKindAccessRequest) { + friendlyMsg := fmt.Sprintf("%s\nTry searching for specific kinds with:\n> tsh request search --kube-cluster=KUBE_CLUSTER_NAME --kind=KIND", err.Error()) + return trace.BadParameter(friendlyMsg) + } return trace.Wrap(err) } cf.RequestID = req.GetName()