forked from openshift/apiserver-library-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
withseccomp.go
113 lines (92 loc) · 3.89 KB
/
withseccomp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package seccomp
import (
"fmt"
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
)
const (
allowAnyProfile = "*"
)
// withSeccompProfile implements the SeccompStrategy.
type withSeccompProfile struct {
allowedProfiles []string
}
var _ SeccompStrategy = &withSeccompProfile{}
// NewWithSeccompProfile creates a new must run as strategy or returns an error if it cannot
// be created.
func NewWithSeccompProfile(allowedProfiles []string) (SeccompStrategy, error) {
return &withSeccompProfile{allowedProfiles}, nil
}
// Generate creates the profile based on policy rules.
func (s *withSeccompProfile) Generate(pod *api.Pod) (string, error) {
// return the first non-wildcard profile
for _, p := range s.allowedProfiles {
if p != allowAnyProfile {
return p, nil
}
}
// if we reached this point then either there are no allowed profiles (empty slice)
// or the only thing in the slice is the wildcard. In either case just return empty
// which means use the runtime default.
return "", nil
}
// 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
}
// 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
}
// isProfileAllowed checks if profile is in allowedProfiles or if allowedProfiles
// contains the wildcard.
func isProfileAllowed(profile string, allowedProfiles []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(allowedProfiles) == 0 && profile == "" {
return true
}
for _, p := range allowedProfiles {
if profile == p || p == allowAnyProfile {
return true
}
}
return false
}
// profileForContainer returns the container profile or the pod profile if the container annotatation is not set.
// If the container profile is set but empty then empty will be returned. This mirrors the functionality in the
// kubelet's docker tools.
func profileForContainer(pod *api.Pod, container *api.Container) string {
containerProfile, hasContainerProfile := pod.Annotations[api.SeccompContainerAnnotationKeyPrefix+container.Name]
if hasContainerProfile {
return containerProfile
}
return pod.Annotations[api.SeccompPodAnnotationKey]
}