// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update func TestValidNamespace(t *testing.T) { ctx := api.NewDefaultContext() namespace, _ := api.NamespaceFrom(ctx) resource := api.ReplicationController{} if !api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("expected success") } if namespace != resource.Namespace { t.Errorf("expected resource to have the default namespace assigned during validation") } resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}} if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match because resource has different namespace") } ctx = api.NewContext() if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match since context has no namespace") } ctx = api.NewContext() ns := api.NamespaceValue(ctx) if ns != "" { t.Errorf("Expected the empty string") } }
// Get retrieves all pull type secrets in the current namespace. Name is currently ignored and // reserved for future use. func (r *REST) Get(ctx kapi.Context, _ string, options runtime.Object) (runtime.Object, error) { listOptions, ok := options.(*kapi.ListOptions) if !ok { return nil, fmt.Errorf("unexpected options: %v", listOptions) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { ns = kapi.NamespaceAll } secrets, err := r.secrets.Secrets(ns).List(*listOptions) if err != nil { return nil, err } filtered := make([]kapi.Secret, 0, len(secrets.Items)) for i := range secrets.Items { if secrets.Items[i].Annotations[api.ExcludeImageSecretAnnotation] == "true" { continue } switch secrets.Items[i].Type { case kapi.SecretTypeDockercfg, kapi.SecretTypeDockerConfigJson: filtered = append(filtered, secrets.Items[i]) } } secrets.Items = filtered return secrets, nil }
func (g *podGetter) Get(ctx kapi.Context, name string) (runtime.Object, error) { ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("namespace parameter required.") } return g.podsNamespacer.Pods(ns).Get(name) }
// TestNamespaceContext validates that a namespace can be get/set on a context object func TestNamespaceContext(t *testing.T) { ctx := api.NewDefaultContext() result, ok := api.NamespaceFrom(ctx) if !ok { t.Errorf("Error getting namespace") } if api.NamespaceDefault != result { t.Errorf("Expected: %v, Actual: %v", api.NamespaceDefault, result) } ctx = api.NewContext() result, ok = api.NamespaceFrom(ctx) if ok { t.Errorf("Should not be ok because there is no namespace on the context") } }
// namespacingFilter adds a filter that adds the namespace of the request to the context. Not all requests will have namespaces, // but any that do will have the appropriate value added. func namespacingFilter(handler http.Handler, contextMapper kapi.RequestContextMapper) http.Handler { infoResolver := &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "osapi", "oapi", "apis"), GrouplessAPIPrefixes: sets.NewString("api", "osapi", "oapi")} return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx, ok := contextMapper.Get(req) if !ok { http.Error(w, "Unable to find request context", http.StatusInternalServerError) return } if _, exists := kapi.NamespaceFrom(ctx); !exists { if requestInfo, err := infoResolver.GetRequestInfo(req); err == nil { // only set the namespace if the apiRequestInfo was resolved // keep in mind that GetAPIRequestInfo will fail on non-api requests, so don't fail the entire http request on that // kind of failure. // TODO reconsider special casing this. Having the special case hereallow us to fully share the kube // APIRequestInfoResolver without any modification or customization. namespace := requestInfo.Namespace if (requestInfo.Resource == "projects") && (len(requestInfo.Name) > 0) { namespace = requestInfo.Name } ctx = kapi.WithNamespace(ctx, namespace) contextMapper.Update(req, ctx) } } handler.ServeHTTP(w, req) }) }
func NewTestGenericEtcdRegistry(t *testing.T) (*etcdtesting.EtcdTestServer, *Etcd) { podPrefix := "/pods" server := etcdtesting.NewEtcdTestClientServer(t) s := etcdstorage.NewEtcdStorage(server.Client, testapi.Default.Codec(), etcdtest.PathPrefix()) strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} return server, &Etcd{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, EndpointName: "pods", CreateStrategy: strategy, UpdateStrategy: strategy, KeyRootFunc: func(ctx api.Context) string { return podPrefix }, KeyFunc: func(ctx api.Context, id string) (string, error) { if _, ok := api.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, Storage: s, } }
func cacheKey(ctx kapi.Context, a authorizer.Action) (string, error) { if a.GetRequestAttributes() != nil { // TODO: see if we can serialize this? return "", errors.New("cannot cache request attributes") } keyData := map[string]interface{}{ "verb": a.GetVerb(), "apiVersion": a.GetAPIVersion(), "apiGroup": a.GetAPIGroup(), "resource": a.GetResource(), "resourceName": a.GetResourceName(), "nonResourceURL": a.IsNonResourceURL(), "url": a.GetURL(), } if namespace, ok := kapi.NamespaceFrom(ctx); ok { keyData["namespace"] = namespace } if user, ok := kapi.UserFrom(ctx); ok { keyData["user"] = user.GetName() keyData["groups"] = user.GetGroups() keyData["scopes"] = user.GetExtra()[authorizationapi.ScopesKey] } key, err := json.Marshal(keyData) return string(key), err }
// Update scales the DeploymentConfig for the given Scale subresource, returning the updated Scale. func (r *ScaleREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*extensions.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } // fake an existing object to validate existing := &extensions.Scale{ ObjectMeta: kapi.ObjectMeta{ Name: scale.Name, CreationTimestamp: scale.CreationTimestamp, }, } if existing.Namespace, ok = kapi.NamespaceFrom(ctx); !ok { existing.Namespace = scale.Namespace } if errs := extvalidation.ValidateScaleUpdate(scale, existing); len(errs) > 0 { return nil, false, errors.NewInvalid("scale", scale.Name, errs) } deploymentConfig, err := r.registry.GetDeploymentConfig(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound("scale", scale.Name) } scaleRet := &extensions.Scale{ ObjectMeta: kapi.ObjectMeta{ Name: deploymentConfig.Name, Namespace: deploymentConfig.Namespace, CreationTimestamp: deploymentConfig.CreationTimestamp, }, Spec: extensions.ScaleSpec{ Replicas: scale.Spec.Replicas, }, Status: extensions.ScaleStatus{ Selector: deploymentConfig.Spec.Selector, }, } // TODO(directxman12): this is going to be a bit out of sync, since we are calculating it // here and not as part of the deploymentconfig loop -- is there a better way of doing it? totalReplicas, err := r.replicasForDeploymentConfig(deploymentConfig.Namespace, deploymentConfig.Name) if err != nil { return nil, false, err } oldReplicas := deploymentConfig.Spec.Replicas deploymentConfig.Spec.Replicas = scale.Spec.Replicas if err := r.registry.UpdateDeploymentConfig(ctx, deploymentConfig); err != nil { return nil, false, err } scaleRet.Status.Replicas = totalReplicas + (scale.Spec.Replicas - oldReplicas) return scaleRet, false, nil }
// Create registers a given new PodSecurityPolicyReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspr, ok := obj.(*securityapi.PodSecurityPolicyReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicyReview: %#v", obj)) } if errs := securityvalidation.ValidatePodSecurityPolicyReview(pspr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicyReview"), "", errs) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } serviceAccounts, err := getServiceAccounts(pspr.Spec, r.saCache, ns) if err != nil { return nil, kapierrors.NewBadRequest(err.Error()) } if len(serviceAccounts) == 0 { glog.Errorf("No service accounts for namespace %s", ns) return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find ServiceAccount for namespace: %s", ns)) } errs := []error{} newStatus := securityapi.PodSecurityPolicyReviewStatus{} for _, sa := range serviceAccounts { userInfo := serviceaccount.UserInfo(ns, sa.Name, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { errs = append(errs, fmt.Errorf("unable to find SecurityContextConstraints for ServiceAccount %s: %v", sa.Name, err)) continue } oscc.DeduplicateSecurityContextConstraints(saConstraints) sort.Sort(oscc.ByPriority(saConstraints)) var namespace *kapi.Namespace for _, constraint := range saConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) pspsrs := securityapi.PodSecurityPolicySubjectReviewStatus{} if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { errs = append(errs, fmt.Errorf("unable to create provider for service account %s: %v", sa.Name, err)) continue } _, err = podsecuritypolicysubjectreview.FillPodSecurityPolicySubjectReviewStatus(&pspsrs, provider, pspr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicyReviewStatus from constraint %v", err) continue } sapsprs := securityapi.ServiceAccountPodSecurityPolicyReviewStatus{pspsrs, sa.Name} newStatus.AllowedServiceAccounts = append(newStatus.AllowedServiceAccounts, sapsprs) } } if len(errs) > 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("%s", kerrors.NewAggregate(errs))) } pspr.Status = newStatus return pspr, nil }
// NamespaceKeyRootFunc is the default function for constructing storage paths to resource directories enforcing namespace rules. func NamespaceKeyRootFunc(ctx api.Context, prefix string) string { key := prefix ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { key = key + "/" + ns } return key }
// MakeEtcdListKey constructs etcd paths to resource directories enforcing namespace rules func MakeEtcdListKey(ctx api.Context, prefix string) string { key := prefix ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { key = key + "/" + ns } return key }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { istag, ok := obj.(*imageapi.ImageStreamTag) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("obj is not an ImageStreamTag: %#v", obj)) } if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { return nil, err } namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("a namespace must be specified to import images") } imageStreamName, imageTag, ok := imageapi.SplitImageStreamTag(istag.Name) if !ok { return nil, fmt.Errorf("%q must be of the form <stream_name>:<tag>", istag.Name) } target, err := r.imageStreamRegistry.GetImageStream(ctx, imageStreamName) if err != nil { if !kapierrors.IsNotFound(err) { return nil, err } // try to create the target if it doesn't exist target = &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: imageStreamName, Namespace: namespace, }, } } if target.Spec.Tags == nil { target.Spec.Tags = make(map[string]imageapi.TagReference) } // The user wants to symlink a tag. _, exists := target.Spec.Tags[imageTag] if exists { return nil, kapierrors.NewAlreadyExists(imageapi.Resource("imagestreamtag"), istag.Name) } target.Spec.Tags[imageTag] = *istag.Tag // Check the stream creation timestamp and make sure we will not // create a new image stream while deleting. if target.CreationTimestamp.IsZero() { _, err = r.imageStreamRegistry.CreateImageStream(ctx, target) } else { _, err = r.imageStreamRegistry.UpdateImageStream(ctx, target) } if err != nil { return nil, err } return istag, nil }
func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (*etcdtesting.EtcdTestServer, *Store) { podPrefix := "/pods" server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} sc.Codec = testapi.Default.StorageCodec() s, err := factory.Create(*sc) if err != nil { t.Fatalf("Error creating storage: %v", err) } if hasCacheEnabled { config := storage.CacherConfig{ CacheCapacity: 10, Storage: s, Versioner: etcdstorage.APIObjectVersioner{}, Type: &api.Pod{}, ResourcePrefix: podPrefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(podPrefix, obj) }, NewListFunc: func() runtime.Object { return &api.PodList{} }, Codec: sc.Codec, } s = storage.NewCacherFromConfig(config) } return server, &Store{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, QualifiedResource: api.Resource("pods"), CreateStrategy: strategy, UpdateStrategy: strategy, DeleteStrategy: strategy, KeyRootFunc: func(ctx api.Context) string { return podPrefix }, KeyFunc: func(ctx api.Context, id string) (string, error) { if _, ok := api.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod, ok := obj.(*api.Pod) if !ok { return nil, nil, fmt.Errorf("not a pod") } return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(pod.ObjectMeta, true), nil }, } }, Storage: s, } }
// NoNamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing // If a namespace is on context, it errors. func NoNamespaceKeyFunc(ctx kapi.Context, prefix string, name string) (string, error) { ns, ok := kapi.NamespaceFrom(ctx) if ok && len(ns) > 0 { return "", kerrors.NewBadRequest("Namespace parameter is not allowed.") } if len(name) == 0 { return "", kerrors.NewBadRequest("Name parameter required.") } return path.Join(prefix, name), nil }
func (r *staticRoles) ListClusterRoleBindings(ctx api.Context, options *api.ListOptions) (*rbac.ClusterRoleBindingList, error) { namespace, ok := api.NamespaceFrom(ctx) if ok && namespace != "" { return nil, errors.New("cannot list cluster role bindings from within a namespace") } clusterRoleBindings := new(rbac.ClusterRoleBindingList) clusterRoleBindings.Items = make([]rbac.ClusterRoleBinding, len(r.clusterRoleBindings)) copy(clusterRoleBindings.Items, r.clusterRoleBindings) return clusterRoleBindings, nil }
// Create registers a given new PodSecurityPolicySubjectReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspsr, ok := obj.(*securityapi.PodSecurityPolicySubjectReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicySubjectReview: %#v", obj)) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } if errs := securityvalidation.ValidatePodSecurityPolicySubjectReview(pspsr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicySubjectReview"), "", errs) } userInfo := &user.DefaultInfo{Name: pspsr.Spec.User, Groups: pspsr.Spec.Groups} matchedConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } saName := pspsr.Spec.Template.Spec.ServiceAccountName if len(saName) > 0 { saUserInfo := serviceaccount.UserInfo(ns, saName, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(saUserInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } matchedConstraints = append(matchedConstraints, saConstraints...) } oscc.DeduplicateSecurityContextConstraints(matchedConstraints) sort.Sort(oscc.ByPriority(matchedConstraints)) var namespace *kapi.Namespace for _, constraint := range matchedConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { glog.Errorf("Unable to create provider for constraint: %v", err) continue } filled, err := FillPodSecurityPolicySubjectReviewStatus(&pspsr.Status, provider, pspsr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicySubjectReviewStatus from constraint %v", err) continue } if filled { return pspsr, nil } } return pspsr, nil }
// MakeEtcdItemKey constructs etcd paths to a resource relative to prefix enforcing namespace rules. If no namespace is on context, it errors. func MakeEtcdItemKey(ctx api.Context, prefix string, id string) (string, error) { key := MakeEtcdListKey(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", fmt.Errorf("invalid request. Namespace parameter required.") } if len(id) == 0 { return "", fmt.Errorf("invalid request. Id parameter required.") } key = key + "/" + id return key, nil }
// NamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } key = key + "/" + name return key, nil }
func (r *staticRoles) GetRole(ctx api.Context, id string) (*rbac.Role, error) { namespace, ok := api.NamespaceFrom(ctx) if !ok || namespace == "" { return nil, errors.New("must provide namespace when getting role") } for _, role := range r.roles { if role.Namespace == namespace && role.Name == id { return &role, nil } } return nil, errors.New("role not found") }
func (r *staticRoles) GetClusterRole(ctx api.Context, id string) (*rbac.ClusterRole, error) { namespace, ok := api.NamespaceFrom(ctx) if ok && namespace != "" { return nil, errors.New("cannot provide namespace when getting cluster role") } for _, clusterRole := range r.clusterRoles { if clusterRole.Namespace == namespace && clusterRole.Name == id { return &clusterRole, nil } } return nil, errors.New("role not found") }
// Create generates a new DeploymentConfig representing a rollback. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kerrors.NewBadRequest("namespace parameter required.") } rollback, ok := obj.(*deployapi.DeploymentConfigRollback) if !ok { return nil, kerrors.NewBadRequest(fmt.Sprintf("not a rollback spec: %#v", obj)) } if errs := validation.ValidateDeploymentConfigRollback(rollback); len(errs) > 0 { return nil, kerrors.NewInvalid(deployapi.Kind("DeploymentConfigRollback"), rollback.Name, errs) } from, err := r.dn.DeploymentConfigs(namespace).Get(rollback.Name) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("cannot get deployment config %q: %v", rollback.Name, err)) } switch from.Status.LatestVersion { case 0: return nil, newInvalidError(rollback, "cannot rollback an undeployed config") case 1: return nil, newInvalidError(rollback, fmt.Sprintf("no previous deployment exists for %q", deployutil.LabelForDeploymentConfig(from))) } revision := from.Status.LatestVersion - 1 if rollback.Spec.Revision > 0 { revision = rollback.Spec.Revision } // Find the target deployment and decode its config. name := deployutil.DeploymentNameForConfigVersion(from.Name, revision) targetDeployment, err := r.rn.ReplicationControllers(namespace).Get(name) if err != nil { return nil, newInvalidError(rollback, err.Error()) } to, err := deployutil.DecodeDeploymentConfig(targetDeployment, r.codec) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("couldn't decode deployment config from deployment: %v", err)) } if from.Annotations == nil && len(rollback.UpdatedAnnotations) > 0 { from.Annotations = make(map[string]string) } for key, value := range rollback.UpdatedAnnotations { from.Annotations[key] = value } return r.generator.GenerateRollback(from, to, &rollback.Spec) }
func ConfirmNoEscalation(ctx kapi.Context, resource unversioned.GroupResource, name string, ruleResolver, cachedRuleResolver AuthorizationRuleResolver, role authorizationinterfaces.Role) error { var ruleResolutionErrors []error user, ok := kapi.UserFrom(ctx) if !ok { return kapierrors.NewForbidden(resource, name, fmt.Errorf("no user provided in context")) } namespace, _ := kapi.NamespaceFrom(ctx) // if a cached resolver is provided, attempt to verify coverage against the cache, then fall back to the normal // path otherwise if cachedRuleResolver != nil { if ownerRules, err := cachedRuleResolver.RulesFor(user, namespace); err == nil { if ownerRightsCover, _ := Covers(ownerRules, role.Rules()); ownerRightsCover { return nil } } } ownerRules, err := ruleResolver.RulesFor(user, namespace) if err != nil { // do not fail in this case. Rules are purely additive, so we can continue with a coverage check based on the rules we have glog.V(1).Infof("non-fatal error getting rules for %v: %v", user, err) ruleResolutionErrors = append(ruleResolutionErrors, err) } ownerRightsCover, missingRights := Covers(ownerRules, role.Rules()) if ownerRightsCover { return nil } // determine what resources the user is missing if compactedMissingRights, err := CompactRules(missingRights); err == nil { missingRights = compactedMissingRights } missingRightsStrings := make([]string, 0, len(missingRights)) for _, missingRight := range missingRights { missingRightsStrings = append(missingRightsStrings, missingRight.CompactString()) } sort.Strings(missingRightsStrings) var internalErr error if len(ruleResolutionErrors) > 0 { internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v\nrule resolution errors: %v)", user.GetName(), strings.Join(missingRightsStrings, "\n"), ruleResolutionErrors) } else { internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v", user.GetName(), strings.Join(missingRightsStrings, "\n")) } return kapierrors.NewForbidden(resource, name, internalErr) }
// NamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } if ok, msg := validation.ValidatePathSegmentName(name, false); !ok { return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %v.", msg)) } key = key + "/" + name return key, nil }
// NamespaceKeyFunc is the default function for constructing storage paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } if msgs := validation.IsValidPathSegmentName(name); len(msgs) != 0 { return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) } key = key + "/" + name return key, nil }
func (r *staticRoles) ListRoleBindings(ctx api.Context, options *api.ListOptions) (*rbac.RoleBindingList, error) { namespace, ok := api.NamespaceFrom(ctx) if !ok || namespace == "" { return nil, errors.New("must provide namespace when listing role bindings") } roleBindingList := new(rbac.RoleBindingList) for _, roleBinding := range r.roleBindings { if roleBinding.Namespace != namespace { continue } // TODO(ericchiang): need to implement label selectors? roleBindingList.Items = append(roleBindingList.Items, roleBinding) } return roleBindingList, nil }
func (s StatusStrategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList { newIS := obj.(*api.ImageStream) errs := field.ErrorList{} ns, ok := kapi.NamespaceFrom(ctx) if !ok { ns = newIS.Namespace } err := s.limitVerifier.VerifyLimits(ns, newIS) if err != nil { errs = append(errs, field.Forbidden(field.NewPath("imageStream"), err.Error())) } // TODO: merge valid fields after update errs = append(errs, validation.ValidateImageStreamStatusUpdate(newIS, old.(*api.ImageStream))...) return errs }
// ListPolicyBindings obtains list of policyBindings that match a selector. It conforms to rulevalidation.BindingLister func (c readOnlyAuthorizationCache) ListPolicyBindings(ctx kapi.Context, options *unversioned.ListOptions) (*authorizationapi.PolicyBindingList, error) { namespace, _ := kapi.NamespaceFrom(ctx) if namespaceRefersToCluster(namespace) { clusterPolicyBindingList, err := c.ReadOnlyClusterPolicyBindings().List(options) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return authorizationapi.ToPolicyBindingList(clusterPolicyBindingList), nil } else { policyBindingList, err := c.ReadOnlyPolicyBindings(namespace).List(options) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return policyBindingList, nil } }
// ListPolicyBindings obtains list of policyBindings that match a selector. It conforms to rulevalidation.BindingLister func (c readOnlyAuthorizationCache) ListPolicyBindings(ctx kapi.Context, label labels.Selector, field fields.Selector) (*authorizationapi.PolicyBindingList, error) { namespace, _ := kapi.NamespaceFrom(ctx) if namespaceRefersToCluster(namespace) { clusterPolicyBindingList, err := c.ReadOnlyClusterPolicyBindings().List(label, field) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return authorizationapi.ToPolicyBindingList(clusterPolicyBindingList), nil } else { policyBindingList, err := c.ReadOnlyPolicyBindings(namespace).List(label, field) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return policyBindingList, nil } }
// GetPolicy retrieves a specific policy. It conforms to rulevalidation.PolicyGetter. func (c readOnlyAuthorizationCache) GetPolicy(ctx kapi.Context, name string) (*authorizationapi.Policy, error) { namespace, _ := kapi.NamespaceFrom(ctx) if namespaceRefersToCluster(namespace) { clusterPolicy, err := c.ReadOnlyClusterPolicies().Get(name) if err != nil { return &authorizationapi.Policy{}, err } return authorizationapi.ToPolicy(clusterPolicy), nil } else { policy, err := c.ReadOnlyPolicies(namespace).Get(name) if err != nil { return &authorizationapi.Policy{}, err } return policy, nil } }
func (r *RemoteAuthorizer) Authorize(ctx kapi.Context, a authorizer.AuthorizationAttributes) (bool, string, error) { var ( result *authzapi.SubjectAccessReviewResponse err error ) // Extract namespace from context namespace, _ := kapi.NamespaceFrom(ctx) // Extract user from context user := "" groups := sets.NewString() if userInfo, ok := kapi.UserFrom(ctx); ok { user = userInfo.GetName() groups.Insert(userInfo.GetGroups()...) } // Make sure we don't run a subject access review on our own permissions if len(user) == 0 && len(groups) == 0 { user = bootstrappolicy.UnauthenticatedUsername groups = sets.NewString(bootstrappolicy.UnauthenticatedGroup) } if len(namespace) > 0 { result, err = r.client.LocalSubjectAccessReviews(namespace).Create(&authzapi.LocalSubjectAccessReview{ User: user, Groups: groups, Action: getAction(namespace, a), }) } else { result, err = r.client.SubjectAccessReviews().Create(&authzapi.SubjectAccessReview{ User: user, Groups: groups, Action: getAction(namespace, a), }) } if err != nil { glog.Errorf("error running subject access review: %v", err) return false, "", kerrs.NewInternalError(err) } glog.V(2).Infof("allowed=%v, reason=%s", result.Allowed, result.Reason) return result.Allowed, result.Reason, nil }