Skip to content

Commit 993391c

Browse files
Run livenessprobe as non-root + Run all possible sidecars as nonRootGroup (#65)
* Create CSI socket file using non-root user Signed-off-by: Prankul <[email protected]> --------- Signed-off-by: Prankul <[email protected]>
1 parent 46b65d3 commit 993391c

File tree

7 files changed

+436
-4
lines changed

7 files changed

+436
-4
lines changed

deploy/kubernetes/driver/kubernetes/manifests/config-map.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ data:
1616
VPC_RETRY_INTERVAL: "60" # This is max retry Gap in seconds even considering for exponential retry
1717
VPC_API_VERSION: "2021-04-20"
1818
VPC_API_GENERATION: "1"
19-
IKS_ENABLED: "True"
19+
IKS_ENABLED: "True"

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ spec:
2525
securityContext:
2626
runAsNonRoot: true
2727
runAsUser: 2121
28+
runAsGroup: 2121
2829
containers:
2930
- name: csi-provisioner
3031
image: MUSTPATCHWITHKUSTOMIZE
@@ -187,6 +188,13 @@ spec:
187188
configMapKeyRef:
188189
name: ibm-vpc-file-csi-configmap
189190
key: SIDECAR_ENDPOINT
191+
resources:
192+
limits:
193+
cpu: 12m
194+
memory: 20Mi
195+
requests:
196+
cpu: 3m
197+
memory: 5Mi
190198
volumeMounts:
191199
- mountPath: /sidecardir
192200
name: socket-dir

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ spec:
3131
securityContext:
3232
runAsNonRoot: false
3333
runAsUser: 0
34+
runAsGroup: 0
3435
privileged: false
3536
args:
3637
- "--v=5"
@@ -64,6 +65,7 @@ spec:
6465
securityContext:
6566
runAsNonRoot: false
6667
runAsUser: 0
68+
runAsGroup: 0
6769
privileged: true
6870
image: MUSTPATCHWITHKUSTOMIZE
6971
imagePullPolicy: Always
@@ -91,6 +93,10 @@ spec:
9193
fieldPath: spec.nodeName
9294
- name: SOCKET_PATH
9395
value: "/var/lib/ibmshare.sock"
96+
- name: IS_NODE_SERVER
97+
value: "true"
98+
- name: SIDECAR_GROUP_ID
99+
value: "2121"
94100
resources:
95101
limits:
96102
cpu: 200m
@@ -139,11 +145,15 @@ spec:
139145
- mountPath: /tmp/mount-helper
140146
name: mh-logs
141147
- name: liveness-probe
142-
image: MUSTPATCHWITHKUSTOMIZE
143148
securityContext:
144-
runAsNonRoot: false
145-
runAsUser: 0
149+
runAsNonRoot: true
150+
runAsUser: 2121
151+
runAsGroup: 2121
146152
privileged: false
153+
seLinuxOptions: # seLinux label is set as a precaution for accessing csi socket
154+
type: spc_t
155+
level: s0
156+
image: MUSTPATCHWITHKUSTOMIZE
147157
args:
148158
- "--csi-address=$(CSI_ADDRESS)"
149159
env:
@@ -163,6 +173,11 @@ spec:
163173
- name: plugin-dir
164174
mountPath: /csi
165175
- name: storage-secret-sidecar
176+
securityContext:
177+
runAsNonRoot: true
178+
runAsUser: 2121
179+
runAsGroup: 2121
180+
privileged: false
166181
image: MUSTPATCHWITHKUSTOMIZE
167182
imagePullPolicy: Always
168183
args:

pkg/ibmcsidriver/fileOps.go

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

pkg/ibmcsidriver/fileOps_test.go

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

0 commit comments

Comments
 (0)