Skip to content

Commit 088d0a7

Browse files
Run livenessprobe as nonroot (#192)
* Run livenessprobe as nonroot * updated copyright
1 parent 9068a97 commit 088d0a7

File tree

6 files changed

+424
-7
lines changed

6 files changed

+424
-7
lines changed

deploy/kubernetes/driver/kubernetes/manifests/controller-server.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ spec:
2828
securityContext:
2929
runAsNonRoot: true
3030
runAsUser: 2121
31+
runAsGroup: 2121
3132
containers:
3233
- name: csi-snapshotter
3334
image: MUSTPATCHWITHKUSTOMIZE

deploy/kubernetes/driver/kubernetes/manifests/node-server.yaml

+12-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ spec:
3333
securityContext:
3434
runAsNonRoot: false
3535
runAsUser: 0
36+
runAsGroup: 0
3637
privileged: false
3738
args:
3839
- "--v=5"
@@ -65,6 +66,7 @@ spec:
6566
securityContext:
6667
runAsNonRoot: false
6768
runAsUser: 0
69+
runAsGroup: 0
6870
privileged: true
6971
image: MUSTPATCHWITHKUSTOMIZE
7072
imagePullPolicy: Always
@@ -76,6 +78,10 @@ spec:
7678
valueFrom:
7779
fieldRef:
7880
fieldPath: spec.nodeName
81+
- name: IS_NODE_SERVER
82+
value: "true"
83+
- name: SIDECAR_GROUP_ID
84+
value: "2121"
7985
envFrom:
8086
- configMapRef:
8187
name: ibm-vpc-block-csi-configmap
@@ -120,9 +126,13 @@ spec:
120126
- name: liveness-probe
121127
image: MUSTPATCHWITHKUSTOMIZE
122128
securityContext:
123-
runAsNonRoot: false
124-
runAsUser: 0
129+
runAsNonRoot: true
130+
runAsUser: 2121
131+
runAsGroup: 2121
125132
privileged: false
133+
seLinuxOptions: # seLinux label is set as a precaution for accessing csi socket
134+
type: spc_t
135+
level: s0
126136
args:
127137
- --csi-address=/csi/csi.sock
128138
resources:

pkg/ibmcsidriver/fileOps.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package ibmcsidriver ...
18+
package ibmcsidriver
19+
20+
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
21+
22+
import (
23+
"os"
24+
"strconv"
25+
26+
"go.uber.org/zap"
27+
)
28+
29+
const (
30+
filePermission = 0660
31+
)
32+
33+
//counterfeiter:generate . socketPermission
34+
35+
// socketPermission represents file system operations
36+
type socketPermission interface {
37+
Chown(name string, uid, gid int) error
38+
Chmod(name string, mode os.FileMode) error
39+
}
40+
41+
// realSocketPermission implements socketPermission
42+
type opsSocketPermission struct{}
43+
44+
func (f *opsSocketPermission) Chown(name string, uid, gid int) error {
45+
return os.Chown(name, uid, gid)
46+
}
47+
48+
func (f *opsSocketPermission) Chmod(name string, mode os.FileMode) error {
49+
return os.Chmod(name, mode)
50+
}
51+
52+
// setupSidecar updates owner/group and permission of the file given(addr)
53+
func setupSidecar(addr string, ops socketPermission, logger *zap.Logger) error {
54+
groupSt := os.Getenv("SIDECAR_GROUP_ID")
55+
56+
logger.Info("Setting owner and permissions of csi socket file. SIDECAR_GROUP_ID env must match the 'livenessprobe' sidecar container groupID for csi socket connection.")
57+
58+
// If env is not set, set default to 0
59+
if groupSt == "" {
60+
logger.Warn("Unable to fetch SIDECAR_GROUP_ID environment variable. Sidecar container(s) might fail...")
61+
groupSt = "0"
62+
}
63+
64+
group, err := strconv.Atoi(groupSt)
65+
if err != nil {
66+
return err
67+
}
68+
69+
// Change group of csi socket to non-root user for enabling the csi sidecar
70+
if err := ops.Chown(addr, -1, group); err != nil {
71+
return err
72+
}
73+
74+
// Modify permissions of csi socket
75+
// Only the users and the group owners will have read/write access to csi socket
76+
if err := ops.Chmod(addr, filePermission); err != nil {
77+
return err
78+
}
79+
80+
logger.Info("Successfully set owner and permissions of csi socket file.")
81+
82+
return nil
83+
}

pkg/ibmcsidriver/fileOps_test.go

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ibmcsidriver
18+
19+
import (
20+
"errors"
21+
"os"
22+
"testing"
23+
24+
cloudProvider "github.com/IBM/ibm-csi-common/pkg/ibmcloudprovider"
25+
"github.com/kubernetes-sigs/ibm-vpc-block-csi-driver/pkg/ibmcsidriver/ibmcsidriverfakes"
26+
"github.com/stretchr/testify/assert"
27+
)
28+
29+
func TestSetupSidecar(t *testing.T) {
30+
tests := []struct {
31+
name string
32+
groupID string
33+
expectedErr bool
34+
chownErr error
35+
chmodErr error
36+
expectedChownCalls int
37+
expectedChmodCalls int
38+
expectedGroupID int
39+
}{
40+
{
41+
name: "ValidGroupID",
42+
groupID: "2121",
43+
expectedErr: false,
44+
chownErr: nil,
45+
chmodErr: nil,
46+
expectedChownCalls: 1,
47+
expectedChmodCalls: 1,
48+
expectedGroupID: 2121,
49+
},
50+
{
51+
name: "EmptyGroupID",
52+
groupID: "",
53+
expectedErr: false,
54+
chownErr: nil,
55+
chmodErr: nil,
56+
expectedChownCalls: 1,
57+
expectedChmodCalls: 1,
58+
expectedGroupID: 0, // Default to 0 if SIDECAR_GROUP_ID is empty
59+
},
60+
{
61+
name: "ChownError",
62+
groupID: "1000",
63+
expectedErr: true,
64+
chownErr: errors.New("chown error"),
65+
chmodErr: nil,
66+
expectedChownCalls: 1,
67+
expectedChmodCalls: 0, // No chmod expected if chown fails
68+
expectedGroupID: 1000,
69+
},
70+
{
71+
name: "ChmodError",
72+
groupID: "1000",
73+
expectedErr: true,
74+
chownErr: nil,
75+
chmodErr: errors.New("chmod error"),
76+
expectedChownCalls: 1,
77+
expectedChmodCalls: 1,
78+
expectedGroupID: 1000,
79+
},
80+
}
81+
82+
for _, tc := range tests {
83+
t.Run(tc.name, func(t *testing.T) {
84+
// Set SIDECAR_GROUP_ID environment variable
85+
if tc.groupID != "" {
86+
os.Setenv("SIDECAR_GROUP_ID", tc.groupID)
87+
} else {
88+
os.Unsetenv("SIDECAR_GROUP_ID")
89+
}
90+
defer os.Unsetenv("SIDECAR_GROUP_ID")
91+
92+
// Create the fake object generated by counterfeiter
93+
fakeSocketPermission := new(ibmcsidriverfakes.FakeSocketPermission)
94+
95+
// Set return values for chown and chmod methods
96+
fakeSocketPermission.ChownReturns(tc.chownErr)
97+
fakeSocketPermission.ChmodReturns(tc.chmodErr)
98+
99+
// Creating test logger
100+
logger, teardown := cloudProvider.GetTestLogger(t)
101+
defer teardown()
102+
103+
// Call the function under test
104+
err := setupSidecar("/path/to/socket", fakeSocketPermission, logger)
105+
106+
// Verify the result
107+
if tc.expectedErr {
108+
assert.Error(t, err)
109+
} else {
110+
assert.NoError(t, err)
111+
}
112+
113+
// Verify the number of times Chown and Chmod were called
114+
assert.Equal(t, tc.expectedChownCalls, fakeSocketPermission.ChownCallCount())
115+
assert.Equal(t, tc.expectedChmodCalls, fakeSocketPermission.ChmodCallCount())
116+
117+
// Verify the group ID passed to chown
118+
if tc.expectedChownCalls > 0 {
119+
_, _, actualGroupID := fakeSocketPermission.ChownArgsForCall(0)
120+
assert.Equal(t, tc.expectedGroupID, actualGroupID)
121+
}
122+
})
123+
}
124+
}

0 commit comments

Comments
 (0)