Skip to content

Commit

Permalink
Set container file label on workload API directory
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
azdagron committed May 14, 2023
1 parent 2aae3aa commit fc4fe9c
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ Ensure that the Workload API socket directory is shared with the SPIFFE CSI
Driver via a `hostPath` volume. The directory backing `emptyDir` volumes are
tied to the pod instance and invalidated when the pod is restarted.

### Permission Denied accessing Workload API directory

This may be caused by SELinux in environments like OpenShift. The SPIFFE CSI
Driver attempts to set the container file label on the Workload API socket
directory on startup. Check the logs to see if it was successful. To be
successful, the Workload API socket directory must be mounted read-write into
the CSI driver container.

## Reporting a Vulnerability

Vulnerabilities can be reported by sending an email to [email protected]. A
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
16 changes: 16 additions & 0 deletions pkg/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@ 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"
"google.golang.org/grpc/codes"
"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
Expand Down Expand Up @@ -49,6 +55,16 @@ 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. This will fail if the
// Workload API socket directory is mounted read-only.
if err := chcon(config.WorkloadAPISocketDir, seLinuxContainerFileLabel, true); err != nil {
config.Log.Error(err, "Failed to set the container file label on the Workload API socket directory. Is the Workload API directory mounted read-write?")
} else {
config.Log.Info("Successfully set the container file label on the Workload API socket directory")
}

return &Driver{
log: config.Log,
nodeID: config.NodeID,
Expand Down
25 changes: 25 additions & 0 deletions pkg/driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,36 @@ func init() {
unmount = func(dst string) error {
return os.Remove(metaPath(dst))
}
chcon = writeSELinuxLabel
}

func TestNew(t *testing.T) {
workloadAPISocketDir := t.TempDir()

t.Run("node ID is required", func(t *testing.T) {
_, err := New(Config{
Log: logr.Discard(),
WorkloadAPISocketDir: workloadAPISocketDir,
})
require.EqualError(t, err, "node ID is required")
})

t.Run("workload API socket directory is required", func(t *testing.T) {
_, err := New(Config{
Log: logr.Discard(),
NodeID: testNodeID,
})
require.EqualError(t, err, "workload API socket directory is required")
})

t.Run("success", func(t *testing.T) {
_, err := New(Config{
Log: logr.Discard(),
NodeID: testNodeID,
WorkloadAPISocketDir: workloadAPISocketDir,
})
require.NoError(t, err)
assertSELinuxLabelWritten(t, workloadAPISocketDir)
})
}

Expand Down Expand Up @@ -469,6 +474,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
Expand All @@ -478,10 +490,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(
Expand Down
2 changes: 1 addition & 1 deletion test/config/spiffe-csi-driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion test/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
}
Expand Down Expand Up @@ -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..."
Expand Down Expand Up @@ -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."

0 comments on commit fc4fe9c

Please sign in to comment.