Skip to content

Commit 6a1c22c

Browse files
balamuruganawlan0
authored andcommitted
Add PodSecurityPolicy creation and binding.
Fixes #292 Signed-off-by: Bala.FA <bala.gluster@gmail.com>
1 parent e8f0759 commit 6a1c22c

File tree

3 files changed

+167
-22
lines changed

3 files changed

+167
-22
lines changed

cmd/kubectl-direct_csi/install.go

+28-12
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ package main
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223

2324
"github.com/spf13/cobra"
2425
"github.com/spf13/viper"
2526
"k8s.io/klog"
2627

27-
"k8s.io/apimachinery/pkg/api/errors"
28+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
2829

2930
"github.com/minio/direct-csi/pkg/utils"
3031
"github.com/minio/direct-csi/pkg/utils/installer"
@@ -49,6 +50,8 @@ var (
4950
loopBackOnly = false
5051
nodeSelectorValues = []string{}
5152
tolerationValues = []string{}
53+
seccompProfile = ""
54+
apparmorProfile = ""
5255
)
5356

5457
func init() {
@@ -61,6 +64,8 @@ func init() {
6164
installCmd.PersistentFlags().MarkDeprecated("crd", "Will be removed in version 1.5 or greater")
6265
installCmd.PersistentFlags().StringSliceVarP(&nodeSelectorValues, "node-selector", "n", nodeSelectorValues, "node selector parameters")
6366
installCmd.PersistentFlags().StringSliceVarP(&tolerationValues, "tolerations", "t", tolerationValues, "tolerations parameters")
67+
installCmd.PersistentFlags().StringVarP(&seccompProfile, "seccomp-profile", "", seccompProfile, "set Seccomp profile")
68+
installCmd.PersistentFlags().StringVarP(&apparmorProfile, "apparmor-profile", "", apparmorProfile, "set Apparmor profile")
6469

6570
installCmd.PersistentFlags().BoolVarP(&loopBackOnly, "loopback-only", "", loopBackOnly, "Uses 4 free loopback devices per node and treat them as DirectCSIDrive resources. This is recommended only for testing/development purposes")
6671
installCmd.PersistentFlags().MarkHidden("loopback-only")
@@ -90,16 +95,27 @@ func install(ctx context.Context, args []string) error {
9095
utils.Init()
9196

9297
if err := installer.CreateNamespace(ctx, identity, dryRun); err != nil {
93-
if !errors.IsAlreadyExists(err) {
98+
if !k8serrors.IsAlreadyExists(err) {
9499
return err
95100
}
96101
}
97102
if !dryRun {
98103
klog.Infof("'%s' namespace created", utils.Bold(identity))
99104
}
100105

106+
if err := installer.CreatePodSecurityPolicy(ctx, identity, dryRun); err != nil {
107+
switch {
108+
case errors.Is(err, installer.ErrKubeVersionNotSupported):
109+
klog.Infof("pod security policy is not supported in your kubernetes")
110+
case !k8serrors.IsAlreadyExists(err):
111+
return err
112+
}
113+
} else if !dryRun {
114+
klog.Infof("'%s' pod security policy created", utils.Bold(identity))
115+
}
116+
101117
if err := installer.CreateRBACRoles(ctx, identity, dryRun); err != nil {
102-
if !errors.IsAlreadyExists(err) {
118+
if !k8serrors.IsAlreadyExists(err) {
103119
return err
104120
}
105121
}
@@ -116,14 +132,14 @@ func install(ctx context.Context, args []string) error {
116132

117133
crdInstall:
118134
if err := registerCRDs(ctx, identity); err != nil {
119-
if !errors.IsAlreadyExists(err) {
135+
if !k8serrors.IsAlreadyExists(err) {
120136
return err
121137
}
122138
// if it exists
123139
if !dryRun && overwriteCRD {
124140
klog.V(4).Infof("overwriting CRDs")
125141
if err := unregisterCRDs(ctx); err != nil {
126-
if !errors.IsNotFound(err) {
142+
if !k8serrors.IsNotFound(err) {
127143
return err
128144
}
129145
}
@@ -136,7 +152,7 @@ crdInstall:
136152
}
137153

138154
if err := installer.CreateCSIDriver(ctx, identity, dryRun); err != nil {
139-
if !errors.IsAlreadyExists(err) {
155+
if !k8serrors.IsAlreadyExists(err) {
140156
return err
141157
}
142158
}
@@ -145,7 +161,7 @@ crdInstall:
145161
}
146162

147163
if err := installer.CreateStorageClass(ctx, identity, dryRun); err != nil {
148-
if !errors.IsAlreadyExists(err) {
164+
if !k8serrors.IsAlreadyExists(err) {
149165
return err
150166
}
151167
}
@@ -154,16 +170,16 @@ crdInstall:
154170
}
155171

156172
if err := installer.CreateService(ctx, identity, dryRun); err != nil {
157-
if !errors.IsAlreadyExists(err) {
173+
if !k8serrors.IsAlreadyExists(err) {
158174
return err
159175
}
160176
}
161177
if !dryRun {
162178
klog.Infof("'%s' service created", utils.Bold(identity))
163179
}
164180

165-
if err := installer.CreateDaemonSet(ctx, identity, image, dryRun, registry, org, loopBackOnly, nodeSelector, tolerations); err != nil {
166-
if !errors.IsAlreadyExists(err) {
181+
if err := installer.CreateDaemonSet(ctx, identity, image, dryRun, registry, org, loopBackOnly, nodeSelector, tolerations, seccompProfile, apparmorProfile); err != nil {
182+
if !k8serrors.IsAlreadyExists(err) {
167183
return err
168184
}
169185
}
@@ -172,7 +188,7 @@ crdInstall:
172188
}
173189

174190
if err := installer.CreateDeployment(ctx, identity, image, dryRun, registry, org); err != nil {
175-
if !errors.IsAlreadyExists(err) {
191+
if !k8serrors.IsAlreadyExists(err) {
176192
return err
177193
}
178194
}
@@ -182,7 +198,7 @@ crdInstall:
182198

183199
if admissionControl {
184200
if err := installer.RegisterDriveValidationRules(ctx, identity, dryRun); err != nil {
185-
if !errors.IsAlreadyExists(err) {
201+
if !k8serrors.IsAlreadyExists(err) {
186202
return err
187203
}
188204
}

pkg/utils/installer/install.go

+21-10
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
"k8s.io/klog"
2423
"path/filepath"
2524
"regexp"
2625
"strings"
2726
"time"
2827

28+
"k8s.io/klog/v2"
29+
2930
"github.com/minio/direct-csi/pkg/topology"
3031
"github.com/minio/direct-csi/pkg/utils"
3132

@@ -364,12 +365,21 @@ func getConversionWebhookURL(identity string) (conversionWebhookURL string) {
364365
return
365366
}
366367

367-
func CreateDaemonSet(ctx context.Context, identity string, directCSIContainerImage string, dryRun bool, registry, org string, loopBackOnly bool, nodeSelector map[string]string, tolerations []corev1.Toleration) error {
368+
func CreateDaemonSet(ctx context.Context, identity string, directCSIContainerImage string, dryRun bool, registry, org string, loopBackOnly bool, nodeSelector map[string]string, tolerations []corev1.Toleration, seccompProfileName, apparmorProfileName string) error {
368369
name := sanitizeName(identity)
369370
generatedSelectorValue := generateSanitizedUniqueNameFrom(name)
370371
conversionWebhookURL := getConversionWebhookURL(identity)
371372

372373
privileged := true
374+
securityContext := &corev1.SecurityContext{Privileged: &privileged}
375+
376+
if seccompProfileName != "" {
377+
securityContext.SeccompProfile = &corev1.SeccompProfile{
378+
Type: corev1.SeccompProfileTypeLocalhost,
379+
LocalhostProfile: &seccompProfileName,
380+
}
381+
}
382+
373383
podSpec := corev1.PodSpec{
374384
ServiceAccountName: name,
375385
HostNetwork: false,
@@ -429,9 +439,7 @@ func CreateDaemonSet(ctx context.Context, identity string, directCSIContainerIma
429439
}
430440
return args
431441
}(),
432-
SecurityContext: &corev1.SecurityContext{
433-
Privileged: &privileged,
434-
},
442+
SecurityContext: securityContext,
435443
Env: []corev1.EnvVar{
436444
{
437445
Name: kubeNodeNameEnvVar,
@@ -495,6 +503,11 @@ func CreateDaemonSet(ctx context.Context, identity string, directCSIContainerIma
495503
Tolerations: tolerations,
496504
}
497505

506+
annotations := map[string]string{CreatedByLabel: DirectCSIPluginName}
507+
if apparmorProfileName != "" {
508+
annotations["container.apparmor.security.beta.kubernetes.io/direct-csi"] = apparmorProfileName
509+
}
510+
498511
daemonset := &appsv1.DaemonSet{
499512
TypeMeta: metav1.TypeMeta{
500513
Kind: "DaemonSet",
@@ -505,11 +518,9 @@ func CreateDaemonSet(ctx context.Context, identity string, directCSIContainerIma
505518
Selector: metav1.AddLabelToSelector(&metav1.LabelSelector{}, directCSISelector, generatedSelectorValue),
506519
Template: corev1.PodTemplateSpec{
507520
ObjectMeta: metav1.ObjectMeta{
508-
Name: sanitizeName(name),
509-
Namespace: sanitizeName(name),
510-
Annotations: map[string]string{
511-
CreatedByLabel: DirectCSIPluginName,
512-
},
521+
Name: sanitizeName(name),
522+
Namespace: sanitizeName(name),
523+
Annotations: annotations,
513524
Labels: map[string]string{
514525
directCSISelector: generatedSelectorValue,
515526
},

pkg/utils/installer/psp.go

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* This file is part of MinIO Direct CSI
3+
* Copyright (C) 2021, MinIO, Inc.
4+
*
5+
* This code is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License, version 3,
7+
* as published by the Free Software Foundation.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License, version 3,
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>
16+
*
17+
*/
18+
19+
package installer
20+
21+
import (
22+
"context"
23+
24+
"github.com/minio/direct-csi/pkg/utils"
25+
policy "k8s.io/api/policy/v1beta1"
26+
rbac "k8s.io/api/rbac/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
)
29+
30+
func createPodSecurityPolicy(ctx context.Context, identity string, dryRun bool) error {
31+
psp := &policy.PodSecurityPolicy{
32+
TypeMeta: metav1.TypeMeta{
33+
APIVersion: "policy/v1beta1",
34+
Kind: "PodSecurityPolicy",
35+
},
36+
ObjectMeta: objMeta(identity),
37+
Spec: policy.PodSecurityPolicySpec{
38+
Privileged: true,
39+
HostPID: true,
40+
HostIPC: true,
41+
AllowedHostPaths: []policy.AllowedHostPath{
42+
{PathPrefix: "/proc", ReadOnly: true},
43+
{PathPrefix: "/sys", ReadOnly: true},
44+
{PathPrefix: "/var/lib/direct-csi"},
45+
{PathPrefix: "/csi"},
46+
{PathPrefix: "/var/lib/kubelet"},
47+
},
48+
SELinux: policy.SELinuxStrategyOptions{
49+
Rule: policy.SELinuxStrategyRunAsAny,
50+
},
51+
RunAsUser: policy.RunAsUserStrategyOptions{
52+
Rule: policy.RunAsUserStrategyRunAsAny,
53+
},
54+
SupplementalGroups: policy.SupplementalGroupsStrategyOptions{
55+
Rule: policy.SupplementalGroupsStrategyRunAsAny,
56+
},
57+
FSGroup: policy.FSGroupStrategyOptions{
58+
Rule: policy.FSGroupStrategyRunAsAny,
59+
},
60+
},
61+
}
62+
63+
if dryRun {
64+
utils.LogYAML(psp)
65+
} else if _, err := utils.GetKubeClient().PolicyV1beta1().PodSecurityPolicies().Create(ctx, psp, metav1.CreateOptions{}); err != nil {
66+
return err
67+
}
68+
69+
crb := &rbac.ClusterRoleBinding{
70+
TypeMeta: metav1.TypeMeta{
71+
APIVersion: "rbac.authorization.k8s.io/v1",
72+
Kind: "ClusterRoleBinding",
73+
},
74+
ObjectMeta: metav1.ObjectMeta{
75+
Name: sanitizeName("psp-" + identity),
76+
Namespace: sanitizeName(identity),
77+
Annotations: map[string]string{
78+
CreatedByLabel: DirectCSIPluginName,
79+
},
80+
Labels: map[string]string{
81+
"app": DirectCSI,
82+
"type": CSIDriver,
83+
},
84+
},
85+
Subjects: []rbac.Subject{
86+
{
87+
Kind: "Group",
88+
APIGroup: "rbac.authorization.k8s.io",
89+
Name: "system:serviceaccounts:" + sanitizeName(identity),
90+
},
91+
},
92+
RoleRef: rbac.RoleRef{
93+
APIGroup: "rbac.authorization.k8s.io",
94+
Kind: "ClusterRole",
95+
Name: sanitizeName(identity),
96+
},
97+
}
98+
99+
if dryRun {
100+
return utils.LogYAML(crb)
101+
}
102+
103+
_, err := utils.GetKubeClient().RbacV1().ClusterRoleBindings().Create(ctx, crb, metav1.CreateOptions{})
104+
return err
105+
}
106+
107+
func CreatePodSecurityPolicy(ctx context.Context, identity string, dryRun bool) error {
108+
info, err := utils.GetGroupKindVersions("policy", "PodSecurityPolicy", "v1beta1")
109+
if err != nil {
110+
return err
111+
}
112+
113+
if info.Version == "v1beta1" {
114+
return createPodSecurityPolicy(ctx, identity, dryRun)
115+
}
116+
117+
return ErrKubeVersionNotSupported
118+
}

0 commit comments

Comments
 (0)