From 6d03ceb73d7bc5ea2c776387728d5b2431e4830c Mon Sep 17 00:00:00 2001 From: Andrew Harding Date: Sat, 13 May 2023 18:51:47 -0600 Subject: [PATCH] Set container file label on workload API directory This allows the driver to be used within OpenShift without using an init container to set the label. Fixes #54. Signed-off-by: Andrew Harding --- go.mod | 1 + go.sum | 2 ++ pkg/driver/driver.go | 13 +++++++++++++ pkg/driver/driver_test.go | 26 ++++++++++++++++++++++++++ test/config/spiffe-csi-driver.yaml | 2 +- test/run.sh | 12 +++++++++++- 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 32e9169..322654b 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/opencontainers/selinux v1.11.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect diff --git a/go.sum b/go.sum index 521af54..30be342 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go index edc6230..c3a5030 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go @@ -8,6 +8,7 @@ import ( "github.com/container-storage-interface/spec/lib/go/csi" "github.com/go-logr/logr" + "github.com/opencontainers/selinux/go-selinux" "github.com/spiffe/spiffe-csi/internal/version" "github.com/spiffe/spiffe-csi/pkg/logkeys" "github.com/spiffe/spiffe-csi/pkg/mount" @@ -15,11 +16,16 @@ import ( "google.golang.org/grpc/status" ) +const ( + seLinuxContainerFileLabel = "container_file_t" +) + var ( // We replace these in tests since bind mounting generally requires root. bindMountRW = mount.BindMountRW unmount = mount.Unmount isMountPoint = mount.IsMountPoint + chcon = selinux.Chcon ) // Config is the configuration for the driver @@ -49,6 +55,13 @@ func New(config Config) (*Driver, error) { case config.WorkloadAPISocketDir == "": return nil, errors.New("workload API socket directory is required") } + + // Set the SELinux label on the workload API directory. This allows the + // mount to be used within OpenShift, for example. + if err := chcon(config.WorkloadAPISocketDir, seLinuxContainerFileLabel, true); err != nil { + return nil, fmt.Errorf("failed to set the SELinux label: %w", err) + } + return &Driver{ log: config.Log, nodeID: config.NodeID, diff --git a/pkg/driver/driver_test.go b/pkg/driver/driver_test.go index 90e1196..026ace2 100644 --- a/pkg/driver/driver_test.go +++ b/pkg/driver/driver_test.go @@ -34,6 +34,10 @@ func init() { unmount = func(dst string) error { return os.Remove(metaPath(dst)) } + chcon = func(fpath, label string, recursive bool) error { + fmt.Println("CHCON", fpath, label, recursive) + return writeSELinuxLabel(fpath, label, recursive) + } } func TestNew(t *testing.T) { @@ -283,6 +287,8 @@ func TestNodePublishVolume(t *testing.T) { client, workloadAPISocketDir := startDriver(t) + assertSELinuxLabelWritten(t, workloadAPISocketDir) + resp, err := client.NodePublishVolume(context.Background(), req) requireGRPCStatusPrefix(t, err, tt.expectCode, tt.expectMsgPrefix) if err == nil { @@ -469,6 +475,13 @@ func assertNotMounted(t *testing.T, targetPath string) { assert.Error(t, err, "should not be mounted") } +func assertSELinuxLabelWritten(t *testing.T, fpath string) { + label, err := readSELinuxLabel(fpath) + if assert.NoError(t, err, "failed to read selinux label file") { + assert.Equal(t, "container_file_t-recursive-true", label) + } +} + func readMeta(targetPath string) (string, error) { data, err := os.ReadFile(metaPath(targetPath)) return string(data), err @@ -478,10 +491,23 @@ func writeMeta(targetPath string, meta string) error { return os.WriteFile(metaPath(targetPath), []byte(meta), 0600) } +func readSELinuxLabel(fpath string) (string, error) { + data, err := os.ReadFile(seLinuxLabelPath(fpath)) + return string(data), err +} + +func writeSELinuxLabel(fpath string, label string, recursive bool) error { + return os.WriteFile(seLinuxLabelPath(fpath), []byte(fmt.Sprintf("%s-recursive-%t", label, recursive)), 0600) +} + func metaPath(targetPath string) string { return filepath.Join(targetPath, "meta") } +func seLinuxLabelPath(targetPath string) string { + return filepath.Join(targetPath, "selinux-label") +} + func dumpIt(t *testing.T, when, dir string) { t.Logf(">>>>>>>>>> DUMPING %s %s", when, dir) assert.NoError(t, filepath.Walk(dir, filepath.WalkFunc( diff --git a/test/config/spiffe-csi-driver.yaml b/test/config/spiffe-csi-driver.yaml index d6752fd..ce334fa 100644 --- a/test/config/spiffe-csi-driver.yaml +++ b/test/config/spiffe-csi-driver.yaml @@ -50,7 +50,7 @@ spec: # driver will mount this directory into containers. - mountPath: /spire-agent-socket name: spire-agent-socket-dir - readOnly: true + #readOnly: true # The volume that will contain the CSI driver socket shared # with the kubelet and the driver registrar. - mountPath: /spiffe-csi diff --git a/test/run.sh b/test/run.sh index 0be0c69..a24afc4 100755 --- a/test/run.sh +++ b/test/run.sh @@ -51,6 +51,14 @@ esac cleanup() { + if [ -z "${SUCCESS}" ]; then + "${KUBECTL}" logs deployment/spire-server -nspire-system --all-containers=true || true + "${KUBECTL}" logs daemonset/spire-agent -nspire-system --all-containers=true || true + "${KUBECTL}" logs daemonset/spiffe-csi-driver -nspire-system --all-containers=true || true + "${KUBECTL}" logs deployment/test-workload-1 --all-containers=true || true + "${KUBECTL}" logs deployment/test-workload-2 --all-containers=true || true + fi + delete-cluster rm -rf "${TMPDIR}" } @@ -104,6 +112,8 @@ apply-yaml() { "${KUBECTL}" rollout status -w --timeout=1m -nspire-system deployment/spire-server echo "Waiting for SPIRE agent rollout..." "${KUBECTL}" rollout status -w --timeout=1m -nspire-system daemonset/spire-agent + echo "Waiting for SPIFFE CSI driver rollout..." + "${KUBECTL}" rollout status -w --timeout=1m -nspire-system daemonset/spiffe-csi-driver echo "Waiting for test workload 1 rollout..." "${KUBECTL}" rollout status -w --timeout=1m deployment/test-workload-1 echo "Waiting for test workload 2 rollout..." @@ -159,5 +169,5 @@ apply-yaml register-workload check-workload-status "test-workload-1" check-workload-status "test-workload-2" -"${KUBECTL}" logs -nspire-system daemonset/spiffe-csi-driver -c spiffe-csi-driver +SUCCESS=1 echo "Done."