Exemple #1
0
func (s *strategy) Validate(pod *api.Pod, container *api.Container) field.ErrorList {
	if s.allowedProfiles == nil {
		// Unrestricted: allow all.
		return nil
	}

	allErrs := field.ErrorList{}
	fieldPath := field.NewPath("pod", "metadata", "annotations").Key(apparmor.ContainerAnnotationKeyPrefix + container.Name)

	profile := apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name)
	if profile == "" {
		if len(s.allowedProfiles) > 0 {
			allErrs = append(allErrs, field.Forbidden(fieldPath, "AppArmor profile must be set"))
			return allErrs
		}
		return nil
	}

	if !s.allowedProfiles[profile] {
		msg := fmt.Sprintf("%s is not an allowed profile. Allowed values: %q", profile, s.allowedProfilesString)
		allErrs = append(allErrs, field.Forbidden(fieldPath, msg))
	}

	return allErrs
}
// Admit determines if the service should be admitted based on the configured network CIDR.
func (r *externalIPRanger) Admit(a kadmission.Attributes) error {
	if a.GetResource() != kapi.Resource("services") {
		return nil
	}

	svc, ok := a.GetObject().(*kapi.Service)
	// if we can't convert then we don't handle this object so just return
	if !ok {
		return nil
	}

	var errs field.ErrorList
	switch {
	// administrator disabled externalIPs
	case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0:
		errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled"))
	// administrator has limited the range
	case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0:
		for i, s := range svc.Spec.ExternalIPs {
			ip := net.ParseIP(s)
			if ip == nil {
				errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address"))
				continue
			}
			if networkSlice(r.reject).Contains(ip) || !networkSlice(r.admit).Contains(ip) {
				errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed"))
				continue
			}
		}
	}
	if len(errs) > 0 {
		return apierrs.NewInvalid(a.GetKind(), a.GetName(), errs)
	}
	return nil
}
Exemple #3
0
func validateRoleBindingSubject(subject kapi.ObjectReference, isNamespaced bool, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}

	if len(subject.Name) == 0 {
		allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
	}
	if len(subject.UID) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("uid"), fmt.Sprintf("%v", subject.UID)))
	}
	if len(subject.APIVersion) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("apiVersion"), subject.APIVersion))
	}
	if len(subject.ResourceVersion) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("resourceVersion"), subject.ResourceVersion))
	}
	if len(subject.FieldPath) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("fieldPath"), subject.FieldPath))
	}

	switch subject.Kind {
	case authorizationapi.ServiceAccountKind:
		if reasons := validation.ValidateServiceAccountName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
		}
		if !isNamespaced && len(subject.Namespace) == 0 {
			allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "Service account subjects for ClusterRoleBindings must have a namespace"))
		}

	case authorizationapi.UserKind:
		if reasons := uservalidation.ValidateUserName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
		}

	case authorizationapi.GroupKind:
		if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
		}

	case authorizationapi.SystemUserKind:
		isValidSAName := len(validation.ValidateServiceAccountName(subject.Name, false)) == 0
		isValidUserName := len(uservalidation.ValidateUserName(subject.Name, false)) == 0
		if isValidSAName || isValidUserName {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to User.name or ServiceAccount.name restrictions"))
		}

	case authorizationapi.SystemGroupKind:
		if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) == 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to Group.name restrictions"))
		}

	default:
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("kind"), subject.Kind, []string{authorizationapi.ServiceAccountKind, authorizationapi.UserKind, authorizationapi.GroupKind, authorizationapi.SystemGroupKind, authorizationapi.SystemUserKind}))
	}

	return allErrs
}
// Admit determines if the service should be admitted based on the configured network CIDR.
func (r *externalIPRanger) Admit(a kadmission.Attributes) error {
	if a.GetResource().GroupResource() != kapi.Resource("services") {
		return nil
	}

	svc, ok := a.GetObject().(*kapi.Service)
	// if we can't convert then we don't handle this object so just return
	if !ok {
		return nil
	}

	// Determine if an ingress ip address should be allowed as an
	// external ip by checking the loadbalancer status of the previous
	// object state. Only updates need to be validated against the
	// ingress ip since the loadbalancer status cannot be set on
	// create.
	ingressIP := ""
	retrieveIngressIP := a.GetOperation() == kadmission.Update &&
		r.allowIngressIP && svc.Spec.Type == kapi.ServiceTypeLoadBalancer
	if retrieveIngressIP {
		old, ok := a.GetOldObject().(*kapi.Service)
		ipPresent := ok && old != nil && len(old.Status.LoadBalancer.Ingress) > 0
		if ipPresent {
			ingressIP = old.Status.LoadBalancer.Ingress[0].IP
		}
	}

	var errs field.ErrorList
	switch {
	// administrator disabled externalIPs
	case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0:
		onlyIngressIP := len(svc.Spec.ExternalIPs) == 1 && svc.Spec.ExternalIPs[0] == ingressIP
		if !onlyIngressIP {
			errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled"))
		}
	// administrator has limited the range
	case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0:
		for i, s := range svc.Spec.ExternalIPs {
			ip := net.ParseIP(s)
			if ip == nil {
				errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address"))
				continue
			}
			notIngressIP := s != ingressIP
			if (NetworkSlice(r.reject).Contains(ip) || !NetworkSlice(r.admit).Contains(ip)) && notIngressIP {
				errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed"))
				continue
			}
		}
	}
	if len(errs) > 0 {
		return apierrs.NewInvalid(a.GetKind().GroupKind(), a.GetName(), errs)
	}
	return nil
}
Exemple #5
0
func validateImageSignature(signature *api.ImageSignature, fldPath *field.Path) field.ErrorList {
	allErrs := validation.ValidateObjectMeta(&signature.ObjectMeta, false, oapi.MinimalNameRequirements, fldPath.Child("metadata"))
	if len(signature.Labels) > 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("metadata").Child("labels"), "signature labels cannot be set"))
	}
	if len(signature.Annotations) > 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("metadata").Child("annotations"), "signature annotations cannot be set"))
	}

	if _, _, err := api.SplitImageSignatureName(signature.Name); err != nil {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata").Child("name"), signature.Name, "name must be of format <imageName>@<signatureName>"))
	}
	if len(signature.Type) == 0 {
		allErrs = append(allErrs, field.Required(fldPath.Child("type"), ""))
	}
	if len(signature.Content) == 0 {
		allErrs = append(allErrs, field.Required(fldPath.Child("content"), ""))
	}

	var trustedCondition, forImageCondition *api.SignatureCondition
	for i := range signature.Conditions {
		cond := &signature.Conditions[i]
		if cond.Type == api.SignatureTrusted && (trustedCondition == nil || !cond.LastProbeTime.Before(trustedCondition.LastProbeTime)) {
			trustedCondition = cond
		} else if cond.Type == api.SignatureForImage && forImageCondition == nil || !cond.LastProbeTime.Before(forImageCondition.LastProbeTime) {
			forImageCondition = cond
		}
	}

	if trustedCondition != nil && forImageCondition == nil {
		msg := fmt.Sprintf("missing %q condition type", api.SignatureForImage)
		allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg))
	} else if forImageCondition != nil && trustedCondition == nil {
		msg := fmt.Sprintf("missing %q condition type", api.SignatureTrusted)
		allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg))
	}

	if trustedCondition == nil || trustedCondition.Status == kapi.ConditionUnknown {
		if len(signature.ImageIdentity) != 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("imageIdentity"), signature.ImageIdentity, "must be unset for unknown signature state"))
		}
		if len(signature.SignedClaims) != 0 {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("signedClaims"), signature.SignedClaims, "must be unset for unknown signature state"))
		}
		if signature.IssuedBy != nil {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedBy"), signature.IssuedBy, "must be unset for unknown signature state"))
		}
		if signature.IssuedTo != nil {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedTo"), signature.IssuedTo, "must be unset for unknown signature state"))
		}
	}

	return allErrs
}
Exemple #6
0
// ValidateStorageClassUpdate tests if an update to StorageClass is valid.
func ValidateStorageClassUpdate(storageClass, oldStorageClass *extensions.StorageClass) field.ErrorList {
	allErrs := apivalidation.ValidateObjectMetaUpdate(&storageClass.ObjectMeta, &oldStorageClass.ObjectMeta, field.NewPath("metadata"))
	if !reflect.DeepEqual(oldStorageClass.Parameters, storageClass.Parameters) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("parameters"), "updates to parameters are forbidden."))
	}

	if strings.Compare(storageClass.Provisioner, oldStorageClass.Provisioner) != 0 {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("provisioner"), "updates to provisioner are forbidden."))
	}
	return allErrs
}
Exemple #7
0
// ValidateImageSignatureUpdate ensures that the new ImageSignature is valid.
func ValidateImageSignatureUpdate(newImageSignature, oldImageSignature *api.ImageSignature) field.ErrorList {
	allErrs := validation.ValidateObjectMetaUpdate(&newImageSignature.ObjectMeta, &oldImageSignature.ObjectMeta, field.NewPath("metadata"))
	allErrs = append(allErrs, ValidateImageSignature(newImageSignature)...)

	if newImageSignature.Type != oldImageSignature.Type {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("type"), "cannot change signature type"))
	}
	if !bytes.Equal(newImageSignature.Content, oldImageSignature.Content) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("content"), "cannot change signature content"))
	}

	return allErrs
}
Exemple #8
0
// ValidateNetworkPolicySpec tests if required fields in the networkpolicy spec are set.
func ValidateNetworkPolicySpec(spec *extensions.NetworkPolicySpec, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(&spec.PodSelector, fldPath.Child("podSelector"))...)

	// Validate ingress rules.
	for _, i := range spec.Ingress {
		// TODO: Update From to be a pointer to slice as soon as auto-generation supports it.
		for _, f := range i.From {
			numFroms := 0
			if f.PodSelector != nil {
				numFroms++
				allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(f.PodSelector, fldPath.Child("podSelector"))...)
			}
			if f.NamespaceSelector != nil {
				if numFroms > 0 {
					allErrs = append(allErrs, field.Forbidden(fldPath, "may not specify more than 1 from type"))
				} else {
					numFroms++
					allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(f.NamespaceSelector, fldPath.Child("namespaces"))...)
				}
			}

			if numFroms == 0 {
				// At least one of PodSelector and NamespaceSelector must be defined.
				allErrs = append(allErrs, field.Required(fldPath, "must specify a from type"))
			}
		}
	}
	return allErrs
}
Exemple #9
0
// ValidateNetworkPolicyUpdate tests if an update to a NetworkPolicy is valid.
func ValidateNetworkPolicyUpdate(np, oldNP *extensions.NetworkPolicy) field.ErrorList {
	allErrs := field.ErrorList{}
	if !reflect.DeepEqual(np, oldNP) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to networkpolicy spec are forbidden."))
	}
	return allErrs
}
Exemple #10
0
func (v *WrappingValidator) ValidateUpdate(obj, old runtime.Object) field.ErrorList {
	if v.validateUpdate == nil {
		// if there is no update validation, fail.
		return field.ErrorList{field.Forbidden(field.NewPath("obj"), obj)}
	}

	return callValidateUpdate(reflect.ValueOf(obj), reflect.ValueOf(old), *v.validateUpdate)
}
// ValidatePod ensures that the specified values on the pod fall within the range
// of the strategy.
func (s *strategy) ValidatePod(pod *api.Pod) field.ErrorList {
	allErrs := field.ErrorList{}
	podSpecFieldPath := field.NewPath("pod", "metadata", "annotations").Key(api.SeccompPodAnnotationKey)
	podProfile := pod.Annotations[api.SeccompPodAnnotationKey]

	if !s.allowAnyProfile && len(s.allowedProfiles) == 0 && podProfile != "" {
		allErrs = append(allErrs, field.Forbidden(podSpecFieldPath, "seccomp may not be set"))
		return allErrs
	}

	if !s.profileAllowed(podProfile) {
		msg := fmt.Sprintf("%s is not an allowed seccomp profile. Valid values are %v", podProfile, s.allowedProfilesString)
		allErrs = append(allErrs, field.Forbidden(podSpecFieldPath, msg))
	}

	return allErrs
}
// ValidateContainer ensures that the specified values on the container fall within
// the range of the strategy.
func (s *strategy) ValidateContainer(pod *api.Pod, container *api.Container) field.ErrorList {
	allErrs := field.ErrorList{}
	fieldPath := field.NewPath("pod", "metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix + container.Name)
	containerProfile := profileForContainer(pod, container)

	if !s.allowAnyProfile && len(s.allowedProfiles) == 0 && containerProfile != "" {
		allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set"))
		return allErrs
	}

	if !s.profileAllowed(containerProfile) {
		msg := fmt.Sprintf("%s is not an allowed seccomp profile. Valid values are %v", containerProfile, s.allowedProfilesString)
		allErrs = append(allErrs, field.Forbidden(fieldPath, msg))
	}

	return allErrs
}
Exemple #13
0
// ValidateNetworkPolicyUpdate tests if an update to a NetworkPolicy is valid.
func ValidateNetworkPolicyUpdate(update, old *extensions.NetworkPolicy) field.ErrorList {
	allErrs := field.ErrorList{}
	allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...)
	if !reflect.DeepEqual(update.Spec, old.Spec) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to networkpolicy spec are forbidden."))
	}
	return allErrs
}
Exemple #14
0
// ValidateUpdate is the default update validation for an end user.
func (petSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
	return field.ErrorList{field.Forbidden(field.NewPath("spec"), "updates to petset spec are forbidden.")}

	// TODO: For now we're taking the safe route and disallowing all updates to spec.
	// Enable on a case by case basis.
	//validationErrorList := validation.ValidatePetSet(obj.(*apps.PetSet))
	//updateErrorList := validation.ValidatePetSetUpdate(obj.(*apps.PetSet), old.(*apps.PetSet))
	//return append(validationErrorList, updateErrorList...)
}
Exemple #15
0
// ValidatePod ensures that the specified values on the pod fall within the range
// of the strategy.
func (s *withSeccompProfile) ValidatePod(pod *api.Pod) field.ErrorList {
	allErrs := field.ErrorList{}
	fieldPath := field.NewPath("pod", "metadata", "annotations", api.SeccompPodAnnotationKey)

	podProfile, _ := pod.Annotations[api.SeccompPodAnnotationKey]

	if len(s.allowedProfiles) == 0 && podProfile != "" {

		allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set"))
		return allErrs
	}

	if !isProfileAllowed(podProfile, s.allowedProfiles) {
		msg := fmt.Sprintf("%s is not a valid seccomp profile. Valid values are %v", podProfile, s.allowedProfiles)
		allErrs = append(allErrs, field.Forbidden(fieldPath, msg))
	}

	return allErrs
}
Exemple #16
0
// Validate validates a new image stream.
func (s Strategy) Validate(ctx kapi.Context, obj runtime.Object) field.ErrorList {
	stream := obj.(*api.ImageStream)
	user, ok := kapi.UserFrom(ctx)
	if !ok {
		return field.ErrorList{field.Forbidden(field.NewPath("imageStream"), stream.Name)}
	}
	errs := s.tagVerifier.Verify(nil, stream, user)
	errs = append(errs, s.tagsChanged(nil, stream)...)
	errs = append(errs, validation.ValidateImageStream(stream)...)
	return errs
}
Exemple #17
0
// ValidateContainer ensures that the specified values on the container fall within
// the range of the strategy.
func (s *withSeccompProfile) ValidateContainer(pod *api.Pod, container *api.Container) field.ErrorList {
	allErrs := field.ErrorList{}
	fieldPath := field.NewPath("pod", "metadata", "annotations", api.SeccompContainerAnnotationKeyPrefix+container.Name)

	// container inherits the pod profile if not set.  TODO: when this is a field this can be removed and it should
	// be accounted for in DetermineEffectiveSecurityContext
	containerProfile := profileForContainer(pod, container)

	if len(s.allowedProfiles) == 0 && containerProfile != "" {
		allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set"))
		return allErrs
	}

	if !isProfileAllowed(containerProfile, s.allowedProfiles) {
		msg := fmt.Sprintf("%s is not a valid seccomp profile. Valid values are %v", containerProfile, s.allowedProfiles)
		allErrs = append(allErrs, field.Forbidden(fieldPath, msg))
	}

	return allErrs
}
Exemple #18
0
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	if strategy.RollingUpdate == nil {
		return allErrs
	}
	switch strategy.Type {
	case extensions.RecreateDeploymentStrategyType:
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "may not be specified when strategy `type` is '"+string(extensions.RecreateDeploymentStrategyType+"'")))
	case extensions.RollingUpdateDeploymentStrategyType:
		allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...)
	}
	return allErrs
}
Exemple #19
0
// ValidateDaemonSetTemplateUpdate tests that certain fields in the daemon set's pod template are not updated.
func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	podSpec := podTemplate.Spec
	// podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly.
	podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector
	podSpec.NodeName = oldPodTemplate.Spec.NodeName
	// In particular, we do not allow updates to container images at this point.
	if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) {
		// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec"), "daemonSet updates may not change fields other than `nodeSelector`"))
	}
	return allErrs
}
Exemple #20
0
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	if strategy.RollingUpdate == nil {
		return allErrs
	}
	switch strategy.Type {
	case extensions.RecreateDeploymentStrategyType:
		allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType))
	case extensions.RollingUpdateDeploymentStrategyType:
		allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...)
	}
	return allErrs
}
Exemple #21
0
func ValidatePodDisruptionBudgetUpdate(pdb, oldPdb *policy.PodDisruptionBudget) field.ErrorList {
	allErrs := field.ErrorList{}

	restoreGeneration := pdb.Generation
	pdb.Generation = oldPdb.Generation

	if !reflect.DeepEqual(pdb, oldPdb) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to poddisruptionbudget spec are forbidden."))
	}

	pdb.Generation = restoreGeneration
	return allErrs
}
func (s *mustMatchPatterns) ValidateSysctl(sysctlName string, fldPath *field.Path) field.ErrorList {
	for _, s := range s.patterns {
		if s[len(s)-1] == '*' {
			prefix := s[:len(s)-1]
			if strings.HasPrefix(sysctlName, string(prefix)) {
				return nil
			}
		} else if sysctlName == s {
			return nil
		}
	}
	return field.ErrorList{field.Forbidden(fldPath, fmt.Sprintf("sysctl %q is not allowed", sysctlName))}
}
Exemple #23
0
// ValidateUpdate is the default update validation for an end user.
func (s Strategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList {
	stream := obj.(*api.ImageStream)

	user, ok := kapi.UserFrom(ctx)
	if !ok {
		return field.ErrorList{field.Forbidden(field.NewPath("imageStream"), stream.Name)}
	}
	oldStream := old.(*api.ImageStream)

	errs := s.tagVerifier.Verify(oldStream, stream, user)
	errs = append(errs, s.tagsChanged(oldStream, stream)...)

	ns, ok := kapi.NamespaceFrom(ctx)
	if !ok {
		ns = stream.Namespace
	}
	if err := s.limitVerifier.VerifyLimits(ns, stream); err != nil {
		errs = append(errs, field.Forbidden(field.NewPath("imageStream"), err.Error()))
	}

	errs = append(errs, validation.ValidateImageStreamUpdate(stream, oldStream)...)
	return errs
}
Exemple #24
0
func (v *TagVerifier) Verify(old, stream *api.ImageStream, user user.Info) field.ErrorList {
	var errors field.ErrorList
	oldTags := map[string]api.TagReference{}
	if old != nil && old.Spec.Tags != nil {
		oldTags = old.Spec.Tags
	}
	for tag, tagRef := range stream.Spec.Tags {
		if tagRef.From == nil {
			continue
		}
		if len(tagRef.From.Namespace) == 0 {
			continue
		}
		if stream.Namespace == tagRef.From.Namespace {
			continue
		}
		if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) {
			continue
		}

		streamName, _, err := parseFromReference(stream, tagRef.From)
		fromPath := field.NewPath("spec", "tags").Key(tag).Child("from")
		if err != nil {
			errors = append(errors, field.Invalid(fromPath.Child("name"), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>"))
			continue
		}

		subjectAccessReview := authorizationapi.SubjectAccessReview{
			Action: authorizationapi.AuthorizationAttributes{
				Verb:         "get",
				Group:        api.GroupName,
				Resource:     "imagestreams",
				ResourceName: streamName,
			},
			User:   user.GetName(),
			Groups: sets.NewString(user.GetGroups()...),
		}
		ctx := kapi.WithNamespace(kapi.NewContext(), tagRef.From.Namespace)
		glog.V(4).Infof("Performing SubjectAccessReview for user=%s, groups=%v to %s/%s", user.GetName(), user.GetGroups(), tagRef.From.Namespace, streamName)
		resp, err := v.subjectAccessReviewClient.CreateSubjectAccessReview(ctx, &subjectAccessReview)
		if err != nil || resp == nil || (resp != nil && !resp.Allowed) {
			errors = append(errors, field.Forbidden(fromPath, fmt.Sprintf("%s/%s", tagRef.From.Namespace, streamName)))
			continue
		}
	}
	return errors
}
Exemple #25
0
func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	switch sr.Operator {
	case extensions.LabelSelectorOpIn, extensions.LabelSelectorOpNotIn:
		if len(sr.Values) == 0 {
			allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'"))
		}
	case extensions.LabelSelectorOpExists, extensions.LabelSelectorOpDoesNotExist:
		if len(sr.Values) > 0 {
			allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'"))
		}
	default:
		allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), sr.Operator, "not a valid selector operator"))
	}
	allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...)
	return allErrs
}
Exemple #26
0
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
}
Exemple #27
0
func ValidatePodLogOptions(opts *v1.PodLogOptions) field.ErrorList {
	allErrs := field.ErrorList{}
	if opts.TailLines != nil && *opts.TailLines < 0 {
		allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg))
	}
	if opts.LimitBytes != nil && *opts.LimitBytes < 1 {
		allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "must be greater than 0"))
	}
	switch {
	case opts.SinceSeconds != nil && opts.SinceTime != nil:
		allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "at most one of `sinceTime` or `sinceSeconds` may be specified"))
	case opts.SinceSeconds != nil:
		if *opts.SinceSeconds < 1 {
			allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0"))
		}
	}
	return allErrs
}
Exemple #28
0
func Validate(config *api.ClusterResourceOverrideConfig) field.ErrorList {
	allErrs := field.ErrorList{}
	if config == nil {
		return allErrs
	}
	if config.LimitCPUToMemoryPercent == 0 && config.CPURequestToLimitPercent == 0 && config.MemoryRequestToLimitPercent == 0 {
		allErrs = append(allErrs, field.Forbidden(field.NewPath(api.PluginName), "plugin enabled but no percentages were specified"))
	}
	if config.LimitCPUToMemoryPercent < 0 {
		allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "LimitCPUToMemoryPercent"), config.LimitCPUToMemoryPercent, "must be positive"))
	}
	if config.CPURequestToLimitPercent < 0 || config.CPURequestToLimitPercent > 100 {
		allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "CPURequestToLimitPercent"), config.CPURequestToLimitPercent, "must be between 0 and 100"))
	}
	if config.MemoryRequestToLimitPercent < 0 || config.MemoryRequestToLimitPercent > 100 {
		allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "MemoryRequestToLimitPercent"), config.MemoryRequestToLimitPercent, "must be between 0 and 100"))
	}
	return allErrs
}
Exemple #29
0
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	switch strategy.Type {
	case extensions.RecreateDeploymentStrategyType:
		if strategy.RollingUpdate != nil {
			allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "may not be specified when strategy `type` is '"+string(extensions.RecreateDeploymentStrategyType+"'")))
		}
	case extensions.RollingUpdateDeploymentStrategyType:
		// This should never happen since it's set and checked in defaults.go
		if strategy.RollingUpdate == nil {
			allErrs = append(allErrs, field.Required(fldPath.Child("rollingUpdate"), "this should be defaulted and never be nil"))
		} else {
			allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...)
		}
	default:
		validValues := []string{string(extensions.RecreateDeploymentStrategyType), string(extensions.RollingUpdateDeploymentStrategyType)}
		allErrs = append(allErrs, field.NotSupported(fldPath, strategy, validValues))
	}
	return allErrs
}
Exemple #30
0
// ValidatePetSetUpdate tests if required fields in the PetSet are set.
func ValidatePetSetUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList {
	allErrs := field.ErrorList{}

	// TODO: For now we're taking the safe route and disallowing all updates to spec except for Spec.Replicas.
	// Enable on a case by case basis.
	restoreReplicas := petSet.Spec.Replicas
	petSet.Spec.Replicas = oldPetSet.Spec.Replicas

	// The generation changes for this update
	restoreGeneration := petSet.Generation
	petSet.Generation = oldPetSet.Generation

	if !reflect.DeepEqual(petSet, oldPetSet) {
		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to petset spec for fields other than 'replicas' are forbidden."))
	}
	petSet.Spec.Replicas = restoreReplicas
	petSet.Generation = restoreGeneration
	allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(petSet.Spec.Replicas), field.NewPath("spec", "replicas"))...)
	return allErrs
}