Pass k8s api group around. (#54760)

* Pass the api group around. Set the default value as wildcard. No behavior/logic change.

* Revert presets back to v7 to pass the merge queue tests.
This commit is contained in:
Guillaume J. Charmes
2025-05-22 23:38:27 +00:00
committed by GitHub
parent d9a78d08c3
commit 2c73757c8b
29 changed files with 358 additions and 233 deletions
+1 -1
View File
@@ -1593,7 +1593,7 @@ protos-up-to-date/host: must-start-clean/host grpc/host
.PHONY: must-start-clean/host
must-start-clean/host:
@if ! git diff --quiet; then \
@echo 'This must be run from a repo with no unstaged commits.'; \
echo 'This must be run from a repo with no unstaged commits.'; \
git diff; \
exit 1; \
fi
+1
View File
@@ -1196,6 +1196,7 @@ func (r *RoleV6) CheckAndSetDefaults() error {
Namespace: Wildcard,
Name: Wildcard,
Verbs: []string{Wildcard},
APIGroup: Wildcard,
},
}
}
+1
View File
@@ -197,6 +197,7 @@ func withFullKubeAccessUserRole(t *testing.T) testOptionsFunc {
Name: types.Wildcard,
Namespace: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
+18 -3
View File
@@ -1,7 +1,7 @@
{
"access": {
"kind": "role",
"version": "v8",
"version": "v7",
"metadata": {
"name": "access",
"description": "Access cluster resources",
@@ -25,6 +25,11 @@
"desktop_directory_sharing": true,
"pin_source_ip": false,
"ssh_file_copy": true,
"idp": {
"saml": {
"enabled": true
}
},
"create_desktop_user": false,
"create_db_user": false,
"ssh_port_forwarding": {
@@ -147,7 +152,7 @@
},
"auditor": {
"kind": "role",
"version": "v8",
"version": "v7",
"metadata": {
"name": "auditor",
"description": "Review cluster events and replay sessions",
@@ -171,6 +176,11 @@
"desktop_directory_sharing": true,
"pin_source_ip": false,
"ssh_file_copy": true,
"idp": {
"saml": {
"enabled": true
}
},
"create_desktop_user": false,
"create_db_user": false
},
@@ -266,7 +276,7 @@
},
"editor": {
"kind": "role",
"version": "v8",
"version": "v7",
"metadata": {
"name": "editor",
"description": "Edit cluster configuration",
@@ -290,6 +300,11 @@
"desktop_directory_sharing": true,
"pin_source_ip": false,
"ssh_file_copy": true,
"idp": {
"saml": {
"enabled": true
}
},
"create_desktop_user": false,
"create_db_user": false,
"ssh_port_forwarding": {
+15 -14
View File
@@ -222,7 +222,7 @@ func testExec(t *testing.T, suite *KubeSuite, pinnedIP string, clientError strin
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -433,7 +433,7 @@ func testKubeDeny(t *testing.T, suite *KubeSuite) {
KubeUsers: kubeUsers,
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -491,7 +491,7 @@ func testKubePortForward(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -621,7 +621,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -667,7 +667,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -891,7 +891,7 @@ func testKubeTrustedClustersSNI(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -941,7 +941,7 @@ func testKubeTrustedClustersSNI(t *testing.T, suite *KubeSuite) {
KubeGroups: auxKubeGroups,
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -1191,7 +1191,7 @@ func runKubeDisconnectTest(t *testing.T, suite *KubeSuite, tc disconnectTestCase
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -1290,7 +1290,7 @@ func testKubeTransportProtocol(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -1403,6 +1403,7 @@ func testKubeEphemeralContainers(t *testing.T, suite *KubeSuite) {
Name: types.Wildcard,
Namespace: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -1682,7 +1683,7 @@ func testKubeExecWeb(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.Wildcard, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.Wildcard, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -2179,7 +2180,7 @@ func testKubeJoin(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -2401,7 +2402,7 @@ func testKubeJoinWeb(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -2696,7 +2697,7 @@ func testExecNoAuth(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -2715,7 +2716,7 @@ func testExecNoAuth(t *testing.T, suite *KubeSuite) {
},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
RequireSessionJoin: []*types.SessionRequirePolicy{
+5 -5
View File
@@ -349,7 +349,7 @@ func TestALPNSNIProxyKube(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -427,7 +427,7 @@ func TestALPNSNIProxyKubeV2Leaf(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -544,7 +544,7 @@ func TestKubePROXYProtocol(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -726,7 +726,7 @@ func TestKubeIPPinning(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
@@ -1791,7 +1791,7 @@ func TestALPNSNIProxyGRPCSecure(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
+1 -1
View File
@@ -415,7 +415,7 @@ func TestTeletermKubeGateway(t *testing.T) {
KubeUsers: []string{k8User},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard},
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard,
},
},
},
+1 -1
View File
@@ -90,7 +90,7 @@ func TestListKubernetesResources(t *testing.T) {
// override the role to allow access to all kube resources.
r.SetKubeResources(
types.Allow,
[]types.KubernetesResource{{Kind: types.Wildcard, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}}},
[]types.KubernetesResource{{Kind: types.Wildcard, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard}},
)
},
},
-1
View File
@@ -338,7 +338,6 @@ current-context: foo
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.desc, func(t *testing.T) {
t.Parallel()
fwd := &Forwarder{
+25 -2
View File
@@ -185,6 +185,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubePod,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.CoreV1().Pods(namespace).Delete(ctx, name, deleteOptions))
@@ -198,6 +199,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeSecret,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.CoreV1().Secrets(namespace).Delete(ctx, name, deleteOptions))
@@ -211,6 +213,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeConfigmap,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.CoreV1().ConfigMaps(namespace).Delete(ctx, name, deleteOptions))
@@ -224,6 +227,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeNamespace,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, _ string) error {
return trace.Wrap(client.CoreV1().Namespaces().Delete(ctx, name, deleteOptions))
@@ -237,6 +241,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeServiceAccount,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, deleteOptions))
@@ -250,6 +255,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubePersistentVolume,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, _ string) error {
return trace.Wrap(client.CoreV1().PersistentVolumes().Delete(ctx, name, deleteOptions))
@@ -264,6 +270,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubePersistentVolumeClaim,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, name, deleteOptions))
@@ -277,6 +284,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeDeployment,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.AppsV1().Deployments(namespace).Delete(ctx, name, deleteOptions))
@@ -290,6 +298,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeReplicaSet,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.AppsV1().ReplicaSets(namespace).Delete(ctx, name, deleteOptions))
@@ -304,6 +313,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeStatefulset,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.AppsV1().StatefulSets(namespace).Delete(ctx, name, deleteOptions))
@@ -317,6 +327,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeDaemonSet,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.AppsV1().DaemonSets(namespace).Delete(ctx, name, deleteOptions))
@@ -331,6 +342,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeClusterRole,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, _ string) error {
return trace.Wrap(client.RbacV1().ClusterRoles().Delete(ctx, name, deleteOptions))
@@ -344,6 +356,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeRole,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.RbacV1().Roles(namespace).Delete(ctx, name, deleteOptions))
@@ -357,6 +370,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeClusterRoleBinding,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, _ string) error {
return trace.Wrap(client.RbacV1().ClusterRoleBindings().Delete(ctx, name, deleteOptions))
@@ -370,6 +384,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeRoleBinding,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.RbacV1().RoleBindings(namespace).Delete(ctx, name, deleteOptions))
@@ -383,6 +398,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeCronjob,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.BatchV1().CronJobs(namespace).Delete(ctx, name, deleteOptions))
@@ -396,6 +412,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeJob,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.BatchV1().Jobs(namespace).Delete(ctx, name, deleteOptions))
@@ -409,6 +426,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeCertificateSigningRequest,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, _ string) error {
return trace.Wrap(client.CertificatesV1().CertificateSigningRequests().Delete(ctx, name, deleteOptions))
@@ -422,6 +440,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeIngress,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.NetworkingV1().Ingresses(namespace).Delete(ctx, name, deleteOptions))
@@ -435,6 +454,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeIngress,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.ExtensionsV1beta1().Ingresses(namespace).Delete(ctx, name, deleteOptions))
@@ -448,6 +468,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeDaemonSet,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.ExtensionsV1beta1().DaemonSets(namespace).Delete(ctx, name, deleteOptions))
@@ -461,6 +482,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeDeployment,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.ExtensionsV1beta1().Deployments(namespace).Delete(ctx, name, deleteOptions))
@@ -474,6 +496,7 @@ func (f *Forwarder) handleDeleteCollectionReq(req *http.Request, sess *clusterSe
items, err := deleteResources(
params,
types.KindKubeReplicaSet,
sess.apiResource.apiGroup,
slices.ToPointers(o.Items),
func(ctx context.Context, client kubernetes.Interface, name, namespace string) error {
return trace.Wrap(client.ExtensionsV1beta1().ReplicaSets(namespace).Delete(ctx, name, deleteOptions))
@@ -591,7 +614,7 @@ type deleteResourcesCommonParams struct {
func deleteResources[T kubeObjectInterface](
params deleteResourcesCommonParams,
kind string,
kind, group string,
items []T,
deleteOP func(ctx context.Context, client kubernetes.Interface, name, namespace string) error,
) ([]T, error) {
@@ -607,7 +630,7 @@ func deleteResources[T kubeObjectInterface](
params.authCtx.Checker.Traits(),
),
services.NewKubernetesResourceMatcher(
getKubeResource(kind, types.KubeVerbDeleteCollection, item),
getKubeResource(kind, group, types.KubeVerbDeleteCollection, item),
),
)
// no match was found, we ignore the request.
+74 -68
View File
@@ -52,7 +52,7 @@ import (
// - deniedResources: excluded if (namespace,name) matches an entry even if it matches
// the allowedResources's list.
// - allowedResources: excluded if (namespace,name) not match a single entry.
func newResourceFilterer(kind, verb string, codecs *serializer.CodecFactory, allowedResources, deniedResources []types.KubernetesResource, log *slog.Logger) responsewriters.FilterWrapper {
func newResourceFilterer(kind, group, verb string, codecs *serializer.CodecFactory, allowedResources, deniedResources []types.KubernetesResource, log *slog.Logger) responsewriters.FilterWrapper {
// If the list of allowed resources contains a wildcard and no deniedResources, then we
// don't need to filter anything.
if containsWildcard(allowedResources) && len(deniedResources) == 0 {
@@ -74,6 +74,7 @@ func newResourceFilterer(kind, verb string, codecs *serializer.CodecFactory, all
deniedResources: deniedResources,
log: log,
kind: kind,
group: group,
verb: verb,
}, nil
}
@@ -118,6 +119,8 @@ type resourceFilterer struct {
log *slog.Logger
// kind is the type of the resource.
kind string
// group is the api group of the resource.
group string
// verb is the kube API verb based on HTTP verb.
verb string
}
@@ -167,7 +170,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
// should be forwarded to the user.
return true, false, nil
case *corev1.Pod:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -176,12 +179,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.PodList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.Secret:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -190,12 +193,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.SecretList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.ConfigMap:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -204,12 +207,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.ConfigMapList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.Namespace:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -218,12 +221,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.NamespaceList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.Service:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -232,12 +235,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.ServiceList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.Endpoints: //nolint:staticcheck // SA1019. Rreserve compatibility until RBAC is tweaked to support discovery endpoints.
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
case *corev1.Endpoints: //nolint:staticcheck // SA1019. Preserve compatibility until RBAC is tweaked to support discovery endpoints.
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -246,12 +249,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.EndpointsList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.ServiceAccount:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -260,12 +263,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.ServiceAccountList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.Node:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -274,12 +277,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.NodeList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.PersistentVolume:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -288,12 +291,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.PersistentVolumeList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *corev1.PersistentVolumeClaim:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -302,13 +305,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *corev1.PersistentVolumeClaimList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *appsv1.Deployment:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -317,13 +320,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *appsv1.DeploymentList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *appsv1.ReplicaSet:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -332,12 +335,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *appsv1.ReplicaSetList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *appsv1.StatefulSet:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -346,13 +349,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *appsv1.StatefulSetList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *appsv1.DaemonSet:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -361,12 +364,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *appsv1.DaemonSetList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *authv1.ClusterRole:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -375,12 +378,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *authv1.ClusterRoleList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *authv1.Role:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -389,13 +392,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *authv1.RoleList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *authv1.ClusterRoleBinding:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -404,13 +407,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *authv1.ClusterRoleBindingList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *authv1.RoleBinding:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -419,13 +422,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *authv1.RoleBindingList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *batchv1.CronJob:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -434,13 +437,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *batchv1.CronJobList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *batchv1.Job:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -449,13 +452,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *batchv1.JobList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *certificatesv1.CertificateSigningRequest:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -464,12 +467,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *certificatesv1.CertificateSigningRequestList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *networkingv1.Ingress:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -478,12 +481,12 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *networkingv1.IngressList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *extensionsv1beta1.Ingress:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -492,13 +495,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *extensionsv1beta1.IngressList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *extensionsv1beta1.DaemonSet:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -507,13 +510,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *extensionsv1beta1.DaemonSetList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *extensionsv1beta1.Deployment:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -522,13 +525,13 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *extensionsv1beta1.DeploymentList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *extensionsv1beta1.ReplicaSet:
result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources)
result, err := filterResource(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources)
if err != nil {
d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err)
}
@@ -537,18 +540,18 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList
case *extensionsv1beta1.ReplicaSetList:
o.Items = slices.FromPointers(
filterResourceList(
d.kind, d.verb,
d.kind, d.group, d.verb,
slices.ToPointers(o.Items), d.allowedResources, d.deniedResources, d.log),
)
return len(o.Items) > 0, true, nil
case *unstructured.Unstructured:
if o.IsList() {
hasElemts := filterUnstructuredList(d.verb, o, d.allowedResources, d.deniedResources, d.log)
hasElemts := filterUnstructuredList(d.kind, d.group, d.verb, o, d.allowedResources, d.deniedResources, d.log)
return hasElemts, true, nil
}
r := getKubeResource(utils.KubeCustomResource, d.verb, o)
r := getKubeResource(d.kind, d.group, d.verb, o)
result, err := matchKubernetesResource(
r,
d.allowedResources, d.deniedResources,
@@ -617,10 +620,10 @@ func (d *resourceFilterer) encode(obj runtime.Object, w io.Writer) error {
}
// filterResourceList excludes resources the user should not have access to.
func filterResourceList[T kubeObjectInterface](kind, verb string, originalList []T, allowed, denied []types.KubernetesResource, log *slog.Logger) []T {
func filterResourceList[T kubeObjectInterface](kind, group, verb string, originalList []T, allowed, denied []types.KubernetesResource, log *slog.Logger) []T {
filteredList := make([]T, 0, len(originalList))
for _, resource := range originalList {
if result, err := filterResource(kind, verb, resource, allowed, denied); err == nil && result {
if result, err := filterResource(kind, group, verb, resource, allowed, denied); err == nil && result {
filteredList = append(filteredList, resource)
} else if err != nil {
slog.WarnContext(context.Background(), "Unable to compile regex expressions within kubernetes_resources", "error", err)
@@ -638,20 +641,21 @@ type kubeObjectInterface interface {
}
// filterResource validates if the user should access the current resource.
func filterResource(kind, verb string, resource kubeObjectInterface, allowed, denied []types.KubernetesResource) (bool, error) {
func filterResource(kind, group, verb string, resource kubeObjectInterface, allowed, denied []types.KubernetesResource) (bool, error) {
result, err := matchKubernetesResource(
getKubeResource(kind, verb, resource),
getKubeResource(kind, group, verb, resource),
allowed, denied,
)
return result, trace.Wrap(err)
}
func getKubeResource(kind, verb string, obj kubeObjectInterface) types.KubernetesResource {
func getKubeResource(kind, group, verb string, obj kubeObjectInterface) types.KubernetesResource {
return types.KubernetesResource{
Kind: kind,
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
Verbs: []string{verb},
APIGroup: group,
}
}
@@ -664,7 +668,7 @@ func (d *resourceFilterer) filterMetaV1Table(table *metav1.Table, allowedResourc
if err := d.decodePartialObjectMetadata(row); err != nil {
return nil, trace.Wrap(err)
}
resource, err := getKubeResourcePartialMetadataObject(d.kind, d.verb, row.Object.Object)
resource, err := getKubeResourcePartialMetadataObject(d.kind, d.group, d.verb, row.Object.Object)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -680,7 +684,7 @@ func (d *resourceFilterer) filterMetaV1Table(table *metav1.Table, allowedResourc
// getKubeResourcePartialMetadataObject checks if obj satisfies namespaceNamer or namer interfaces
// otherwise returns an error.
func getKubeResourcePartialMetadataObject(kind, verb string, obj runtime.Object) (types.KubernetesResource, error) {
func getKubeResourcePartialMetadataObject(kind, group, verb string, obj runtime.Object) (types.KubernetesResource, error) {
type namer interface {
GetName() string
}
@@ -695,12 +699,14 @@ func getKubeResourcePartialMetadataObject(kind, verb string, obj runtime.Object)
Name: o.GetName(),
Kind: kind,
Verbs: []string{verb},
APIGroup: group,
}, nil
case namer:
return types.KubernetesResource{
Name: o.GetName(),
Kind: kind,
Verbs: []string{verb},
Name: o.GetName(),
Kind: kind,
Verbs: []string{verb},
APIGroup: group,
}, nil
default:
return types.KubernetesResource{}, trace.BadParameter("unexpected %T type", obj)
@@ -784,7 +790,7 @@ func filterBuffer(filterWrapper responsewriters.FilterWrapper, src *responsewrit
// filterUnstructuredList filters the unstructured list object to exclude resources
// that the user must not have access to.
// The filtered list is re-assigned to `obj.Object["items"]`.
func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed, denied []types.KubernetesResource, log *slog.Logger) (hasElems bool) {
func filterUnstructuredList(kind, group, verb string, obj *unstructured.Unstructured, allowed, denied []types.KubernetesResource, log *slog.Logger) (hasElems bool) {
const (
itemsKey = "items"
)
@@ -800,7 +806,7 @@ func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed
filteredList := make([]any, 0, len(objList.Items))
for _, resource := range objList.Items {
r := getKubeResource(utils.KubeCustomResource, verb, &resource)
r := getKubeResource(utils.KubeCustomResource, group, verb, &resource)
if result, err := matchKubernetesResource(
r,
allowed, denied,
+3 -2
View File
@@ -155,6 +155,7 @@ func Test_filterBuffer(t *testing.T) {
allowedResources := []types.KubernetesResource{
{
Kind: r,
APIGroup: "*",
Namespace: "default",
Name: "*",
Verbs: []string{types.KubeVerbList},
@@ -175,7 +176,7 @@ func Test_filterBuffer(t *testing.T) {
buf, decompress := newMemoryResponseWriter(t, data.Bytes(), tt.args.contentEncoding)
err = filterBuffer(newResourceFilterer(r, types.KubeVerbList, &globalKubeCodecs, allowedResources, nil, utils.NewSlogLoggerForTests()), buf)
err = filterBuffer(newResourceFilterer(r, "", types.KubeVerbList, &globalKubeCodecs, allowedResources, nil, utils.NewSlogLoggerForTests()), buf)
require.NoError(t, err)
// Decompress the buffer to compare the result.
@@ -235,7 +236,7 @@ func Test_filterBuffer(t *testing.T) {
require.NoError(t, err)
}
resource, err := getKubeResourcePartialMetadataObject(r, "list", row.Object.Object)
resource, err := getKubeResourcePartialMetadataObject(r, "", "list", row.Object.Object)
require.NoError(t, err)
resources = append(resources, resource.Namespace+"/"+resource.Name)
}
+6 -3
View File
@@ -71,7 +71,7 @@ func (f *Forwarder) listResources(sess *clusterSession, w http.ResponseWriter, r
status = rw.Status()
} else {
allowedResources, deniedResources := sess.Checker.GetKubeResources(sess.kubeCluster)
shouldBeAllowed, err := matchListRequestShouldBeAllowed(sess, resourceKind, allowedResources, deniedResources)
shouldBeAllowed, err := matchListRequestShouldBeAllowed(sess, resourceKind, sess.apiResource.apiGroup, allowedResources, deniedResources)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -123,7 +123,7 @@ func (f *Forwarder) listResourcesList(req *http.Request, w http.ResponseWriter,
// filterBuffer filters the response to exclude resources the user doesn't have access to.
// The filtered payload will be written into memBuffer again.
if err := filterBuffer(
newResourceFilterer(resourceKind, verb, sess.codecFactory, allowedResources, deniedResources, f.log),
newResourceFilterer(resourceKind, sess.apiResource.apiGroup, verb, sess.codecFactory, allowedResources, deniedResources, f.log),
memBuffer,
); err != nil {
return memBuffer.Status(), trace.Wrap(err)
@@ -140,12 +140,14 @@ func (f *Forwarder) listResourcesList(req *http.Request, w http.ResponseWriter,
// has no access and present then a more user-friendly error message instead of returning
// an empty list.
// This function is not responsible for enforcing access rules.
func matchListRequestShouldBeAllowed(sess *clusterSession, resourceKind string, allowedResources, deniedResources []types.KubernetesResource) (bool, error) {
func matchListRequestShouldBeAllowed(sess *clusterSession, resourceKind, resourceGroup string, allowedResources, deniedResources []types.KubernetesResource) (bool, error) {
resource := types.KubernetesResource{
Kind: resourceKind,
Namespace: sess.apiResource.namespace,
Verbs: []string{sess.requestVerb},
APIGroup: resourceGroup,
}
result, err := utils.KubeResourceCouldMatchRules(resource, deniedResources, types.Deny)
if err != nil {
return false, trace.Wrap(err)
@@ -182,6 +184,7 @@ func (f *Forwarder) listResourcesWatcher(req *http.Request, w http.ResponseWrite
negotiator,
newResourceFilterer(
resourceKind,
sess.apiResource.resourceKind,
verb,
sess.codecFactory,
allowedResources,
+32 -15
View File
@@ -100,6 +100,7 @@ func TestListPodRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -123,6 +124,7 @@ func TestListPodRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: metav1.NamespaceDefault,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -148,6 +150,7 @@ func TestListPodRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: "{{external.namespaces}}",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -172,6 +175,7 @@ func TestListPodRBAC(t *testing.T) {
Name: "nginx-*",
Namespace: metav1.NamespaceDefault,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
@@ -196,6 +200,7 @@ func TestListPodRBAC(t *testing.T) {
Name: "*",
Namespace: metav1.NamespaceDefault,
Verbs: []string{"get"},
APIGroup: types.Wildcard,
},
},
)
@@ -221,6 +226,7 @@ func TestListPodRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
@@ -231,6 +237,7 @@ func TestListPodRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: metav1.NamespaceDefault,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
@@ -476,7 +483,6 @@ func TestListPodRBAC(t *testing.T) {
return pods
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// generate a kube client with user certs for auth
@@ -562,6 +568,7 @@ func TestWatcherResponseWriter(t *testing.T) {
Namespace: "*",
Name: "*",
Verbs: []string{types.Wildcard},
APIGroup: "core",
},
},
},
@@ -576,6 +583,7 @@ func TestWatcherResponseWriter(t *testing.T) {
Namespace: defaultNamespace,
Name: "*",
Verbs: []string{types.Wildcard},
APIGroup: "core",
},
},
},
@@ -590,6 +598,7 @@ func TestWatcherResponseWriter(t *testing.T) {
Namespace: defaultNamespace,
Name: "*",
Verbs: []string{types.Wildcard},
APIGroup: "core",
},
},
denied: []types.KubernetesResource{
@@ -598,6 +607,7 @@ func TestWatcherResponseWriter(t *testing.T) {
Namespace: defaultNamespace,
Name: "otherPod",
Verbs: []string{types.Wildcard},
APIGroup: "core",
},
},
},
@@ -612,6 +622,7 @@ func TestWatcherResponseWriter(t *testing.T) {
Namespace: defaultNamespace,
Name: "rand*",
Verbs: []string{types.Wildcard},
APIGroup: "core",
},
},
},
@@ -627,11 +638,10 @@ func TestWatcherResponseWriter(t *testing.T) {
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
userReader, userWriter := io.Pipe()
negotiator := newClientNegotiator(&globalKubeCodecs)
filterWrapper := newResourceFilterer(types.KindKubePod, types.KubeVerbWatch, &globalKubeCodecs, tt.args.allowed, tt.args.denied, utils.NewSlogLoggerForTests())
filterWrapper := newResourceFilterer(types.KindKubePod, "core", types.KubeVerbWatch, &globalKubeCodecs, tt.args.allowed, tt.args.denied, utils.NewSlogLoggerForTests())
// watcher parses the data written into itself and if the user is allowed to
// receive the update, it writes the event into target.
watcher, err := responsewriters.NewWatcherResponseWriter(newFakeResponseWriter(userWriter) /*target*/, negotiator, filterWrapper)
@@ -867,6 +877,7 @@ func TestDeletePodCollectionRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -890,6 +901,7 @@ func TestDeletePodCollectionRBAC(t *testing.T) {
Name: types.Wildcard,
Namespace: metav1.NamespaceDefault,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -914,6 +926,7 @@ func TestDeletePodCollectionRBAC(t *testing.T) {
Name: "nginx-*",
Namespace: metav1.NamespaceDefault,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
@@ -1052,9 +1065,10 @@ func TestListClusterRoleRBAC(t *testing.T) {
SetupRoleFunc: func(r types.Role) {
r.SetKubeResources(types.Allow, []types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
Kind: types.KindKubeClusterRole,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -1075,9 +1089,10 @@ func TestListClusterRoleRBAC(t *testing.T) {
r.SetKubeResources(types.Allow,
[]types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: "nginx-*",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeClusterRole,
Name: "nginx-*",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
@@ -1276,9 +1291,10 @@ func TestCustomResourcesRBAC(t *testing.T) {
SetupRoleFunc: func(r types.Role) {
r.SetKubeResources(types.Allow, []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
},
@@ -1298,9 +1314,10 @@ func TestCustomResourcesRBAC(t *testing.T) {
r.SetKubeResources(types.Allow,
[]types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "dev",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
)
+48 -31
View File
@@ -77,6 +77,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -94,6 +95,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -111,6 +113,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -128,6 +131,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Name: "pod-2",
Namespace: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -145,12 +149,14 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Name: "pod-2",
Namespace: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "pod-1",
Namespace: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -168,6 +174,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Name: "pod-2",
Namespace: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -185,6 +192,7 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
Name: "pod-2",
Namespace: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -197,9 +205,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
kind: "namespaces",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -212,9 +221,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
kind: "namespaces",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -227,9 +237,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
kind: "pods",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -259,9 +270,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "resources.teleport.dev",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -275,9 +287,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "rbac.authorization.k8s.io",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace-2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -291,9 +304,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "rbac.authorization.k8s.io",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -307,9 +321,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "rbac.authorization.k8s.io",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -323,9 +338,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "rbac.authorization.k8s.io",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -339,9 +355,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
apiGroup: "rbac.authorization.k8s.io",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{"get"},
Kind: types.KindKubeClusterRole,
Name: "role",
Verbs: []string{"get"},
APIGroup: types.Wildcard,
},
},
},
@@ -355,9 +372,10 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
namespace: "namespace-1",
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "namespace-1",
Verbs: []string{types.Wildcard},
Kind: types.KindKubeNamespace,
Name: "namespace-1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -366,7 +384,6 @@ func TestSelfSubjectAccessReviewsRBAC(t *testing.T) {
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// create a user with full access to kubernetes Pods.
+3 -3
View File
@@ -115,7 +115,7 @@ func TestSingleCertRouting(t *testing.T) {
KubeUsers: roleKubeUsers,
KubeGroups: roleKubeGroups,
SetupRoleFunc: func(r types.Role) {
r.SetKubeResources(types.Deny, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}}})
r.SetKubeResources(types.Deny, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard}})
},
},
assert: func(t *testing.T, restConfig *rest.Config) {
@@ -143,7 +143,7 @@ func TestSingleCertRouting(t *testing.T) {
KubeUsers: roleKubeUsers,
KubeGroups: roleKubeGroups,
SetupRoleFunc: func(r types.Role) {
r.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}}})
r.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard}})
r.SetOptions(types.RoleOptions{
RequireMFAType: types.RequireMFAType_SESSION,
})
@@ -165,7 +165,7 @@ func TestSingleCertRouting(t *testing.T) {
KubeUsers: roleKubeUsers,
KubeGroups: roleKubeGroups,
SetupRoleFunc: func(r types.Role) {
r.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}}})
r.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: types.Wildcard}})
r.SetOptions(types.RoleOptions{
RequireMFAType: types.RequireMFAType_SESSION,
})
+1
View File
@@ -249,6 +249,7 @@ func getResourceFromRequest(req *http.Request, kubeDetails *kubeDetails) (*types
Namespace: apiResource.namespace,
Name: apiResource.resourceName,
Verbs: []string{verb},
APIGroup: apiResource.apiGroup,
}, apiResource, nil
}
+50 -50
View File
@@ -102,120 +102,120 @@ func Test_getResourceFromRequest(t *testing.T) {
{path: "/apis/apps/v1/", want: nil},
{path: "/api/v1/pods", want: nil},
{path: "/api/v1/watch/pods", want: nil},
{path: "/api/v1/namespaces/kube-system", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "kube-system", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/kube-system", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "kube-system", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/kube-system", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "kube-system", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/kube-system", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "kube-system", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/kube-system/pods", want: nil},
{path: "/api/v1/watch/namespaces/kube-system/pods", want: nil},
{path: "/api/v1/namespaces/kube-system/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/kube-system/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/kube-system/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/kube-system/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/apis/apiregistration.k8s.io/v1/apiservices/foo/status", want: nil},
// core
// Pods
{path: "/api/v1/pods", want: nil},
{path: "/api/v1/namespaces/default/pods", want: nil},
{path: "/api/v1/namespaces/default/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/kube-system/pods/foo/exec", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"exec"}}},
{path: "/api/v1/namespaces/kube-system/pods/foo/attach", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"exec"}}},
{path: "/api/v1/namespaces/kube-system/pods/foo/portforward", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"portforward"}}},
{path: "/api/v1/namespaces/default/pods", body: bodyFunc("Pod", "v1"), want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/pods", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/pods/foo", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/kube-system/pods/foo/exec", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"exec"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/kube-system/pods/foo/attach", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"exec"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/kube-system/pods/foo/portforward", want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "kube-system", Name: "foo", Verbs: []string{"portforward"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/pods", body: bodyFunc("Pod", "v1"), want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/pods", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubePod, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
// Secrets
{path: "/api/v1/secrets", want: nil},
{path: "/api/v1/namespaces/default/secrets", want: nil},
{path: "/api/v1/namespaces/default/secrets/foo", want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/secrets/foo", want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/secrets", body: bodyFunc("Secret", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/secrets", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/secrets/foo", want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/secrets/foo", want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/secrets", body: bodyFunc("Secret", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/secrets", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeSecret, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
// Configmaps
{path: "/api/v1/configmaps", want: nil},
{path: "/api/v1/namespaces/default/configmaps", want: nil},
{path: "/api/v1/namespaces/default/configmaps/foo", want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/configmaps/foo", want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/configmaps", body: bodyFunc("ConfigMap", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/configmaps", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/configmaps/foo", want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/configmaps/foo", want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/configmaps", body: bodyFunc("ConfigMap", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/configmaps", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeConfigmap, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
// Namespaces
{path: "/api/v1/namespaces", want: nil},
{path: "/api/v1/namespaces/default", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "default", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "default", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces", body: bodyFunc("Namespace", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "default", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default", want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "default", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces", body: bodyFunc("Namespace", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
{path: "/api/v1/namespaces", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeNamespace, Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
// Nodes
{path: "/api/v1/nodes", want: nil},
{path: "/api/v1/nodes/foo/proxy/bar", want: &types.KubernetesResource{Kind: types.KindKubeNode, Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/nodes/foo/proxy/bar", want: &types.KubernetesResource{Kind: types.KindKubeNode, Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
// Services
{path: "/api/v1/services", want: nil},
{path: "/api/v1/namespaces/default/services", want: nil},
{path: "/api/v1/namespaces/default/services/foo", want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/services/foo", want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/services", body: bodyFunc("Service", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/api/v1/namespaces/default/services/foo", want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/services/foo", want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
{path: "/api/v1/namespaces/default/services", body: bodyFunc("Service", "v1"), want: &types.KubernetesResource{Kind: types.KindKubeService, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "core"}},
// ServiceAccounts
{path: "/api/v1/serviceaccounts", want: nil},
{path: "/api/v1/namespaces/default/serviceaccounts", want: nil},
{path: "/api/v1/namespaces/default/serviceaccounts/foo", want: &types.KubernetesResource{Kind: types.KindKubeServiceAccount, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/serviceaccounts/foo", want: &types.KubernetesResource{Kind: types.KindKubeServiceAccount, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/serviceaccounts/foo", want: &types.KubernetesResource{Kind: types.KindKubeServiceAccount, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/serviceaccounts/foo", want: &types.KubernetesResource{Kind: types.KindKubeServiceAccount, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
// PersistentVolumes
{path: "/api/v1/persistentvolumes", want: nil},
{path: "/api/v1/namespaces/default/persistentvolumes", want: nil},
{path: "/api/v1/namespaces/default/persistentvolumes/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolume, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/persistentvolumes/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolume, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/persistentvolumes/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolume, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/persistentvolumes/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolume, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
// PersistentVolumeClaims
{path: "/api/v1/persistentvolumeclaims", want: nil},
{path: "/api/v1/namespaces/default/persistentvolumeclaims", want: nil},
{path: "/api/v1/namespaces/default/persistentvolumeclaims/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolumeClaim, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/api/v1/watch/namespaces/default/persistentvolumeclaims/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolumeClaim, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/api/v1/namespaces/default/persistentvolumeclaims/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolumeClaim, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "core"}},
{path: "/api/v1/watch/namespaces/default/persistentvolumeclaims/foo", want: &types.KubernetesResource{Kind: types.KindKubePersistentVolumeClaim, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "core"}},
// apis/apps
// Deployments
{path: "/apis/apps/v1/deployments", want: nil},
{path: "/apis/apps/v1/namespaces/default/deployments", want: nil},
{path: "/apis/apps/v1/namespaces/default/deployments/foo", want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/apps/v1/watch/namespaces/default/deployments/foo", want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/apps/v1/namespaces/default/deployments", body: bodyFunc("Deployment", "apps/v1"), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/apis/apps/v1beta2/namespaces/default/deployments", body: bodyFunc("Deployment", "apps/v1beta2"), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/apis/apps/v1/namespaces/default/deployments", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}}},
{path: "/apis/apps/v1/namespaces/default/deployments/foo", want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/watch/namespaces/default/deployments/foo", want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/namespaces/default/deployments", body: bodyFunc("Deployment", "apps/v1"), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "apps"}},
{path: "/apis/apps/v1beta2/namespaces/default/deployments", body: bodyFunc("Deployment", "apps/v1beta2"), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/namespaces/default/deployments", body: bodyFuncWithoutGVK(), want: &types.KubernetesResource{Kind: types.KindKubeDeployment, Namespace: "default", Name: "foo-create", Verbs: []string{"create"}, APIGroup: "apps"}},
// Statefulsets
{path: "/apis/apps/v1/statefulsets", want: nil},
{path: "/apis/apps/v1/namespaces/default/statefulsets", want: nil},
{path: "/apis/apps/v1/namespaces/default/statefulsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeStatefulset, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/apps/v1/watch/namespaces/default/statefulsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeStatefulset, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/apps/v1/namespaces/default/statefulsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeStatefulset, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/watch/namespaces/default/statefulsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeStatefulset, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "apps"}},
// Replicasets
{path: "/apis/apps/v1/replicasets", want: nil},
{path: "/apis/apps/v1/namespaces/default/replicasets", want: nil},
{path: "/apis/apps/v1/namespaces/default/replicasets/foo", want: &types.KubernetesResource{Kind: types.KindKubeReplicaSet, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/apps/v1/watch/namespaces/default/replicasets/foo", want: &types.KubernetesResource{Kind: types.KindKubeReplicaSet, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/apps/v1/namespaces/default/replicasets/foo", want: &types.KubernetesResource{Kind: types.KindKubeReplicaSet, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/watch/namespaces/default/replicasets/foo", want: &types.KubernetesResource{Kind: types.KindKubeReplicaSet, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "apps"}},
// Daemonsets
{path: "/apis/apps/v1/daemonsets", want: nil},
{path: "/apis/apps/v1/namespaces/default/daemonsets", want: nil},
{path: "/apis/apps/v1/namespaces/default/daemonsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeDaemonSet, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/apps/v1/watch/namespaces/default/daemonsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeDaemonSet, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/apps/v1/namespaces/default/daemonsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeDaemonSet, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "apps"}},
{path: "/apis/apps/v1/watch/namespaces/default/daemonsets/foo", want: &types.KubernetesResource{Kind: types.KindKubeDaemonSet, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "apps"}},
// apis/batch
// Job
{path: "/apis/batch/v1/jobs", want: nil},
{path: "/apis/batch/v1/namespaces/default/jobs", want: nil},
{path: "/apis/batch/v1/namespaces/default/jobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeJob, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/batch/v1/watch/namespaces/default/jobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeJob, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/batch/v1/namespaces/default/jobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeJob, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "batch"}},
{path: "/apis/batch/v1/watch/namespaces/default/jobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeJob, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "batch"}},
// CronJob
{path: "/apis/batch/v1/cronjobs", want: nil},
{path: "/apis/batch/v1/namespaces/default/cronjobs", want: nil},
{path: "/apis/batch/v1/namespaces/default/cronjobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeCronjob, Namespace: "default", Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/batch/v1/watch/namespaces/default/cronjobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeCronjob, Namespace: "default", Name: "foo", Verbs: []string{"watch"}}},
{path: "/apis/batch/v1/namespaces/default/cronjobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeCronjob, Namespace: "default", Name: "foo", Verbs: []string{"get"}, APIGroup: "batch"}},
{path: "/apis/batch/v1/watch/namespaces/default/cronjobs/foo", want: &types.KubernetesResource{Kind: types.KindKubeCronjob, Namespace: "default", Name: "foo", Verbs: []string{"watch"}, APIGroup: "batch"}},
// apis/certificates.k8s.io
{path: "/apis/certificates.k8s.io/v1/certificatesigningrequests", want: nil},
{path: "/apis/certificates.k8s.io/v1/certificatesigningrequests/foo", want: &types.KubernetesResource{Kind: types.KindKubeCertificateSigningRequest, Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/certificates.k8s.io/v1/certificatesigningrequests/foo", want: &types.KubernetesResource{Kind: types.KindKubeCertificateSigningRequest, Name: "foo", Verbs: []string{"get"}, APIGroup: "certificates.k8s.io"}},
// apis/networking.k8s.io
{path: "/apis/networking.k8s.io/v1/ingresses", want: nil},
{path: "/apis/networking.k8s.io/v1/ingresses/foo", want: &types.KubernetesResource{Kind: types.KindKubeIngress, Name: "foo", Verbs: []string{"get"}}},
{path: "/apis/networking.k8s.io/v1/ingresses/foo", want: &types.KubernetesResource{Kind: types.KindKubeIngress, Name: "foo", Verbs: []string{"get"}, APIGroup: "networking.k8s.io"}},
}
for _, tt := range tests {
+1 -1
View File
@@ -465,7 +465,7 @@ func (c *TestContext) CreateUserWithTraitsAndRole(ctx context.Context, t *testin
role.SetSessionRequirePolicies(roleSpec.SessionRequire)
role.SetSessionJoinPolicies(roleSpec.SessionJoin)
if roleSpec.SetupRoleFunc == nil {
role.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}}})
role.SetKubeResources(types.Allow, []types.KubernetesResource{{Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, Verbs: []string{types.Wildcard}, APIGroup: "core"}})
} else {
roleSpec.SetupRoleFunc(role)
}
+3 -1
View File
@@ -538,6 +538,8 @@ func (a *accessChecker) GetKubeResources(cluster types.KubeCluster) (allowed, de
Kind: r.Kind,
Namespace: namespace,
Name: name,
// TODO(@creack): Add support for Groups in AccessRequests.
APIGroup: types.Wildcard,
}
// matchKubernetesResource checks if the Kubernetes Resource matches the tuple
// (kind, namespace, kame) from the allowed/denied list and does not match the resource
@@ -554,7 +556,7 @@ func (a *accessChecker) GetKubeResources(cluster types.KubeCluster) (allowed, de
return rolesAllowed, rolesDenied
}
}
return
return allowed, denied
}
// matchKubernetesResource checks if the Kubernetes Resource does not match any
+21
View File
@@ -45,6 +45,7 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "dev",
Namespace: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
rv.SetKubernetesLabels(types.Allow, kubeDevLabels)
@@ -58,12 +59,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
})
rv.SetKubernetesLabels(types.Allow, kubeAnyLabels)
@@ -79,12 +82,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
})
rv.SetKubernetesLabels(types.Allow, kubeAnyLabels)
@@ -126,12 +131,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -158,18 +165,21 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "dev",
Namespace: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -221,6 +231,7 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "dev",
Namespace: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -302,18 +313,21 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "dev",
Namespace: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -353,6 +367,7 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "dev",
Namespace: "dev",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -392,12 +407,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -451,12 +468,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
@@ -483,12 +502,14 @@ func TestAccessCheckerKubeResources(t *testing.T) {
Name: "any1",
Namespace: "any1",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Name: "any1",
Namespace: "any2",
Verbs: []string{types.KubeVerbList},
APIGroup: types.Wildcard,
},
},
wantDenied: emptySet,
+4 -4
View File
@@ -2928,7 +2928,7 @@ func TestValidate_WithAllowRequestKubernetesResources(t *testing.T) {
"*": {"*"},
},
KubernetesResources: []types.KubernetesResource{
{Kind: "*", Namespace: "*", Name: "*", Verbs: []string{"*"}},
{Kind: "*", Namespace: "*", Name: "*", Verbs: []string{"*"}, APIGroup: "*"},
},
},
},
@@ -2941,7 +2941,7 @@ func TestValidate_WithAllowRequestKubernetesResources(t *testing.T) {
"*": {"*"},
},
KubernetesResources: []types.KubernetesResource{
{Kind: types.KindNamespace, Namespace: "*", Name: "*", Verbs: []string{"*"}},
{Kind: types.KindNamespace, Namespace: "*", Name: "*", Verbs: []string{"*"}, APIGroup: "*"},
},
},
},
@@ -2951,7 +2951,7 @@ func TestValidate_WithAllowRequestKubernetesResources(t *testing.T) {
"*": {"*"},
},
KubernetesResources: []types.KubernetesResource{
{Kind: types.KindKubePod, Namespace: "*", Name: "*", Verbs: []string{"*"}},
{Kind: types.KindKubePod, Namespace: "*", Name: "*", Verbs: []string{"*"}, APIGroup: "*"},
},
},
},
@@ -2961,7 +2961,7 @@ func TestValidate_WithAllowRequestKubernetesResources(t *testing.T) {
"*": {"*"},
},
KubernetesResources: []types.KubernetesResource{
{Kind: types.KindKubeDeployment, Namespace: "*", Name: "*", Verbs: []string{"*"}},
{Kind: types.KindKubeDeployment, Namespace: "*", Name: "*", Verbs: []string{"*"}, APIGroup: "*"},
},
},
},
+16 -15
View File
@@ -47,7 +47,7 @@ func NewSystemAutomaticAccessApproverRole() types.Role {
}
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemAutomaticAccessApprovalRoleName,
Namespace: apidefaults.Namespace,
@@ -113,7 +113,7 @@ func NewPresetEditorRole() types.Role {
// YAML.
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetEditorRoleName,
Namespace: apidefaults.Namespace,
@@ -234,7 +234,7 @@ func NewPresetAccessRole() types.Role {
// YAML.
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetAccessRoleName,
Namespace: apidefaults.Namespace,
@@ -284,6 +284,7 @@ func NewPresetAccessRole() types.Role {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: "",
},
},
GitHubPermissions: []types.GitHubPermission{{
@@ -326,7 +327,7 @@ func NewPresetAuditorRole() types.Role {
// YAML.
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetAuditorRoleName,
Namespace: apidefaults.Namespace,
@@ -371,7 +372,7 @@ func NewPresetReviewerRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetReviewerRoleName,
Namespace: apidefaults.Namespace,
@@ -398,7 +399,7 @@ func NewPresetRequesterRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetRequesterRoleName,
Namespace: apidefaults.Namespace,
@@ -425,7 +426,7 @@ func NewPresetGroupAccessRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetGroupAccessRoleName,
Namespace: apidefaults.Namespace,
@@ -459,7 +460,7 @@ func NewPresetDeviceAdminRole() types.Role {
return &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetDeviceAdminRoleName,
Namespace: apidefaults.Namespace,
@@ -488,7 +489,7 @@ func NewPresetDeviceEnrollRole() types.Role {
return &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetDeviceEnrollRoleName,
Namespace: apidefaults.Namespace,
@@ -518,7 +519,7 @@ func NewPresetRequireTrustedDeviceRole() types.Role {
return &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetRequireTrustedDeviceRoleName,
Namespace: apidefaults.Namespace,
@@ -566,7 +567,7 @@ func NewPresetRequireTrustedDeviceRole() types.Role {
func NewPresetWildcardWorkloadIdentityIssuerRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetWildcardWorkloadIdentityIssuerRoleName,
Namespace: apidefaults.Namespace,
@@ -599,7 +600,7 @@ func NewSystemOktaAccessRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemOktaAccessRoleName,
Namespace: apidefaults.Namespace,
@@ -635,7 +636,7 @@ func NewSystemOktaRequesterRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemOktaRequesterRoleName,
Namespace: apidefaults.Namespace,
@@ -662,7 +663,7 @@ func NewSystemIdentityCenterAccessRole() types.Role {
}
return &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemIdentityCenterAccessRoleName,
Namespace: apidefaults.Namespace,
@@ -689,7 +690,7 @@ func NewSystemIdentityCenterAccessRole() types.Role {
func NewPresetTerraformProviderRole() types.Role {
role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V8,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.PresetTerraformProviderRoleName,
Namespace: apidefaults.Namespace,
+1
View File
@@ -540,6 +540,7 @@ func ApplyTraits(r types.Role, traits map[string][]string) (types.Role, error) {
Namespace: namespace,
Name: name,
Verbs: verbs,
APIGroup: rec.APIGroup,
})
}
}
+7
View File
@@ -1077,6 +1077,7 @@ func TestValidateRole(t *testing.T) {
Namespace: "{{external.namespace",
Name: "{{email.localz(external.email)}}",
Verbs: []string{"{{external.verbs"},
APIGroup: types.Wildcard,
},
},
},
@@ -1087,6 +1088,7 @@ func TestValidateRole(t *testing.T) {
Namespace: "{{external.namespace",
Name: "{{email.localz(external.email)}}",
Verbs: []string{"{{external.verbs"},
APIGroup: types.Wildcard,
},
},
},
@@ -9289,11 +9291,13 @@ func TestKubeResourcesMatcher(t *testing.T) {
Kind: types.KindKubePod,
Namespace: "dev",
Name: types.Wildcard,
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubePod,
Namespace: "default",
Name: "nginx-*",
APIGroup: types.Wildcard,
},
},
},
@@ -9303,6 +9307,7 @@ func TestKubeResourcesMatcher(t *testing.T) {
Kind: types.KindKubePod,
Namespace: "default",
Name: "restricted",
APIGroup: types.Wildcard,
},
},
},
@@ -9318,6 +9323,7 @@ func TestKubeResourcesMatcher(t *testing.T) {
Kind: types.KindKubePod,
Namespace: "prod",
Name: "pod",
APIGroup: types.Wildcard,
},
},
},
@@ -9333,6 +9339,7 @@ func TestKubeResourcesMatcher(t *testing.T) {
Kind: types.KindKubePod,
Namespace: `^[($`,
Name: `^[($`,
APIGroup: types.Wildcard,
},
},
},
+10 -6
View File
@@ -608,12 +608,14 @@ func TestKubeResourceMatchesRegex(t *testing.T) {
Namespace: "default",
Name: "name",
Verbs: []string{types.KubeVerbGet},
APIGroup: "stable.example.com",
},
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "default",
Verbs: []string{types.KubeVerbGet},
Kind: types.KindKubeNamespace,
Name: "default",
Verbs: []string{types.KubeVerbGet},
APIGroup: "*",
},
},
assert: require.NoError,
@@ -627,12 +629,14 @@ func TestKubeResourceMatchesRegex(t *testing.T) {
Namespace: "default",
Name: "name",
Verbs: []string{types.KubeVerbUpdate},
APIGroup: "stable.example.com",
},
resources: []types.KubernetesResource{
{
Kind: types.KindKubeNamespace,
Name: "default",
Verbs: []string{types.KubeVerbGet},
Kind: types.KindKubeNamespace,
Name: "default",
Verbs: []string{types.KubeVerbGet},
APIGroup: "*",
},
},
assert: require.NoError,
+6 -3
View File
@@ -4361,10 +4361,12 @@ func TestClusterKubeResourcesGet(t *testing.T) {
Kind: types.KindKubePod,
Namespace: types.Wildcard,
Name: types.Wildcard,
APIGroup: types.Wildcard,
},
{
Kind: types.KindKubeNamespace,
Name: types.Wildcard,
Kind: types.KindKubeNamespace,
Name: types.Wildcard,
APIGroup: types.Wildcard,
},
},
},
@@ -4455,7 +4457,6 @@ func TestClusterKubeResourcesGet(t *testing.T) {
pack := proxy.authPack(t, user, roleWithFullAccess(user))
for _, tc := range tt {
tc := tc
t.Run(tc.name, func(t *testing.T) {
endpoint := pack.clt.Endpoint("webapi", "sites", env.server.ClusterName(), "kubernetes", "resources")
params := url.Values{}
@@ -6886,6 +6887,7 @@ func TestDiagnoseKubeConnection(t *testing.T) {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
@@ -6911,6 +6913,7 @@ func TestDiagnoseKubeConnection(t *testing.T) {
Namespace: types.Wildcard,
Name: types.Wildcard,
Verbs: []string{types.Wildcard},
APIGroup: types.Wildcard,
},
},
},
+3 -2
View File
@@ -218,7 +218,8 @@ spec:
kubernetes_labels:
'*': '*'
kubernetes_resources:
- kind: pod
- api_group: '*'
kind: pod
name: '*'
namespace: '*'
logins:
@@ -253,7 +254,7 @@ version: v8
KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard,
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, APIGroup: types.Wildcard,
},
},
},
+1 -1
View File
@@ -2612,7 +2612,7 @@ func TestKubeCredentialsLock(t *testing.T) {
KubeUsers: []string{alice.GetName()},
KubernetesResources: []types.KubernetesResource{
{
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard,
Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, APIGroup: types.Wildcard,
},
},
},