...

Source file src/github.com/Microsoft/hcsshim/pkg/securitypolicy/securitypolicy_internal.go

Documentation: github.com/Microsoft/hcsshim/pkg/securitypolicy

     1  package securitypolicy
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"syscall"
     7  )
     8  
     9  // Internal version of SecurityPolicy
    10  type securityPolicyInternal struct {
    11  	Containers                       []*securityPolicyContainer
    12  	ExternalProcesses                []*externalProcess
    13  	Fragments                        []*fragment
    14  	AllowPropertiesAccess            bool
    15  	AllowDumpStacks                  bool
    16  	AllowRuntimeLogging              bool
    17  	AllowEnvironmentVariableDropping bool
    18  	AllowUnencryptedScratch          bool
    19  	AllowCapabilityDropping          bool
    20  }
    21  
    22  type securityPolicyFragment struct {
    23  	Namespace         string
    24  	SVN               string
    25  	Containers        []*securityPolicyContainer
    26  	ExternalProcesses []*externalProcess
    27  	Fragments         []*fragment
    28  }
    29  
    30  func containersToInternal(containers []*Container) ([]*securityPolicyContainer, error) {
    31  	result := make([]*securityPolicyContainer, len(containers))
    32  	for i, cConf := range containers {
    33  		cInternal, err := cConf.toInternal()
    34  		if err != nil {
    35  			return nil, err
    36  		}
    37  		result[i] = cInternal
    38  	}
    39  
    40  	return result, nil
    41  }
    42  
    43  func externalProcessToInternal(externalProcesses []ExternalProcessConfig) []*externalProcess {
    44  	result := make([]*externalProcess, len(externalProcesses))
    45  	for i, pConf := range externalProcesses {
    46  		pInternal := pConf.toInternal()
    47  		result[i] = &pInternal
    48  	}
    49  
    50  	return result
    51  }
    52  
    53  func fragmentsToInternal(fragments []FragmentConfig) []*fragment {
    54  	result := make([]*fragment, len(fragments))
    55  	for i, fConf := range fragments {
    56  		fInternal := fConf.toInternal()
    57  		result[i] = &fInternal
    58  	}
    59  
    60  	return result
    61  }
    62  
    63  func newSecurityPolicyInternal(
    64  	containers []*Container,
    65  	externalProcesses []ExternalProcessConfig,
    66  	fragments []FragmentConfig,
    67  	allowPropertiesAccess bool,
    68  	allowDumpStacks bool,
    69  	allowRuntimeLogging bool,
    70  	allowDropEnvironmentVariables bool,
    71  	allowUnencryptedScratch bool,
    72  	allowDropCapabilities bool,
    73  ) (*securityPolicyInternal, error) {
    74  	containersInternal, err := containersToInternal(containers)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	return &securityPolicyInternal{
    80  		Containers:                       containersInternal,
    81  		ExternalProcesses:                externalProcessToInternal(externalProcesses),
    82  		Fragments:                        fragmentsToInternal(fragments),
    83  		AllowPropertiesAccess:            allowPropertiesAccess,
    84  		AllowDumpStacks:                  allowDumpStacks,
    85  		AllowRuntimeLogging:              allowRuntimeLogging,
    86  		AllowEnvironmentVariableDropping: allowDropEnvironmentVariables,
    87  		AllowUnencryptedScratch:          allowUnencryptedScratch,
    88  		AllowCapabilityDropping:          allowDropCapabilities,
    89  	}, nil
    90  }
    91  
    92  func newSecurityPolicyFragment(
    93  	namespace string,
    94  	svn string,
    95  	containers []*Container,
    96  	externalProcesses []ExternalProcessConfig,
    97  	fragments []FragmentConfig) (*securityPolicyFragment, error) {
    98  	containersInternal, err := containersToInternal(containers)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return &securityPolicyFragment{
   104  		Namespace:         namespace,
   105  		SVN:               svn,
   106  		Containers:        containersInternal,
   107  		ExternalProcesses: externalProcessToInternal(externalProcesses),
   108  		Fragments:         fragmentsToInternal(fragments),
   109  	}, nil
   110  }
   111  
   112  // Internal version of Container
   113  type securityPolicyContainer struct {
   114  	// The command that we will allow the container to execute
   115  	Command []string `json:"command"`
   116  	// The rules for determining if a given environment variable is allowed
   117  	EnvRules []EnvRuleConfig `json:"env_rules"`
   118  	// An ordered list of dm-verity root hashes for each layer that makes up
   119  	// "a container". Containers are constructed as an overlay file system. The
   120  	// order that the layers are overlayed is important and needs to be enforced
   121  	// as part of policy.
   122  	Layers []string `json:"layers"`
   123  	// WorkingDir is a path to container's working directory, which all the processes
   124  	// will default to.
   125  	WorkingDir string `json:"working_dir"`
   126  	// A list of constraints for determining if a given mount is allowed.
   127  	Mounts        []mountInternal `json:"mounts"`
   128  	AllowElevated bool            `json:"allow_elevated"`
   129  	// A list of lists of commands that can be used to execute additional
   130  	// processes within the container
   131  	ExecProcesses []containerExecProcess `json:"exec_processes"`
   132  	// A list of signals that are allowed to be sent to the container's init
   133  	// process.
   134  	Signals []syscall.Signal `json:"signals"`
   135  	// Whether to allow the capture of init process standard out and standard error
   136  	AllowStdioAccess bool `json:"allow_stdio_access"`
   137  	// Whether to deny new privileges
   138  	NoNewPrivileges bool `json:"no_new_privileges"`
   139  	// The user that the container will run as
   140  	User UserConfig `json:"user"`
   141  	// Capability sets for the container
   142  	Capabilities *capabilitiesInternal `json:"capabilities"`
   143  	// Seccomp configuration for the container
   144  	SeccompProfileSHA256 string `json:"seccomp_profile_sha256"`
   145  }
   146  
   147  type containerExecProcess struct {
   148  	Command []string `json:"command"`
   149  	// A list of signals that are allowed to be sent to this process
   150  	Signals []syscall.Signal `json:"signals"`
   151  }
   152  
   153  type externalProcess struct {
   154  	command          []string
   155  	envRules         []EnvRuleConfig
   156  	workingDir       string
   157  	allowStdioAccess bool
   158  }
   159  
   160  // Internal version of Mount
   161  type mountInternal struct {
   162  	Source      string   `json:"source"`
   163  	Destination string   `json:"destination"`
   164  	Type        string   `json:"type"`
   165  	Options     []string `json:"options"`
   166  }
   167  
   168  // Internal version of Capabilities
   169  type capabilitiesInternal struct {
   170  	Bounding    []string
   171  	Effective   []string
   172  	Inheritable []string
   173  	Permitted   []string
   174  	Ambient     []string
   175  }
   176  
   177  type fragment struct {
   178  	issuer     string
   179  	feed       string
   180  	minimumSVN string
   181  	includes   []string
   182  }
   183  
   184  func (c *Container) toInternal() (*securityPolicyContainer, error) {
   185  	command, err := c.Command.toInternal()
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	envRules, err := c.EnvRules.toInternal()
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	layers, err := c.Layers.toInternal()
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	mounts, err := c.Mounts.toInternal()
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  
   205  	execProcesses := make([]containerExecProcess, len(c.ExecProcesses))
   206  	for i, ep := range c.ExecProcesses {
   207  		execProcesses[i] = containerExecProcess(ep)
   208  	}
   209  
   210  	var capabilities *capabilitiesInternal
   211  	if c.Capabilities != nil {
   212  		c := c.Capabilities.toInternal()
   213  		capabilities = &c
   214  	}
   215  
   216  	return &securityPolicyContainer{
   217  		Command:  command,
   218  		EnvRules: envRules,
   219  		Layers:   layers,
   220  		// No need to have toInternal(), because WorkingDir is a string both
   221  		// internally and in the policy.
   222  		WorkingDir:           c.WorkingDir,
   223  		Mounts:               mounts,
   224  		AllowElevated:        c.AllowElevated,
   225  		ExecProcesses:        execProcesses,
   226  		Signals:              c.Signals,
   227  		AllowStdioAccess:     c.AllowStdioAccess,
   228  		NoNewPrivileges:      c.NoNewPrivileges,
   229  		User:                 c.User,
   230  		Capabilities:         capabilities,
   231  		SeccompProfileSHA256: c.SeccompProfileSHA256,
   232  	}, nil
   233  }
   234  
   235  func (c CommandArgs) toInternal() ([]string, error) {
   236  	return stringMapToStringArray(c.Elements)
   237  }
   238  
   239  func (e EnvRules) toInternal() ([]EnvRuleConfig, error) {
   240  	envRulesMapLength := len(e.Elements)
   241  	envRules := make([]EnvRuleConfig, envRulesMapLength)
   242  	for i := 0; i < envRulesMapLength; i++ {
   243  		eIndex := strconv.Itoa(i)
   244  		elem, ok := e.Elements[eIndex]
   245  		if !ok {
   246  			return nil, fmt.Errorf("env rule with index %q doesn't exist", eIndex)
   247  		}
   248  		envRules[i] = elem
   249  	}
   250  
   251  	return envRules, nil
   252  }
   253  
   254  func (l Layers) toInternal() ([]string, error) {
   255  	return stringMapToStringArray(l.Elements)
   256  }
   257  
   258  func (o Options) toInternal() ([]string, error) {
   259  	return stringMapToStringArray(o.Elements)
   260  }
   261  
   262  func (m Mounts) toInternal() ([]mountInternal, error) {
   263  	mountLength := len(m.Elements)
   264  	mountConstraints := make([]mountInternal, mountLength)
   265  	for i := 0; i < mountLength; i++ {
   266  		mIndex := strconv.Itoa(i)
   267  		mount, ok := m.Elements[mIndex]
   268  		if !ok {
   269  			return nil, fmt.Errorf("mount constraint with index %q not found", mIndex)
   270  		}
   271  		opts, err := mount.Options.toInternal()
   272  		if err != nil {
   273  			return nil, err
   274  		}
   275  		mountConstraints[i] = mountInternal{
   276  			Source:      mount.Source,
   277  			Destination: mount.Destination,
   278  			Type:        mount.Type,
   279  			Options:     opts,
   280  		}
   281  	}
   282  	return mountConstraints, nil
   283  }
   284  
   285  func (p ExternalProcessConfig) toInternal() externalProcess {
   286  	return externalProcess{
   287  		command: p.Command,
   288  		envRules: []EnvRuleConfig{{
   289  			Strategy: "string",
   290  			Rule:     "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
   291  			Required: true,
   292  		}},
   293  		workingDir:       p.WorkingDir,
   294  		allowStdioAccess: p.AllowStdioAccess,
   295  	}
   296  }
   297  
   298  func (f FragmentConfig) toInternal() fragment {
   299  	return fragment{
   300  		issuer:     f.Issuer,
   301  		feed:       f.Feed,
   302  		minimumSVN: f.MinimumSVN,
   303  		includes:   f.Includes,
   304  	}
   305  }
   306  
   307  func (c CapabilitiesConfig) toInternal() capabilitiesInternal {
   308  	return capabilitiesInternal(c)
   309  }
   310  
   311  func stringMapToStringArray(m map[string]string) ([]string, error) {
   312  	mapSize := len(m)
   313  	out := make([]string, mapSize)
   314  
   315  	for i := 0; i < mapSize; i++ {
   316  		index := strconv.Itoa(i)
   317  		value, ok := m[index]
   318  		if !ok {
   319  			return nil, fmt.Errorf("element with index %q not found", index)
   320  		}
   321  		out[i] = value
   322  	}
   323  
   324  	return out, nil
   325  }
   326  

View as plain text