Skip to content

Commit

Permalink
new SCCs
Browse files Browse the repository at this point in the history
  • Loading branch information
pweil- committed Oct 29, 2015
1 parent 67bb208 commit 161f408
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 7 deletions.
133 changes: 127 additions & 6 deletions pkg/cmd/server/bootstrappolicy/securitycontextconstraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,42 @@ import (
)

const (
// SecurityContextConstraintPrivileged is used as the name for the system default privileged scc.
// SecurityContextConstraintPrivileged allows access to all privileged and host features and the ability
// to run as any user, any group, any fsGroup, and with any SELinux context.
//
// WARNING: this is the most relaxed SCC and should be used only for cluster administration.
// Grant with caution.
SecurityContextConstraintPrivileged = "privileged"
// SecurityContextConstraintRestricted is used as the name for the system default restricted scc.
// SecurityContextConstraintRestricted denys access to all host features and requires pods
// to be run with a UID, SELinux context, fs group, and supplemental groups that are
// allocated to the namespace. This is the most restrictive SCC.
SecurityContextConstraintRestricted = "restricted"
// SecurityContextConstraintNonRoot provides all features of the SecurityContextConstraintRestricted
// SCC but allows users to run with any non-root UID. The user must specify the UID or it
// must be specified on the by the manifest of the container runtime.
SecurityContextConstraintNonRoot = "nonroot"
// SecurityContextConstraintHostMount provides all the features of SecurityContextConstraintRestricted
// but allows host mounts by a pod. This is primarily used by the persistent volume recycler.
//
// WARNING: this SCC allows host file system access. Grant with caution.
SecurityContextConstraintHostMount = "hostmount"
// SecurityContextConstraintHostNS allows access to all host namespaces but still requires pods
// to be run with a UID, SELinux context, fs group, and supplemental groups that are
// allocated to the namespace.
//
// WARNING: this SCC allows host access to namespaces, file systems, and PIDS. It should only
// be used by trusted pods. Grant with caution.
SecurityContextConstraintHostNS = "hostaccess"
// SecurityContextConstraintsAnyUID provides all features of the SecurityContextConstraintRestricted
// SCC but allows users to run with any UID. This is the default SCC for authenticated users.
SecurityContextConstraintsAnyUID = "anyuid"
)

// GetBootstrapSecurityContextConstraints returns the slice of default SecurityContextConstraints
// for system bootstrapping.
func GetBootstrapSecurityContextConstraints(buildControllerUsername string) []kapi.SecurityContextConstraints {
func GetBootstrapSecurityContextConstraints(sccNameToAdditionalGroups map[string][]string, sccNameToAdditionalUsers map[string][]string) []kapi.SecurityContextConstraints {
constraints := []kapi.SecurityContextConstraints{
// SecurityContextConstraintPrivileged allows all access for every field
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintPrivileged,
Expand All @@ -31,9 +57,70 @@ func GetBootstrapSecurityContextConstraints(buildControllerUsername string) []ka
RunAsUser: kapi.RunAsUserStrategyOptions{
Type: kapi.RunAsUserStrategyRunAsAny,
},
Users: []string{buildControllerUsername},
Groups: []string{ClusterAdminGroup, NodesGroup},
},
// SecurityContextConstraintNonRoot does not allow host access, allocates SELinux labels
// and allows the user to request a specific UID or provide the default in the dockerfile.
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintNonRoot,
},
SELinuxContext: kapi.SELinuxContextStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.SELinuxStrategyMustRunAs,
},
RunAsUser: kapi.RunAsUserStrategyOptions{
// This strategy requires that the user request to run as a specific UID or that
// the docker file contain a USER directive.
Type: kapi.RunAsUserStrategyMustRunAsNonRoot,
},
},
// SecurityContextConstraintHostMount is the same as the restricted scc but allows host mounts.
// Used by the PV recycler.
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintHostMount,
},
AllowHostDirVolumePlugin: true,
SELinuxContext: kapi.SELinuxContextStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.SELinuxStrategyMustRunAs,
},
RunAsUser: kapi.RunAsUserStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.RunAsUserStrategyMustRunAsRange,
},
},
// SecurityContextConstraintHostNS allows access to everything except privileged on the host
// but still allocates UIDs and SELinux.
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintHostNS,
},
AllowHostDirVolumePlugin: true,
AllowHostNetwork: true,
AllowHostPorts: true,
AllowHostPID: true,
AllowHostIPC: true,
SELinuxContext: kapi.SELinuxContextStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.SELinuxStrategyMustRunAs,
},
RunAsUser: kapi.RunAsUserStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.RunAsUserStrategyMustRunAsRange,
},
},
// SecurityContextConstraintRestricted allows no host access and allocates UIDs and SELinux.
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintRestricted,
Expand All @@ -50,8 +137,42 @@ func GetBootstrapSecurityContextConstraints(buildControllerUsername string) []ka
// will fail.
Type: kapi.RunAsUserStrategyMustRunAsRange,
},
Groups: []string{AuthenticatedGroup},
},
// SecurityContextConstraintsAnyUID allows no host access and allocates SELinux.
{
ObjectMeta: kapi.ObjectMeta{
Name: SecurityContextConstraintsAnyUID,
},
SELinuxContext: kapi.SELinuxContextStrategyOptions{
// This strategy requires that annotations on the namespace which will be populated
// by the admission controller. If namespaces are not annotated creating the strategy
// will fail.
Type: kapi.SELinuxStrategyMustRunAs,
},
RunAsUser: kapi.RunAsUserStrategyOptions{
Type: kapi.RunAsUserStrategyRunAsAny,
},
},
}

// add default access
for i, constraint := range constraints {
if usersToAdd, ok := sccNameToAdditionalUsers[constraint.Name]; ok {
constraints[i].Users = append(constraints[i].Users, usersToAdd...)
}
if groupsToAdd, ok := sccNameToAdditionalGroups[constraint.Name]; ok {
constraints[i].Groups = append(constraints[i].Groups, groupsToAdd...)
}
}
return constraints
}

// GetBoostrapSCCAccess provides the default set of access that should be passed to GetBootstrapSecurityContextConstraints.
func GetBoostrapSCCAccess() (map[string][]string, map[string][]string) {
groups := map[string][]string{
SecurityContextConstraintPrivileged: {ClusterAdminGroup, NodesGroup},
SecurityContextConstraintsAnyUID: {AuthenticatedGroup},
}
users := map[string][]string{}
return groups, users
}
70 changes: 70 additions & 0 deletions pkg/cmd/server/bootstrappolicy/securitycontextconstraints_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package bootstrappolicy

import (
"reflect"
"testing"
)

func TestBootstrappedConstraints(t *testing.T) {
expectedConstraints := []string{
SecurityContextConstraintPrivileged,
SecurityContextConstraintRestricted,
SecurityContextConstraintNonRoot,
SecurityContextConstraintHostMount,
SecurityContextConstraintHostNS,
SecurityContextConstraintsAnyUID,
}
expectedGroups, expectedUsers := getExpectedAccess()

groups, users := GetBoostrapSCCAccess()
bootstrappedConstraints := GetBootstrapSecurityContextConstraints(groups, users)

if len(expectedConstraints) != len(bootstrappedConstraints) {
t.Errorf("unexpected number of constraints: found %d, wanted %d", len(bootstrappedConstraints), len(expectedConstraints))
}

for _, constraint := range bootstrappedConstraints {
g := expectedGroups[constraint.Name]
if !reflect.DeepEqual(g, constraint.Groups) {
t.Errorf("unexpected group access for %s. Found %v, wanted %v", constraint.Name, constraint.Groups, g)
}

u := expectedUsers[constraint.Name]
if !reflect.DeepEqual(u, constraint.Users) {
t.Errorf("unexpected user access for %s. Found %v, wanted %v", constraint.Name, constraint.Users, u)
}
}
}

func TestBootstrappedConstraintsWithAddedUser(t *testing.T) {
expectedGroups, expectedUsers := getExpectedAccess()

// get default access and add our own user to it
groups, users := GetBoostrapSCCAccess()
users[SecurityContextConstraintPrivileged] = append(users[SecurityContextConstraintPrivileged], "foo")
bootstrappedConstraints := GetBootstrapSecurityContextConstraints(groups, users)

// add it to expected
expectedUsers[SecurityContextConstraintPrivileged] = append(expectedUsers[SecurityContextConstraintPrivileged], "foo")

for _, constraint := range bootstrappedConstraints {
g := expectedGroups[constraint.Name]
if !reflect.DeepEqual(g, constraint.Groups) {
t.Errorf("unexpected group access for %s. Found %v, wanted %v", constraint.Name, constraint.Groups, g)
}

u := expectedUsers[constraint.Name]
if !reflect.DeepEqual(u, constraint.Users) {
t.Errorf("unexpected user access for %s. Found %v, wanted %v", constraint.Name, constraint.Users, u)
}
}
}

func getExpectedAccess() (map[string][]string, map[string][]string) {
groups := map[string][]string{
SecurityContextConstraintPrivileged: {ClusterAdminGroup, NodesGroup},
SecurityContextConstraintsAnyUID: {AuthenticatedGroup},
}
users := map[string][]string{}
return groups, users
}
7 changes: 6 additions & 1 deletion pkg/cmd/server/origin/ensure.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,14 @@ func (c *MasterConfig) ensureDefaultSecurityContextConstraints() {
}

glog.Infof("No security context constraints detected, adding defaults")

// add the build user to the privileged SCC access
ns := c.Options.PolicyConfig.OpenShiftInfrastructureNamespace
buildControllerUsername := serviceaccount.MakeUsername(ns, c.BuildControllerServiceAccount)
for _, scc := range bootstrappolicy.GetBootstrapSecurityContextConstraints(buildControllerUsername) {
bootstrapSCCGroups, bootstrapSCCUsers := bootstrappolicy.GetBoostrapSCCAccess()
bootstrapSCCUsers[bootstrappolicy.SecurityContextConstraintPrivileged] = append(bootstrapSCCUsers[bootstrappolicy.SecurityContextConstraintPrivileged], buildControllerUsername)

for _, scc := range bootstrappolicy.GetBootstrapSecurityContextConstraints(bootstrapSCCGroups, bootstrapSCCUsers) {
_, err = c.KubeClient().SecurityContextConstraints().Create(&scc)
if err != nil {
glog.Errorf("Unable to create default security context constraint %s. Got error: %v", scc.Name, err)
Expand Down

0 comments on commit 161f408

Please sign in to comment.