@@ -2,13 +2,17 @@ package helpers
2
2
3
3
import (
4
4
"fmt"
5
+ "regexp"
6
+ "strings"
5
7
8
+ "github.com/Microsoft/hcsshim/internal/guestpath"
6
9
"github.com/google/go-containerregistry/pkg/authn"
7
10
"github.com/google/go-containerregistry/pkg/name"
8
11
v1 "github.com/google/go-containerregistry/pkg/v1"
9
12
"github.com/google/go-containerregistry/pkg/v1/remote"
10
13
11
14
"github.com/Microsoft/hcsshim/ext4/tar2ext4"
15
+ "github.com/Microsoft/hcsshim/internal/tools/securitypolicy/config"
12
16
"github.com/Microsoft/hcsshim/pkg/securitypolicy"
13
17
)
14
18
@@ -67,17 +71,17 @@ func ParseEnvFromImage(img v1.Image) ([]string, error) {
67
71
// DefaultContainerConfigs returns a hardcoded slice of container configs, which should
68
72
// be included by default in the security policy.
69
73
// The slice includes only a sandbox pause container.
70
- func DefaultContainerConfigs () []securitypolicy .ContainerConfig {
71
- pause := securitypolicy .NewContainerConfig (
74
+ func DefaultContainerConfigs () []config .ContainerConfig {
75
+ pause := config .NewContainerConfig (
72
76
"k8s.gcr.io/pause:3.1" ,
73
77
[]string {"/pause" },
74
- []securitypolicy .EnvRuleConfig {},
75
- securitypolicy .AuthConfig {},
78
+ []config .EnvRuleConfig {},
79
+ config .AuthConfig {},
76
80
"" ,
77
81
[]string {},
78
- []securitypolicy .MountConfig {},
82
+ []config .MountConfig {},
79
83
)
80
- return []securitypolicy .ContainerConfig {pause }
84
+ return []config .ContainerConfig {pause }
81
85
}
82
86
83
87
// ParseWorkingDirFromImage inspects the image spec and returns working directory if
@@ -95,9 +99,9 @@ func ParseWorkingDirFromImage(img v1.Image) (string, error) {
95
99
}
96
100
97
101
// PolicyContainersFromConfigs returns a slice of securitypolicy.Container generated
98
- // from a slice of securitypolicy .ContainerConfig's
99
- func PolicyContainersFromConfigs (containerConfigs []securitypolicy .ContainerConfig ) ([]* securitypolicy.Container , error ) {
100
- var policyContainers []* securitypolicy.Container
102
+ // from a slice of config .ContainerConfig's
103
+ func PolicyContainersFromConfigs (containerConfigs []config .ContainerConfig ) ([]securitypolicy.Container , error ) {
104
+ var policyContainers []securitypolicy.Container
101
105
for _ , containerConfig := range containerConfigs {
102
106
var imageOptions []remote.Option
103
107
@@ -126,7 +130,7 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
126
130
if err != nil {
127
131
return nil , err
128
132
}
129
- envRules := securitypolicy . NewEnvVarRules (envVars )
133
+ envRules := config . NewEnvVarRuleConfigs (envVars )
130
134
envRules = append (envRules , containerConfig .EnvRules ... )
131
135
132
136
workingDir , err := ParseWorkingDirFromImage (img )
@@ -138,7 +142,7 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
138
142
workingDir = containerConfig .WorkingDir
139
143
}
140
144
141
- container , err := securitypolicy . CreateContainerPolicy (
145
+ container , err := CreateContainerPolicy (
142
146
containerConfig .Command ,
143
147
layerHashes ,
144
148
envRules ,
@@ -154,3 +158,107 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
154
158
155
159
return policyContainers , nil
156
160
}
161
+
162
+ // CreateContainerPolicy creates a new Container policy instance from the
163
+ // provided constraints or an error if parameter validation fails.
164
+ func CreateContainerPolicy (
165
+ command , layers []string ,
166
+ envRuleConfigs []config.EnvRuleConfig ,
167
+ workingDir string ,
168
+ eMounts []string ,
169
+ mntConfigs []config.MountConfig ,
170
+ ) (securitypolicy.Container , error ) {
171
+ envRules , err := createEnvVarRules (envRuleConfigs )
172
+ if err != nil {
173
+ return securitypolicy.Container {}, err
174
+ }
175
+ mntConstraints , err := createMountConstraints (mntConfigs )
176
+ if err != nil {
177
+ return securitypolicy.Container {}, err
178
+ }
179
+ return securitypolicy .NewContainer (
180
+ command ,
181
+ layers ,
182
+ envRules ,
183
+ workingDir ,
184
+ eMounts ,
185
+ mntConstraints ,
186
+ ), nil
187
+ }
188
+
189
+ func createEnvVarRules (rules []config.EnvRuleConfig ) ([]securitypolicy.EnvVarRule , error ) {
190
+ var envRules []securitypolicy.EnvVarRule
191
+ for _ , rule := range rules {
192
+ switch rule .Strategy {
193
+ case securitypolicy .EnvRuleRegex :
194
+ if _ , err := regexp .Compile (rule .Rule ); err != nil {
195
+ return nil , err
196
+ }
197
+ case securitypolicy .EnvRuleString :
198
+ default :
199
+ return nil , fmt .Errorf ("invalid env_var strategy: %s" , rule .Strategy )
200
+ }
201
+ envRules = append (envRules , securitypolicy.EnvVarRule {
202
+ Strategy : rule .Strategy ,
203
+ Rule : rule .Rule ,
204
+ })
205
+ }
206
+ return envRules , nil
207
+ }
208
+
209
+ func createMountConstraints (mntConfigs []config.MountConfig ) ([]securitypolicy.Mount , error ) {
210
+ var mntConstraints []securitypolicy.Mount
211
+ for _ , m := range mntConfigs {
212
+ if _ , err := regexp .Compile (m .HostPath ); err != nil {
213
+ return nil , err
214
+ }
215
+ mntConstraints = append (mntConstraints , newMountFromConfig (& m ))
216
+ }
217
+ return mntConstraints , nil
218
+ }
219
+
220
+ // newOptionsFromConfig applies the same logic as CRI plugin to generate
221
+ // mount options given readonly and propagation config.
222
+ // TODO: (anmaxvl) update when support for other mount types is added,
223
+ // e.g., vhd:// or evd://
224
+ // TODO: (anmaxvl) Do we need to set/validate Linux rootfs propagation?
225
+ // In case we do, update securityPolicyContainer and Container structs
226
+ // as well as mount enforcement logic.
227
+ func newOptionsFromConfig (mCfg * config.MountConfig ) []string {
228
+ mountOpts := []string {"rbind" }
229
+
230
+ if strings .HasPrefix (mCfg .HostPath , guestpath .SandboxMountPrefix ) ||
231
+ strings .HasPrefix (mCfg .HostPath , guestpath .HugePagesMountPrefix ) {
232
+ mountOpts = append (mountOpts , "rshared" )
233
+ } else {
234
+ mountOpts = append (mountOpts , "rprivate" )
235
+ }
236
+
237
+ if mCfg .Readonly {
238
+ mountOpts = append (mountOpts , "ro" )
239
+ } else {
240
+ mountOpts = append (mountOpts , "rw" )
241
+ }
242
+ return mountOpts
243
+ }
244
+
245
+ // newMountTypeFromConfig mimics the behavior in CRI when figuring out OCI
246
+ // mount type.
247
+ func newMountTypeFromConfig (mCfg * config.MountConfig ) string {
248
+ if strings .HasPrefix (mCfg .HostPath , guestpath .SandboxMountPrefix ) ||
249
+ strings .HasPrefix (mCfg .HostPath , guestpath .HugePagesMountPrefix ) {
250
+ return "bind"
251
+ }
252
+ return "none"
253
+ }
254
+
255
+ // newMountFromConfig converts user provided MountConfig into internal representation
256
+ // of mount constraint.
257
+ func newMountFromConfig (mntConfig * config.MountConfig ) securitypolicy.Mount {
258
+ return securitypolicy .NewMountConstraint (
259
+ mntConfig .HostPath ,
260
+ mntConfig .ContainerPath ,
261
+ newMountTypeFromConfig (mntConfig ),
262
+ newOptionsFromConfig (mntConfig ),
263
+ )
264
+ }
0 commit comments