Skip to content

Commit ed88272

Browse files
committed
pr feedback: move config closer to tooling and refactor code
Signed-off-by: Maksim An <[email protected]>
1 parent e277c5f commit ed88272

File tree

17 files changed

+864
-758
lines changed

17 files changed

+864
-758
lines changed

internal/spec/spec.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ func DevShmMountWithSize(sizeString string) (*specs.Mount, error) {
2020
return nil, errors.New("only linux runtimes are supported")
2121
}
2222

23-
size, err := strconv.ParseInt(sizeString, 10, 64)
23+
size, err := strconv.ParseUint(sizeString, 10, 64)
2424
if err != nil {
2525
return nil, fmt.Errorf("/dev/shm size must be a valid integer: %w", err)
2626
}
27-
if size <= 0 {
28-
return nil, fmt.Errorf("/dev/shm size must be a positive integer, got: %d", size)
27+
if size == 0 {
28+
return nil, errors.New("/dev/shm size must be non-zero")
2929
}
3030

3131
// Use the same options as in upstream https://github.com/containerd/containerd/blob/0def98e462706286e6eaeff4a90be22fda75e761/oci/mounts.go#L49
@@ -39,7 +39,7 @@ func DevShmMountWithSize(sizeString string) (*specs.Mount, error) {
3939
}
4040

4141
// GenerateWorkloadContainerNetworkMounts generates an array of specs.Mount
42-
// required for container networking. Original spec is left untouched and
42+
// required for container networking. Original spec is left untouched, so
4343
// it's the responsibility of a caller to update it.
4444
func GenerateWorkloadContainerNetworkMounts(sandboxID string, spec *specs.Spec) []specs.Mount {
4545
var nMounts []specs.Mount

pkg/securitypolicy/config.go renamed to internal/tools/securitypolicy/config/config.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
package securitypolicy
1+
package config
22

3-
type EnvVarRule string
4-
5-
const (
6-
EnvVarRuleString EnvVarRule = "string"
7-
EnvVarRuleRegex EnvVarRule = "re2"
3+
import (
4+
"github.com/Microsoft/hcsshim/pkg/securitypolicy"
85
)
96

107
// PolicyConfig contains toml or JSON config for security policy.
@@ -22,8 +19,8 @@ type AuthConfig struct {
2219
// EnvRuleConfig contains toml or JSON config for environment variable
2320
// security policy enforcement.
2421
type EnvRuleConfig struct {
25-
Strategy EnvVarRule `json:"strategy" toml:"strategy"`
26-
Rule string `json:"rule" toml:"rule"`
22+
Strategy securitypolicy.EnvRuleStrategy `json:"strategy" toml:"strategy"`
23+
Rule string `json:"rule" toml:"rule"`
2724
}
2825

2926
// ContainerConfig contains toml or JSON config for container described
@@ -46,13 +43,13 @@ type MountConfig struct {
4643
Readonly bool `json:"readonly" toml:"readonly"`
4744
}
4845

49-
// NewEnvVarRules creates slice of EnvRuleConfig's from environment variables
46+
// NewEnvVarRuleConfigs creates slice of EnvRuleConfig's from environment variables
5047
// strings slice.
51-
func NewEnvVarRules(envVars []string) []EnvRuleConfig {
48+
func NewEnvVarRuleConfigs(envVars []string) []EnvRuleConfig {
5249
var rules []EnvRuleConfig
5350
for _, env := range envVars {
5451
r := EnvRuleConfig{
55-
Strategy: EnvVarRuleString,
52+
Strategy: securitypolicy.EnvRuleString,
5653
Rule: env,
5754
}
5855
rules = append(rules, r)

internal/tools/securitypolicy/helpers/helpers.go

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ package helpers
22

33
import (
44
"fmt"
5+
"regexp"
6+
"strings"
57

8+
"github.com/Microsoft/hcsshim/internal/guestpath"
69
"github.com/google/go-containerregistry/pkg/authn"
710
"github.com/google/go-containerregistry/pkg/name"
811
v1 "github.com/google/go-containerregistry/pkg/v1"
912
"github.com/google/go-containerregistry/pkg/v1/remote"
1013

1114
"github.com/Microsoft/hcsshim/ext4/tar2ext4"
15+
"github.com/Microsoft/hcsshim/internal/tools/securitypolicy/config"
1216
"github.com/Microsoft/hcsshim/pkg/securitypolicy"
1317
)
1418

@@ -67,17 +71,17 @@ func ParseEnvFromImage(img v1.Image) ([]string, error) {
6771
// DefaultContainerConfigs returns a hardcoded slice of container configs, which should
6872
// be included by default in the security policy.
6973
// 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(
7276
"k8s.gcr.io/pause:3.1",
7377
[]string{"/pause"},
74-
[]securitypolicy.EnvRuleConfig{},
75-
securitypolicy.AuthConfig{},
78+
[]config.EnvRuleConfig{},
79+
config.AuthConfig{},
7680
"",
7781
[]string{},
78-
[]securitypolicy.MountConfig{},
82+
[]config.MountConfig{},
7983
)
80-
return []securitypolicy.ContainerConfig{pause}
84+
return []config.ContainerConfig{pause}
8185
}
8286

8387
// ParseWorkingDirFromImage inspects the image spec and returns working directory if
@@ -95,9 +99,9 @@ func ParseWorkingDirFromImage(img v1.Image) (string, error) {
9599
}
96100

97101
// 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
101105
for _, containerConfig := range containerConfigs {
102106
var imageOptions []remote.Option
103107

@@ -126,7 +130,7 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
126130
if err != nil {
127131
return nil, err
128132
}
129-
envRules := securitypolicy.NewEnvVarRules(envVars)
133+
envRules := config.NewEnvVarRuleConfigs(envVars)
130134
envRules = append(envRules, containerConfig.EnvRules...)
131135

132136
workingDir, err := ParseWorkingDirFromImage(img)
@@ -138,7 +142,7 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
138142
workingDir = containerConfig.WorkingDir
139143
}
140144

141-
container, err := securitypolicy.CreateContainerPolicy(
145+
container, err := CreateContainerPolicy(
142146
containerConfig.Command,
143147
layerHashes,
144148
envRules,
@@ -154,3 +158,107 @@ func PolicyContainersFromConfigs(containerConfigs []securitypolicy.ContainerConf
154158

155159
return policyContainers, nil
156160
}
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+
}

internal/tools/securitypolicy/main.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/BurntSushi/toml"
1212

13+
"github.com/Microsoft/hcsshim/internal/tools/securitypolicy/config"
1314
"github.com/Microsoft/hcsshim/internal/tools/securitypolicy/helpers"
1415
"github.com/Microsoft/hcsshim/pkg/securitypolicy"
1516
)
@@ -32,18 +33,18 @@ func main() {
3233
return err
3334
}
3435

35-
config := &securitypolicy.PolicyConfig{}
36+
cfg := &config.PolicyConfig{}
3637

37-
err = toml.Unmarshal(configData, config)
38+
err = toml.Unmarshal(configData, cfg)
3839
if err != nil {
3940
return err
4041
}
4142

4243
policy, err := func() (*securitypolicy.SecurityPolicy, error) {
43-
if config.AllowAll {
44+
if cfg.AllowAll {
4445
return securitypolicy.NewOpenDoorPolicy(), nil
4546
} else {
46-
return createPolicyFromConfig(config)
47+
return createPolicyFromConfig(cfg)
4748
}
4849
}()
4950

@@ -70,12 +71,12 @@ func main() {
7071
}
7172
}
7273

73-
func createPolicyFromConfig(config *securitypolicy.PolicyConfig) (*securitypolicy.SecurityPolicy, error) {
74+
func createPolicyFromConfig(cfg *config.PolicyConfig) (*securitypolicy.SecurityPolicy, error) {
7475
// Add default containers to the policy config to get the root hash
7576
// and any environment variable rules we might need
7677
defaultContainers := helpers.DefaultContainerConfigs()
77-
config.Containers = append(config.Containers, defaultContainers...)
78-
policyContainers, err := helpers.PolicyContainersFromConfigs(config.Containers)
78+
cfg.Containers = append(cfg.Containers, defaultContainers...)
79+
policyContainers, err := helpers.PolicyContainersFromConfigs(cfg.Containers)
7980
if err != nil {
8081
return nil, err
8182
}

0 commit comments

Comments
 (0)