diff --git a/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation.go b/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation.go new file mode 100644 index 00000000000..795d5520387 --- /dev/null +++ b/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation.go @@ -0,0 +1,19 @@ +package impersonation + +import ( + "context" + + "k8s.io/apiserver/pkg/authorization/authorizer" +) + +var _ authorizer.Authorizer = (*ImpersonationAuthorizer)(nil) + +// ImpersonationAuthorizer denies all impersonation requests. +type ImpersonationAuthorizer struct{} + +func (auth ImpersonationAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { + if a.GetVerb() == "impersonate" { + return authorizer.DecisionDeny, "user impersonation is not supported", nil + } + return authorizer.DecisionNoOpinion, "", nil +} diff --git a/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation_test.go b/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation_test.go new file mode 100644 index 00000000000..61c7bcb75e2 --- /dev/null +++ b/pkg/services/grafana-apiserver/auth/authorizer/impersonation/impersonation_test.go @@ -0,0 +1,48 @@ +package impersonation_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apiserver/pkg/authorization/authorizer" + + "github.com/grafana/grafana/pkg/services/grafana-apiserver/auth/authorizer/impersonation" +) + +func TestImpersonationAuthorizer_Authorize(t *testing.T) { + auth := impersonation.ImpersonationAuthorizer{} + + t.Run("impersonate verb", func(t *testing.T) { + attrs := &fakeAttributes{ + verb: "impersonate", + } + + authorized, reason, err := auth.Authorize(context.Background(), attrs) + + require.Equal(t, authorizer.DecisionDeny, authorized) + require.Equal(t, "user impersonation is not supported", reason) + require.NoError(t, err) + }) + + t.Run("other verb", func(t *testing.T) { + attrs := &fakeAttributes{ + verb: "get", + } + + authorized, reason, err := auth.Authorize(context.Background(), attrs) + + require.Equal(t, authorizer.DecisionNoOpinion, authorized) + require.Equal(t, "", reason) + require.NoError(t, err) + }) +} + +type fakeAttributes struct { + authorizer.Attributes + verb string +} + +func (a fakeAttributes) GetVerb() string { + return a.verb +} diff --git a/pkg/services/grafana-apiserver/auth/authorizer/provider.go b/pkg/services/grafana-apiserver/auth/authorizer/provider.go index 4deb3e414ee..84a73c50757 100644 --- a/pkg/services/grafana-apiserver/auth/authorizer/provider.go +++ b/pkg/services/grafana-apiserver/auth/authorizer/provider.go @@ -4,6 +4,7 @@ import ( "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/union" + "github.com/grafana/grafana/pkg/services/grafana-apiserver/auth/authorizer/impersonation" "github.com/grafana/grafana/pkg/services/grafana-apiserver/auth/authorizer/org" "github.com/grafana/grafana/pkg/services/grafana-apiserver/auth/authorizer/stack" "github.com/grafana/grafana/pkg/setting" @@ -15,7 +16,9 @@ func ProvideAuthorizer( stackIDAuthorizer *stack.StackIDAuthorizer, cfg *setting.Cfg, ) authorizer.Authorizer { - authorizers := []authorizer.Authorizer{} + authorizers := []authorizer.Authorizer{ + &impersonation.ImpersonationAuthorizer{}, + } // In Hosted grafana, the StackID replaces the orgID as a valid namespace if cfg.StackID != "" {