Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ab4a863
refactor: update Dockerfile to install `krb5-user` to facilitate kerb…
GamerGirlandCo Oct 31, 2025
16b2aa7
refactor: add storageClass parameters for kerberos auth
GamerGirlandCo Oct 31, 2025
dd80225
refactor: add `secrets` parameter to `internalMount` func
GamerGirlandCo Nov 1, 2025
41ead10
refactor: modify `NodePublishVolume` to invoke `kinit` if kerberos cr…
GamerGirlandCo Nov 1, 2025
8a474ca
refactor: update dockerfile
GamerGirlandCo Nov 3, 2025
ae1b082
refactor(examples): add deployment example for an nfs server with ker…
GamerGirlandCo Nov 4, 2025
c377d73
refactor(charts): invoke controller pod's entrypoint with `true` as t…
GamerGirlandCo Nov 4, 2025
c466707
test: add tests for mounting shares with kerberos auth
GamerGirlandCo Nov 4, 2025
f634818
chore: update `install-nfs-server` makefile goal
GamerGirlandCo Nov 4, 2025
903cfea
refactor: add `authKrbConf` mount parameter
GamerGirlandCo Nov 5, 2025
250ff6d
fix: unused variable error
GamerGirlandCo Nov 5, 2025
714dfa5
style: run gofmt
GamerGirlandCo Nov 5, 2025
ed9596a
chore: fix invalid krb5.conf
GamerGirlandCo Nov 5, 2025
afbbd54
fix: add `sleep 5` to Dockerfile
GamerGirlandCo Nov 5, 2025
530c840
fix: update `deploy/example/nfs-provisioner/nfs-krb-server.yaml`
GamerGirlandCo Nov 6, 2025
c72a7fe
refactor: handle error returned by `os.WriteFile`
GamerGirlandCo Nov 6, 2025
f9351ae
refactor: update nodeserver.go
GamerGirlandCo Nov 7, 2025
8c62980
style: run gofmt
GamerGirlandCo Nov 7, 2025
f29f24c
fix: update `nfs-krb-server` example deployment
GamerGirlandCo Nov 10, 2025
2a4e0cd
refactor: output more logs on the kerberos server pod
GamerGirlandCo Nov 11, 2025
d615d7f
style: appease yaml linter
GamerGirlandCo Nov 11, 2025
13221c1
refactor: update `nfs-krb-server.yaml`
GamerGirlandCo Nov 11, 2025
a6e1f33
update nfs-krb-server.yaml
GamerGirlandCo Nov 11, 2025
a3003d7
refactor: try not to fail on `kinit -k`
GamerGirlandCo Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.

FROM registry.k8s.io/build-image/debian-base:bookworm-v1.0.6
FROM debian:stable-slim

ARG ARCH
ARG binary=./bin/${ARCH}/nfsplugin
COPY ${binary} /nfsplugin

RUN apt update && apt upgrade -y && apt-mark unhold libcap2 && clean-install ca-certificates mount nfs-common netbase
RUN apt update && apt upgrade -y && apt-mark unhold libcap2 && apt-get install -y --reinstall --purge ca-certificates mount nfs-common netbase krb5-user lsb-base bash

ENTRYPOINT ["/nfsplugin"]
RUN cat > /etc/default/nfs-common <<EOC
NEED_STATD=yes

NEED_IDMAPD=yes

NEED_GSSD=yes
EOC

RUN cat > /usr/local/bin/entry.sh <<'EOF'
#!/bin/sh
set -x

if [ "$1" = "true" ]; then
shift 1
service rpcbind start
service nfs-common start
sleep 5
fi

/nfsplugin $@
EOF
RUN chmod +x /usr/local/bin/entry.sh

ENTRYPOINT ["entry.sh"]
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,9 @@ endif
.PHONY: install-nfs-server
install-nfs-server:
kubectl apply -f ./deploy/example/nfs-provisioner/nfs-server.yaml
kubectl apply -f ./deploy/example/nfs-provisioner/nfs-krb-server.yaml
kubectl delete secret mount-options -n default --ignore-not-found
kubectl create secret generic mount-options --from-literal mountOptions="nfsvers=4.1" -n default
kubectl create secret generic mount-options --from-literal mountOptions="nfsvers=4.1" --from-literal krb-pwd='password!' --from-file=krb5.conf=./test/krb5.conf -n default

.PHONY: install-helm
install-helm:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ spec:
allowPrivilegeEscalation: true
imagePullPolicy: {{ .Values.image.nfs.pullPolicy }}
args:
- 'true' # needed to distinguish controller from node
- "--v={{ .Values.controller.logLevel }}"
- "--nodeid=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
Expand Down
1 change: 1 addition & 0 deletions deploy/csi-nfs-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ spec:
allowPrivilegeEscalation: true
imagePullPolicy: IfNotPresent
args:
- "true"
- "-v=5"
- "--nodeid=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
Expand Down
93 changes: 93 additions & 0 deletions deploy/example/nfs-provisioner/nfs-krb-server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
kind: Service
apiVersion: v1
metadata:
name: nfs-krb-server
namespace: default
labels:
app: nfs-krb-server
spec:
type: ClusterIP # use "LoadBalancer" to get a public ip
selector:
app: nfs-krb-server
ports:
- name: tcp-2049
port: 2049
protocol: TCP
- name: udp-111
port: 111
protocol: UDP
- name: tcp-111
port: 111
protocol: TCP
- name: tcp-88
port: 88
protocol: TCP
- name: tcp-749
port: 749
protocol: TCP
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-krb-server
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nfs-krb-server
template:
metadata:
name: nfs-krb-server
labels:
app: nfs-krb-server
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: nfs-krb-server
image: docker.io/thealmightydrawingtablet/nfs-krb:alpine
imagePullPolicy: Always
command:
- bash
- -c
- ./init.sh & sleep 10; ls /var/log; tail -f /var/log/messages /var/log/rpc-gssd.log
env:
- name: SHARED_DIRECTORY
value: /srv/shared
- name: NFS_KRB_REALM
value: NFS-KRB-SERVER.DEFAULT.SVC.CLUSTER.LOCAL
- name: NFS_KRB_PRINC
value: nfs/nfs-krb-server.default.svc.cluster.local
- name: NFS_KRB_PWD
valueFrom:
secretKeyRef:
name: mount-options
key: krb-pwd
volumeMounts:
- mountPath: /srv/shared
name: nfs-vol
securityContext:
privileged: true
ports:
- name: tcp-2049
containerPort: 2049
protocol: TCP
- name: udp-111
containerPort: 111
protocol: UDP
- name: tcp-111
containerPort: 111
protocol: TCP
- name: tcp-88
containerPort: 88
protocol: TCP
- name: tcp-749
containerPort: 749
protocol: TCP
volumes:
- name: nfs-vol
hostPath:
path: /srv/nfs-krb-vol # modify this to specify another path to store nfs share data
type: DirectoryOrCreate
4 changes: 2 additions & 2 deletions deploy/example/nfs-provisioner/nfs-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ spec:
app: nfs-server
spec:
nodeSelector:
"kubernetes.io/os": linux
kubernetes.io/os: linux
containers:
- name: nfs-server
image: itsthenetwork/nfs-server-alpine:latest
env:
- name: SHARED_DIRECTORY
value: "/exports"
value: /exports
volumeMounts:
- mountPath: /exports
name: nfs-vol
Expand Down
11 changes: 4 additions & 7 deletions deploy/example/nfs-provisioner/nginx-pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ metadata:
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
accessModes: [ReadWriteOnce]
persistentVolumeReclaimPolicy: Delete
mountOptions:
- nfsvers=4.1
mountOptions: [nfsvers=4.1]
csi:
driver: nfs.csi.k8s.io
# volumeHandle format: {nfs-server-address}#{sub-dir-name}#{share-name}
Expand All @@ -29,13 +27,12 @@ metadata:
name: pvc-nginx
namespace: default
spec:
accessModes:
- ReadWriteOnce
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 10Gi
volumeName: pv-nginx
storageClassName: ""
storageClassName: ''
---
apiVersion: v1
kind: Pod
Expand Down
24 changes: 14 additions & 10 deletions pkg/nfs/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
case pvcNamespaceKey:
case pvcNameKey:
case pvNameKey:
case paramKrbPrincipal:
case paramKrbPasswordSecret:
case paramKrbConf:
// no op
case mountPermissionsField:
if v != "" {
Expand Down Expand Up @@ -168,7 +171,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
volCap = req.GetVolumeCapabilities()[0]
}
// Mount nfs base share so we can create a subdirectory
if err = cs.internalMount(ctx, nfsVol, parameters, volCap); err != nil {
if err = cs.internalMount(ctx, nfsVol, parameters, volCap, req.GetSecrets()); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err)
}
defer func() {
Expand Down Expand Up @@ -241,7 +244,7 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
}
// mount nfs base share so we can delete the subdirectory
volCap := getVolumeCapabilityFromSecret(volumeID, req.GetSecrets())
if err = cs.internalMount(ctx, nfsVol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, nfsVol, nil, volCap, req.GetSecrets()); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err)
}
defer func() {
Expand Down Expand Up @@ -365,7 +368,7 @@ func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
}
snapVol := volumeFromSnapshot(snapshot)
volCap := getVolumeCapabilityFromSecret(req.GetSourceVolumeId(), req.GetSecrets())
if err = cs.internalMount(ctx, snapVol, req.GetParameters(), volCap); err != nil {
if err = cs.internalMount(ctx, snapVol, req.GetParameters(), volCap, req.GetSecrets()); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount snapshot nfs server: %v", err)
}
defer func() {
Expand All @@ -381,7 +384,7 @@ func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
return nil, err
}

if err = cs.internalMount(ctx, srcVol, req.GetParameters(), volCap); err != nil {
if err = cs.internalMount(ctx, srcVol, req.GetParameters(), volCap, req.GetSecrets()); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount src nfs server: %v", err)
}
defer func() {
Expand Down Expand Up @@ -436,7 +439,7 @@ func (cs *ControllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS

volCap := getVolumeCapabilityFromSecret(req.SnapshotId, req.GetSecrets())
vol := volumeFromSnapshot(snap)
if err = cs.internalMount(ctx, vol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, vol, nil, volCap, req.GetSecrets()); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount nfs server for snapshot deletion: %v", err)
}
defer func() {
Expand Down Expand Up @@ -475,7 +478,7 @@ func (cs *ControllerServer) ControllerExpandVolume(_ context.Context, req *csi.C
}

// Mount nfs server at base-dir
func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, volumeContext map[string]string, volCap *csi.VolumeCapability) error {
func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, volumeContext map[string]string, volCap *csi.VolumeCapability, secrets map[string]string) error {
if volCap == nil {
volCap = &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{
Expand Down Expand Up @@ -504,6 +507,7 @@ func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, v
VolumeContext: volContext,
VolumeCapability: volCap,
VolumeId: vol.id,
Secrets: secrets,
})
return err
}
Expand Down Expand Up @@ -533,15 +537,15 @@ func (cs *ControllerServer) copyFromSnapshot(ctx context.Context, req *csi.Creat
volCap = req.GetVolumeCapabilities()[0]
}

if err = cs.internalMount(ctx, snapVol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, snapVol, nil, volCap, req.GetSecrets()); err != nil {
return status.Errorf(codes.Internal, "failed to mount src nfs server for snapshot volume copy: %v", err)
}
defer func() {
if err = cs.internalUnmount(ctx, snapVol); err != nil {
klog.Warningf("failed to unmount src nfs server after snapshot volume copy: %v", err)
}
}()
if err = cs.internalMount(ctx, dstVol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, dstVol, nil, volCap, req.GetSecrets()); err != nil {
return status.Errorf(codes.Internal, "failed to mount dst nfs server for snapshot volume copy: %v", err)
}
defer func() {
Expand Down Expand Up @@ -582,15 +586,15 @@ func (cs *ControllerServer) copyFromVolume(ctx context.Context, req *csi.CreateV
if len(req.GetVolumeCapabilities()) > 0 {
volCap = req.GetVolumeCapabilities()[0]
}
if err = cs.internalMount(ctx, srcVol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, srcVol, nil, volCap, req.GetSecrets()); err != nil {
return status.Errorf(codes.Internal, "failed to mount src nfs server: %v", err)
}
defer func() {
if err = cs.internalUnmount(ctx, srcVol); err != nil {
klog.Warningf("failed to unmount nfs server: %v", err)
}
}()
if err = cs.internalMount(ctx, dstVol, nil, volCap); err != nil {
if err = cs.internalMount(ctx, dstVol, nil, volCap, req.GetSecrets()); err != nil {
return status.Errorf(codes.Internal, "failed to mount dst nfs server: %v", err)
}
defer func() {
Expand Down
11 changes: 9 additions & 2 deletions pkg/nfs/nfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,15 @@ const (
// The base directory must be a direct child of the root directory.
// The root directory is omitted from the string, for example:
// "base" instead of "/base"
paramShare = "share"
paramSubDir = "subdir"
paramShare = "share"
paramSubDir = "subdir"
// Kerberos principal to use when mounting with `-o sec=krb5*`
paramKrbPrincipal = "authprincipal"
// name of a secret containing the Kerberos password to use when authenticating
paramKrbPasswordSecret = "authpasswordsecret"
// name of a secret containing the contents of a krb5.conf file with
// realm and/or KDC information
paramKrbConf = "authkrbconf"
paramOnDelete = "ondelete"
mountOptionsField = "mountoptions"
mountPermissionsField = "mountpermissions"
Expand Down
Loading