Skip to content

fenio/pv-mounter

Repository files navigation

pv-mounter

build test Go Report Card Latest GitHub release GitHub license GitHub stars GitHub issues GitHub all releases Docker Pulls Docker Pulls

A tool to locally mount Kubernetes Persistent Volumes (PVs) using SSHFS.

This tool can also be used as a kubectl plugin.

Disclaimer

This tool was created with significant help from ChatGPT-4o and perplexity. In fact, I didn't have to write much of the code myself, but I spent a lot of time crafting the correct prompts for these tools.

Update

The above was true for versions 0.0.x. With version 0.5.0, I actually had to learn some Go. While I still used help from GPT, I had to completely change my approach. AI alone wasn't able to create fully functional code that met all my requirements.

I published it using the Apache-2.0 license because the initial repository was licensed this way. However, to be honest, I'm not sure how such copy-and-paste code should be licensed.

Rationale

I often need to copy some files from my homelab which is running on Kubernetes. Having the ability to work on these files locally greatly simplifies this task. Thus, pv-mounter was born to automate that process.

What exactly does it do?

It performs a few tasks. In the case of volumes with RWX (ReadWriteMany) access mode or unmounted RWO (ReadWriteOnce):

  • Spawns a POD with a minimalistic image that contains an SSH daemon and binds it to the existing PVC.
  • Creates a port-forward to make it locally accessible.
  • Mounts the volume locally using SSHFS.

RWX

For already mounted RWO volumes, it's a bit more complex:

  • Spawns a POD with a minimalistic image that contains an SSH daemon and acts as a proxy to an ephemeral container.
  • Creates an ephemeral container within the POD that currently mounts the volume.
  • From that ephemeral container, establishes a reverse SSH tunnel to the proxy POD.
  • Creates a port-forward to the proxy POD onto the port exposed by the tunnel to make it locally accessible.
  • Mounts the volume locally using SSHFS.

RWO

See the demo below for more details.

Prerequisities

  • You need a working SSHFS setup.

Instructions for macOS.

Instructions for Linux.

Quick Start

kubectl krew install pv-mounter

kubectl pv-mounter mount [--needs-root] [--debug] <namespace> <pvc-name> <local-mountpoint>
kubectl pv-mounter clean <namespace> <pvc-name> <local-mountpoint>

Obviously, you need to have working krew installation first.

Or you can simply grab binaries from releases.

Security

I spent quite some time to make the solution as secure as possible.

  • SSH keys used for connections between various components are generated every time from scratch and once you wipe the environment clean, you won't be able to connect back into it using the same credentials.
  • Containers / PODs are using minimal possible privileges:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser = XYZ
runAsGroup = XYZ
runAsNonRoot = true

sshd_config is also limited as much as possible:

PermitRootLogin no
PasswordAuthentication no

Above, it's not true if you're using the --needs-root option or the NEEDS_ROOT environment variable, but well, you've asked for it.

Limitations

The tool has a "clean" option that does its best to clean up all the resources it created for mounting the volume locally. However, ephemeral containers can't be removed or deleted. That's the way Kubernetes works. As part of the cleanup, this tool kills the process that keeps its ephemeral container alive. I confirmed it also kills other processes that were running in that container, but the container itself remains in a limbo state.

Demo

Created with VHS tool.

RWX or unmounted RWO volume

Demo-unmounted

Mounted RWO volume

Demo-mounted

Windows

Since I can't test Windows binaries, they are not included. However, since there seems to exist a working Windows implementation of SSHFS, in theory it should work.

FAQ

Ask more questions, if you like ;)

I need to run the mounter pod as root, but my Pod Security Admission blocks the creation. What needs to be done?

You can add a label to the namespace you want the pod to be spawned in, to create an exception.

kubectl label namespace NAMESPACE-NAME pod-security.kubernetes.io/enforce=privileged