在 Linux 客户端上装载 SMB Azure 文件共享

适用于: ✔️ SMB 文件共享

可以使用 SMB 内核客户端在 Linux 分发版中装载Azure文件共享。

本文介绍如何使用 NTLMv2 身份验证(存储帐户密钥)装载 SMB Azure文件共享。 出于安全原因,首选基于标识的身份验证。 请参阅 通过 SMB 为访问 Azure 文件的 Linux 客户端启用 Active Directory 身份验证

协议

默认情况下,Azure 文件在传输中强制实施加密。 SMB 加密从 SMB 3.0 开始可用。 Azure 文件还支持不支持 SMB 加密的 SMB 2.1。 因此,出于安全原因,Azure 文件存储不允许从另一个Azure区域或本地使用 SMB 2.1 装载文件共享,而无需其他网络配置。 应使用 SMB 3.1.1,除非应用程序特别需要较旧版本。

配送 SMB 3.1.1(推荐) SMB 3.0
Linux 内核版本
  • 基本 3.1.1 支持:4.17
  • 默认装载:5.0
  • AES-128-GCM 加密:5.3
  • AES-256-GCM 加密:5.10
  • 基本3.0支持:3.12
  • AES-128-CCM 加密:4.11
Ubuntu AES-128-GCM 加密:18.04.5 LTS+ AES-128-CCM 加密:16.04.4 LTS+
Red Hat Enterprise Linux (RHEL)
  • 基本:8.0+
  • 默认装载:8.2+
  • AES-128-GCM 加密:8.2+
7.5+
Debian 基本:10+ AES-128-CCM 加密:10+
SUSE Linux Enterprise Server AES-128-GCM 加密:15 SP2+ AES-128-CCM 加密:12 SP2+

如果上表中未列出 Linux 分发版,请使用 uname 以下命令检查 Linux 内核版本:

uname -r

先决条件

  • 确保已安装 cifs-utils 包。 使用所选 Linux 分发版上的包管理器安装最新版本的 cifs-utils 包。

在 Ubuntu 和 Debian 上,使用 apt 包管理器。

sudo apt update
sudo apt install cifs-utils

在其他分发版上,请使用相应的包管理器,或从源编译

  • 最新版本的 Azure 命令行接口 (CLI)。 若要详细了解如何安装 Azure CLI,请参阅安装 Azure CLI 并选择操作系统。 如果想要在 PowerShell 6+ 中使用 Azure PowerShell 模块,可以。 但是,本文中的说明适用于Azure CLI。

  • 确保端口 445 已打开:SMB 通过 TCP 端口 445 进行通信。 确保防火墙或 ISP 未阻止来自客户端计算机的 TCP 端口 445。 替换 <your-resource-group><your-storage-account>,然后运行以下脚本:

    RESOURCE_GROUP_NAME="<your-resource-group>"
    STORAGE_ACCOUNT_NAME="<your-storage-account>"
    
    # This command assumes you have logged in with az login
    HTTP_ENDPOINT=$(az storage account show \
        --resource-group $RESOURCE_GROUP_NAME \
        --name $STORAGE_ACCOUNT_NAME \
        --query "primaryEndpoints.file" --output tsv | tr -d '"')
    SMBPATH=$(echo $HTTP_ENDPOINT | cut -c7-${#HTTP_ENDPOINT})
    FILE_HOST=$(echo $SMBPATH | tr -d "/")
    
    nc -zvw3 $FILE_HOST 445
    

    如果连接成功,则会看到如下所示的输出:

    Connection to <your-storage-account> 445 port [tcp/microsoft-ds] succeeded!
    

    如果网络上阻止了端口 445,则可以使用 VPN 连接或Azure ExpressRoute。 有关详细信息,请参阅直接访问 Azure 文件共享时的网络注意事项

权限

本文中的所有装载脚本都使用默认的 0755 Linux 文件和文件夹权限装载文件共享。 此权限设置授予文件或目录所有者的读取、写入和执行权限,并为所有者组和其他用户中的用户读取和执行权限。 根据组织的安全策略,可能需要在装载选项中设置备用 uid/giddir_modefile_mode 权限。 若要详细了解如何设置权限,请参阅 Unix 符号表示法。 有关装载选项的列表,请参阅装载选项

Unix 样式权限支持

您还可以通过使用客户端强制访问控制,并在您的装载命令中添加 modefromsid,idsfromsid 装载选项,为 SMB Azure 文件共享提供 Unix 样式的权限支持。 若要使此支持正常工作:

  • 所有访问该共享的客户端都需要使用 modefromsid,idsfromsid 进行挂载。
  • UID 和 GID 必须跨所有客户端保持一致。
  • 客户端必须运行以下受支持的 Linux 发行版之一:Ubuntu 20.04+、SLES 15 SP3+。

延迟关闭和双协议访问

Linux SMB 客户端使用称为 延迟关闭 (句柄缓存)的性能优化。 当应用程序关闭文件时,客户端可能会延迟将 SMB CLOSE 请求发送到服务器,默认情况下最多一秒钟,以防文件快速重新打开。 当Azure 文件存储收到写入后的 CLOSE 请求时,它会更新文件的上次修改时间(LMT),并因此更新其 ETag。

如果同时通过 SMB 和 FileREST API(双协议访问)访问同一文件共享,则此延迟可能会导致竞争条件。 SMB 客户端完成写入并关闭文件后,REST 客户端读取该文件的 ETag 并开始条件操作时,可能会因延迟的 CLOSE 请求到达并更新 LMT 和 ETag 而失败,并出现“文件已被并发修改”错误(HTTP 412 前提条件失败)。

对于在 SMB 写入程序和基于 REST 的读取程序之间交接文件的工作负载,请通过添加 closetimeo=0 挂载选项来禁用延迟关闭。 此选项会强制客户端立即发送 SMB CLOSE 请求(并最终确定 LMT 和 ETag),从而消除竞态条件,但代价是打开和关闭性能会略有下降。

使用 mount 按需装载 Azure 文件共享

在 Linux OS 上装载文件共享时,远程文件共享将在本地文件系统中以文件夹的形式表示。 可将文件共享装载到系统上的任何位置。 以下示例将装载到 /media 路径下。 可以通过修改 $MNT_ROOT 变量将此路径更改为首选路径。

请将 <resource-group-name><storage-account-name><file-share-name> 替换为适合你的环境的信息。

RESOURCE_GROUP_NAME="<resource-group-name>"
STORAGE_ACCOUNT_NAME="<storage-account-name>"
FILE_SHARE_NAME="<file-share-name>"

MNT_ROOT="/media"
MNT_PATH="$MNT_ROOT/$STORAGE_ACCOUNT_NAME/$FILE_SHARE_NAME"

sudo mkdir -p $MNT_PATH

接下来,运行以下脚本来初始化凭据文件。

# Create a folder to store the credentials for this storage account and
# any other that you might set up.
CREDENTIAL_ROOT="/etc/smbcredentials"
sudo mkdir -p "/etc/smbcredentials"

# Get the storage account key for the indicated storage account.
# You must be logged in with az login and your user identity must have
# permissions to list the storage account keys for this command to work.
STORAGE_ACCOUNT_KEY=$(az storage account keys list \
    --resource-group $RESOURCE_GROUP_NAME \
    --account-name $STORAGE_ACCOUNT_NAME \
    --query "[0].value" --output tsv | tr -d '"')

# Create the credential file for this individual storage account
SMB_CREDENTIAL_FILE="$CREDENTIAL_ROOT/$STORAGE_ACCOUNT_NAME.cred"
if [ ! -f $SMB_CREDENTIAL_FILE ]; then
    echo "username=$STORAGE_ACCOUNT_NAME" | sudo tee $SMB_CREDENTIAL_FILE > /dev/null
    echo "password=$STORAGE_ACCOUNT_KEY" | sudo tee -a $SMB_CREDENTIAL_FILE > /dev/null
else
    echo "The credential file $SMB_CREDENTIAL_FILE already exists, and was not modified."
fi

# Change permissions on the credential file so only root can read or modify the password file.
sudo chmod 600 $SMB_CREDENTIAL_FILE

现在,你可以使用凭据文件通过 mount 命令装载文件共享。 在以下示例中,该 $SMB_PATH 命令使用存储帐户的文件终结点的完全限定域名进行填充。 有关 SMB 装载选项的列表,请参阅装载选项

注意

从 Linux 内核版本 5.0 开始,SMB 3.1.1 是默认的协商协议。 如果使用的 Linux 内核版本低于 5.0,请在装载选项列表中指定 vers=3.1.1

# This command assumes you have logged in with az login
HTTP_ENDPOINT=$(az storage account show \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $STORAGE_ACCOUNT_NAME \
    --query "primaryEndpoints.file" --output tsv | tr -d '"')
SMB_PATH=$(echo $HTTP_ENDPOINT | cut -c7-${#HTTP_ENDPOINT})$FILE_SHARE_NAME

STORAGE_ACCOUNT_KEY=$(az storage account keys list \
    --resource-group $RESOURCE_GROUP_NAME \
    --account-name $STORAGE_ACCOUNT_NAME \
    --query "[0].value" --output tsv | tr -d '"')

sudo mount -t cifs $SMB_PATH $MNT_PATH -o credentials=$SMB_CREDENTIAL_FILE,serverino,nosharesock,actimeo=30,mfsymlinks

如果需要,还可将同一个 Azure 文件共享装载到多个装入点。

使用完 Azure 文件共享后,请使用 sudo umount $mntPath 卸载共享。

自动装载文件共享

在 Linux OS 上装载文件共享时,远程文件共享将在本地文件系统中以文件夹的形式表示。 可将文件共享装载到系统上的任何位置。 以下示例将装载到 /media 路径下。 可以通过修改 $MNT_ROOT 变量将此路径更改为首选路径。

MNT_ROOT="/media"
sudo mkdir -p $MNT_ROOT

使用存储帐户名称作为文件共享的用户名,将存储帐户密钥用作密码。 因为存储帐户凭据可随时更改,所以应将存储帐户的凭据与装载配置分开存储。

以下示例演示如何创建一个用于存储凭据的文件。 请记得将 <resource-group-name><storage-account-name> 替换为适合你的环境的信息。

RESOURCE_GROUP_NAME="<resource-group-name>"
STORAGE_ACCOUNT_NAME="<storage-account-name>"

# Create a folder to store the credentials for this storage account and
# any other that you might set up.
CREDENTIAL_ROOT="/etc/smbcredentials"
sudo mkdir -p "/etc/smbcredentials"

# Get the storage account key for the indicated storage account.
# You must be logged in with az login and your user identity must have
# permissions to list the storage account keys for this command to work.
STORAGE_ACCOUNT_KEY=$(az storage account keys list \
    --resource-group $RESOURCE_GROUP_NAME \
    --account-name $STORAGE_ACCOUNT_NAME \
    --query "[0].value" --output tsv | tr -d '"')

# Create the credential file for this individual storage account
SMB_CREDENTIAL_FILE="$CREDENTIAL_ROOT/$STORAGE_ACCOUNT_NAME.cred"
if [ ! -f $SMB_CREDENTIAL_FILE ]; then
    echo "username=$STORAGE_ACCOUNT_NAME" | sudo tee $SMB_CREDENTIAL_FILE > /dev/null
    echo "password=$STORAGE_ACCOUNT_KEY" | sudo tee -a $SMB_CREDENTIAL_FILE > /dev/null
else
    echo "The credential file $SMB_CREDENTIAL_FILE already exists, and was not modified."
fi

# Change permissions on the credential file so only root can read or modify the password file.
sudo chmod 600 $SMB_CREDENTIAL_FILE

若要自动装载文件共享,可以选择通过 /etc/fstab 实用工具使用静态装载,或者通过 autofs 实用工具使用动态装载。

通过 /etc/fstab 进行静态装载

使用前面创建的环境,在挂载文件夹下为存储帐户和文件共享创建文件夹。 请将 <file-share-name> 替换为你的 Azure 文件共享的相应名称。

FILE_SHARE_NAME="<file-share-name>"

MNT_PATH="$MNT_ROOT/$STORAGE_ACCOUNT_NAME/$FILE_SHARE_NAME"
sudo mkdir -p $MNT_PATH

最后,在 /etc/fstab 文件中为 Azure 文件共享创建一条记录。 在以下命令中,使用默认的 0755 Linux 文件和文件夹权限。 这些权限表示:所有者(基于文件或目录在 Linux 中的所有者)具有读取、写入和执行权限,所有者组中的用户具有读取和执行权限,而系统中的其他用户也具有读取和执行权限。 您可能希望根据需要为挂载设置备用的 uidgiddir_modefile_mode 权限。 若要详细了解如何设置权限,请参阅 UNIX 数值表示法。 有关 SMB 装载选项的列表,请参阅装载选项

提示

如果希望运行 .NET Core 应用程序的 Docker 容器能够写入 Azure 文件共享,请在 SMB 装载选项中包含 nobrl,以避免将字节范围锁定请求发送到服务器。

HTTP_ENDPOINT=$(az storage account show \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $STORAGE_ACCOUNT_NAME \
    --query "primaryEndpoints.file" --output tsv | tr -d '"')
SMB_PATH=$(echo $HTTP_ENDPOINT | cut -c7-${#HTTP_ENDPOINT})$FILE_SHARE_NAME

if [ -z "$(grep $SMB_PATH\ $MNT_PATH /etc/fstab)" ]; then
    echo "$SMB_PATH $MNT_PATH cifs _netdev,nofail,credentials=$SMB_CREDENTIAL_FILE,serverino,nosharesock,actimeo=30,mfsymlinks" | sudo tee -a /etc/fstab > /dev/null
else
    echo "/etc/fstab was not modified to avoid conflicting entries as this Azure file share was already present. You might want to double check /etc/fstab to ensure the configuration is as desired."
fi

sudo mount -a

注意

从 Linux 内核版本 5.0 开始,SMB 3.1.1 是默认的协商协议。 可以使用装载选项指定备用协议版本 vers 。 协议版本是 3.1.13.02.1

通过 autofs 进行动态装载

若要使用 autofs 实用工具动态装载文件共享,请使用所选 Linux 分发版上的包管理器进行安装。

在 Ubuntu 和 Debian 发行版上,使用 apt 包管理器:

sudo apt update
sudo apt install autofs

接下来,更新 autofs 配置文件。 有关 SMB 装载选项的列表,请参阅 装载选项

FILE_SHARE_NAME="<file-share-name>"

HTTP_ENDPOINT=$(az storage account show \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $STORAGE_ACCOUNT_NAME \
    --query "primaryEndpoints.file" --output tsv | tr -d '"')
SMB_PATH=$(echo $HTTP_ENDPOINT | cut -c7-$(expr length $HTTP_ENDPOINT))$FILE_SHARE_NAME

echo "$FILE_SHARE_NAME -fstype=cifs,credentials=$SMB_CREDENTIAL_FILE,serverino,nosharesock,actimeo=30,mfsymlinks :$SMB_PATH" > /etc/auto.fileshares

echo "/fileshares /etc/auto.fileshares --timeout=60" > /etc/auto.master

最后一步是重启 autofs 服务。

sudo systemctl restart autofs

使用密码轮换进行挂载

定期轮换密码(存储帐户密钥)是一种安全最佳做法。 不过,过去这种做法需要预先安排一些计划内停机时间。 现在,可以指定装载选项 password2= ,以便在主密码过期或轮换时,文件共享装载将继续运行,不会给用户造成停机。 传递给 Linux SMB 客户端的此可选第二个机密可实现无缝凭据轮换,而无需卸载共享或中断 I/O。

当启用此挂载选项时,客户端在会话建立和重新连接期间都会接受 passwordpassword2,因此您可以在旧密钥仍在使用时引入新密钥。

可通过以下两种方式之一提供 password2

  • 在 SMB 凭据文件中,与用户名和密码一起
  • 在命令行中更新现有卷挂载:-o password2=new-secret,包括在轮转期间通过 -o remount 更新

先决条件

需要使用 cifs-utils 版本 7.4 或更高版本才能使用 password2 装载选项。 除了正确的 cifs-utils 包之外,Linux 分发版还必须支持下表中突出显示的最低所需内核版本:

Distribution 发布 支持的内核版本
Ubuntu 22.04 LTS 6.8-1027
Ubuntu 24.04 LTS 6.14.0-1006
Ubuntu 24.04 LTS 6.14.0-1006
RHEL 9.5 5.14.0-503.11.1.el9_5
RHEL 9.6 5.14.0-570.12.1.el9_6
阿尔玛 9.6 5.14.0-570.12.1
洛奇 9.6 5.14.0-570.17.1

注意

如果您的发行版不在列表中,则它当前没有从内核 6.6 稳定分支获取所需的回移植。

通过凭据文件

将这两个机密放入凭据文件中,然后使用凭据进行装载。 轮换时,先更新 password2 到新密钥,重新装载或等待重新连接,然后在下一个维护时段交换值,使新密钥变为 password

# /etc/smbcredentials/<storage-account-name>.cred
username=<storage-account-name>
password=<current-key>
password2=<new-rotating-key>

更新现有卷装载

如果您已经在受支持的发行版上挂载了卷,且安装了适当版本的 cifs-utils,则可以使用以下命令,通过添加 password2= 选项来修改挂载选项。

# During rotation:
sudo mount -o remount,password2=<new-rotating-key> /mnt/share

装载选项

在 Linux 上装载 SMB Azure文件共享时,请使用以下装载选项。

装载选项 建议的值 说明
username= 存储帐户名称 NTLMv2 身份验证所必需的。
password= 存储帐户主密钥 NTLMv2 身份验证所必需的。
password2= 存储帐户辅助密钥 用于无停机时间密钥轮换。
mfsymlinks n/a 推荐。 强制该挂载支持符号链接,这样 git 等应用程序就可以克隆包含符号链接的仓库。
actimeo= 30-60 推荐。 CIFS 客户端在从服务器请求属性信息之前缓存文件或目录的属性的时间(以秒为单位)。 使用小于 30 秒的值可能会导致性能下降,因为文件和目录的属性缓存很快就会过期。 将 actimeo 设置为 30 到 60 秒之间。
nosharesock n/a 可选。 强制客户端始终与服务器建立新连接,即使它已经有一个与 SMB 装载的现有连接。 此连接可以提高性能,因为每个装入点使用不同的 TCP 套接字。 在某些情况下,nosharesock 可能会降低性能,因为当从同一客户端的两个挂载点打开同一个文件时,它不会对该文件使用同一份缓存。
remount n/a 重新装载文件共享并更改装载选项(如果已指定)。 与 password2 选项配合使用,以指定备用密码,在初次挂载后处理密码过期问题。
nobrl n/a 在单客户端场景下,当需要建议锁时使用。 Azure 文件存储不支持咨询锁,此设置会阻止向服务器发送字节范围锁请求。
snapshot= 时间 装载文件共享的特定快照。 Time 必须是一个正整数,用于标识所请求的快照,其值表示自 1601 年 1 月 1 日起经过的时间,以 100 纳秒为单位;或者,也可以将其指定为 GMT 格式,例如 @GMT-2024.03.27-20.52.19
closetimeo= 1 配置延迟关闭(句柄缓存)的超时时间(以秒为单位);设置为 0 时则禁用该功能。 默认值为 1 秒。 对于双协议工作负载,请设置 closetimeo=0,例如,当通过 SMB 和 REST API 同时访问文件共享时。 有关详细信息,请参阅 延迟关闭和双重协议访问
nostrictsync n/a 不要让服务器在执行 fsync() 时刷新。 某些服务器默认执行非缓冲写入,在这种情况下刷新是多余的。 此选项可提高以下工作负载的性能:客户端执行大量小型写入和 fsync 操作组合,且网络延迟远高于服务器端延迟。
multiuser n/a 在访问服务器时,将用户访问映射到单个凭据。 默认情况下,CIFS 装载仅在访问共享时使用一组用户凭据(装载凭据)。 使用此选项,每当有新用户访问挂载点时,客户端将会使用用户的凭据与服务器创建一个新的会话。 该用户的后续访问也使用这些凭据。 由于内核无法提示用户输入密码,因此多用户装载仅限于使用不需要密码的 sec= 选项的装载。
cifsacl n/a 用于在 CIFS/NTFS ACL 与 Linux 权限位之间进行映射、在 SID 与 UID 和 GID 之间进行映射,以及获取和设置安全描述符。 仅支持用于 NTLMv2 身份验证。
idsfromsid,modefromsid n/a 客户端需要执行客户端强制授权时使用。 启用 Unix 样式权限。 仅当 UID 和 GID 在所有客户端中统一时才有效。 仅支持用于 NTLMv2 身份验证。
cruid= uid 或 用户名称 可选。 设置凭据缓存所有者的 uid。 此值主要用于 sec=krb5. 默认值是执行挂载操作的进程的真实 uid。 将此参数设置为在其默认凭据缓存文件中具有必要 Kerberos 票证的用户的 uid 或用户名。 这会指示上行调用查找该用户拥有的凭据缓存。
sec= krb5 Kerberos 身份验证的必需项。 若要启用 Kerberos 安全模式,请设置 sec=krb5。 示例:sudo mount -t cifs $SMB_PATH $MNT_PATH -o sec=krb5,cruid=$UID,serverino,nosharesock,actimeo=30,mfsymlinks。 使用此选项时省略用户名和密码。 Linux 客户端必须已加入域。 请参阅通过 SMB 为 Linux 客户端启用 Active Directory 身份验证
uid= 0 可选。 设置在服务器不提供所有权信息时,装载的文件系统上的所有文件或目录将被一个特定的 uid 所拥有。 指定为用户名或数字 UID 之一。 在未指定的情况下,默认值为 0。
gid= 0 可选。 设置在服务器不提供所有权信息时,将拥有装载文件系统上所有文件或目录的 GID。 指定为组名或数字 gid 之一。 在未指定的情况下,默认值为 0。
file_mode= n/a 可选。 如果服务器不支持 CIFS Unix 扩展,则此值将替代默认文件模式。
dir_mode= n/a 可选。 如果服务器不支持 CIFS Unix 扩展,则此值将替代目录的默认模式。
handletimeout= n/a 可选。 发生故障转移后,服务器在等待客户端重新连接期间应保留文件句柄的时间(以毫秒为单位)。
max_channels= 4 在 Linux CIFS 装载上启用 SMB 多通道。 从 Linux 客户端访问Azure 文件存储时,始终使用 SMB 多通道连接的推荐值 (4)。

后续步骤

若要详细了解如何通过 Linux 使用 SMB Azure 文件共享,请参阅: