mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-05 11:11:28 +00:00
[Backport release-1.4] Feat: enhance controller auth by removing useless features & add authentication for componentrevision+healthcheck (#4023)
* Feat: use application identity in gc & componentrevision & collectHealthStatus Signed-off-by: Somefive <yd219913@alibaba-inc.com> (cherry picked from commit63fc4bcc69) * Chore: remove useless features and roles Signed-off-by: Somefive <yd219913@alibaba-inc.com> (cherry picked from commitf4ef77b2b3) * Fix: remove DELETE from mutating webhook Signed-off-by: Somefive <yd219913@alibaba-inc.com> (cherry picked from commit75f3d5dc35) * Chore: enhance deploy error display Signed-off-by: Somefive <yd219913@alibaba-inc.com> (cherry picked from commite69079bdae) * Fix: e2e test vela cli output match & controllerrevision recycle for serviceaccount impersonation Signed-off-by: Somefive <yd219913@alibaba-inc.com> (cherry picked from commit05b85573a2) Co-authored-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
committed by
GitHub
parent
371affb389
commit
e20ef02a6a
@@ -25,7 +25,6 @@ import (
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/client-go/transport"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -54,11 +53,8 @@ func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Respons
|
||||
if exists && userInfo != nil {
|
||||
if name := userInfo.GetName(); name != "" {
|
||||
req.Header.Set(transport.ImpersonateUserHeader, name)
|
||||
req.Header.Set(transport.ImpersonateGroupHeader, types.ClusterGatewayAccessorGroup)
|
||||
for _, group := range userInfo.GetGroups() {
|
||||
if group != types.ClusterGatewayAccessorGroup {
|
||||
req.Header.Add(transport.ImpersonateGroupHeader, group)
|
||||
}
|
||||
req.Header.Add(transport.ImpersonateGroupHeader, group)
|
||||
}
|
||||
q := req.URL.Query()
|
||||
q.Add(impersonateKey, "true")
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
@@ -66,21 +65,21 @@ func TestImpersonatingRoundTripper(t *testing.T) {
|
||||
return ContextWithUserInfo(ctx, app)
|
||||
},
|
||||
expectedUser: "system:serviceaccount:vela-system:default",
|
||||
expectedGroup: []string{types.ClusterGatewayAccessorGroup},
|
||||
expectedGroup: nil,
|
||||
},
|
||||
"without service account and app": {
|
||||
ctxFn: func(ctx context.Context) context.Context {
|
||||
return ContextWithUserInfo(ctx, nil)
|
||||
},
|
||||
expectedUser: "",
|
||||
expectedGroup: []string{types.ClusterGatewayAccessorGroup},
|
||||
expectedGroup: nil,
|
||||
},
|
||||
"without service account": {
|
||||
ctxFn: func(ctx context.Context) context.Context {
|
||||
return ContextWithUserInfo(ctx, &v1beta1.Application{})
|
||||
},
|
||||
expectedUser: AuthenticationDefaultUser,
|
||||
expectedGroup: []string{types.ClusterGatewayAccessorGroup},
|
||||
expectedGroup: nil,
|
||||
},
|
||||
"with user and groups": {
|
||||
ctxFn: func(ctx context.Context) context.Context {
|
||||
@@ -92,7 +91,7 @@ func TestImpersonatingRoundTripper(t *testing.T) {
|
||||
return ContextWithUserInfo(ctx, app)
|
||||
},
|
||||
expectedUser: "username",
|
||||
expectedGroup: []string{types.ClusterGatewayAccessorGroup, "kubevela:group1", "kubevela:group2"},
|
||||
expectedGroup: []string{"kubevela:group1", "kubevela:group2"},
|
||||
},
|
||||
}
|
||||
for name, ts := range testSets {
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application/assemble"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
@@ -219,7 +220,7 @@ func (h *AppHandler) checkComponentHealth(appParser *appfile.Parser, appRev *v1b
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
wl.Ctx.SetCtx(ctx)
|
||||
wl.Ctx.SetCtx(auth.ContextWithUserInfo(ctx, h.app))
|
||||
|
||||
readyWorkload, readyTraits, err := renderComponentsAndTraits(h.r.Client, manifest, appRev, clusterName, overrideNamespace, env)
|
||||
if err != nil {
|
||||
@@ -258,7 +259,7 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1bet
|
||||
return nil, nil, false, errors.WithMessage(err, "cannot dispatch packaged workload resources")
|
||||
}
|
||||
}
|
||||
wl.Ctx.SetCtx(ctx)
|
||||
wl.Ctx.SetCtx(auth.ContextWithUserInfo(ctx, h.app))
|
||||
|
||||
readyWorkload, readyTraits, err := renderComponentsAndTraits(h.r.Client, manifest, appRev, clusterName, overrideNamespace, env)
|
||||
if err != nil {
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
helmapi "github.com/oam-dev/kubevela/pkg/appfile/helm/flux2apis"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/component"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model"
|
||||
@@ -542,7 +543,7 @@ func (h *AppHandler) handleComponentRevisionNameSpecified(ctx context.Context, c
|
||||
revisionName := comp.ExternalRevision
|
||||
cr := &appsv1.ControllerRevision{}
|
||||
|
||||
if err := h.r.Client.Get(ctx, client.ObjectKey{Namespace: h.getComponentRevisionNamespace(ctx), Name: revisionName}, cr); err != nil {
|
||||
if err := h.r.Client.Get(auth.ContextWithUserInfo(ctx, h.app), client.ObjectKey{Namespace: h.getComponentRevisionNamespace(ctx), Name: revisionName}, cr); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "failed to get controllerRevision:%s", revisionName)
|
||||
}
|
||||
@@ -592,7 +593,7 @@ func (h *AppHandler) handleComponentRevisionNameUnspecified(ctx context.Context,
|
||||
listOpts := []client.ListOption{client.MatchingLabels{
|
||||
oam.LabelControllerRevisionComponent: comp.Name,
|
||||
}, client.InNamespace(h.getComponentRevisionNamespace(ctx))}
|
||||
if err := h.r.List(ctx, crList, listOpts...); err != nil {
|
||||
if err := h.r.List(auth.ContextWithUserInfo(ctx, h.app), crList, listOpts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ const (
|
||||
|
||||
// Edge Features
|
||||
|
||||
// ControllerAutoImpersonation enable the auto impersonation for controller (to use explicit identity for requests)
|
||||
ControllerAutoImpersonation featuregate.Feature = "ControllerAutoImpersonation"
|
||||
// AuthenticateApplication enable the authentication for application
|
||||
AuthenticateApplication featuregate.Feature = "AuthenticateApplication"
|
||||
)
|
||||
@@ -47,7 +45,6 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
LegacyObjectTypeIdentifier: {Default: false, PreRelease: featuregate.Alpha},
|
||||
DeprecatedObjectLabelSelector: {Default: false, PreRelease: featuregate.Alpha},
|
||||
LegacyResourceTrackerGC: {Default: true, PreRelease: featuregate.Alpha},
|
||||
ControllerAutoImpersonation: {Default: true, PreRelease: featuregate.Alpha},
|
||||
AuthenticateApplication: {Default: false, PreRelease: featuregate.Alpha},
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/resourcetracker"
|
||||
@@ -45,7 +46,7 @@ func (h *resourceKeeper) DispatchComponentRevision(ctx context.Context, cr *v1.C
|
||||
if err = resourcetracker.RecordManifestsInResourceTracker(multicluster.ContextInLocalCluster(ctx), h.Client, rt, []*unstructured.Unstructured{obj}, true, common.WorkflowResourceCreator); err != nil {
|
||||
return errors.Wrapf(err, "failed to record componentrevision %s/%s/%s", oam.GetCluster(cr), cr.Namespace, cr.Name)
|
||||
}
|
||||
if err = h.Client.Create(multicluster.ContextWithClusterName(ctx, oam.GetCluster(cr)), cr); err != nil {
|
||||
if err = h.Client.Create(auth.ContextWithUserInfo(multicluster.ContextWithClusterName(ctx, oam.GetCluster(cr)), h.app), cr); err != nil {
|
||||
return errors.Wrapf(err, "failed to create componentrevision %s/%s/%s", oam.GetCluster(cr), cr.Namespace, cr.Name)
|
||||
}
|
||||
return nil
|
||||
@@ -63,7 +64,7 @@ func (h *resourceKeeper) DeleteComponentRevision(ctx context.Context, cr *v1.Con
|
||||
obj.SetName(cr.Name)
|
||||
obj.SetNamespace(cr.Namespace)
|
||||
obj.SetLabels(cr.Labels)
|
||||
if err = h.Client.Delete(multicluster.ContextWithClusterName(ctx, oam.GetCluster(cr)), cr); err != nil && !errors2.IsNotFound(err) {
|
||||
if err = h.Client.Delete(auth.ContextWithUserInfo(multicluster.ContextWithClusterName(ctx, oam.GetCluster(cr)), h.app), cr); err != nil && !errors2.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "failed to delete componentrevision %s/%s/%s", oam.GetCluster(cr), cr.Namespace, cr.Name)
|
||||
}
|
||||
if err = resourcetracker.DeletedManifestInResourceTracker(multicluster.ContextInLocalCluster(ctx), h.Client, rt, obj, true); err != nil {
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
@@ -182,7 +183,7 @@ func (h *gcHandler) scan(ctx context.Context) (inactiveRTs []*v1beta1.ResourceTr
|
||||
if rt != nil {
|
||||
inactive := true
|
||||
for _, mr := range rt.Spec.ManagedResources {
|
||||
entry := h.cache.get(ctx, mr)
|
||||
entry := h.cache.get(auth.ContextWithUserInfo(ctx, h.app), mr)
|
||||
if entry.err == nil && (entry.gcExecutorRT != rt || !entry.exists) {
|
||||
continue
|
||||
}
|
||||
@@ -225,7 +226,7 @@ func (h *gcHandler) Mark(ctx context.Context) error {
|
||||
// checkAndRemoveResourceTrackerFinalizer return (all resource recycled, error)
|
||||
func (h *gcHandler) checkAndRemoveResourceTrackerFinalizer(ctx context.Context, rt *v1beta1.ResourceTracker) (bool, v1beta1.ManagedResource, error) {
|
||||
for _, mr := range rt.Spec.ManagedResources {
|
||||
entry := h.cache.get(ctx, mr)
|
||||
entry := h.cache.get(auth.ContextWithUserInfo(ctx, h.app), mr)
|
||||
if entry.err != nil {
|
||||
return false, entry.mr, entry.err
|
||||
}
|
||||
@@ -257,6 +258,7 @@ func (h *gcHandler) Sweep(ctx context.Context) (finished bool, waiting []v1beta1
|
||||
}
|
||||
|
||||
func (h *gcHandler) recycleResourceTracker(ctx context.Context, rt *v1beta1.ResourceTracker) error {
|
||||
ctx = auth.ContextWithUserInfo(ctx, h.app)
|
||||
switch h.cfg.order {
|
||||
case v1alpha1.OrderDependency:
|
||||
for _, mr := range rt.Spec.ManagedResources {
|
||||
@@ -380,14 +382,16 @@ func (h *gcHandler) GarbageCollectComponentRevisionResourceTracker(ctx context.C
|
||||
}
|
||||
var managedResources []v1beta1.ManagedResource
|
||||
for _, cr := range h._crRT.Spec.ManagedResources { // legacy code for rollout-plan
|
||||
_ctx := multicluster.ContextWithClusterName(ctx, cr.Cluster)
|
||||
_ctx = auth.ContextWithUserInfo(_ctx, h.app)
|
||||
if _, exists := inUseComponents[cr.ComponentKey()]; !exists {
|
||||
_cr := &appsv1.ControllerRevision{}
|
||||
err := h.Client.Get(multicluster.ContextWithClusterName(ctx, cr.Cluster), cr.NamespacedName(), _cr)
|
||||
err := h.Client.Get(_ctx, cr.NamespacedName(), _cr)
|
||||
if err != nil && !multicluster.IsNotFoundOrClusterNotExists(err) {
|
||||
return errors.Wrapf(err, "failed to get component revision %s", cr.ResourceKey())
|
||||
}
|
||||
if err == nil {
|
||||
if err = h.Client.Delete(multicluster.ContextWithClusterName(ctx, cr.Cluster), _cr); err != nil && !kerrors.IsNotFound(err) {
|
||||
if err = h.Client.Delete(_ctx, _cr); err != nil && !kerrors.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "failed to delete component revision %s", cr.ResourceKey())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
@@ -52,7 +51,7 @@ func (h *MutatingHandler) Handle(ctx context.Context, req admission.Request) adm
|
||||
return admission.Patched("")
|
||||
}
|
||||
|
||||
if slices.Contains(req.UserInfo.Groups, common.Group) || slices.Contains(h.skipUsers, req.UserInfo.Username) {
|
||||
if slices.Contains(h.skipUsers, req.UserInfo.Username) {
|
||||
return admission.Patched("")
|
||||
}
|
||||
|
||||
@@ -86,11 +85,9 @@ func (h *MutatingHandler) InjectDecoder(d *admission.Decoder) error {
|
||||
func RegisterMutatingHandler(mgr manager.Manager) {
|
||||
server := mgr.GetWebhookServer()
|
||||
handler := &MutatingHandler{}
|
||||
if !utilfeature.DefaultMutableFeatureGate.Enabled(features.ControllerAutoImpersonation) {
|
||||
if userInfo := utils.GetUserInfoFromConfig(mgr.GetConfig()); userInfo != nil {
|
||||
klog.Infof("[ApplicationMutatingHandler] add skip user %s", userInfo.Username)
|
||||
handler.skipUsers = []string{userInfo.Username}
|
||||
}
|
||||
if userInfo := utils.GetUserInfoFromConfig(mgr.GetConfig()); userInfo != nil {
|
||||
klog.Infof("[ApplicationMutatingHandler] add skip user %s", userInfo.Username)
|
||||
handler.skipUsers = []string{userInfo.Username}
|
||||
}
|
||||
server.Register("/mutating-core-oam-dev-v1beta1-applications", &webhook.Admission{Handler: handler})
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
@@ -40,7 +40,7 @@ var _ = Describe("Test Application Mutator", func() {
|
||||
var mutatingHandler *MutatingHandler
|
||||
|
||||
BeforeEach(func() {
|
||||
mutatingHandler = &MutatingHandler{}
|
||||
mutatingHandler = &MutatingHandler{skipUsers: []string{types.VelaCoreName}}
|
||||
Expect(mutatingHandler.InjectDecoder(decoder)).Should(BeNil())
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ var _ = Describe("Test Application Mutator", func() {
|
||||
Expect(utilfeature.DefaultMutableFeatureGate.Set(fmt.Sprintf("%s=true", features.AuthenticateApplication))).Should(Succeed())
|
||||
resp := mutatingHandler.Handle(ctx, admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
UserInfo: authv1.UserInfo{Groups: []string{common.Group}},
|
||||
UserInfo: authv1.UserInfo{Username: types.VelaCoreName},
|
||||
}})
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
Expect(resp.Patches).Should(BeNil())
|
||||
|
||||
@@ -208,7 +208,7 @@ func applyComponents(apply oamProvider.ComponentApply, healthCheck oamProvider.C
|
||||
var reasons []string
|
||||
for i, res := range results {
|
||||
if res.err != nil {
|
||||
errs = append(errs, res.err)
|
||||
errs = append(errs, fmt.Errorf("error encountered in cluster %s: %w", todoTasks[i].placement.Cluster, res.err))
|
||||
}
|
||||
if !res.healthy {
|
||||
allHealthy = false
|
||||
|
||||
Reference in New Issue
Block a user