Skip to content

Commit

Permalink
PodSecurityPolicy switch (#218)
Browse files Browse the repository at this point in the history
* move pkg/installer/util -> pkg/util

* PodSecurityPolicy admission plugin

* new config option features.enabled_psp
* regenerate kubeadm config every upgrade

* Fixed panic: runtime error: index out of range

* errors.Wrap() missed errors

* Permissive PSP for kube-system pods

* drop if -f /etc/kubernetes/kubelet.conf before kubeadm upgrade

* make defaultAdmissionPlugins a []string

* Improve naming
  • Loading branch information
kron4eg authored and kubermatic-bot committed Mar 1, 2019
1 parent 805b686 commit 8e55f57
Show file tree
Hide file tree
Showing 47 changed files with 421 additions and 138 deletions.
2 changes: 2 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions config.yaml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ network:
provider:
name: '' # Kubernetes cloud provider, like "aws"

features:
# enables PodSecurityPolicy admission plugin in API server, as well as creates
# default `privileged` PodSecurityPolicy, plus RBAC rules to authorize
# `kube-system` namespace pods to `use` it.
enable_pod_security_policy: false

backup:
# Ark supported provider, see https://heptio.github.io/ark/v0.10.0/support-matrix
provider: '' # currently only aws is supported, empty provider disable ark backups
Expand Down
2 changes: 1 addition & 1 deletion pkg/certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/pkg/errors"

"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/util"

"k8s.io/client-go/util/cert"
"k8s.io/client-go/util/cert/triple"
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/util"
)

type kubeconfigOptions struct {
Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func upgradeCmd(rootFlags *pflag.FlagSet) *cobra.Command {
This command takes KubeOne manifest which contains information about hosts and how the cluster should be provisioned.
It's possible to source information about hosts from Terraform output, using the '--tfjson' flag.`,
Hidden: true,
Args: cobra.ExactArgs(1),
Example: `kubeone upgrade mycluster.yaml -t terraformoutput.json`,
RunE: func(_ *cobra.Command, args []string) error {
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Cluster struct {
Workers []WorkerConfig `json:"workers"`
Backup BackupConfig `json:"backup"`
MachineController MachineControllerConfig `json:"machine_controller"`
Features Features `json:"features"`
}

// DefaultAndValidate checks if the cluster config makes sense.
Expand Down Expand Up @@ -460,6 +461,11 @@ func (m *MachineControllerConfig) DefaultAndValidate() error {
return nil
}

// Features switches
type Features struct {
EnablePodSecurityPolicy bool `json:"enable_pod_security_policy"`
}

func boolPtr(val bool) *bool {
return &val
}
29 changes: 29 additions & 0 deletions pkg/features/activate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package features

import (
"github.com/pkg/errors"

kubeadmv1beta1 "github.com/kubermatic/kubeone/pkg/apis/kubeadm/v1beta1"
"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/util"
)

// Activate configured features.
// Installing CRDs, creating policies and so on
func Activate(ctx *util.Context) error {
if err := installKubeSystemPSP(ctx.Cluster.Features.EnablePodSecurityPolicy, ctx); err != nil {
return errors.Wrap(err, "failed to install PodSecurityPolicy")
}

return nil
}

// UpdateKubeadmClusterConfiguration update additional config options in the kubeadm's
// v1beta1.ClusterConfiguration according to enabled features
func UpdateKubeadmClusterConfiguration(featuresCfg config.Features, clusterConfig *kubeadmv1beta1.ClusterConfiguration) {
if clusterConfig.APIServer.ExtraArgs == nil {
clusterConfig.APIServer.ExtraArgs = make(map[string]string)
}

activateKubeadmPSP(featuresCfg.EnablePodSecurityPolicy, clusterConfig)
}
164 changes: 164 additions & 0 deletions pkg/features/psp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package features

import (
"strings"

"github.com/pkg/errors"

kubeadmv1beta1 "github.com/kubermatic/kubeone/pkg/apis/kubeadm/v1beta1"
"github.com/kubermatic/kubeone/pkg/templates"
"github.com/kubermatic/kubeone/pkg/util"

corev1 "k8s.io/api/core/v1"
policybeta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
pspAdmissionPlugin = "PodSecurityPolicy"
apiServerAdmissionPluginsFlag = "enable-admission-plugins"
pspRoleNamespace = "kube-system"
)

var (
defaultAdmissionPlugins = []string{
"NamespaceLifecycle",
"LimitRanger",
"ServiceAccount",
"PersistentVolumeClaimResize",
"DefaultStorageClass",
"DefaultTolerationSeconds",
"MutatingAdmissionWebhook",
"ValidatingAdmissionWebhook",
"ResourceQuota",
"Priority",
}
)

func activateKubeadmPSP(activate bool, clusterConfig *kubeadmv1beta1.ClusterConfiguration) {
if !activate {
return
}

if _, ok := clusterConfig.APIServer.ExtraArgs[apiServerAdmissionPluginsFlag]; ok {
clusterConfig.APIServer.ExtraArgs[apiServerAdmissionPluginsFlag] += "," + pspAdmissionPlugin
} else {
clusterConfig.APIServer.ExtraArgs[apiServerAdmissionPluginsFlag] = strings.Join(append(defaultAdmissionPlugins, pspAdmissionPlugin), ",")
}
}

func installKubeSystemPSP(activate bool, ctx *util.Context) error {
if !activate {
return nil
}

rbacClient := ctx.Clientset.RbacV1()

err := templates.EnsurePodSecurityPolicy(ctx.Clientset.PolicyV1beta1().PodSecurityPolicies(), privilegedPSP())
if err != nil {
return errors.Wrap(err, "failed to ensure PodSecurityPolicy")
}

err = templates.EnsureClusterRole(rbacClient.ClusterRoles(), privilegedPSPClusterRole())
if err != nil {
return errors.Wrap(err, "failed to ensure PodSecurityPolicy cluster role")
}

err = templates.EnsureRoleBinding(rbacClient.RoleBindings(pspRoleNamespace), privilegedPSPRoleBinding())
if err != nil {
return errors.Wrap(err, "failed to ensure PodSecurityPolicy role binding")
}

return nil
}

func privilegedPSP() *policybeta1.PodSecurityPolicy {
return &policybeta1.PodSecurityPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "policy/v1beta1",
Kind: "PodSecurityPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Name: "privileged",
},
Spec: policybeta1.PodSecurityPolicySpec{
Privileged: true,
HostNetwork: true,
HostIPC: true,
HostPID: true,
AllowPrivilegeEscalation: boolPtr(true),
AllowedCapabilities: []corev1.Capability{"*"},
Volumes: []policybeta1.FSType{policybeta1.All},
HostPorts: []policybeta1.HostPortRange{
{Min: 0, Max: 65535},
},
RunAsUser: policybeta1.RunAsUserStrategyOptions{
Rule: policybeta1.RunAsUserStrategyRunAsAny,
},
SELinux: policybeta1.SELinuxStrategyOptions{
Rule: policybeta1.SELinuxStrategyRunAsAny,
},
SupplementalGroups: policybeta1.SupplementalGroupsStrategyOptions{
Rule: policybeta1.SupplementalGroupsStrategyRunAsAny,
},
FSGroup: policybeta1.FSGroupStrategyOptions{
Rule: policybeta1.FSGroupStrategyRunAsAny,
},
},
}
}

func privilegedPSPClusterRole() *rbacv1.ClusterRole {
return &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "ClusterRole",
},
ObjectMeta: metav1.ObjectMeta{
Name: "privileged-psp",
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{"policy"},
Resources: []string{"podsecuritypolicies"},
Verbs: []string{"use"},
ResourceNames: []string{"privileged"},
},
},
}
}

func privilegedPSPRoleBinding() *rbacv1.RoleBinding {
return &rbacv1.RoleBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "RoleBinding",
},
ObjectMeta: metav1.ObjectMeta{
Name: "privileged-psp",
Namespace: pspRoleNamespace,
},
RoleRef: rbacv1.RoleRef{
Name: "privileged-psp",
Kind: "ClusterRole",
APIGroup: rbacv1.GroupName,
},
Subjects: []rbacv1.Subject{
{
APIGroup: rbacv1.GroupName,
Kind: "Group",
Name: "system:nodes",
},
{
APIGroup: rbacv1.GroupName,
Kind: "Group",
Name: "system:serviceaccounts:" + pspRoleNamespace,
},
},
}
}

func boolPtr(b bool) *bool {
return &b
}
2 changes: 1 addition & 1 deletion pkg/installer/installation/ark.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package installation

import (
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/templates/ark"
"github.com/kubermatic/kubeone/pkg/util"
)

func deployArk(ctx *util.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"github.com/pkg/errors"

"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/util"
)

func downloadCA(ctx *util.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/cni.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package installation

import (
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/templates/canal"
"github.com/kubermatic/kubeone/pkg/util"
)

func applyCanalCNI(ctx *util.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/controlplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"strconv"

"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/util"
)

func joinControlplaneNode(ctx *util.Context) error {
Expand Down
4 changes: 3 additions & 1 deletion pkg/installer/installation/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package installation
import (
"github.com/pkg/errors"

"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/features"
"github.com/kubermatic/kubeone/pkg/util"
)

// Install performs all the steps required to install Kubernetes on
Expand All @@ -23,6 +24,7 @@ func Install(ctx *util.Context) error {
{fn: joinControlplaneNode, errMsg: "unable to join other masters a cluster"},
{fn: copyKubeconfig, errMsg: "unable to copy kubeconfig to home directory"},
{fn: util.BuildKubernetesClientset, errMsg: "unable to build kubernetes clientset"},
{fn: features.Activate, errMsg: "unable to activate features"},
{fn: applyCanalCNI, errMsg: "failed to install cni plugin canal"},
{fn: installMachineController, errMsg: "failed to install machine-controller"},
{fn: createWorkerMachines, errMsg: "failed to create worker machines"},
Expand Down
9 changes: 2 additions & 7 deletions pkg/installer/installation/kubeadm_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"github.com/pkg/errors"

"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/templates/kubeadm"
"github.com/kubermatic/kubeone/pkg/util"
)

func generateKubeadm(ctx *util.Context) error {
Expand All @@ -27,10 +27,5 @@ func generateKubeadm(ctx *util.Context) error {
}

func generateKubeadmOnNode(ctx *util.Context, _ *config.HostConfig, conn ssh.Connection) error {
err := ctx.Configuration.UploadTo(conn, ctx.WorkDir)
if err != nil {
return errors.Wrap(err, "failed to upload")
}

return nil
return errors.Wrap(ctx.Configuration.UploadTo(conn, ctx.WorkDir), "failed to upload")
}
2 changes: 1 addition & 1 deletion pkg/installer/installation/kubeadm_leader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"strconv"

"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/util"
)

const (
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package installation

import (
"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/util"
)

func copyKubeconfig(ctx *util.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/machine_controller.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package installation

import (
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/templates/machinecontroller"
"github.com/kubermatic/kubeone/pkg/util"
)

func installMachineController(ctx *util.Context) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/installer/installation/prerequisites.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"github.com/pkg/errors"

"github.com/kubermatic/kubeone/pkg/config"
"github.com/kubermatic/kubeone/pkg/installer/util"
"github.com/kubermatic/kubeone/pkg/ssh"
"github.com/kubermatic/kubeone/pkg/util"
)

const dockerVersion = "18.09.2"
Expand Down
Loading

0 comments on commit 8e55f57

Please sign in to comment.