...

Source file src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1/authorize.go

Documentation: kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1

     1  /*
     2  Copyright 2020 The CDI 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 v1beta1
    18  
    19  import (
    20  	"errors"
    21  
    22  	authentication "k8s.io/api/authentication/v1"
    23  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    24  	"k8s.io/klog/v2"
    25  
    26  	"kubevirt.io/containerized-data-importer-api/pkg/apis/core"
    27  )
    28  
    29  const (
    30  	// AnnPrePopulated is a PVC annotation telling the datavolume controller that the PVC is already populated
    31  	AnnPrePopulated = core.GroupName + "/storage.prePopulated"
    32  	// AnnCheckStaticVolume checks if a statically allocated PV exists before creating the target PVC.
    33  	// If so, PVC is still created but population is skipped
    34  	AnnCheckStaticVolume = core.GroupName + "/storage.checkStaticVolume"
    35  )
    36  
    37  // ErrNoTokenOkay indicates proceeding without token is allowed
    38  // This error should only be of interest to entities that give out DataVolume tokens
    39  var ErrNoTokenOkay = errors.New("proceeding without token is okay under the circumstances")
    40  
    41  // AuthorizeUser indicates if the creating user is authorized to create the data volume
    42  // For sources other than clone (import/upload/etc), this is a no-op
    43  func (dv *DataVolume) AuthorizeUser(requestNamespace, requestName string, proxy AuthorizationHelperProxy, userInfo authentication.UserInfo) (CloneAuthResponse, error) {
    44  	_, prePopulated := dv.Annotations[AnnPrePopulated]
    45  	_, checkStaticVolume := dv.Annotations[AnnCheckStaticVolume]
    46  	noTokenOkay := prePopulated || checkStaticVolume
    47  
    48  	targetNamespace, targetName := dv.Namespace, dv.Name
    49  	if targetNamespace == "" {
    50  		targetNamespace = requestNamespace
    51  	}
    52  	if targetName == "" {
    53  		targetName = requestName
    54  	}
    55  
    56  	cloneSourceHandler, err := newCloneSourceHandler(dv, proxy.GetDataSource)
    57  	if err != nil {
    58  		if k8serrors.IsNotFound(err) && noTokenOkay {
    59  			// no token needed, likely since no datasource
    60  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, no datasource", targetNamespace, targetName)
    61  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
    62  		}
    63  		return CloneAuthResponse{Allowed: false, Reason: "", Handler: cloneSourceHandler}, err
    64  	}
    65  
    66  	if cloneSourceHandler.CloneType == noClone {
    67  		klog.V(3).Infof("DataVolume %s/%s not cloning", targetNamespace, targetName)
    68  		return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
    69  	}
    70  
    71  	sourceName, sourceNamespace := cloneSourceHandler.SourceName, cloneSourceHandler.SourceNamespace
    72  	if sourceNamespace == "" {
    73  		sourceNamespace = targetNamespace
    74  	}
    75  
    76  	_, err = proxy.GetNamespace(sourceNamespace)
    77  	if err != nil {
    78  		if k8serrors.IsNotFound(err) && noTokenOkay {
    79  			// no token needed, likely since no source namespace
    80  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, no source namespace", targetNamespace, targetName)
    81  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
    82  		}
    83  		return CloneAuthResponse{Allowed: false, Reason: "", Handler: cloneSourceHandler}, err
    84  	}
    85  
    86  	ok, reason, err := cloneSourceHandler.UserCloneAuthFunc(proxy.CreateSar, sourceNamespace, sourceName, targetNamespace, userInfo)
    87  	if err != nil {
    88  		return CloneAuthResponse{Allowed: false, Reason: reason, Handler: cloneSourceHandler}, err
    89  	}
    90  
    91  	if !ok {
    92  		if noTokenOkay {
    93  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, auth failed", targetNamespace, targetName)
    94  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
    95  		}
    96  	}
    97  
    98  	return CloneAuthResponse{Allowed: ok, Reason: reason, Handler: cloneSourceHandler}, err
    99  }
   100  
   101  // AuthorizeSA indicates if the creating ServiceAccount is authorized to create the data volume
   102  // For sources other than clone (import/upload/etc), this is a no-op
   103  func (dv *DataVolume) AuthorizeSA(requestNamespace, requestName string, proxy AuthorizationHelperProxy, saNamespace, saName string) (CloneAuthResponse, error) {
   104  	_, prePopulated := dv.Annotations[AnnPrePopulated]
   105  	_, checkStaticVolume := dv.Annotations[AnnCheckStaticVolume]
   106  	noTokenOkay := prePopulated || checkStaticVolume
   107  
   108  	targetNamespace, targetName := dv.Namespace, dv.Name
   109  	if targetNamespace == "" {
   110  		targetNamespace = requestNamespace
   111  	}
   112  	if saNamespace == "" {
   113  		saNamespace = targetNamespace
   114  	}
   115  	if targetName == "" {
   116  		targetName = requestName
   117  	}
   118  
   119  	cloneSourceHandler, err := newCloneSourceHandler(dv, proxy.GetDataSource)
   120  	if err != nil {
   121  		if k8serrors.IsNotFound(err) && noTokenOkay {
   122  			// no token needed, likely since no datasource
   123  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, no datasource", targetNamespace, targetName)
   124  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
   125  		}
   126  		return CloneAuthResponse{Allowed: false, Reason: "", Handler: cloneSourceHandler}, err
   127  	}
   128  
   129  	if cloneSourceHandler.CloneType == noClone {
   130  		klog.V(3).Infof("DataVolume %s/%s not cloning", targetNamespace, targetName)
   131  		return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
   132  	}
   133  
   134  	sourceName, sourceNamespace := cloneSourceHandler.SourceName, cloneSourceHandler.SourceNamespace
   135  	if sourceNamespace == "" {
   136  		sourceNamespace = targetNamespace
   137  	}
   138  
   139  	_, err = proxy.GetNamespace(sourceNamespace)
   140  	if err != nil {
   141  		if k8serrors.IsNotFound(err) && noTokenOkay {
   142  			// no token needed, likely since no source namespace
   143  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, no source namespace", targetNamespace, targetName)
   144  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
   145  		}
   146  		return CloneAuthResponse{Allowed: false, Reason: "", Handler: cloneSourceHandler}, err
   147  	}
   148  
   149  	ok, reason, err := cloneSourceHandler.SACloneAuthFunc(proxy.CreateSar, sourceNamespace, sourceName, saNamespace, saName)
   150  	if err != nil {
   151  		return CloneAuthResponse{Allowed: false, Reason: reason, Handler: cloneSourceHandler}, err
   152  	}
   153  
   154  	if !ok {
   155  		if noTokenOkay {
   156  			klog.V(3).Infof("DataVolume %s/%s is pre/static populated, not adding token, auth failed", targetNamespace, targetName)
   157  			return CloneAuthResponse{Allowed: true, Reason: "", Handler: cloneSourceHandler}, ErrNoTokenOkay
   158  		}
   159  	}
   160  
   161  	return CloneAuthResponse{Allowed: ok, Reason: reason, Handler: cloneSourceHandler}, err
   162  }
   163  

View as plain text