123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*
- Copyright 2016 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package capabilities
- import (
- "fmt"
- corev1 "k8s.io/api/core/v1"
- policy "k8s.io/api/policy/v1beta1"
- "k8s.io/apimachinery/pkg/util/sets"
- "k8s.io/apimachinery/pkg/util/validation/field"
- api "k8s.io/kubernetes/pkg/apis/core"
- )
- // defaultCapabilities implements the Strategy interface
- type defaultCapabilities struct {
- defaultAddCapabilities []api.Capability
- requiredDropCapabilities []api.Capability
- allowedCaps []api.Capability
- }
- var _ Strategy = &defaultCapabilities{}
- // NewDefaultCapabilities creates a new defaultCapabilities strategy that will provide defaults and validation
- // based on the configured initial caps and allowed caps.
- func NewDefaultCapabilities(defaultAddCapabilities, requiredDropCapabilities, allowedCaps []corev1.Capability) (Strategy, error) {
- internalDefaultAddCaps := make([]api.Capability, len(defaultAddCapabilities))
- for i, capability := range defaultAddCapabilities {
- internalDefaultAddCaps[i] = api.Capability(capability)
- }
- internalRequiredDropCaps := make([]api.Capability, len(requiredDropCapabilities))
- for i, capability := range requiredDropCapabilities {
- internalRequiredDropCaps[i] = api.Capability(capability)
- }
- internalAllowedCaps := make([]api.Capability, len(allowedCaps))
- for i, capability := range allowedCaps {
- internalAllowedCaps[i] = api.Capability(capability)
- }
- return &defaultCapabilities{
- defaultAddCapabilities: internalDefaultAddCaps,
- requiredDropCapabilities: internalRequiredDropCaps,
- allowedCaps: internalAllowedCaps,
- }, nil
- }
- // Generate creates the capabilities based on policy rules. Generate will produce the following:
- // 1. a capabilities.Add set containing all the required adds (unless the
- // container specifically is dropping the cap) and container requested adds
- // 2. a capabilities.Drop set containing all the required drops and container requested drops
- //
- // Returns the original container capabilities if no changes are required.
- func (s *defaultCapabilities) Generate(pod *api.Pod, container *api.Container) (*api.Capabilities, error) {
- defaultAdd := makeCapSet(s.defaultAddCapabilities)
- requiredDrop := makeCapSet(s.requiredDropCapabilities)
- containerAdd := sets.NewString()
- containerDrop := sets.NewString()
- var containerCapabilities *api.Capabilities
- if container.SecurityContext != nil && container.SecurityContext.Capabilities != nil {
- containerCapabilities = container.SecurityContext.Capabilities
- containerAdd = makeCapSet(container.SecurityContext.Capabilities.Add)
- containerDrop = makeCapSet(container.SecurityContext.Capabilities.Drop)
- }
- // remove any default adds that the container is specifically dropping
- defaultAdd = defaultAdd.Difference(containerDrop)
- combinedAdd := defaultAdd.Union(containerAdd)
- combinedDrop := requiredDrop.Union(containerDrop)
- // no changes? return the original capabilities
- if (len(combinedAdd) == len(containerAdd)) && (len(combinedDrop) == len(containerDrop)) {
- return containerCapabilities, nil
- }
- return &api.Capabilities{
- Add: capabilityFromStringSlice(combinedAdd.List()),
- Drop: capabilityFromStringSlice(combinedDrop.List()),
- }, nil
- }
- // Validate ensures that the specified values fall within the range of the strategy.
- func (s *defaultCapabilities) Validate(fldPath *field.Path, pod *api.Pod, container *api.Container, capabilities *api.Capabilities) field.ErrorList {
- allErrs := field.ErrorList{}
- if capabilities == nil {
- // if container.SC.Caps is nil then nothing was defaulted by the strategy or requested by the pod author
- // if there are no required caps on the strategy and nothing is requested on the pod
- // then we can safely return here without further validation.
- if len(s.defaultAddCapabilities) == 0 && len(s.requiredDropCapabilities) == 0 {
- return allErrs
- }
- // container has no requested caps but we have required caps. We should have something in
- // at least the drops on the container.
- allErrs = append(allErrs, field.Invalid(fldPath, capabilities,
- "required capabilities are not set on the securityContext"))
- return allErrs
- }
- allowedAdd := makeCapSet(s.allowedCaps)
- allowAllCaps := allowedAdd.Has(string(policy.AllowAllCapabilities))
- if allowAllCaps {
- // skip validation against allowed/defaultAdd/requiredDrop because all capabilities are allowed by a wildcard
- return allErrs
- }
- // validate that anything being added is in the default or allowed sets
- defaultAdd := makeCapSet(s.defaultAddCapabilities)
- for _, cap := range capabilities.Add {
- sCap := string(cap)
- if !defaultAdd.Has(sCap) && !allowedAdd.Has(sCap) {
- allErrs = append(allErrs, field.Invalid(fldPath.Child("add"), sCap, "capability may not be added"))
- }
- }
- // validate that anything that is required to be dropped is in the drop set
- containerDrops := makeCapSet(capabilities.Drop)
- for _, requiredDrop := range s.requiredDropCapabilities {
- sDrop := string(requiredDrop)
- if !containerDrops.Has(sDrop) {
- allErrs = append(allErrs, field.Invalid(fldPath.Child("drop"), capabilities.Drop,
- fmt.Sprintf("%s is required to be dropped but was not found", sDrop)))
- }
- }
- return allErrs
- }
- // capabilityFromStringSlice creates a capability slice from a string slice.
- func capabilityFromStringSlice(slice []string) []api.Capability {
- if len(slice) == 0 {
- return nil
- }
- caps := []api.Capability{}
- for _, c := range slice {
- caps = append(caps, api.Capability(c))
- }
- return caps
- }
- // makeCapSet makes a string set from capabilities.
- func makeCapSet(caps []api.Capability) sets.String {
- s := sets.NewString()
- for _, c := range caps {
- s.Insert(string(c))
- }
- return s
- }
|