Ejemplo n.º 1
0
func TestAssignSecurityContext(t *testing.T) {
	// set up test data
	// scc that will deny privileged container requests and has a default value for a field (uid)
	var uid int64 = 9999
	fsGroup := int64(1)
	scc := &kapi.SecurityContextConstraints{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test scc",
		},
		SELinuxContext: kapi.SELinuxContextStrategyOptions{
			Type: kapi.SELinuxStrategyRunAsAny,
		},
		RunAsUser: kapi.RunAsUserStrategyOptions{
			Type: kapi.RunAsUserStrategyMustRunAs,
			UID:  &uid,
		},

		// require allocation for a field in the psc as well to test changes/no changes
		FSGroup: kapi.FSGroupStrategyOptions{
			Type: kapi.FSGroupStrategyMustRunAs,
			Ranges: []kapi.IDRange{
				{Min: fsGroup, Max: fsGroup},
			},
		},
		SupplementalGroups: kapi.SupplementalGroupsStrategyOptions{
			Type: kapi.SupplementalGroupsStrategyRunAsAny,
		},
	}
	provider, err := kscc.NewSimpleProvider(scc)
	if err != nil {
		t.Fatalf("failed to create provider: %v", err)
	}

	createContainer := func(priv bool) kapi.Container {
		return kapi.Container{
			SecurityContext: &kapi.SecurityContext{
				Privileged: &priv,
			},
		}
	}

	// these are set up such that the containers always have a nil uid.  If the case should not
	// validate then the uids should not have been updated by the strategy.  If the case should
	// validate then uids should be set.  This is ensuring that we're hanging on to the old SC
	// as we generate/validate and only updating the original container if the entire pod validates
	testCases := map[string]struct {
		pod            *kapi.Pod
		shouldValidate bool
		expectedUID    *int64
	}{
		"pod and container SC is not changed when invalid": {
			pod: &kapi.Pod{
				Spec: kapi.PodSpec{
					SecurityContext: &kapi.PodSecurityContext{},
					Containers:      []kapi.Container{createContainer(true)},
				},
			},
			shouldValidate: false,
		},
		"must validate all containers": {
			pod: &kapi.Pod{
				Spec: kapi.PodSpec{
					// good pod and bad pod
					SecurityContext: &kapi.PodSecurityContext{},
					Containers:      []kapi.Container{createContainer(false), createContainer(true)},
				},
			},
			shouldValidate: false,
		},
		"pod validates": {
			pod: &kapi.Pod{
				Spec: kapi.PodSpec{
					SecurityContext: &kapi.PodSecurityContext{},
					Containers:      []kapi.Container{createContainer(false)},
				},
			},
			shouldValidate: true,
		},
	}

	for k, v := range testCases {
		errs := assignSecurityContext(provider, v.pod, nil)
		if v.shouldValidate && len(errs) > 0 {
			t.Errorf("%s expected to validate but received errors %v", k, errs)
			continue
		}
		if !v.shouldValidate && len(errs) == 0 {
			t.Errorf("%s expected validation errors but received none", k)
			continue
		}

		// if we shouldn't have validated ensure that uid is not set on the containers
		// and ensure the psc does not have fsgroup set
		if !v.shouldValidate {
			if v.pod.Spec.SecurityContext.FSGroup != nil {
				t.Errorf("%s had a non-nil FSGroup %d.  FSGroup should not be set on test cases that don't validate", k, *v.pod.Spec.SecurityContext.FSGroup)
			}
			for _, c := range v.pod.Spec.Containers {
				if c.SecurityContext.RunAsUser != nil {
					t.Errorf("%s had non-nil UID %d.  UID should not be set on test cases that don't validate", k, *c.SecurityContext.RunAsUser)
				}
			}
		}

		// if we validated then the pod sc should be updated now with the defaults from the SCC
		if v.shouldValidate {
			if *v.pod.Spec.SecurityContext.FSGroup != fsGroup {
				t.Errorf("%s expected fsgroup to be defaulted but found %v", k, v.pod.Spec.SecurityContext.FSGroup)
			}
			for _, c := range v.pod.Spec.Containers {
				if *c.SecurityContext.RunAsUser != uid {
					t.Errorf("%s expected uid to be defaulted to %d but found %v", k, uid, c.SecurityContext.RunAsUser)
				}
			}
		}
	}
}
Ejemplo n.º 2
0
// createProvidersFromConstraints creates providers from the constraints supplied, including
// looking up pre-allocated values if necessary using the pod's namespace.
func (c *constraint) createProvidersFromConstraints(ns string, sccs []*kapi.SecurityContextConstraints) ([]scc.SecurityContextConstraintsProvider, []error) {
	var (
		// namespace is declared here for reuse but we will not fetch it unless required by the matched constraints
		namespace *kapi.Namespace
		// collected providers
		providers []scc.SecurityContextConstraintsProvider
		// collected errors to return
		errs []error
	)

	// set pre-allocated values on constraints
	for _, constraint := range sccs {
		var err error
		resolveUIDRange := requiresPreAllocatedUIDRange(constraint)
		resolveSELinuxLevel := requiresPreAllocatedSELinuxLevel(constraint)

		if resolveUIDRange || resolveSELinuxLevel {
			var min, max *int64
			var level string

			// Ensure we have the namespace
			if namespace, err = c.getNamespace(ns, namespace); err != nil {
				errs = append(errs, fmt.Errorf("error fetching namespace %s required to preallocate values for %s: %v", ns, constraint.Name, err))
				continue
			}

			// Resolve the values from the namespace
			if resolveUIDRange {
				if min, max, err = getPreallocatedUIDRange(namespace); err != nil {
					errs = append(errs, fmt.Errorf("unable to find pre-allocated uid annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
					continue
				}
			}
			if resolveSELinuxLevel {
				if level, err = getPreallocatedLevel(namespace); err != nil {
					errs = append(errs, fmt.Errorf("unable to find pre-allocated mcs annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
					continue
				}
			}

			// Make a copy of the constraint so we don't mutate the store's cache
			var constraintCopy kapi.SecurityContextConstraints = *constraint
			constraint = &constraintCopy
			if resolveSELinuxLevel && constraint.SELinuxContext.SELinuxOptions != nil {
				// Make a copy of the SELinuxOptions so we don't mutate the store's cache
				var seLinuxOptionsCopy kapi.SELinuxOptions = *constraint.SELinuxContext.SELinuxOptions
				constraint.SELinuxContext.SELinuxOptions = &seLinuxOptionsCopy
			}

			// Set the resolved values
			if resolveUIDRange {
				constraint.RunAsUser.UIDRangeMin = min
				constraint.RunAsUser.UIDRangeMax = max
			}
			if resolveSELinuxLevel {
				if constraint.SELinuxContext.SELinuxOptions == nil {
					constraint.SELinuxContext.SELinuxOptions = &kapi.SELinuxOptions{}
				}
				constraint.SELinuxContext.SELinuxOptions.Level = level
			}
		}

		// Create the provider
		provider, err := scc.NewSimpleProvider(constraint)
		if err != nil {
			errs = append(errs, fmt.Errorf("error creating provider for SCC %s in namespace %s: %v", constraint.Name, ns, err))
			continue
		}
		providers = append(providers, provider)
	}
	return providers, errs
}
Ejemplo n.º 3
0
// createProvidersFromConstraints creates providers from the constraints supplied, including
// looking up pre-allocated values if necessary using the pod's namespace.
func (c *constraint) createProvidersFromConstraints(ns string, sccs []*kapi.SecurityContextConstraints) ([]scc.SecurityContextConstraintsProvider, []error) {
	var (
		// namespace is declared here for reuse but we will not fetch it unless required by the matched constraints
		namespace *kapi.Namespace
		// collected providers
		providers []scc.SecurityContextConstraintsProvider
		// collected errors to return
		errs []error
	)

	// set pre-allocated values on constraints
	for _, constraint := range sccs {
		var err error
		resolveUIDRange := requiresPreAllocatedUIDRange(constraint)
		resolveSELinuxLevel := requiresPreAllocatedSELinuxLevel(constraint)
		resolveFSGroup := requiresPreallocatedFSGroup(constraint)
		resolveSupplementalGroups := requiresPreallocatedSupplementalGroups(constraint)
		requiresNamespaceAllocations := resolveUIDRange || resolveSELinuxLevel || resolveFSGroup || resolveSupplementalGroups

		if requiresNamespaceAllocations {
			// Ensure we have the namespace
			namespace, err = c.getNamespace(ns, namespace)
			if err != nil {
				errs = append(errs, fmt.Errorf("error fetching namespace %s required to preallocate values for %s: %v", ns, constraint.Name, err))
				continue
			}
		}

		// Make a copy of the constraint so we don't mutate the store's cache
		var constraintCopy kapi.SecurityContextConstraints = *constraint
		constraint = &constraintCopy

		// Resolve the values from the namespace
		if resolveUIDRange {
			constraint.RunAsUser.UIDRangeMin, constraint.RunAsUser.UIDRangeMax, err = getPreallocatedUIDRange(namespace)
			if err != nil {
				errs = append(errs, fmt.Errorf("unable to find pre-allocated uid annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
				continue
			}
		}
		if resolveSELinuxLevel {
			var level string
			if level, err = getPreallocatedLevel(namespace); err != nil {
				errs = append(errs, fmt.Errorf("unable to find pre-allocated mcs annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
				continue
			}

			// SELinuxOptions is a pointer, if we are resolving and it is already initialized
			// we need to make a copy of it so we don't manipulate the store's cache.
			if constraint.SELinuxContext.SELinuxOptions != nil {
				var seLinuxOptionsCopy kapi.SELinuxOptions = *constraint.SELinuxContext.SELinuxOptions
				constraint.SELinuxContext.SELinuxOptions = &seLinuxOptionsCopy
			} else {
				constraint.SELinuxContext.SELinuxOptions = &kapi.SELinuxOptions{}
			}
			constraint.SELinuxContext.SELinuxOptions.Level = level
		}
		if resolveFSGroup {
			fsGroup, err := getPreallocatedFSGroup(namespace)
			if err != nil {
				errs = append(errs, fmt.Errorf("unable to find pre-allocated group annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
				continue
			}
			constraint.FSGroup.Ranges = fsGroup
		}
		if resolveSupplementalGroups {
			supplementalGroups, err := getPreallocatedSupplementalGroups(namespace)
			if err != nil {
				errs = append(errs, fmt.Errorf("unable to find pre-allocated group annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err))
				continue
			}
			constraint.SupplementalGroups.Ranges = supplementalGroups
		}

		// Create the provider
		provider, err := scc.NewSimpleProvider(constraint)
		if err != nil {
			errs = append(errs, fmt.Errorf("error creating provider for SCC %s in namespace %s: %v", constraint.Name, ns, err))
			continue
		}
		providers = append(providers, provider)
	}
	return providers, errs
}
Ejemplo n.º 4
0
// CreateProviderFromConstraint creates a SecurityContextConstraintProvider from a SecurityContextConstraint
func CreateProviderFromConstraint(ns string, namespace *kapi.Namespace, constraint *kapi.SecurityContextConstraints, client clientset.Interface) (kscc.SecurityContextConstraintsProvider, *kapi.Namespace, error) {
	var err error
	resolveUIDRange := requiresPreAllocatedUIDRange(constraint)
	resolveSELinuxLevel := requiresPreAllocatedSELinuxLevel(constraint)
	resolveFSGroup := requiresPreallocatedFSGroup(constraint)
	resolveSupplementalGroups := requiresPreallocatedSupplementalGroups(constraint)
	requiresNamespaceAllocations := resolveUIDRange || resolveSELinuxLevel || resolveFSGroup || resolveSupplementalGroups

	if requiresNamespaceAllocations {
		// Ensure we have the namespace
		namespace, err = getNamespaceByName(ns, namespace, client)
		if err != nil {
			return nil, namespace, fmt.Errorf("error fetching namespace %s required to preallocate values for %s: %v", ns, constraint.Name, err)
		}
	}

	// Make a copy of the constraint so we don't mutate the store's cache
	var constraintCopy kapi.SecurityContextConstraints = *constraint
	constraint = &constraintCopy

	// Resolve the values from the namespace
	if resolveUIDRange {
		constraint.RunAsUser.UIDRangeMin, constraint.RunAsUser.UIDRangeMax, err = getPreallocatedUIDRange(namespace)
		if err != nil {
			return nil, namespace, fmt.Errorf("unable to find pre-allocated uid annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err)
		}
	}
	if resolveSELinuxLevel {
		var level string
		if level, err = getPreallocatedLevel(namespace); err != nil {
			return nil, namespace, fmt.Errorf("unable to find pre-allocated mcs annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err)
		}

		// SELinuxOptions is a pointer, if we are resolving and it is already initialized
		// we need to make a copy of it so we don't manipulate the store's cache.
		if constraint.SELinuxContext.SELinuxOptions != nil {
			var seLinuxOptionsCopy kapi.SELinuxOptions = *constraint.SELinuxContext.SELinuxOptions
			constraint.SELinuxContext.SELinuxOptions = &seLinuxOptionsCopy
		} else {
			constraint.SELinuxContext.SELinuxOptions = &kapi.SELinuxOptions{}
		}
		constraint.SELinuxContext.SELinuxOptions.Level = level
	}
	if resolveFSGroup {
		fsGroup, err := getPreallocatedFSGroup(namespace)
		if err != nil {
			return nil, namespace, fmt.Errorf("unable to find pre-allocated group annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err)
		}
		constraint.FSGroup.Ranges = fsGroup
	}
	if resolveSupplementalGroups {
		supplementalGroups, err := getPreallocatedSupplementalGroups(namespace)
		if err != nil {
			return nil, namespace, fmt.Errorf("unable to find pre-allocated group annotation for namespace %s while trying to configure SCC %s: %v", namespace.Name, constraint.Name, err)
		}
		constraint.SupplementalGroups.Ranges = supplementalGroups
	}

	// Create the provider
	provider, err := kscc.NewSimpleProvider(constraint)
	if err != nil {
		return nil, namespace, fmt.Errorf("error creating provider for SCC %s in namespace %s: %v", constraint.Name, ns, err)
	}
	return provider, namespace, nil
}