github.com/oam-dev/kubevela@v1.9.11/pkg/auth/userinfo.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package auth
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"regexp"
    23  	"strings"
    24  
    25  	authv1 "k8s.io/api/authentication/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apiserver/pkg/authentication/user"
    28  	"k8s.io/apiserver/pkg/endpoints/request"
    29  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    30  	"k8s.io/utils/strings/slices"
    31  
    32  	monitorContext "github.com/kubevela/pkg/monitor/context"
    33  
    34  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    35  	"github.com/oam-dev/kubevela/pkg/features"
    36  	"github.com/oam-dev/kubevela/pkg/oam"
    37  )
    38  
    39  const (
    40  	groupSeparator = ","
    41  )
    42  
    43  // ContextWithUserInfo inject username & group from app annotations into context
    44  // If serviceAccount is set and username is empty, identity will user the serviceAccount
    45  func ContextWithUserInfo(ctx context.Context, app *v1beta1.Application) context.Context {
    46  	if app == nil {
    47  		return ctx
    48  	}
    49  	return request.WithUser(ctx, GetUserInfoInAnnotation(&app.ObjectMeta))
    50  }
    51  
    52  // MonitorContextWithUserInfo inject username & group from app annotations into monitor context
    53  func MonitorContextWithUserInfo(ctx monitorContext.Context, app *v1beta1.Application) monitorContext.Context {
    54  	_ctx := ctx.GetContext()
    55  	authCtx := ContextWithUserInfo(_ctx, app)
    56  	ctx.SetContext(authCtx)
    57  	return ctx
    58  }
    59  
    60  // ContextClearUserInfo clear user info in context
    61  func ContextClearUserInfo(ctx context.Context) context.Context {
    62  	return request.WithUser(ctx, nil)
    63  }
    64  
    65  // SetUserInfoInAnnotation set username and group from userInfo into annotations
    66  // it will clear the existing service account annotation in avoid of permission leak
    67  func SetUserInfoInAnnotation(obj *metav1.ObjectMeta, userInfo authv1.UserInfo) {
    68  	if AuthenticationWithUser {
    69  		metav1.SetMetaDataAnnotation(obj, oam.AnnotationApplicationUsername, userInfo.Username)
    70  	}
    71  	re := regexp.MustCompile(strings.ReplaceAll(AuthenticationGroupPattern, "*", ".*"))
    72  	var groups []string
    73  	for _, group := range userInfo.Groups {
    74  		if re.MatchString(group) {
    75  			groups = append(groups, group)
    76  		}
    77  	}
    78  	metav1.SetMetaDataAnnotation(obj, oam.AnnotationApplicationGroup, strings.Join(groups, groupSeparator))
    79  }
    80  
    81  // GetUserInfoInAnnotation extract user info from annotations
    82  // support compatibility for serviceAccount when name is empty
    83  func GetUserInfoInAnnotation(obj *metav1.ObjectMeta) user.Info {
    84  	annotations := obj.GetAnnotations()
    85  	if annotations == nil {
    86  		annotations = map[string]string{}
    87  	}
    88  
    89  	name := annotations[oam.AnnotationApplicationUsername]
    90  	if serviceAccountName := annotations[oam.AnnotationApplicationServiceAccountName]; serviceAccountName != "" && name == "" {
    91  		name = fmt.Sprintf("system:serviceaccount:%s:%s", obj.GetNamespace(), serviceAccountName)
    92  	}
    93  
    94  	if name == "" && utilfeature.DefaultMutableFeatureGate.Enabled(features.AuthenticateApplication) {
    95  		name = AuthenticationDefaultUser
    96  	}
    97  
    98  	return &user.DefaultInfo{
    99  		Name: name,
   100  		Groups: slices.Filter(
   101  			[]string{},
   102  			strings.Split(annotations[oam.AnnotationApplicationGroup], groupSeparator),
   103  			func(s string) bool {
   104  				return len(strings.TrimSpace(s)) > 0
   105  			}),
   106  	}
   107  }