Skip to content
Snippets Groups Projects
Commit 3256bdf6 authored by Sheng Yang's avatar Sheng Yang
Browse files

Add security context support by creating a user accessible directory beforehand

The permission of directory is 0770, because when a user login as group
e.g. group 1000, they're also belong to group 0. The default permission
for host path is 0700, which prevent group 0 from accessing the directory.

Fixes https://github.com/rancher/local-path-provisioner/issues/7 .

Also added test case `security-context.yaml` derived from @unguiculus 's
comment on the issue.
parent 776ba446
No related branches found
No related tags found
No related merge requests found
apiVersion: v1
kind: Pod
metadata:
name: local-path-test
labels:
app.kubernetes.io/name: local-path-test
spec:
containers:
- name: test
image: busybox
command:
- /config/test.sh
volumeMounts:
- name: test
mountPath: /test
- name: config
mountPath: /config
restartPolicy: Never
securityContext:
fsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
terminationGracePeriodSeconds: 0
volumes:
- name: test
persistentVolumeClaim:
claimName: local-path-test
- name: config
configMap:
name: local-path-test
defaultMode: 0555
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: local-path-test
labels:
app.kubernetes.io/name: local-path-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "1Gi"
storageClassName: local-path
---
apiVersion: v1
kind: ConfigMap
metadata:
name: local-path-test
labels:
app.kubernetes.io/name: local-path-test
data:
test.sh: |
#!/bin/sh
ls -al /test && \
echo 'Hello from local-path-test' && \
cp /config/text.txt /test/test.txt && \
touch /test/foo && \
ls -al /test
text.txt: |
some test content
...@@ -19,6 +19,13 @@ import ( ...@@ -19,6 +19,13 @@ import (
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
) )
type ActionType string
const (
ActionTypeCreate = "create"
ActionTypeDelete = "delete"
)
const ( const (
KeyNode = "kubernetes.io/hostname" KeyNode = "kubernetes.io/hostname"
...@@ -26,7 +33,7 @@ const ( ...@@ -26,7 +33,7 @@ const (
) )
var ( var (
CleanupTimeoutCounts = 120 CmdTimeoutCounts = 120
ConfigFileCheckInterval = 5 * time.Second ConfigFileCheckInterval = 5 * time.Second
) )
...@@ -173,11 +180,19 @@ func (p *LocalPathProvisioner) Provision(opts pvController.VolumeOptions) (*v1.P ...@@ -173,11 +180,19 @@ func (p *LocalPathProvisioner) Provision(opts pvController.VolumeOptions) (*v1.P
} }
name := opts.PVName name := opts.PVName
path := filepath.Join(basePath, name) path := filepath.Join(basePath, name)
logrus.Infof("Creating volume %v at %v:%v", name, node.Name, path)
createCmdsForPath := []string{
"mkdir",
"-m", "0770",
"-p",
}
if err := p.createHelperPod(ActionTypeCreate, createCmdsForPath, name, path, node.Name); err != nil {
return nil, err
}
logrus.Infof("Created volume %v at %v:%v", name, node.Name, path)
fs := v1.PersistentVolumeFilesystem fs := v1.PersistentVolumeFilesystem
hostPathType := v1.HostPathDirectoryOrCreate hostPathType := v1.HostPathDirectoryOrCreate
return &v1.PersistentVolume{ return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
...@@ -225,13 +240,15 @@ func (p *LocalPathProvisioner) Delete(pv *v1.PersistentVolume) (err error) { ...@@ -225,13 +240,15 @@ func (p *LocalPathProvisioner) Delete(pv *v1.PersistentVolume) (err error) {
return err return err
} }
if pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain { if pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain {
if err := p.cleanupVolume(pv.Name, path, node); err != nil { logrus.Infof("Deleting volume %v at %v:%v", pv.Name, node, path)
cleanupCmdsForPath := []string{"rm", "-rf"}
if err := p.createHelperPod(ActionTypeDelete, cleanupCmdsForPath, pv.Name, path, node); err != nil {
logrus.Infof("clean up volume %v failed: %v", pv.Name, err) logrus.Infof("clean up volume %v failed: %v", pv.Name, err)
return err return err
} }
return nil return nil
} }
logrus.Infof("retained volume %v", pv.Name) logrus.Infof("Retained volume %v", pv.Name)
return nil return nil
} }
...@@ -276,9 +293,9 @@ func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (pat ...@@ -276,9 +293,9 @@ func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (pat
return path, node, nil return path, node, nil
} }
func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error) { func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmdsForPath []string, name, path, node string) (err error) {
defer func() { defer func() {
err = errors.Wrapf(err, "failed to cleanup volume %v", name) err = errors.Wrapf(err, "failed to %v volume %v", action, name)
}() }()
if name == "" || path == "" || node == "" { if name == "" || path == "" || node == "" {
return fmt.Errorf("invalid empty name or path or node") return fmt.Errorf("invalid empty name or path or node")
...@@ -293,35 +310,34 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error ...@@ -293,35 +310,34 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error
volumeDir = strings.TrimSuffix(volumeDir, "/") volumeDir = strings.TrimSuffix(volumeDir, "/")
if parentDir == "" || volumeDir == "" { if parentDir == "" || volumeDir == "" {
// it covers the `/` case // it covers the `/` case
return fmt.Errorf("invalid path %v for removal: cannot find parent dir or volume dir", path) return fmt.Errorf("invalid path %v for %v: cannot find parent dir or volume dir", action, path)
} }
hostPathType := v1.HostPathDirectoryOrCreate hostPathType := v1.HostPathDirectoryOrCreate
cleanupPod := &v1.Pod{ helperPod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "cleanup-" + name, Name: string(action) + "-" + name,
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
RestartPolicy: v1.RestartPolicyNever, RestartPolicy: v1.RestartPolicyNever,
NodeName: node, NodeName: node,
Containers: []v1.Container{ Containers: []v1.Container{
{ {
Name: "local-path-cleanup", Name: "local-path-" + string(action),
Image: "busybox", Image: "busybox",
Command: []string{"rm"}, Command: append(cmdsForPath, filepath.Join("/data/", volumeDir)),
Args: []string{"-rf", filepath.Join("/data-to-cleanup/", volumeDir)},
VolumeMounts: []v1.VolumeMount{ VolumeMounts: []v1.VolumeMount{
{ {
Name: "data-to-cleanup", Name: "data",
ReadOnly: false, ReadOnly: false,
MountPath: "/data-to-cleanup/", MountPath: "/data/",
}, },
}, },
}, },
}, },
Volumes: []v1.Volume{ Volumes: []v1.Volume{
{ {
Name: "data-to-cleanup", Name: "data",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{ HostPath: &v1.HostPathVolumeSource{
Path: parentDir, Path: parentDir,
...@@ -333,7 +349,7 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error ...@@ -333,7 +349,7 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error
}, },
} }
pod, err := p.kubeClient.CoreV1().Pods(p.namespace).Create(cleanupPod) pod, err := p.kubeClient.CoreV1().Pods(p.namespace).Create(helperPod)
if err != nil { if err != nil {
return err return err
} }
...@@ -341,12 +357,12 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error ...@@ -341,12 +357,12 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error
defer func() { defer func() {
e := p.kubeClient.CoreV1().Pods(p.namespace).Delete(pod.Name, &metav1.DeleteOptions{}) e := p.kubeClient.CoreV1().Pods(p.namespace).Delete(pod.Name, &metav1.DeleteOptions{})
if e != nil { if e != nil {
logrus.Errorf("unable to delete the cleanup pod: %v", e) logrus.Errorf("unable to delete the helper pod: %v", e)
} }
}() }()
completed := false completed := false
for i := 0; i < CleanupTimeoutCounts; i++ { for i := 0; i < CmdTimeoutCounts; i++ {
if pod, err := p.kubeClient.CoreV1().Pods(p.namespace).Get(pod.Name, metav1.GetOptions{}); err != nil { if pod, err := p.kubeClient.CoreV1().Pods(p.namespace).Get(pod.Name, metav1.GetOptions{}); err != nil {
return err return err
} else if pod.Status.Phase == v1.PodSucceeded { } else if pod.Status.Phase == v1.PodSucceeded {
...@@ -356,10 +372,10 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error ...@@ -356,10 +372,10 @@ func (p *LocalPathProvisioner) cleanupVolume(name, path, node string) (err error
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
if !completed { if !completed {
return fmt.Errorf("cleanup process timeout after %v seconds", CleanupTimeoutCounts) return fmt.Errorf("create process timeout after %v seconds", CmdTimeoutCounts)
} }
logrus.Infof("Volume %v has been cleaned up from %v:%v", name, node, path) logrus.Infof("Volume %v has been %vd on %v:%v", name, action, node, path)
return nil return nil
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment