Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/guest/runtime/hcsv2/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ func (h *Host) CreateContainer(ctx context.Context, id string, settings *prot.VM
return nil, gcserr.NewHresultError(gcserr.HrVmcomputeSystemAlreadyExists)
}

err = h.securityPolicyEnforcer.EnforceCommandPolicy(id, settings.OCISpecification.Process.Args)
err = h.securityPolicyEnforcer.EnforceStartContainerPolicy(id, settings.OCISpecification.Process.Args, settings.OCISpecification.Process.Env)

if err != nil {
return nil, errors.Wrapf(err, "container creation denied due to policy")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ func (p *MountMonitoringSecurityPolicyEnforcer) EnforceOverlayMountPolicy(contai
return nil
}

func (p *MountMonitoringSecurityPolicyEnforcer) EnforceCommandPolicy(containerID string, argList []string) (err error) {
func (p *MountMonitoringSecurityPolicyEnforcer) EnforceStartContainerPolicy(containerID string, argList []string, envList []string) (err error) {
return nil
}
49 changes: 47 additions & 2 deletions internal/tools/securitypolicy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ be downloaded, turned into an ext4, and finally a dm-verity root hash calculated
[[image]]
name = "rust:1.52.1"
command = ["rustc", "--help"]

[[image.env_rule]]
strategy = "re2"
rule = "PREFIX_.+=.+"
```

### Converted to JSON
Expand All @@ -32,13 +36,54 @@ represented in JSON.
"allow_all": false,
"containers": [
{
"command": ["/pause"],
"command": [
"/pause"
],
"env_rules": [
{
"strategy": "string",
"rule": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
},
{
"strategy": "string",
"rule": "TERM=xterm"
}
],
"layers": [
"16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415"
]
},
{
"command": ["rustc", "--help"],
"command": [
"rustc",
"--help"
],
"env_rules": [
{
"strategy": "re2",
"rule": "PREFIX_.+=.+"
},
{
"strategy": "string",
"rule": "TERM=xterm"
},
{
"strategy": "string",
"rule": "PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
},
{
"strategy": "string",
"rule": "RUSTUP_HOME=/usr/local/rustup"
},
{
"strategy": "string",
"rule": "CARGO_HOME=/usr/local/cargo"
},
{
"strategy": "string",
"rule": "RUST_VERSION=1.52.1"
}
],
"layers": [
"fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a",
"4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c",
Expand Down
93 changes: 79 additions & 14 deletions internal/tools/securitypolicy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io/ioutil"
"os"
"regexp"

"github.com/BurntSushi/toml"
"github.com/Microsoft/hcsshim/ext4/dmverity"
Expand Down Expand Up @@ -78,9 +79,15 @@ func main() {
}
}

type EnvironmentVariableRule struct {
Strategy string `toml:"strategy"`
Rule string `toml:"rule"`
Comment thread
SeanTAllen marked this conversation as resolved.
}

type Image struct {
Name string `toml:"name"`
Command []string `toml:"command"`
Name string `toml:"name"`
Command []string `toml:"command"`
EnvRules []EnvironmentVariableRule `toml:"env_rule"`
}

type Config struct {
Expand All @@ -97,16 +104,6 @@ func createOpenDoorPolicy() sp.SecurityPolicy {
func createPolicyFromConfig(config Config) (sp.SecurityPolicy, error) {
p := sp.SecurityPolicy{}

// for now, we hardcode the pause container version 3.1 here
// in a final end user tool, we would not do it this way.
// as this is a tool for use by developers currently working
// on security policy implementation code
pausec := sp.SecurityPolicyContainer{
Command: []string{"/pause"},
Layers: []string{"16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415"},
}
p.Containers = append(p.Containers, pausec)

var imageOptions []remote.Option
if len(*username) != 0 && len(*password) != 0 {
auth := authn.Basic{
Expand All @@ -117,10 +114,25 @@ func createPolicyFromConfig(config Config) (sp.SecurityPolicy, error) {
imageOptions = append(imageOptions, authOption)
}

// Hardcode the pause container version and command. We still pull it
// to get the root hash and any environment variable rules we might need.
pause := Image{
Name: "k8s.gcr.io/pause:3.1",
Command: []string{"/pause"},
EnvRules: []EnvironmentVariableRule{}}
config.Images = append(config.Images, pause)

for _, image := range config.Images {
// validate EnvRules
err := validateEnvRules(image.EnvRules)
if err != nil {
return p, err
}

container := sp.SecurityPolicyContainer{
Command: image.Command,
Layers: []string{},
Command: image.Command,
EnvRules: convertEnvironmentVariableRules(image.EnvRules),
Layers: []string{},
}
ref, err := name.ParseReference(image.Name)
if err != nil {
Expand Down Expand Up @@ -172,8 +184,61 @@ func createPolicyFromConfig(config Config) (sp.SecurityPolicy, error) {
container.Layers = append(container.Layers, hashString)
}

// add rules for all known environment variables from the configuration
// these are in addition to "other rules" from the policy definition file
config, err := img.ConfigFile()
if err != nil {
return p, err
}
for _, env := range config.Config.Env {
rule := sp.SecurityPolicyEnvironmentVariableRule{
Strategy: "string",
Rule: env,
}

container.EnvRules = append(container.EnvRules, rule)
}

// cri adds TERM=xterm for all workload containers. we add to all containers
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kinda worries me if this is ever changed. I'm still not sure how this even always get's set from our investigation. For now, not sure what else you could do at the moment so not saying to change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this tool is a convenience for developers working on gcs and policy, if it changes, it is easy enough to adjust. this merely saves having to put it in every toml for that someone has.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to check where the code I'm reviewing lives before I type. This is fine then

// to prevent any possble erroring
rule := sp.SecurityPolicyEnvironmentVariableRule{
Strategy: "string",
Comment thread
SeanTAllen marked this conversation as resolved.
Rule: "TERM=xterm",
}

container.EnvRules = append(container.EnvRules, rule)

p.Containers = append(p.Containers, container)
}

return p, nil
}

func validateEnvRules(rules []EnvironmentVariableRule) error {
for _, rule := range rules {
switch rule.Strategy {
case "re2":
_, err := regexp.Compile(rule.Rule)
if err != nil {
return err
}
}
}

return nil
}

func convertEnvironmentVariableRules(toml []EnvironmentVariableRule) []sp.SecurityPolicyEnvironmentVariableRule {
json := make([]sp.SecurityPolicyEnvironmentVariableRule, len(toml))
Comment thread
SeanTAllen marked this conversation as resolved.

for i, rule := range toml {
jsonRule := sp.SecurityPolicyEnvironmentVariableRule{
Strategy: rule.Strategy,
Rule: rule.Rule,
}

json[i] = jsonRule
}

return json
}
7 changes: 7 additions & 0 deletions pkg/securitypolicy/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ type SecurityPolicy struct {
type SecurityPolicyContainer struct {
// The command that we will allow the container to execute
Command []string `json:"command"`
// The rules for determining if a given environment variable is allowed
EnvRules []SecurityPolicyEnvironmentVariableRule `json:"env_rules"`
// An ordered list of dm-verity root hashes for each layer that makes up
// "a container". Containers are constructed as an overlay file system. The
// order that the layers are overlayed is important and needs to be enforced
// as part of policy.
Layers []string `json:"layers"`
}

type SecurityPolicyEnvironmentVariableRule struct {
Strategy string `json:"strategy"`
Rule string `json:"rule"`
}

// EncodedSecurityPolicy is a JSON representation of SecurityPolicy that has
// been base64 encoded for storage in an annotation embedded within another
// JSON configuration
Expand Down
Loading