欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

通过 Amazon EFS 对 NFS 文件系统权限进行细粒度控制

程序员文章站 2022-03-18 18:05:38
...

传统的NFS服务是企业应用里非常常见的网络存储服务。用户在搭建NFS服务时,需要对权限进行相应的设置,以防止未授权的客户端非法访问远程文件存储。NFS的权限管理主要依赖Linux文件系统的文件权限管理机制,并通过 /etc/exports 进行文件系统共享的参数设置,如授权客户端的网段,是否只读等。如果需要更进一步的认证机制,需要部署Kerberos,相应的配置也并不轻松。

当我们将现有的NFS服务迁移上云,或是需要在云的环境下面构建NFS服务时,同样也要考虑到权限的控制。 AWS上提供了Amazon Elastic File System (EFS),是托管的NFS服务。用户可以基于EFS快速的部署一个超过PB级别的NFS文件系统。用户不需要管理文件系统的底层存储机制,只要往EFS写入文件或删除文件,EFS即可自动进行扩展和收缩。同时这些数据也是跨多个可用区来进行保护,相当于实现了同城灾备的保护级别。

在权限控制这块,EFS在NFS文件权限控制的基础上,结合AWS云上已有的安全认证机制,如安全组(Security Group),身份与访问管理服务(IAM)和EFS独特的接入点(Access Point)机制,简化了权限控制的配置工作,同时可以更为细粒度的进行管理和审计。

1. 通过安全组进行客户端访问控制

安全组可以理解为是AWS VPC中挂载到虚拟网卡上的防火墙,通过设定规则可以指定入站和出站的白名单。在之前的博客中,我们演示了如何通过向导快速部署一个EFS文件系统,其中挂载目标和EC2实例均使用的是VPC的默认安全组,因此二者之前的所有网络流量都是放通的。接下来我们可以创建自定义的安全组来做更为精细的权限控制。

如下图所示:
通过 Amazon EFS 对 NFS 文件系统权限进行细粒度控制

我们可以为挂载目标和EC2实例各创建一个安全组(分别命名为efsmountpoint和nfsclient,如果EC2实例已有安全组则可利用现有安全组)。EC2实例的安全组可按照业务需求开通相应的入站端口即可,出站默认是所有流量放通。挂载目标的安全组入站规则设置为放通NFS端口2049,来源可以设置为EC2实例的安全组id(即nfsclient),这样即可以通过安全组限制只有指定的EC2实例能够挂载文件系统。

如下是控制台上关于挂载目标安全组的设置截图:
通过 Amazon EFS 对 NFS 文件系统权限进行细粒度控制

注意到每个挂载目标最多可以同时设置5个安全组。

2. 通过IAM对NFS客户端进行授权

安全组可以对访问文件系统的EC2实例进行访问控制,如果需要进一步控制访问权限,如读写权限,能否以Root用户访问等,则可以结合IAM服务来进行更细粒度的控制。

通过AWS Identity and Access Management (IAM) 可以安全地管理对 AWS 服务和资源的访问。可以使用 IAM 创建和管理 AWS 用户和组,并使用各种权限来允许或拒绝他们对 AWS 资源的访问。同时,EFS的文件系统也提供了文件系统策略,可以设置针对文件系统的相应权限。

通过 Amazon EFS 对 NFS 文件系统权限进行细粒度控制

2.1 为文件系统设置只读策略

EFS文件系统创建出来后,默认的文件系统策略是全放通,即任何NFS客户端均可以对其完全访问。用户可以通过设置文件系统策略,来进一步对文件系统权限进行控制。这些权限包括:

elasticfilesystem:ClientMount : 允许客户端以只读方式挂载文件系统
elasticfilesystem:ClientWrite : 允许客户端对文件系统进行写入
elasticfilesystem:ClientRootAccess : 允许客户端以Root用户进行访问
比如我们希望文件系统给予所有用户只读权限,则可以配置如下的文件系统策略:

{
    "Version": "2012-10-17",
    "Id": "efs-policy-wizard-f37947df-cdbb-40c9-8fe2-fb38bedd362e",
    "Statement": [
        {
            "Sid": "efs-statement-204c3f1d-6499-4a4f-9fa5-86592173888e",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "elasticfilesystem:ClientMount",
            "Resource": "arn:aws-cn:elasticfilesystem:cn-northwest-1:402202783068:file-system/fs-57789eb2"
        }
    ]
}

接下来我们可以挂载这个文件系统进行读写测试:

$ sudo mount -t efs fs-57789eb2 /mnt/efs
$ touch /mnt/efs/test
touch: cannot touch '/mnt/efs/test': Read-only file system

可以看到客户端挂载后就是一个只读的文件系统,无法进行修改,也无法以Root用户访问。这是一个典型的基于资源(Resource-based)的IAM策略,通过进一步修改这个IAM策略(即指定Principal)我们还可以为某个特定的用户设置允许或拒绝相应的权限。

注意到NFS客户端发起EFS文件系统挂载命令时,这个操作会被CloudTrail服务所记录下来,EventName为“NewClientConnection”,从CloudTrail详细日志的 “userIdentity”和”serviceEventDetail”中我们可以看到详细的IAM权限检查结果

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSAccount",
        "principalId": "",
        "accountId": "ANONYMOUS_PRINCIPAL"
        
...中间省略...

    "serviceEventDetails": {
        "permissions": {
            "ClientRootAccess": false,
            "ClientMount": true,
            "ClientWrite": false
        },
        "sourceIpAddress": "172.31.44.108"
    }
}

从这个记录可以看到,这个挂载操作是匿名用户发起,EFS根据文件系统权限,给予NFS客户端只读的权限。

2.2 为EC2实例授予读写权限

如果我们希望某个EC2实例做为管理节点,具有文件系统的读写权限,那应该如何配置呢?其中一种可行的方式是创建一个IAM角色(本示例中该角色命为FSWrite),并为这个角色配置具有文件系统写权限的策略,通过将这个IAM角色附加给管理节点的EC2实例,从而使该实例上运行的程序具有对文件系统的写操作权限,如下是相应的策略的示例:

{
    "Version": "2012-10-17",
    "Id": "efsid",
    "Statement": [
        {
            "Sid": "efssid",
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:ClientWrite",
                "elasticfilesystem:ClientRootAccess"
            ],
            "Resource": "arn:aws-cn:elasticfilesystem:cn-northwest-1:402202783068:file-system/fs-57789eb2"
        }
    ]
}

在这个管理节点的EC2上面进行挂载时,如果直接使用mount命令并用默认参数进行挂载的话,并不会去使用EC2所附加的角色权限,因此需要使用如下命令及参数进行挂载:

$ sudo mount -t efs fs-57789eb2:/ -o tls,iam /mnt/efs

其中:

tls: NFS客户端与EFS之间的通信需要使用TLS1.2进行加密,
iam: 使用mount程序所运行环境的IAM权限,这个例子中使用的是附加到EC2的角色。使用iam选项时需要同时启用tls选项
检查CloudTrail中的日志,可以看到IAM权限检查的结果:

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROAV3JJHNVOITSOOW6BF:i-04e69fb201d65ce6e",
        "arn": "arn:aws-cn:sts::402202783068:assumed-role/FSWrite/i-04e69fb201d65ce6e",

...中间省略...

    "serviceEventDetails": {
        "permissions": {
            "ClientRootAccess": true,
            "ClientMount": true,
            "ClientWrite": true
        },
        "sourceIpAddress": "172.31.44.108"
    }
}

从这个记录可以看到,这个挂载操作使用了FSWrite这个角色,EFS根据角色权限,给予NFS客户端写入的权限和Root访问的权限。

3 通过接入点(Access Points)设置用户访问权限

接下来我们再看一下,如何进一步对NFS客户端进行权限的控制,包括限制操作系统用户身份和限制可访问的文件系统路径等。这里会使用到EFS的接入点(Access Points)设置。

接着上面的例子,假设我们希望这个管理节点的EC2实例,在写入EFS文件系统时,强制使用操作系统用户id为1003, 用户组id也为1003, 同时限制这个用户只能往 /data 目录下面进行数据写入。那我们可以配置如下的接入点:
通过 Amazon EFS 对 NFS 文件系统权限进行细粒度控制

在这个接入点配置里,我们设置了:

POSIX用户: 这里我们可以设置通过该接入点访问时,强制使用的操作系统用户ID/组ID。本示例中我们使用了用户ID和组ID均为1003,以便与现有操作系统用户区分。
目录:这里我们可以设置通过接入点访问时做为根目录的路径,如果该目录不存在,则在第一次通过接入点访问时EFS会自动创建。如果不指定则默认使用文件系统根目录。本示例中我们指定了/data做为根目录
拥有者用户与权限:这里我们可以设置根目录拥有者的用户ID和组ID,同时我们也可以指定这个根目录的权限。本示例我们指定拥有者用户ID和组ID均为1003,权限是755
接着我们需要修改管理员所使用的IAM角色(即FSWrite)的策略,限制其只能通过该接入点访问时才赋予写权限:

{
    "Version": "2012-10-17",
    "Id": "efsid",
    "Statement": [
        {
            "Sid": "efssid",
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:ClientWrite",
                "elasticfilesystem:ClientRootAccess"
            ],
            "Resource": "arn:aws-cn:elasticfilesystem:cn-northwest-1:402202783068:file-system/fs-57789eb2",
            "Condition": {
                "StringEquals": {
                    "elasticfilesystem:AccessPointArn": "arn:aws-cn:elasticfilesystem:cn-northwest-1:402202783068:access-point/fsap-068adf52269d7df77"
                }
            }
        }
    ]
}

可以看到这个策略修改的地方是最后的”Condition”段,增加了指定接入点ARN为fsap-068adf52269d7df77 。

接下来我们在管理节点的EC2实例(附加了FSWrite角色)上,通过这个接入点进行挂载,挂载时需要使用 -o tls,iam,accesspoint 参数指定接入点,启用TLS和IAM权限认证:

$ sudo mount -t efs fs-57789eb2:/ -o tls,iam,accesspoint=fsap-068adf52269d7df77 /mnt/efs

接入我们进行写入测试:

$ touch /mnt/efs/test1
$ ls -l /mnt/efs/test1
-rw-rw-r-- 1 1003 1003 0 Feb  7 13:25 /mnt/efs/test1
$ id
uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal)

可以看到我们获得了写入权限,同时写入的文件所有者用户ID和组ID均为接入点所指定的1003,而不是当前命令行的用户id 1000
注意到我们角色的策略里虽然赋予了Rootaccess的权限,但此时即使客户端使用root用户发起请求,EFS还是会以接入点的用户id为准:

$ sudo touch /mnt/efs/test2
$ ls -l /mnt/efs/test2
-rw-rw-r-- 1 1003 1003 0 Feb  7 14:47 /mnt/efs/test2

接下来我们检查接入点是否指定了/data做为根目录。我们重新挂载文件系统,这次挂载不使用任何接入点:

$ sudo umount /mnt/efs
$ sudo mount -t efs fs-57789eb2:/ /mnt/efs

检查相关的目录和文件:

$ ls -l /mnt/efs/data
total 8
-rw-rw-r-- 1 1003 1003 0 Feb  7 13:25 test1
-rw-rw-r-- 1 1003 1003 0 Feb  7 14:47 test2

可以看到/data目录被自动创建出来,刚才通过接入点挂载后创建的文件test1和test2也在其中。

接下来我们检查,如果不通过这个接入点,我们是否还可以通过IAM角色FSWrite获取写入权限:

$ sudo umount /mnt/efs
$ sudo mount -t efs fs-57789eb2:/ -o tls,iam /mnt/efs
$ touch /mnt/efs/test2
touch: cannot touch '/mnt/efs/test2': Read-only file system

可以看到不通过这个接入点访问时,这个角色(FSWrite)也就没有对文件系统的写入权限。
上述示例可以看到,通过将IAM策略与接入点进行结合,我们可以更细粒度的进行NFS客户端的权限设置,以便满足日常管理维护的安全需求。

小结

通过上面的演示,我们可以看到,EFS在NFS文件权限控制的基础上,结合安全组(Security Group),身份与访问管理服务(IAM)和EFS独特的接入点(Access Point)机制,简化权限控制的配置工作,并进行细粒度的权限管理和审计。

参考资料
EFS IAM策略配置: https://docs.aws.amazon.com/efs/latest/ug/iam-access-control-nfs-efs.html
EFS 安全组配置: https://docs.aws.amazon.com/efs/latest/ug/network-access.html
EFS 接入点配置: https://docs.aws.amazon.com/efs/latest/ug/efs-access-points.html
CloudTrail 对 EFS 访问日志记录: https://docs.aws.amazon.com/efs/latest/ug/logging-using-cloudtrail.html

本篇作者

林俊
AWS解决方案架构师,主要负责企业客户的解决方案咨询与架构设计优化,同时致力于AWS云存储及IoT类服务的应用和推广。

原文链接:https://aws.amazon.com/cn/blogs/china/fine-grained-control-of-nfs-file-system-permissions-with-amazon-efs/

相关标签: 云存储云计算