diff --git a/charts/vela-core/README.md b/charts/vela-core/README.md index 0764fd2a8..80434875e 100644 --- a/charts/vela-core/README.md +++ b/charts/vela-core/README.md @@ -149,7 +149,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai | `kubeClient.qps` | The qps for reconcile clients, default is 100 | `100` | | `kubeClient.burst` | The burst for reconcile clients, default is 200 | `200` | | `authentication.enabled` | Enable authentication for application | `false` | -| `authentication.withUser` | Application authentication will impersonate as the request User | `false` | +| `authentication.withUser` | Application authentication will impersonate as the request User | `true` | | `authentication.defaultUser` | Application authentication will impersonate as the User if no user provided in Application | `kubevela:vela-core` | | `authentication.groupPattern` | Application authentication will impersonate as the request Group that matches the pattern | `kubevela:*` | diff --git a/charts/vela-core/templates/kubevela-controller.yaml b/charts/vela-core/templates/kubevela-controller.yaml index 547d20c8e..05036478e 100644 --- a/charts/vela-core/templates/kubevela-controller.yaml +++ b/charts/vela-core/templates/kubevela-controller.yaml @@ -11,21 +11,6 @@ metadata: {{- end }} {{- end }} ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "kubevela.fullname" . }}:manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ if .Values.authentication.enabled }} {{ include "kubevela.fullname" . }}:manager {{ else }} "cluster-admin" {{ end }} -subjects: - - kind: ServiceAccount - name: {{ include "kubevela.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} - {{ if .Values.authentication.enabled }} --- apiVersion: rbac.authorization.k8s.io/v1 @@ -66,9 +51,41 @@ rules: - apiGroups: ["authorization.k8s.io"] resources: ["subjectaccessreviews"] verbs: ["*"] -{{ end }} --- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kubevela.fullname" . }}:manager-authentication-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kubevela.fullname" . }}:manager +subjects: + - kind: ServiceAccount + name: {{ include "kubevela.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + +{{ else }} + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kubevela.fullname" . }}:manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: "cluster-admin" +subjects: + - kind: ServiceAccount + name: {{ include "kubevela.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + +{{ end }} +--- # permissions to do leader election. apiVersion: rbac.authorization.k8s.io/v1 kind: Role diff --git a/charts/vela-core/values.yaml b/charts/vela-core/values.yaml index 3aebb722d..dee46127c 100644 --- a/charts/vela-core/values.yaml +++ b/charts/vela-core/values.yaml @@ -263,6 +263,6 @@ kubeClient: ## @param authentication.groupPattern Application authentication will impersonate as the request Group that matches the pattern authentication: enabled: false - withUser: false + withUser: true defaultUser: kubevela:vela-core groupPattern: kubevela:* diff --git a/cmd/apiserver/app/options/options.go b/cmd/apiserver/app/options/options.go index 39c486068..1ead7dc93 100644 --- a/cmd/apiserver/app/options/options.go +++ b/cmd/apiserver/app/options/options.go @@ -17,10 +17,13 @@ limitations under the License. package options import ( - "k8s.io/apiserver/pkg/util/feature" + "flag" + cliflag "k8s.io/component-base/cli/flag" + "k8s.io/klog/v2" "github.com/oam-dev/kubevela/pkg/apiserver/config" + "github.com/oam-dev/kubevela/pkg/features" ) // ServerRunOptions contains everything necessary to create and run api server @@ -40,6 +43,9 @@ func NewServerRunOptions() *ServerRunOptions { func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) { fs := fss.FlagSet("generic") s.GenericServerRunOptions.AddFlags(fs, s.GenericServerRunOptions) - feature.DefaultMutableFeatureGate.AddFlag(fss.FlagSet("featuregate")) + features.APIServerMutableFeatureGate.AddFlag(fss.FlagSet("featuregate")) + local := flag.NewFlagSet("klog", flag.ExitOnError) + klog.InitFlags(local) + fs.AddGoFlagSet(local) return fss } diff --git a/pkg/addon/versioned_registry.go b/pkg/addon/versioned_registry.go index 6a0f16ead..fa62e415c 100644 --- a/pkg/addon/versioned_registry.go +++ b/pkg/addon/versioned_registry.go @@ -149,7 +149,7 @@ func (i versionedRegistry) loadAddon(ctx context.Context, name, version string) if addonVersion == nil { return nil, errors.Errorf("specified version %s not exist", utils.Sanitize(version)) } - klog.Infof("Addon '%s' with version '%s' found from registry '%s'", addonVersion.Name, addonVersion.Version, i.name) + klog.V(5).Infof("Addon '%s' with version '%s' found from registry '%s'", addonVersion.Name, addonVersion.Version, i.name) for _, chartURL := range addonVersion.URLs { if !utils.IsValidURL(chartURL) { chartURL, err = utils.JoinURL(i.url, chartURL) @@ -174,7 +174,7 @@ func (i versionedRegistry) loadAddon(ctx context.Context, name, version string) addonPkg.AvailableVersions = availableVersions addonPkg.RegistryName = i.name addonPkg.Meta.SystemRequirements = LoadSystemRequirements(addonVersion.Annotations) - klog.Infof("Addon '%s' with version '%s' loaded successfully from registry '%s'", addonVersion.Name, addonVersion.Version, i.name) + klog.V(5).Infof("Addon '%s' with version '%s' loaded successfully from registry '%s'", addonVersion.Name, addonVersion.Version, i.name) return addonPkg, nil } return nil, ErrFetch diff --git a/pkg/apiserver/domain/repository/env.go b/pkg/apiserver/domain/repository/env.go index 6a5403a93..bc8d07ab1 100644 --- a/pkg/apiserver/domain/repository/env.go +++ b/pkg/apiserver/domain/repository/env.go @@ -48,7 +48,7 @@ func CreateEnv(ctx context.Context, kubeClient client.Client, ds datastore.DataS env.Namespace = env.Name } - // create namespace at first + // Creating the namespace at first. err = util.CreateOrUpdateNamespace(ctx, kubeClient, env.Namespace, util.MergeOverrideLabels(map[string]string{ oam.LabelControlPlaneNamespaceUsage: oam.VelaNamespaceUsageEnv, diff --git a/pkg/apiserver/domain/service/env.go b/pkg/apiserver/domain/service/env.go index 0b760348e..9aa0423cd 100644 --- a/pkg/apiserver/domain/service/env.go +++ b/pkg/apiserver/domain/service/env.go @@ -239,7 +239,9 @@ func (p *envServiceImpl) UpdateEnv(ctx context.Context, name string, req apisv1. return nil, err } - if err := managePrivilegesForEnvironment(ctx, p.KubeClient, env, false); err != nil { + // Updating the role and role binding can't use the login user permissions. + updateRoleCtx := utils.WithProject(ctx, "") + if err := managePrivilegesForEnvironment(updateRoleCtx, p.KubeClient, env, false); err != nil { return nil, err } @@ -289,12 +291,14 @@ func (p *envServiceImpl) CreateEnv(ctx context.Context, req apisv1.CreateEnvRequ } } - err = repository.CreateEnv(ctx, p.KubeClient, p.Store, newEnv) + // Creating the namespace can't use the login user permissions. + createNamespaceCtx := utils.WithProject(ctx, "") + err = repository.CreateEnv(createNamespaceCtx, p.KubeClient, p.Store, newEnv) if err != nil { return nil, err } - if err := managePrivilegesForEnvironment(ctx, p.KubeClient, newEnv, false); err != nil { + if err := managePrivilegesForEnvironment(createNamespaceCtx, p.KubeClient, newEnv, false); err != nil { return nil, err } diff --git a/pkg/apiserver/domain/service/project.go b/pkg/apiserver/domain/service/project.go index 0a218337b..06c099e89 100644 --- a/pkg/apiserver/domain/service/project.go +++ b/pkg/apiserver/domain/service/project.go @@ -31,6 +31,7 @@ import ( "github.com/oam-dev/kubevela/pkg/apiserver/domain/model" "github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore" apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1" + apiutils "github.com/oam-dev/kubevela/pkg/apiserver/utils" "github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode" "github.com/oam-dev/kubevela/pkg/multicluster" "github.com/oam-dev/kubevela/pkg/utils" @@ -322,7 +323,8 @@ func (p *projectServiceImpl) CreateProject(ctx context.Context, req apisv1.Creat if namespace == "" { namespace = req.Name } - if err := utils.CreateNamespace(ctx, p.K8sClient, namespace); err != nil && !apierrors.IsAlreadyExists(err) { + createCtx := apiutils.WithProject(ctx, "") + if err := utils.CreateNamespace(createCtx, p.K8sClient, namespace); err != nil && !apierrors.IsAlreadyExists(err) { return nil, bcode.ErrProjectNamespaceFail } diff --git a/pkg/apiserver/domain/service/target.go b/pkg/apiserver/domain/service/target.go index b3b56451d..3ec836c8e 100644 --- a/pkg/apiserver/domain/service/target.go +++ b/pkg/apiserver/domain/service/target.go @@ -148,10 +148,11 @@ func (dt *targetServiceImpl) CreateTarget(ctx context.Context, req apisv1.Create if req.Cluster == nil { req.Cluster = &apisv1.ClusterTarget{ClusterName: multicluster.ClusterLocalName, Namespace: req.Name} } - if err := repository.CreateTargetNamespace(ctx, dt.K8sClient, req.Cluster.ClusterName, req.Cluster.Namespace, req.Name); err != nil { + createTargetCtx := utils.WithProject(ctx, "") + if err := repository.CreateTargetNamespace(createTargetCtx, dt.K8sClient, req.Cluster.ClusterName, req.Cluster.Namespace, req.Name); err != nil { return nil, err } - if err := managePrivilegesForTarget(ctx, dt.K8sClient, &target, false); err != nil { + if err := managePrivilegesForTarget(createTargetCtx, dt.K8sClient, &target, false); err != nil { return nil, err } err := repository.CreateTarget(ctx, dt.Store, &target) @@ -167,7 +168,8 @@ func (dt *targetServiceImpl) UpdateTarget(ctx context.Context, target *model.Tar return nil, err } // Compatible with historical data, if the existing Target has not been authorized, perform an update action. - if err := managePrivilegesForTarget(ctx, dt.K8sClient, targetModel, false); err != nil { + updateCtx := utils.WithProject(ctx, "") + if err := managePrivilegesForTarget(updateCtx, dt.K8sClient, targetModel, false); err != nil { return nil, err } return dt.DetailTarget(ctx, targetModel) diff --git a/pkg/apiserver/interfaces/api/env.go b/pkg/apiserver/interfaces/api/env.go index 15b7fa712..43134a62b 100644 --- a/pkg/apiserver/interfaces/api/env.go +++ b/pkg/apiserver/interfaces/api/env.go @@ -148,7 +148,7 @@ func (n *env) create(req *restful.Request, res *restful.Response) { // Call the Domain layer code env, err := n.EnvService.CreateEnv(req.Request.Context(), createReq) if err != nil { - klog.Errorf("create application failure %s", err.Error()) + klog.Errorf("create environment failure %s", err.Error()) bcode.ReturnError(req, res, err) return } diff --git a/pkg/apiserver/utils/auth.go b/pkg/apiserver/utils/auth.go index 80756305c..047989da6 100644 --- a/pkg/apiserver/utils/auth.go +++ b/pkg/apiserver/utils/auth.go @@ -24,8 +24,8 @@ import ( "k8s.io/apiserver/pkg/endpoints/request" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" "github.com/oam-dev/kubevela/pkg/apiserver/domain/model" + "github.com/oam-dev/kubevela/pkg/auth" "github.com/oam-dev/kubevela/pkg/features" ) @@ -41,6 +41,9 @@ const KubeVelaAdminGroupPrefix = "kubevela:admin:" // TemplateReaderGroup This group includes the permission that read the ConfigMap in the vela-system namespace. const TemplateReaderGroup = "template-reader" +// UXDefaultGroup This group means directly using the original identity registered by the cluster. +const UXDefaultGroup = "kubevela:ux" + // ContextWithUserInfo extract user from context (parse username and project) for impersonation func ContextWithUserInfo(ctx context.Context) context.Context { if !features.APIServerFeatureGate.Enabled(features.APIServerEnableImpersonation) { @@ -50,10 +53,12 @@ func ContextWithUserInfo(ctx context.Context) context.Context { if username, ok := UsernameFrom(ctx); ok { userInfo.Name = username } - if project, ok := ProjectFrom(ctx); ok { - userInfo.Groups = []string{KubeVelaProjectGroupPrefix + project} + if project, ok := ProjectFrom(ctx); ok && project != "" { + userInfo.Groups = []string{KubeVelaProjectGroupPrefix + project, auth.KubeVelaClientGroup} + } else { + userInfo.Groups = []string{UXDefaultGroup} } - if userInfo.Name == model.DefaultAdminUserName && !features.APIServerFeatureGate.Enabled(features.APIServerEnableAdminImpersonation) { + if userInfo.Name == model.DefaultAdminUserName && features.APIServerFeatureGate.Enabled(features.APIServerEnableAdminImpersonation) { return ctx } return request.WithUser(ctx, userInfo) @@ -83,33 +88,25 @@ func (c *authAppClient) Status() client.StatusWriter { // Create . func (c *authAppClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.Client.Create(ctx, obj, opts...) } // Delete . func (c *authAppClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.Client.Delete(ctx, obj, opts...) } // Update . func (c *authAppClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.Client.Update(ctx, obj, opts...) } // Patch . func (c *authAppClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.Client.Patch(ctx, obj, patch, opts...) } @@ -119,16 +116,12 @@ type authAppStatusClient struct { // Update . func (c *authAppStatusClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.StatusWriter.Update(ctx, obj, opts...) } // Patch . func (c *authAppStatusClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - if _, ok := obj.(*v1beta1.Application); ok { - ctx = ContextWithUserInfo(ctx) - } + ctx = ContextWithUserInfo(ctx) return c.StatusWriter.Patch(ctx, obj, patch, opts...) } diff --git a/pkg/features/apiserver_features.go b/pkg/features/apiserver_features.go index 309a7c3bb..87886021a 100644 --- a/pkg/features/apiserver_features.go +++ b/pkg/features/apiserver_features.go @@ -39,6 +39,6 @@ const ( func init() { runtime.Must(APIServerMutableFeatureGate.Add(map[featuregate.Feature]featuregate.FeatureSpec{ APIServerEnableImpersonation: {Default: false, PreRelease: featuregate.Alpha}, - APIServerEnableAdminImpersonation: {Default: false, PreRelease: featuregate.Alpha}, + APIServerEnableAdminImpersonation: {Default: true, PreRelease: featuregate.Alpha}, })) }