Skip to content

Commit b2296f3

Browse files
committed
feat: support SMB mount with managed identity
1 parent 257194a commit b2296f3

File tree

6 files changed

+54
-19
lines changed

6 files changed

+54
-19
lines changed

pkg/azurefile-proxy/init.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@ if [ "$KUBELET_PATH" != "/var/lib/kubelet" ];then
2323
echo "kubelet path is $KUBELET_PATH, update azurefile-proxy.service...."
2424
sed -i "s#--azurefile-proxy-endpoint[^ ]*#--azurefile-proxy-endpoint=unix:/${KUBELET_PATH}/plugins/file.csi.azure.com/azurefile-proxy.sock#" /azurefile-proxy/azurefile-proxy.service
2525
echo "azurefile-proxy endpoint is updated to unix:/$KUBELET_PATH/plugins/file.csi.azure.com/azurefile-proxy.sock"
26-
fi
26+
fi
2727

2828
HOST_CMD="nsenter --mount=/proc/1/ns/mnt"
2929

30+
echo "set up /var/lib/kubelet/kerberos/krb5.conf"
31+
echo -e '[libdefaults]\ndefault_ccache_name = FILE:/var/lib/kubelet/kerberos/krb5cc_%{uid}' > /var/lib/kubelet/kerberos/krb5.conf
32+
33+
echo "set up /etc/azfilesauth/config.yaml"
34+
echo -e 'USER_UID: 0\nKRB5_CC_NAME: /var/lib/kubelet/kerberos/krb5cc_0' > /etc/azfilesauth/config.yaml
35+
3036
DISTRIBUTION=$($HOST_CMD cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"')
3137
ARCH=$($HOST_CMD uname -m)
3238
echo "Linux distribution: $DISTRIBUTION, Arch: $ARCH"

pkg/azurefile/azurefile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ const (
160160
premium = "premium"
161161
selectRandomMatchingAccountField = "selectrandommatchingaccount"
162162
accountQuotaField = "accountquota"
163+
mountWithManagedIdentityField = "mountwithmanagedidentity"
163164

164165
accountNotProvisioned = "StorageAccountIsNotProvisioned"
165166
// this is a workaround fix for 429 throttling issue, will update cloud provider for better fix later

pkg/azurefile/controllerserver.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
228228
// no op, only used in NodeStageVolume
229229
case folderNameField:
230230
// no op, only used in NodeStageVolume
231+
case mountWithManagedIdentityField:
232+
// no op, only used in NodeStageVolume
231233
case fsGroupChangePolicyField:
232234
fsGroupChangePolicy = v
233235
case mountPermissionsField:

pkg/azurefile/nodeserver.go

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,7 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
263263
// don't respect fsType from req.GetVolumeCapability().GetMount().GetFsType()
264264
// since it's ext4 by default on Linux
265265
var fsType, server, protocol, ephemeralVolMountOptions, storageEndpointSuffix, folderName string
266-
var ephemeralVol bool
267-
var encryptInTransit bool
266+
var ephemeralVol, encryptInTransit, mountWithManagedIdentity bool
268267
fileShareNameReplaceMap := map[string]string{}
269268

270269
mountPermissions := d.mountPermissions
@@ -298,7 +297,6 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
298297
fileShareNameReplaceMap[pvNameMetadata] = v
299298
case mountPermissionsField:
300299
if v != "" {
301-
var err error
302300
var perm uint64
303301
if perm, err = strconv.ParseUint(v, 8, 32); err != nil {
304302
return nil, status.Errorf(codes.InvalidArgument, "invalid mountPermissions %s", v)
@@ -310,11 +308,15 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
310308
}
311309
}
312310
case encryptInTransitField:
313-
var err error
314311
encryptInTransit, err = strconv.ParseBool(v)
315312
if err != nil {
316313
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Volume context property %q must be a boolean value: %v", k, err))
317314
}
315+
case mountWithManagedIdentityField:
316+
mountWithManagedIdentity, err = strconv.ParseBool(v)
317+
if err != nil {
318+
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Volume context property %q must be a boolean value: %v", k, err))
319+
}
318320
}
319321
}
320322

@@ -379,22 +381,27 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
379381
mountOptions = util.JoinMountOptions(mountFlags, []string{"vers=4,minorversion=1,sec=sys"})
380382
mountOptions = appendDefaultNfsMountOptions(mountOptions, d.appendNoResvPortOption, d.appendActimeoOption)
381383
} else {
382-
if accountName == "" || accountKey == "" {
383-
return nil, status.Errorf(codes.Internal, "accountName(%s) or accountKey is empty", accountName)
384-
}
385-
if runtime.GOOS == "windows" {
386-
mountOptions = []string{fmt.Sprintf("AZURE\\%s", accountName)}
387-
sensitiveMountOptions = []string{accountKey}
384+
if mountWithManagedIdentity && runtime.GOOS != "windows" {
385+
mountOptions = []string{"sec=krb5,cruid=0,upcall_target=mount", fmt.Sprintf("username=%s", d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID)}
386+
klog.V(2).Infof("using managed identity %s for volume %s with mount options: %v", d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID, volumeID, mountOptions)
388387
} else {
389-
if err := os.MkdirAll(targetPath, os.FileMode(mountPermissions)); err != nil {
390-
return nil, status.Error(codes.Internal, fmt.Sprintf("MkdirAll %s failed with error: %v", targetPath, err))
388+
if accountName == "" || accountKey == "" {
389+
return nil, status.Errorf(codes.Internal, "accountName(%s) or accountKey is empty", accountName)
391390
}
392-
// parameters suggested by https://azure.microsoft.com/en-us/documentation/articles/storage-how-to-use-files-linux/
393-
sensitiveMountOptions = []string{fmt.Sprintf("username=%s,password=%s", accountName, accountKey)}
394-
if ephemeralVol {
395-
cifsMountFlags = util.JoinMountOptions(cifsMountFlags, strings.Split(ephemeralVolMountOptions, ","))
391+
if runtime.GOOS == "windows" {
392+
mountOptions = []string{fmt.Sprintf("AZURE\\%s", accountName)}
393+
sensitiveMountOptions = []string{accountKey}
394+
} else {
395+
if err := os.MkdirAll(targetPath, os.FileMode(mountPermissions)); err != nil {
396+
return nil, status.Error(codes.Internal, fmt.Sprintf("MkdirAll %s failed with error: %v", targetPath, err))
397+
}
398+
// parameters suggested by https://azure.microsoft.com/en-us/documentation/articles/storage-how-to-use-files-linux/
399+
sensitiveMountOptions = []string{fmt.Sprintf("username=%s,password=%s", accountName, accountKey)}
400+
if ephemeralVol {
401+
cifsMountFlags = util.JoinMountOptions(cifsMountFlags, strings.Split(ephemeralVolMountOptions, ","))
402+
}
403+
mountOptions = appendDefaultCifsMountOptions(cifsMountFlags, d.appendNoShareSockOption, d.appendClosetimeoOption)
396404
}
397-
mountOptions = appendDefaultCifsMountOptions(cifsMountFlags, d.appendNoShareSockOption, d.appendClosetimeoOption)
398405
}
399406
}
400407

@@ -434,6 +441,11 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
434441
klog.V(2).Infof("mount with proxy succeeded for %s", cifsMountPath)
435442
} else {
436443
execFunc := func() error {
444+
if mountWithManagedIdentity && protocol != nfs && runtime.GOOS != "windows" {
445+
if out, err := setCredentialCache(server, d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID); err != nil {
446+
return fmt.Errorf("setCredentialCache failed for %s with error: %v, output: %s", server, err, out)
447+
}
448+
}
437449
return SMBMount(d.mounter, source, cifsMountPath, mountFsType, mountOptions, sensitiveMountOptions)
438450
}
439451
timeoutFunc := func() error { return fmt.Errorf("time out") }

pkg/azurefile/utils.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23+
"os/exec"
2324
"regexp"
2425
"strconv"
2526
"strings"
@@ -374,3 +375,9 @@ func removeOptionIfExists(options []string, removeOption string) ([]string, bool
374375
}
375376
return options, false
376377
}
378+
379+
func setCredentialCache(server, clientID string) ([]byte, error) {
380+
klog.V(2).Infof("setCredentialCache for server %s with clientID %s", server, clientID)
381+
cmd := exec.Command("azfilesauthmanager", "set", server, "--imds-client-id", clientID)
382+
return cmd.CombinedOutput()
383+
}

pkg/azurefileplugin/Dockerfile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ARG ARCH
2222

2323
RUN apt update \
2424
&& apt install -y curl \
25+
&& curl -Lso /tmp/azfilesauth_amd64.deb https://raw.githubusercontent.com/andyzhangx/demo/refs/heads/master/aks/azfilesauth_1.0-2_amd64.deb \
2526
&& curl -Ls https://azcopyvnext-awgzd8g7aagqhzhe.b02.azurefd.net/releases/release-10.29.1-20250515/azcopy_linux_${ARCH}_10.29.1.tar.gz \
2627
| tar xvzf - --strip-components=1 -C /usr/local/bin/ --wildcards "*/azcopy"
2728

@@ -33,18 +34,24 @@ ARG binary=./_output/${ARCH}/azurefileplugin
3334
COPY ${binary} /azurefileplugin
3435
COPY --from=builder --chown=root:root /usr/local/bin/azcopy /usr/local/bin/azcopy
3536

36-
RUN apt update && apt upgrade -y && apt-mark unhold libcap2 && clean-install ca-certificates cifs-utils util-linux e2fsprogs mount udev xfsprogs nfs-common netbase
37+
RUN apt update && apt upgrade -y && apt-mark unhold libcap2 && clean-install ca-certificates cifs-utils util-linux e2fsprogs mount udev xfsprogs nfs-common netbase python3-requests
3738

3839
COPY ./pkg/azurefile-proxy/init.sh /azurefile-proxy/
3940
COPY ./pkg/azurefile-proxy/install-proxy.sh /azurefile-proxy/
4041
COPY ./pkg/azurefile-proxy/azurefile-proxy.service /azurefile-proxy/
4142
COPY ./_output/${ARCH}/azurefile-proxy /azurefile-proxy/
4243

44+
COPY --from=builder --chown=root:root /tmp/azfilesauth_amd64.deb /azurefile-proxy/azfilesauth_amd64.deb
45+
4346
RUN chmod +x /azurefile-proxy/init.sh && \
4447
chmod +x /azurefile-proxy/install-proxy.sh && \
4548
chmod +x /azurefile-proxy/azurefile-proxy.service && \
4649
chmod +x /azurefile-proxy/azurefile-proxy
4750

51+
RUN if [ "$ARCH" = "amd64" ] ; then \
52+
clean-install libcurl4-gnutls-dev \
53+
&& apt update && apt install -y /azurefile-proxy/azfilesauth_amd64.deb; fi
54+
4855
LABEL maintainers="andyzhangx"
4956
LABEL description="AzureFile CSI Driver"
5057

0 commit comments

Comments
 (0)