-
Notifications
You must be signed in to change notification settings - Fork 0
/
byrestrictions.go
174 lines (148 loc) · 5.51 KB
/
byrestrictions.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package securitycontextconstraints
import (
"strings"
"github.com/golang/glog"
securityapi "github.com/openshift/origin/pkg/security/apis/security"
kapi "k8s.io/kubernetes/pkg/apis/core"
)
// ByRestrictions is a helper to sort SCCs in order of most restrictive to least restrictive.
type ByRestrictions []*securityapi.SecurityContextConstraints
func (s ByRestrictions) Len() int {
return len(s)
}
func (s ByRestrictions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByRestrictions) Less(i, j int) bool {
return pointValue(s[i]) < pointValue(s[j])
}
// The following constants define the weight of the restrictions and used for
// calculating the points of the particular SCC. The lower the number, the more
// restrictive SCC is. Make sure that weak restrictions are always valued
// higher than the combination of the strong restrictions.
type points int
const (
privilegedPoints points = 1000000
hostNetworkPoints points = 200000
hostPortsPoints points = 400000
hostVolumePoints points = 100000
nonTrivialVolumePoints points = 50000
runAsAnyUserPoints points = 40000
runAsNonRootPoints points = 30000
runAsRangePoints points = 20000
runAsUserPoints points = 10000
capDefaultPoints points = 5000
capAddOnePoints points = 300
capAllowAllPoints points = 4000
capAllowOnePoints points = 10
capDropAllPoints points = -3000
capDropOnePoints points = -50
capMaxPoints points = 9999
capMinPoints points = 0
noPoints points = 0
)
// pointValue places a value on the SCC based on the settings of the SCC that can be used
// to determine how restrictive it is. The lower the number, the more restrictive it is.
func pointValue(constraint *securityapi.SecurityContextConstraints) points {
totalPoints := noPoints
if constraint.AllowPrivilegedContainer {
totalPoints += privilegedPoints
}
// add points based on volume requests
totalPoints += volumePointValue(constraint)
if constraint.AllowHostNetwork {
totalPoints += hostNetworkPoints
}
if constraint.AllowHostPorts {
totalPoints += hostPortsPoints
}
// add points based on capabilities
totalPoints += capabilitiesPointValue(constraint)
// the map contains points for both RunAsUser and SELinuxContext
// strategies by taking advantage that they have identical strategy names
strategiesPoints := map[string]points{
string(securityapi.RunAsUserStrategyRunAsAny): runAsAnyUserPoints,
string(securityapi.RunAsUserStrategyMustRunAsNonRoot): runAsNonRootPoints,
string(securityapi.RunAsUserStrategyMustRunAsRange): runAsRangePoints,
string(securityapi.RunAsUserStrategyMustRunAs): runAsUserPoints,
}
strategyType := string(constraint.SELinuxContext.Type)
points, found := strategiesPoints[strategyType]
if found {
totalPoints += points
} else {
glog.Warningf("SELinuxContext type %q has no point value, this may cause issues in sorting SCCs by restriction", strategyType)
}
strategyType = string(constraint.RunAsUser.Type)
points, found = strategiesPoints[strategyType]
if found {
totalPoints += points
} else {
glog.Warningf("RunAsUser type %q has no point value, this may cause issues in sorting SCCs by restriction", strategyType)
}
return totalPoints
}
// volumePointValue returns a score based on the volumes allowed by the SCC.
// Allowing a host volume will return a score of 100000. Allowance of anything other
// than Secret, ConfigMap, EmptyDir, DownwardAPI, Projected, and None will result in
// a score of 50000. If the SCC only allows these trivial types, it will have a
// score of 0.
func volumePointValue(scc *securityapi.SecurityContextConstraints) points {
hasHostVolume := false
hasNonTrivialVolume := false
for _, v := range scc.Volumes {
switch v {
case securityapi.FSTypeHostPath, securityapi.FSTypeAll:
hasHostVolume = true
// nothing more to do, this is the max point value
break
// it is easier to specifically list the trivial volumes and allow the
// default case to be non-trivial so we don't have to worry about adding
// volumes in the future unless they're trivial.
case securityapi.FSTypeSecret, securityapi.FSTypeConfigMap, securityapi.FSTypeEmptyDir,
securityapi.FSTypeDownwardAPI, securityapi.FSProjected, securityapi.FSTypeNone:
// do nothing
default:
hasNonTrivialVolume = true
}
}
if hasHostVolume {
return hostVolumePoints
}
if hasNonTrivialVolume {
return nonTrivialVolumePoints
}
return noPoints
}
// hasCap checks for needle in haystack.
func hasCap(needle string, haystack []kapi.Capability) bool {
for _, c := range haystack {
if needle == strings.ToUpper(string(c)) {
return true
}
}
return false
}
// capabilitiesPointValue returns a score based on the capabilities allowed,
// added, or removed by the SCC. This allow us to prefer the more restrictive
// SCC.
func capabilitiesPointValue(scc *securityapi.SecurityContextConstraints) points {
capsPoints := capDefaultPoints
capsPoints += capAddOnePoints * points(len(scc.DefaultAddCapabilities))
if hasCap(string(securityapi.AllowAllCapabilities), scc.AllowedCapabilities) {
capsPoints += capAllowAllPoints
} else if hasCap("ALL", scc.AllowedCapabilities) {
capsPoints += capAllowAllPoints
} else {
capsPoints += capAllowOnePoints * points(len(scc.AllowedCapabilities))
}
if hasCap("ALL", scc.RequiredDropCapabilities) {
capsPoints += capDropAllPoints
} else {
capsPoints += capDropOnePoints * points(len(scc.RequiredDropCapabilities))
}
if capsPoints > capMaxPoints {
return capMaxPoints
} else if capsPoints < capMinPoints {
return capMinPoints
}
return capsPoints
}