Skip to content

Commit 23660a7

Browse files
marossetcji
authored andcommitted
Add funcs in pkg/filesystem/util that can actually set file permissiosn
on Windows and update container log dir perms to 660 on Windows
1 parent 7e92bb9 commit 23660a7

File tree

5 files changed

+300
-8
lines changed

5 files changed

+300
-8
lines changed

pkg/kubelet/kubelet.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ import (
3939
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
4040
"go.opentelemetry.io/otel/trace"
4141
"k8s.io/client-go/informers"
42-
4342
"k8s.io/mount-utils"
43+
44+
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
4445
netutils "k8s.io/utils/net"
4546

4647
v1 "k8s.io/api/core/v1"
@@ -1390,7 +1391,7 @@ func (kl *Kubelet) setupDataDirs() error {
13901391
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
13911392
return fmt.Errorf("error creating root directory: %v", err)
13921393
}
1393-
if err := os.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
1394+
if err := utilfs.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
13941395
return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
13951396
}
13961397
if err := kl.hostutil.MakeRShared(kl.getRootDir()); err != nil {
@@ -1399,17 +1400,17 @@ func (kl *Kubelet) setupDataDirs() error {
13991400
if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
14001401
return fmt.Errorf("error creating pods directory: %v", err)
14011402
}
1402-
if err := os.MkdirAll(kl.getPluginsDir(), 0750); err != nil {
1403+
if err := utilfs.MkdirAll(kl.getPluginsDir(), 0750); err != nil {
14031404
return fmt.Errorf("error creating plugins directory: %v", err)
14041405
}
1405-
if err := os.MkdirAll(kl.getPluginsRegistrationDir(), 0750); err != nil {
1406+
if err := utilfs.MkdirAll(kl.getPluginsRegistrationDir(), 0750); err != nil {
14061407
return fmt.Errorf("error creating plugins registry directory: %v", err)
14071408
}
14081409
if err := os.MkdirAll(kl.getPodResourcesDir(), 0750); err != nil {
14091410
return fmt.Errorf("error creating podresources directory: %v", err)
14101411
}
14111412
if utilfeature.DefaultFeatureGate.Enabled(features.ContainerCheckpoint) {
1412-
if err := os.MkdirAll(kl.getCheckpointsDir(), 0700); err != nil {
1413+
if err := utilfs.MkdirAll(kl.getCheckpointsDir(), 0700); err != nil {
14131414
return fmt.Errorf("error creating checkpoint directory: %v", err)
14141415
}
14151416
}
@@ -1502,6 +1503,14 @@ func (kl *Kubelet) initializeModules() error {
15021503
}
15031504
}
15041505

1506+
if sysruntime.GOOS == "windows" {
1507+
// On Windows we should not allow other users to read the logs directory
1508+
// to avoid allowing non-root containers from reading the logs of other containers.
1509+
if err := utilfs.Chmod(ContainerLogsDir, 0750); err != nil {
1510+
return fmt.Errorf("failed to set permissions on directory %q: %w", ContainerLogsDir, err)
1511+
}
1512+
}
1513+
15051514
// Start the image manager.
15061515
kl.imageManager.Start()
15071516

pkg/util/filesystem/defaultfs.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ func (fs *DefaultFs) Rename(oldpath, newpath string) error {
7272
return os.Rename(oldpath, newpath)
7373
}
7474

75-
// MkdirAll via os.MkdirAll
7675
func (fs *DefaultFs) MkdirAll(path string, perm os.FileMode) error {
77-
return os.MkdirAll(fs.prefix(path), perm)
76+
return MkdirAll(fs.prefix(path), perm)
7877
}
7978

8079
// MkdirAllWithPathCheck checks if path exists already. If not, it creates a directory
@@ -97,7 +96,7 @@ func MkdirAllWithPathCheck(path string, perm os.FileMode) error {
9796
return fmt.Errorf("path %v exists but is not a directory", path)
9897
}
9998
// If existence of path not known, attempt to create it.
100-
if err := os.MkdirAll(path, perm); err != nil {
99+
if err := MkdirAll(path, perm); err != nil {
101100
return err
102101
}
103102
return nil

pkg/util/filesystem/util_unix.go

+10
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ func IsUnixDomainSocket(filePath string) (bool, error) {
3737
return true, nil
3838
}
3939

40+
// Chmod is the same as os.Chmod on Linux.
41+
func Chmod(name string, mode os.FileMode) error {
42+
return os.Chmod(name, mode)
43+
}
44+
45+
// MkdirAll is the same as os.MkdirAll on Linux.
46+
func MkdirAll(path string, perm os.FileMode) error {
47+
return os.MkdirAll(path, perm)
48+
}
49+
4050
// IsAbs is same as filepath.IsAbs on Unix.
4151
func IsAbs(path string) bool {
4252
return filepath.IsAbs(path)

pkg/util/filesystem/util_windows.go

+156
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929

3030
"k8s.io/apimachinery/pkg/util/wait"
3131
"k8s.io/klog/v2"
32+
33+
"golang.org/x/sys/windows"
3234
)
3335

3436
const (
@@ -88,6 +90,160 @@ func IsUnixDomainSocket(filePath string) (bool, error) {
8890
return true, nil
8991
}
9092

93+
// On Windows os.Mkdir all doesn't set any permissions so call the Chown function below to set
94+
// permissions once the directory is created.
95+
func MkdirAll(path string, perm os.FileMode) error {
96+
klog.V(6).InfoS("Function MkdirAll starts", "path", path, "perm", perm)
97+
err := os.MkdirAll(path, perm)
98+
if err != nil {
99+
return fmt.Errorf("Error creating directory %s: %v", path, err)
100+
}
101+
102+
err = Chmod(path, perm)
103+
if err != nil {
104+
return fmt.Errorf("Error setting permissions for directory %s: %v", path, err)
105+
}
106+
107+
return nil
108+
}
109+
110+
const (
111+
// These aren't defined in the syscall package for Windows :(
112+
USER_READ = 0x100
113+
USER_WRITE = 0x80
114+
USER_EXECUTE = 0x40
115+
GROUP_READ = 0x20
116+
GROUP_WRITE = 0x10
117+
GROUP_EXECUTE = 0x8
118+
OTHERS_READ = 0x4
119+
OTHERS_WRITE = 0x2
120+
OTHERS_EXECUTE = 0x1
121+
USER_ALL = USER_READ | USER_WRITE | USER_EXECUTE
122+
GROUP_ALL = GROUP_READ | GROUP_WRITE | GROUP_EXECUTE
123+
OTHERS_ALL = OTHERS_READ | OTHERS_WRITE | OTHERS_EXECUTE
124+
)
125+
126+
// On Windows os.Chmod only sets the read-only flag on files, so we need to use Windows APIs to set the desired access on files / directories.
127+
// The OWNER mode will set file permissions for the file owner SID, the GROUP mode will set file permissions for the file group SID,
128+
// and the OTHERS mode will set file permissions for BUILTIN\Users.
129+
// Please note that Windows containers can be run as one of two user accounts; ContainerUser or ContainerAdministrator.
130+
// Containers run as ContainerAdministrator will inherit permissions from BUILTIN\Administrators,
131+
// while containers run as ContainerUser will inherit permissions from BUILTIN\Users.
132+
// Windows containers do not have the ability to run as a custom user account that is known to the host so the OTHERS group mode
133+
// is used to grant / deny permissions of files on the hosts to the ContainerUser account.
134+
func Chmod(path string, filemode os.FileMode) error {
135+
klog.V(6).InfoS("Function Chmod starts", "path", path, "filemode", filemode)
136+
// Get security descriptor for the file
137+
sd, err := windows.GetNamedSecurityInfo(
138+
path,
139+
windows.SE_FILE_OBJECT,
140+
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION)
141+
if err != nil {
142+
return fmt.Errorf("Error getting security descriptor for file %s: %v", path, err)
143+
}
144+
145+
// Get owner SID from the security descriptor for assigning USER permissions
146+
owner, _, err := sd.Owner()
147+
if err != nil {
148+
return fmt.Errorf("Error getting owner SID for file %s: %v", path, err)
149+
}
150+
ownerString := owner.String()
151+
152+
// Get the group SID from the security descriptor for assigning GROUP permissions
153+
group, _, err := sd.Group()
154+
if err != nil {
155+
return fmt.Errorf("Error getting group SID for file %s: %v", path, err)
156+
}
157+
groupString := group.String()
158+
159+
mask := uint32(windows.ACCESS_MASK(filemode))
160+
161+
// Build a new Discretionary Access Control List (DACL) with the desired permissions using
162+
//the Security Descriptor Definition Language (SDDL) format.
163+
// https://learn.microsoft.com/windows/win32/secauthz/security-descriptor-definition-language
164+
// the DACL is a list of Access Control Entries (ACEs) where each ACE represents the permissions (Allow or Deny) for a specific SID.
165+
// Each ACE has the following format:
166+
// (AceType;AceFlags;Rights;ObjectGuid;InheritObjectGuid;AccountSid)
167+
// We can leave ObjectGuid and InheritObjectGuid empty for our purposes.
168+
169+
dacl := "D:"
170+
171+
// build the owner ACE
172+
dacl += "(A;OICI;"
173+
if mask&USER_ALL == USER_ALL {
174+
dacl += "FA"
175+
} else {
176+
if mask&USER_READ == USER_READ {
177+
dacl += "FR"
178+
}
179+
if mask&USER_WRITE == USER_WRITE {
180+
dacl += "FW"
181+
}
182+
if mask&USER_EXECUTE == USER_EXECUTE {
183+
dacl += "FX"
184+
}
185+
}
186+
dacl += ";;;" + ownerString + ")"
187+
188+
// Build the group ACE
189+
dacl += "(A;OICI;"
190+
if mask&GROUP_ALL == GROUP_ALL {
191+
dacl += "FA"
192+
} else {
193+
if mask&GROUP_READ == GROUP_READ {
194+
dacl += "FR"
195+
}
196+
if mask&GROUP_WRITE == GROUP_WRITE {
197+
dacl += "FW"
198+
}
199+
if mask&GROUP_EXECUTE == GROUP_EXECUTE {
200+
dacl += "FX"
201+
}
202+
}
203+
dacl += ";;;" + groupString + ")"
204+
205+
// Build the others ACE
206+
dacl += "(A;OICI;"
207+
if mask&OTHERS_ALL == OTHERS_ALL {
208+
dacl += "FA"
209+
} else {
210+
if mask&OTHERS_READ == OTHERS_READ {
211+
dacl += "FR"
212+
}
213+
if mask&OTHERS_WRITE == OTHERS_WRITE {
214+
dacl += "FW"
215+
}
216+
if mask&OTHERS_EXECUTE == OTHERS_EXECUTE {
217+
dacl += "FX"
218+
}
219+
}
220+
dacl += ";;;BU)"
221+
222+
klog.V(6).InfoS("Setting new DACL for path", "path", path, "dacl", dacl)
223+
224+
// create a new security descriptor from the DACL string
225+
newSD, err := windows.SecurityDescriptorFromString(dacl)
226+
if err != nil {
227+
return fmt.Errorf("Error creating new security descriptor from DACL string: %v", err)
228+
}
229+
230+
// get the DACL in binary format from the newly created security descriptor
231+
newDACL, _, err := newSD.DACL()
232+
if err != nil {
233+
return fmt.Errorf("Error getting DACL from new security descriptor: %v", err)
234+
}
235+
236+
// Write the new security descriptor to the file
237+
return windows.SetNamedSecurityInfo(
238+
path,
239+
windows.SE_FILE_OBJECT,
240+
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
241+
nil, // owner SID
242+
nil, // group SID
243+
newDACL,
244+
nil) // SACL
245+
}
246+
91247
// IsAbs returns whether the given path is absolute or not.
92248
// On Windows, filepath.IsAbs will not return True for paths prefixed with a slash, even
93249
// though they can be used as absolute paths (https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats).

0 commit comments

Comments
 (0)