...
1
16
17 package util
18
19 import (
20 "fmt"
21
22 "github.com/opencontainers/selinux/go-selinux"
23 "github.com/opencontainers/selinux/go-selinux/label"
24 v1 "k8s.io/api/core/v1"
25 utilfeature "k8s.io/apiserver/pkg/util/feature"
26 v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
27 "k8s.io/kubernetes/pkg/features"
28 "k8s.io/kubernetes/pkg/volume"
29 )
30
31
32 type SELinuxLabelTranslator interface {
33
34
35
36
37
38 SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error)
39
40
41 SELinuxEnabled() bool
42 }
43
44
45
46 type translator struct{}
47
48 var _ SELinuxLabelTranslator = &translator{}
49
50
51 func NewSELinuxLabelTranslator() SELinuxLabelTranslator {
52 return &translator{}
53 }
54
55
56
57
58
59
60 func (l *translator) SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) {
61 if opts == nil {
62 return "", nil
63 }
64
65 args := contextOptions(opts)
66 if len(args) == 0 {
67 return "", nil
68 }
69
70 processLabel, fileLabel, err := label.InitLabels(args)
71 if err != nil {
72
73
74 return "", err
75 }
76
77
78
79 selinux.ReleaseLabel(processLabel)
80
81 return fileLabel, nil
82 }
83
84
85 func contextOptions(opts *v1.SELinuxOptions) []string {
86 if opts == nil {
87 return nil
88 }
89 args := make([]string, 0, 3)
90 if opts.User != "" {
91 args = append(args, "user:"+opts.User)
92 }
93 if opts.Role != "" {
94 args = append(args, "role:"+opts.Role)
95 }
96 if opts.Type != "" {
97 args = append(args, "type:"+opts.Type)
98 }
99 if opts.Level != "" {
100 args = append(args, "level:"+opts.Level)
101 }
102 return args
103 }
104
105 func (l *translator) SELinuxEnabled() bool {
106 return selinux.GetEnabled()
107 }
108
109
110 type fakeTranslator struct{}
111
112 var _ SELinuxLabelTranslator = &fakeTranslator{}
113
114
115
116
117 func NewFakeSELinuxLabelTranslator() SELinuxLabelTranslator {
118 return &fakeTranslator{}
119 }
120
121
122 func (l *fakeTranslator) SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) {
123 if opts == nil {
124 return "", nil
125 }
126
127 user := opts.User
128 if user == "" {
129 user = "system_u"
130 }
131
132 role := opts.Role
133 if role == "" {
134 role = "object_r"
135 }
136
137
138
139
140 fileType := opts.Type
141 if fileType == "" || fileType == "container_t" {
142 fileType = "container_file_t"
143 }
144
145 level := opts.Level
146 if level == "" {
147
148 level = "s0:c998,c999"
149 }
150
151 ctx := fmt.Sprintf("%s:%s:%s:%s", user, role, fileType, level)
152 return ctx, nil
153 }
154
155 func (l *fakeTranslator) SELinuxEnabled() bool {
156 return true
157 }
158
159
160 func SupportsSELinuxContextMount(volumeSpec *volume.Spec, volumePluginMgr *volume.VolumePluginMgr) (bool, error) {
161 plugin, _ := volumePluginMgr.FindPluginBySpec(volumeSpec)
162 if plugin != nil {
163 return plugin.SupportsSELinuxContextMount(volumeSpec)
164 }
165
166 return false, nil
167 }
168
169
170 func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool {
171 if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
172 return false
173 }
174 if volumeSpec.PersistentVolume == nil {
175 return false
176 }
177 if len(volumeSpec.PersistentVolume.Spec.AccessModes) != 1 {
178 return false
179 }
180 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMount) {
181 return true
182 }
183
184 if !v1helper.ContainsAccessMode(volumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
185 return false
186 }
187 return true
188 }
189
190
191 func AddSELinuxMountOption(options []string, seLinuxContext string) []string {
192 if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
193 return options
194 }
195
196
197 return append(options, fmt.Sprintf("context=%q", seLinuxContext))
198 }
199
View as plain text