mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
vendor update for E2E framework
Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
80
vendor/k8s.io/kubernetes/pkg/security/apparmor/helpers.go
generated
vendored
Normal file
80
vendor/k8s.io/kubernetes/pkg/security/apparmor/helpers.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
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 apparmor
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// TODO: Move these values into the API package.
|
||||
const (
|
||||
// The prefix to an annotation key specifying a container profile.
|
||||
ContainerAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
||||
// The annotation key specifying the default AppArmor profile.
|
||||
DefaultProfileAnnotationKey = "apparmor.security.beta.kubernetes.io/defaultProfileName"
|
||||
// The annotation key specifying the allowed AppArmor profiles.
|
||||
AllowedProfilesAnnotationKey = "apparmor.security.beta.kubernetes.io/allowedProfileNames"
|
||||
|
||||
// The profile specifying the runtime default.
|
||||
ProfileRuntimeDefault = "runtime/default"
|
||||
// The prefix for specifying profiles loaded on the node.
|
||||
ProfileNamePrefix = "localhost/"
|
||||
|
||||
// Unconfined profile
|
||||
ProfileNameUnconfined = "unconfined"
|
||||
)
|
||||
|
||||
// Checks whether app armor is required for pod to be run.
|
||||
func isRequired(pod *v1.Pod) bool {
|
||||
for key, value := range pod.Annotations {
|
||||
if strings.HasPrefix(key, ContainerAnnotationKeyPrefix) {
|
||||
return value != ProfileNameUnconfined
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the name of the profile to use with the container.
|
||||
func GetProfileName(pod *v1.Pod, containerName string) string {
|
||||
return GetProfileNameFromPodAnnotations(pod.Annotations, containerName)
|
||||
}
|
||||
|
||||
// GetProfileNameFromPodAnnotations gets the name of the profile to use with container from
|
||||
// pod annotations
|
||||
func GetProfileNameFromPodAnnotations(annotations map[string]string, containerName string) string {
|
||||
return annotations[ContainerAnnotationKeyPrefix+containerName]
|
||||
}
|
||||
|
||||
// Sets the name of the profile to use with the container.
|
||||
func SetProfileName(pod *v1.Pod, containerName, profileName string) error {
|
||||
if pod.Annotations == nil {
|
||||
pod.Annotations = map[string]string{}
|
||||
}
|
||||
pod.Annotations[ContainerAnnotationKeyPrefix+containerName] = profileName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sets the name of the profile to use with the container.
|
||||
func SetProfileNameFromPodAnnotations(annotations map[string]string, containerName, profileName string) error {
|
||||
if annotations == nil {
|
||||
return nil
|
||||
}
|
||||
annotations[ContainerAnnotationKeyPrefix+containerName] = profileName
|
||||
return nil
|
||||
}
|
229
vendor/k8s.io/kubernetes/pkg/security/apparmor/validate.go
generated
vendored
Normal file
229
vendor/k8s.io/kubernetes/pkg/security/apparmor/validate.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
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 apparmor
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
utilpath "k8s.io/utils/path"
|
||||
)
|
||||
|
||||
// Whether AppArmor should be disabled by default.
|
||||
// Set to true if the wrong build tags are set (see validate_disabled.go).
|
||||
var isDisabledBuild bool
|
||||
|
||||
// Interface for validating that a pod with an AppArmor profile can be run by a Node.
|
||||
type Validator interface {
|
||||
Validate(pod *v1.Pod) error
|
||||
ValidateHost() error
|
||||
}
|
||||
|
||||
func NewValidator(runtime string) Validator {
|
||||
if err := validateHost(runtime); err != nil {
|
||||
return &validator{validateHostErr: err}
|
||||
}
|
||||
appArmorFS, err := getAppArmorFS()
|
||||
if err != nil {
|
||||
return &validator{
|
||||
validateHostErr: fmt.Errorf("error finding AppArmor FS: %v", err),
|
||||
}
|
||||
}
|
||||
return &validator{
|
||||
appArmorFS: appArmorFS,
|
||||
}
|
||||
}
|
||||
|
||||
type validator struct {
|
||||
validateHostErr error
|
||||
appArmorFS string
|
||||
}
|
||||
|
||||
func (v *validator) Validate(pod *v1.Pod) error {
|
||||
if !isRequired(pod) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.ValidateHost() != nil {
|
||||
return v.validateHostErr
|
||||
}
|
||||
|
||||
loadedProfiles, err := v.getLoadedProfiles()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read loaded profiles: %v", err)
|
||||
}
|
||||
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
if err := validateProfile(GetProfileName(pod, container.Name), loadedProfiles); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, container := range pod.Spec.Containers {
|
||||
if err := validateProfile(GetProfileName(pod, container.Name), loadedProfiles); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) ValidateHost() error {
|
||||
return v.validateHostErr
|
||||
}
|
||||
|
||||
// Verify that the host and runtime is capable of enforcing AppArmor profiles.
|
||||
func validateHost(runtime string) error {
|
||||
// Check feature-gates
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) {
|
||||
return errors.New("AppArmor disabled by feature-gate")
|
||||
}
|
||||
|
||||
// Check build support.
|
||||
if isDisabledBuild {
|
||||
return errors.New("Binary not compiled for linux")
|
||||
}
|
||||
|
||||
// Check kernel support.
|
||||
if !IsAppArmorEnabled() {
|
||||
return errors.New("AppArmor is not enabled on the host")
|
||||
}
|
||||
|
||||
// Check runtime support. Currently only Docker is supported.
|
||||
if runtime != kubetypes.DockerContainerRuntime && runtime != kubetypes.RemoteContainerRuntime {
|
||||
return fmt.Errorf("AppArmor is only enabled for 'docker' and 'remote' runtimes. Found: %q.", runtime)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify that the profile is valid and loaded.
|
||||
func validateProfile(profile string, loadedProfiles map[string]bool) error {
|
||||
if err := ValidateProfileFormat(profile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.HasPrefix(profile, ProfileNamePrefix) {
|
||||
profileName := strings.TrimPrefix(profile, ProfileNamePrefix)
|
||||
if !loadedProfiles[profileName] {
|
||||
return fmt.Errorf("profile %q is not loaded", profileName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateProfileFormat(profile string) error {
|
||||
if profile == "" || profile == ProfileRuntimeDefault || profile == ProfileNameUnconfined {
|
||||
return nil
|
||||
}
|
||||
if !strings.HasPrefix(profile, ProfileNamePrefix) {
|
||||
return fmt.Errorf("invalid AppArmor profile name: %q", profile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) getLoadedProfiles() (map[string]bool, error) {
|
||||
profilesPath := path.Join(v.appArmorFS, "profiles")
|
||||
profilesFile, err := os.Open(profilesPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open %s: %v", profilesPath, err)
|
||||
}
|
||||
defer profilesFile.Close()
|
||||
|
||||
profiles := map[string]bool{}
|
||||
scanner := bufio.NewScanner(profilesFile)
|
||||
for scanner.Scan() {
|
||||
profileName := parseProfileName(scanner.Text())
|
||||
if profileName == "" {
|
||||
// Unknown line format; skip it.
|
||||
continue
|
||||
}
|
||||
profiles[profileName] = true
|
||||
}
|
||||
return profiles, nil
|
||||
}
|
||||
|
||||
// The profiles file is formatted with one profile per line, matching a form:
|
||||
// namespace://profile-name (mode)
|
||||
// profile-name (mode)
|
||||
// Where mode is {enforce, complain, kill}. The "namespace://" is only included for namespaced
|
||||
// profiles. For the purposes of Kubernetes, we consider the namespace part of the profile name.
|
||||
func parseProfileName(profileLine string) string {
|
||||
modeIndex := strings.IndexRune(profileLine, '(')
|
||||
if modeIndex < 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(profileLine[:modeIndex])
|
||||
}
|
||||
|
||||
func getAppArmorFS() (string, error) {
|
||||
mountsFile, err := os.Open("/proc/mounts")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not open /proc/mounts: %v", err)
|
||||
}
|
||||
defer mountsFile.Close()
|
||||
|
||||
scanner := bufio.NewScanner(mountsFile)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
if len(fields) < 3 {
|
||||
// Unknown line format; skip it.
|
||||
continue
|
||||
}
|
||||
if fields[2] == "securityfs" {
|
||||
appArmorFS := path.Join(fields[1], "apparmor")
|
||||
if ok, err := utilpath.Exists(utilpath.CheckFollowSymlink, appArmorFS); !ok {
|
||||
msg := fmt.Sprintf("path %s does not exist", appArmorFS)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: %v", msg, err)
|
||||
} else {
|
||||
return "", errors.New(msg)
|
||||
}
|
||||
} else {
|
||||
return appArmorFS, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return "", fmt.Errorf("error scanning mounts: %v", err)
|
||||
}
|
||||
|
||||
return "", errors.New("securityfs not found")
|
||||
}
|
||||
|
||||
// IsAppArmorEnabled returns true if apparmor is enabled for the host.
|
||||
// This function is forked from
|
||||
// https://github.com/opencontainers/runc/blob/1a81e9ab1f138c091fe5c86d0883f87716088527/libcontainer/apparmor/apparmor.go
|
||||
// to avoid the libapparmor dependency.
|
||||
func IsAppArmorEnabled() bool {
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
|
||||
if _, err = os.Stat("/sbin/apparmor_parser"); err == nil {
|
||||
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
||||
return err == nil && len(buf) > 1 && buf[0] == 'Y'
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
24
vendor/k8s.io/kubernetes/pkg/security/apparmor/validate_disabled.go
generated
vendored
Normal file
24
vendor/k8s.io/kubernetes/pkg/security/apparmor/validate_disabled.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
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 apparmor
|
||||
|
||||
func init() {
|
||||
// If Kubernetes was not built for linux, apparmor is always disabled.
|
||||
isDisabledBuild = true
|
||||
}
|
149
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go
generated
vendored
Normal file
149
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
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 seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
const (
|
||||
// AllowAny is the wildcard used to allow any profile.
|
||||
AllowAny = "*"
|
||||
// The annotation key specifying the default seccomp profile.
|
||||
DefaultProfileAnnotationKey = "seccomp.security.alpha.kubernetes.io/defaultProfileName"
|
||||
// The annotation key specifying the allowed seccomp profiles.
|
||||
AllowedProfilesAnnotationKey = "seccomp.security.alpha.kubernetes.io/allowedProfileNames"
|
||||
)
|
||||
|
||||
// Strategy defines the interface for all seccomp constraint strategies.
|
||||
type Strategy interface {
|
||||
// Generate returns a profile based on constraint rules.
|
||||
Generate(annotations map[string]string, pod *api.Pod) (string, error)
|
||||
// Validate ensures that the specified values fall within the range of the strategy.
|
||||
ValidatePod(pod *api.Pod) field.ErrorList
|
||||
// Validate ensures that the specified values fall within the range of the strategy.
|
||||
ValidateContainer(pod *api.Pod, container *api.Container) field.ErrorList
|
||||
}
|
||||
|
||||
type strategy struct {
|
||||
defaultProfile string
|
||||
allowedProfiles map[string]bool
|
||||
// For printing error messages (preserves order).
|
||||
allowedProfilesString string
|
||||
// does the strategy allow any profile (wildcard)
|
||||
allowAnyProfile bool
|
||||
}
|
||||
|
||||
var _ Strategy = &strategy{}
|
||||
|
||||
// NewStrategy creates a new strategy that enforces seccomp profile constraints.
|
||||
func NewStrategy(pspAnnotations map[string]string) Strategy {
|
||||
var allowedProfiles map[string]bool
|
||||
allowAnyProfile := false
|
||||
if allowed, ok := pspAnnotations[AllowedProfilesAnnotationKey]; ok {
|
||||
profiles := strings.Split(allowed, ",")
|
||||
allowedProfiles = make(map[string]bool, len(profiles))
|
||||
for _, p := range profiles {
|
||||
if p == AllowAny {
|
||||
allowAnyProfile = true
|
||||
continue
|
||||
}
|
||||
allowedProfiles[p] = true
|
||||
}
|
||||
}
|
||||
return &strategy{
|
||||
defaultProfile: pspAnnotations[DefaultProfileAnnotationKey],
|
||||
allowedProfiles: allowedProfiles,
|
||||
allowedProfilesString: pspAnnotations[AllowedProfilesAnnotationKey],
|
||||
allowAnyProfile: allowAnyProfile,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate returns a profile based on constraint rules.
|
||||
func (s *strategy) Generate(annotations map[string]string, pod *api.Pod) (string, error) {
|
||||
if annotations[api.SeccompPodAnnotationKey] != "" {
|
||||
// Profile already set, nothing to do.
|
||||
return annotations[api.SeccompPodAnnotationKey], nil
|
||||
}
|
||||
return s.defaultProfile, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// profileAllowed checks if profile is in allowedProfiles or if allowedProfiles
|
||||
// contains the wildcard.
|
||||
func (s *strategy) profileAllowed(profile string) bool {
|
||||
// for backwards compatibility and PSPs without a defined list of allowed profiles.
|
||||
// If a PSP does not have allowedProfiles set then we should allow an empty profile.
|
||||
// This will mean that the runtime default is used.
|
||||
if len(s.allowedProfiles) == 0 && profile == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return s.allowAnyProfile || s.allowedProfiles[profile]
|
||||
}
|
||||
|
||||
// profileForContainer returns the container profile if set, otherwise the pod profile.
|
||||
func profileForContainer(pod *api.Pod, container *api.Container) string {
|
||||
containerProfile, ok := pod.Annotations[api.SeccompContainerAnnotationKeyPrefix+container.Name]
|
||||
if ok {
|
||||
return containerProfile
|
||||
}
|
||||
return pod.Annotations[api.SeccompPodAnnotationKey]
|
||||
}
|
19
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
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 util contains utility code shared amongst different parts of the
|
||||
// pod security policy apparatus.
|
||||
package util
|
244
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/util.go
generated
vendored
Normal file
244
vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/util.go
generated
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
policy "k8s.io/api/policy/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
const (
|
||||
ValidatedPSPAnnotation = "kubernetes.io/psp"
|
||||
)
|
||||
|
||||
func GetAllFSTypesExcept(exceptions ...string) sets.String {
|
||||
fstypes := GetAllFSTypesAsSet()
|
||||
for _, e := range exceptions {
|
||||
fstypes.Delete(e)
|
||||
}
|
||||
return fstypes
|
||||
}
|
||||
|
||||
func GetAllFSTypesAsSet() sets.String {
|
||||
fstypes := sets.NewString()
|
||||
fstypes.Insert(
|
||||
string(policy.HostPath),
|
||||
string(policy.AzureFile),
|
||||
string(policy.Flocker),
|
||||
string(policy.FlexVolume),
|
||||
string(policy.EmptyDir),
|
||||
string(policy.GCEPersistentDisk),
|
||||
string(policy.AWSElasticBlockStore),
|
||||
string(policy.GitRepo),
|
||||
string(policy.Secret),
|
||||
string(policy.NFS),
|
||||
string(policy.ISCSI),
|
||||
string(policy.Glusterfs),
|
||||
string(policy.PersistentVolumeClaim),
|
||||
string(policy.RBD),
|
||||
string(policy.Cinder),
|
||||
string(policy.CephFS),
|
||||
string(policy.DownwardAPI),
|
||||
string(policy.FC),
|
||||
string(policy.ConfigMap),
|
||||
string(policy.VsphereVolume),
|
||||
string(policy.Quobyte),
|
||||
string(policy.AzureDisk),
|
||||
string(policy.PhotonPersistentDisk),
|
||||
string(policy.StorageOS),
|
||||
string(policy.Projected),
|
||||
string(policy.PortworxVolume),
|
||||
string(policy.ScaleIO),
|
||||
string(policy.CSI),
|
||||
)
|
||||
return fstypes
|
||||
}
|
||||
|
||||
// getVolumeFSType gets the FSType for a volume.
|
||||
func GetVolumeFSType(v api.Volume) (policy.FSType, error) {
|
||||
switch {
|
||||
case v.HostPath != nil:
|
||||
return policy.HostPath, nil
|
||||
case v.EmptyDir != nil:
|
||||
return policy.EmptyDir, nil
|
||||
case v.GCEPersistentDisk != nil:
|
||||
return policy.GCEPersistentDisk, nil
|
||||
case v.AWSElasticBlockStore != nil:
|
||||
return policy.AWSElasticBlockStore, nil
|
||||
case v.GitRepo != nil:
|
||||
return policy.GitRepo, nil
|
||||
case v.Secret != nil:
|
||||
return policy.Secret, nil
|
||||
case v.NFS != nil:
|
||||
return policy.NFS, nil
|
||||
case v.ISCSI != nil:
|
||||
return policy.ISCSI, nil
|
||||
case v.Glusterfs != nil:
|
||||
return policy.Glusterfs, nil
|
||||
case v.PersistentVolumeClaim != nil:
|
||||
return policy.PersistentVolumeClaim, nil
|
||||
case v.RBD != nil:
|
||||
return policy.RBD, nil
|
||||
case v.FlexVolume != nil:
|
||||
return policy.FlexVolume, nil
|
||||
case v.Cinder != nil:
|
||||
return policy.Cinder, nil
|
||||
case v.CephFS != nil:
|
||||
return policy.CephFS, nil
|
||||
case v.Flocker != nil:
|
||||
return policy.Flocker, nil
|
||||
case v.DownwardAPI != nil:
|
||||
return policy.DownwardAPI, nil
|
||||
case v.FC != nil:
|
||||
return policy.FC, nil
|
||||
case v.AzureFile != nil:
|
||||
return policy.AzureFile, nil
|
||||
case v.ConfigMap != nil:
|
||||
return policy.ConfigMap, nil
|
||||
case v.VsphereVolume != nil:
|
||||
return policy.VsphereVolume, nil
|
||||
case v.Quobyte != nil:
|
||||
return policy.Quobyte, nil
|
||||
case v.AzureDisk != nil:
|
||||
return policy.AzureDisk, nil
|
||||
case v.PhotonPersistentDisk != nil:
|
||||
return policy.PhotonPersistentDisk, nil
|
||||
case v.StorageOS != nil:
|
||||
return policy.StorageOS, nil
|
||||
case v.Projected != nil:
|
||||
return policy.Projected, nil
|
||||
case v.PortworxVolume != nil:
|
||||
return policy.PortworxVolume, nil
|
||||
case v.ScaleIO != nil:
|
||||
return policy.ScaleIO, nil
|
||||
case v.CSI != nil:
|
||||
return policy.CSI, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unknown volume type for volume: %#v", v)
|
||||
}
|
||||
|
||||
// FSTypeToStringSet converts an FSType slice to a string set.
|
||||
func FSTypeToStringSet(fsTypes []policy.FSType) sets.String {
|
||||
set := sets.NewString()
|
||||
for _, v := range fsTypes {
|
||||
set.Insert(string(v))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// PSPAllowsAllVolumes checks for FSTypeAll in the psp's allowed volumes.
|
||||
func PSPAllowsAllVolumes(psp *policy.PodSecurityPolicy) bool {
|
||||
return PSPAllowsFSType(psp, policy.All)
|
||||
}
|
||||
|
||||
// PSPAllowsFSType is a utility for checking if a PSP allows a particular FSType.
|
||||
// If all volumes are allowed then this will return true for any FSType passed.
|
||||
func PSPAllowsFSType(psp *policy.PodSecurityPolicy, fsType policy.FSType) bool {
|
||||
if psp == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range psp.Spec.Volumes {
|
||||
if v == fsType || v == policy.All {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UserFallsInRange is a utility to determine it the id falls in the valid range.
|
||||
func UserFallsInRange(id int64, rng policy.IDRange) bool {
|
||||
return id >= rng.Min && id <= rng.Max
|
||||
}
|
||||
|
||||
// GroupFallsInRange is a utility to determine it the id falls in the valid range.
|
||||
func GroupFallsInRange(id int64, rng policy.IDRange) bool {
|
||||
return id >= rng.Min && id <= rng.Max
|
||||
}
|
||||
|
||||
// AllowsHostVolumePath is a utility for checking if a PSP allows the host volume path.
|
||||
// This only checks the path. You should still check to make sure the host volume fs type is allowed.
|
||||
func AllowsHostVolumePath(psp *policy.PodSecurityPolicy, hostPath string) (pathIsAllowed, mustBeReadOnly bool) {
|
||||
if psp == nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
// If no allowed paths are specified then allow any path
|
||||
if len(psp.Spec.AllowedHostPaths) == 0 {
|
||||
return true, false
|
||||
}
|
||||
|
||||
for _, allowedPath := range psp.Spec.AllowedHostPaths {
|
||||
if hasPathPrefix(hostPath, allowedPath.PathPrefix) {
|
||||
if !allowedPath.ReadOnly {
|
||||
return true, allowedPath.ReadOnly
|
||||
}
|
||||
pathIsAllowed = true
|
||||
mustBeReadOnly = true
|
||||
}
|
||||
}
|
||||
|
||||
return pathIsAllowed, mustBeReadOnly
|
||||
}
|
||||
|
||||
// hasPathPrefix returns true if the string matches pathPrefix exactly, or if is prefixed with pathPrefix at a path segment boundary
|
||||
// the string and pathPrefix are both normalized to remove trailing slashes prior to checking.
|
||||
func hasPathPrefix(s, pathPrefix string) bool {
|
||||
|
||||
s = strings.TrimSuffix(s, "/")
|
||||
pathPrefix = strings.TrimSuffix(pathPrefix, "/")
|
||||
|
||||
// Short circuit if s doesn't contain the prefix at all
|
||||
if !strings.HasPrefix(s, pathPrefix) {
|
||||
return false
|
||||
}
|
||||
|
||||
pathPrefixLength := len(pathPrefix)
|
||||
|
||||
if len(s) == pathPrefixLength {
|
||||
// Exact match
|
||||
return true
|
||||
}
|
||||
|
||||
if s[pathPrefixLength:pathPrefixLength+1] == "/" {
|
||||
// The next character in s is a path segment boundary
|
||||
// Check this instead of normalizing pathPrefix to avoid allocating on every call
|
||||
// Example where this check applies: s=/foo/bar and pathPrefix=/foo
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// EqualStringSlices compares string slices for equality. Slices are equal when
|
||||
// their sizes and elements on similar positions are equal.
|
||||
func EqualStringSlices(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user