diff --git a/cmd/apiserver/main.go b/cmd/apiserver/main.go index 7077f3b1..efc84765 100644 --- a/cmd/apiserver/main.go +++ b/cmd/apiserver/main.go @@ -35,8 +35,8 @@ func main() { // +kubebuilder:scaffold:resource-register WithResource(&clusterv1alpha1.ClusterGateway{}). WithLocalDebugExtension(). - DisableAuthorization(). ExposeLoopbackMasterClientConfig(). + ExposeLoopbackAuthorizer(). WithoutEtcd(). WithOptionsFns(func(options *builder.ServerOptions) *builder.ServerOptions { if err := config.ValidateSecret(); err != nil { @@ -53,6 +53,7 @@ func main() { } config.AddSecretFlags(cmd.Flags()) config.AddClusterProxyFlags(cmd.Flags()) + config.AddProxyAuthorizationFlags(cmd.Flags()) cmd.Flags().BoolVarP(&options.OCMIntegration, "ocm-integration", "", false, "Enabling OCM integration, reading cluster CA and api endpoint from managed "+ "cluster.") diff --git a/pkg/apis/cluster/v1alpha1/clustergateway_proxy.go b/pkg/apis/cluster/v1alpha1/clustergateway_proxy.go index 0478eebf..369e5906 100644 --- a/pkg/apis/cluster/v1alpha1/clustergateway_proxy.go +++ b/pkg/apis/cluster/v1alpha1/clustergateway_proxy.go @@ -28,11 +28,15 @@ import ( "github.com/oam-dev/cluster-gateway/pkg/metrics" "github.com/pkg/errors" + v1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilnet "k8s.io/apimachinery/pkg/util/net" apiproxy "k8s.io/apimachinery/pkg/util/proxy" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/apis/audit" + "k8s.io/apiserver/pkg/audit/event" + "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/request" registryrest "k8s.io/apiserver/pkg/registry/rest" @@ -41,6 +45,7 @@ import ( "sigs.k8s.io/apiserver-runtime/pkg/builder/resource" "sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcerest" contextutil "sigs.k8s.io/apiserver-runtime/pkg/util/context" + "sigs.k8s.io/apiserver-runtime/pkg/util/loopback" ) var _ resource.SubResource = &ClusterGatewayProxy{} @@ -107,6 +112,48 @@ func (c *ClusterGatewayProxy) Connect(ctx context.Context, id string, options ru }) proxyReqInfo.Verb = reqInfo.Verb + if config.AuthorizateProxySubpath { + user, _ := request.UserFrom(ctx) + var attr authorizer.Attributes + if proxyReqInfo.IsResourceRequest { + attr, _ = event.NewAttributes(&audit.Event{ + User: v1.UserInfo{ + Username: user.GetName(), + UID: user.GetUID(), + Groups: user.GetGroups(), + }, + ObjectRef: &audit.ObjectReference{ + APIGroup: proxyReqInfo.APIGroup, + APIVersion: proxyReqInfo.APIVersion, + Resource: proxyReqInfo.Resource, + Subresource: proxyReqInfo.Subresource, + Namespace: proxyReqInfo.Namespace, + Name: proxyReqInfo.Name, + }, + Verb: proxyReqInfo.Verb, + }) + } else { + attr, _ = event.NewAttributes(&audit.Event{ + User: v1.UserInfo{ + Username: user.GetName(), + UID: user.GetUID(), + Groups: user.GetGroups(), + }, + ObjectRef: nil, + RequestURI: proxyReqInfo.Path, + Verb: proxyReqInfo.Verb, + }) + } + + decision, reason, err := loopback.GetAuthorizer().Authorize(ctx, attr) + if err != nil { + return nil, errors.Wrapf(err, "authorization failed due to %s", reason) + } + if decision != authorizer.DecisionAllow { + return nil, fmt.Errorf("proxying by user %v is forbidden authorization failed", user.GetName()) + } + } + return &proxyHandler{ parentName: id, path: proxyOpts.Path, diff --git a/pkg/config/args_authorization.go b/pkg/config/args_authorization.go new file mode 100644 index 00000000..4037582e --- /dev/null +++ b/pkg/config/args_authorization.go @@ -0,0 +1,12 @@ +package config + +import ( + "github.com/spf13/pflag" +) + +var AuthorizateProxySubpath bool + +func AddProxyAuthorizationFlags(set *pflag.FlagSet) { + set.BoolVarP(&AuthorizateProxySubpath, "authorize-proxy-subpath", "", false, + "perform an additional delegated authorization against the hub cluster for the target proxying path when invoking clustergateway/proxy subresource") +}