Fix: make the impersonation feature work (#5261)

* Fix: make the impersonation feature work

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

* Fix: update the document of the chart

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
barnettZQG
2023-01-04 16:58:03 +08:00
committed by GitHub
parent b2f4e237c2
commit ba0a726cfc
12 changed files with 78 additions and 54 deletions
+1 -1
View File
@@ -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:*` |
@@ -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
+1 -1
View File
@@ -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:*
+8 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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,
+7 -3
View File
@@ -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
}
+3 -1
View File
@@ -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
}
+5 -3
View File
@@ -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)
+1 -1
View File
@@ -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
}
+15 -22
View File
@@ -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...)
}
+1 -1
View File
@@ -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},
}))
}