使用S3 Access Point访问S3存储桶

一、背景

S3提供Access Point用于数据分享、访问授权,可用于对外隐藏真实的存储桶名称的同时实施权限控制。S3 Access Point有两种类型:从Internet互联网访问类型,以及仅能从特定VPC访问的类型。此外S3 Access Point也支持跨账户访问。

下面分别进行两种配置。

二、创建可从Internet直接访问的S3 Access Point

1、创建S3 Access Point

相比于从AWS控制台网页界面创建Access Point,命令行AWSCLI的操作更加快捷,只需一条命令即可。

执行如下命令:

aws s3control create-access-point --name mys3ap01 --account-id 420029960748 --bucket s3accesspoint01

请替换mys3ap01为要使用的Access Point的名字(友好名称),替换s3accesspoint01为要分享的Bucket名字。

成功的话返回如下结果。

{
    "AccessPointArn": "arn:aws-cn:s3:cn-north-1:420029960748:accesspoint/mys3ap01"
}
(END)

2、测试从AWSCLI访问

创建完毕后,在AWS控制台图形界面内,进入存储桶,然后找到“访问点”标签页内,可以看到访问点的名称,接下来使用这个名称作为存储桶名来访问S3。如下截图。

从以上界面上,复制下来Access Point alias,也就是类似mys3ap01-h5dzfgteuw8so9j1rdhwdqj9p3puncnn1a-s3alias格式的这一段。

从互联网上的客户端,配置AKSK后,用AWSCLI发起验证是否正常:

aws s3 ls s3://mys3ap01-h5dzfgteuw8so9j1rdhwdqj9p3puncnn1a-s3alias/

由此可看到访问正常。这个别名,也被AWSCLI以外的别的应用程序正确解析出来,可完全视为一个独立的存储痛的名字获得正常访问。

3、存储桶内的文件公开在互联网上接受外部访问

如果希望设置S3公开权限,允许从互联网访问,那么可以进入S3的Access Point界面,找到存储桶内的文件,如下截图。

点击文件后,即可看到这个文件被设置为公开访问后的完整域名。这个域名是本S3 Access Point的友好显示名称+账号ID组成的。由此可以看到,原始S3存储桶的名字和地址被保护了起来。如下截图。

至此配置一个从互联网访问的S3 Access Point访问完成。

三、创建仅在VPC内访问的S3 Access Point

在某些场景下,不希望S3存储桶的文件被从互联网访问,而是仅允许从特定VPC内访问。由此可以配置VPC专用S3 Access Point。

1、在VPC网络服务中创建类型为Gateway Endpoint的S3 VPC Endpoint

使用仅限VPC的S3 Access Point的场景需要将本VPC内访问S3的流量通过VPC路由到S3服务。因此这意味着,所有通过互联网访问S3的客户端都将不能访问这个S3 Access Point。后续的测试都将在VPC内的EC2上进行。

不过在默认状态下,即便是在一个部署了NAT Gateway的私有子网去访问S3,包括AWSCLI和SDK调用的默认的行为依然还是通过互联网访问S3。为了能强制位于VPC内的客户端使用VPC内网访问S3服务,就需要为VPC配置S3 VPC Endpoint。方法如下。

进入VPC服务界面,从左侧菜单中选择终端服务Endpoint,点击右上角的创建按钮。如下截图。

在服务类型中选择类型是左侧第一项AWS服务,在服务搜索框中,输入关键字s3搜索服务名。如下截图。

在搜索结果中,会出现两条S3的Endpoint,右侧的类型分别是InterfaceGateway两种类型。此时需要选中Gateway类型。然后在下方的VPC中选择要授权访问的VPC,在路由表中,选择本VPC内的要访问S3的客户端所在的路由表,例如EC2/EKS所在的子网对应的路由表。接下来继续向下滚动页面。如下截图。

在Policy界面,选择默认的Full access,然后将页面滚动到最下方,点击创建。创建完成。如下截图。

2、验证上一步配置的S3 VPC Endpoint工作是否正常

在创建完毕后,接下来要验证下VPC Endpoint的路由表创建成功,以此确保流量被从VPC内送达S3。验证方法如下。

点击VPC Endpoint的名称,检查标签页路由表,查看是否能显示出来关联的路由表ID。如下截图。

点击上图的路由表ID,跳转到路由表条目的页面,查看下方路由表。如果存在形式为pl-xxxxx这种目的地址条目,且目标路由的下一跳是vpce-xxxxxxxx这种形式的地址,则表示配置S3 VPC Endpoint配置生效。

在本VPC内,使用AWSCLI验证存储桶访问是否正常。此时调用的S3是存储桶原始的名字,而不是S3 Access Point。本步骤是用来验证VPC内的S3流量完全通过VPC传输,而不是在互联网传输。

aws s3 ls s3://s3accesspoint01/

如果正常列出存储桶内的文件,这表示配置正常。

3、创建S3 Access Point

请替换如下命令中的endpiont名字、账户ID、S3桶名、要授权访问的VPC ID、AWS区域的名字,然后执行如下命令:

aws s3control create-access-point --name mys3ap02 --account-id 420029960748 --bucket s3accesspoint01 --vpc-configuration VpcId=vpc-36cf9352 --region cn-north-1

配置成功显示如下信息:

{
    "AccessPointArn": "arn:aws-cn:s3:cn-north-1:420029960748:accesspoint/mys3ap02"
}

创建S3 Access Point完毕。

4、验证S3 Access Point访问正常

创建完毕后,在AWS控制台图形界面内,进入存储桶,然后找到“访问点”标签页内,可以看到这个VPC专用的访问点的名称,接下来使用这个名称作为存储桶名来访问S3。注意名称需要唯一,和前文的S3 Access Point区别开来。如下截图。

执行如下命令:

aws s3 ls s3://mys3ap02-sipdycqfuj3gkiqs9tr9szumkr68gcnn1a-s3alias/

可看到访问正常,成功列出了这个存储桶内的对象。

为了验证S3 Access Point是在特定VPC才能访问,此时可以在位于非本VPC的其他位置对存储桶的S3 Access Point发起访问测试。在VPC外通过Internet访问时候本S3 Access Point会报错:

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

这表示本S3 Access Point是完全针对特定VPC的授权的,由此配置成功。

四、通过S3 Access Point控制访问权限

前文实验中,创建S3 Access Point时候使用的默认授权,这意味着使用S3 Access Point的用户对S3存储桶有完全访问权限。这种完全开放所有权限的场景可能不是最佳安全实践。如果只希望本AWS账户内的某用户通过S3 Access Point对存储桶进行特定的操作(如GetObject只读),那么可按照如下方式配置。

1、创建独立的IAM用户(生成AKSK)并绑定IAM策略

创建一个新的IAM用户,并为这个用户创建AKSK。接下来将要授权这个用户能访问S3 Access Point。

在创建用户完毕后,创建一个IAM Policy,请替换其中的账户ID和S3 Access Point名称为实际环境:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws-cn:s3:cn-north-1:420029960748:accesspoint/mys3ap02/object/*"
        }
    ]
}

以上这段策略由此表示本IAM用户(以及AKSK)可以调用S3 Access Point。然后把这段IAM Policy挂载到刚才创建的用户上。

2、配置S3存储桶策略

进入S3存储桶界面,进入策略界面,找到策略位置,点击编辑。如下截图。

填写配置如下策略。

{
    "Version": "2012-10-17",
    "Statement" : [
    {
        "Effect": "Allow",
        "Principal" : { "AWS": "*" },
        "Action" : "S3:GetObject",
        "Resource" : [ "arn:aws-cn:s3:::s3accesspoint01", "arn:aws-cn:s3:::s3accesspoint01/*" ],
        "Condition": {
            "StringEquals" : { "s3:DataAccessPointAccount" : "420029960748" }
        }
    }]
} 

请替换以上策略中的存储桶ARN为实际的桶的名字,并替换最后一个桶Owner的账户ID为桶的所有人的AWS账户。然后保存存储桶策略。如下截图。

这段策略的作用是,允许S3 Access Point进来的流量执行GetObject访问本存储桶。

3、清空S3 Access Point策略

在S3存储桶配置了对应策略的场景下,S3 Access Point的策略无需配置,留空即可。如果之前配置过,需要将其清空。

清空现有S3 Access Point的方法是,进入S3 Access Point界面,点击策略。接下来向下滚动页面。如下截图。

在S3 Access Point位置可看到当前策略为空,如果不为空,点击删除按钮可清空。

4、验证S3 Access Policy工作正常

首先验证被授权的GetObject行为。执行如下命令,从存储桶内向线下本机复制一个文件,可看到复制成功。

aws s3 cp s3://mys3ap02-sipdycqfuj3gkiqs9tr9szumkr68gcnn1a-s3alias/AWS.png AWS3.png

接下来验证策略中没有授权的PutObject行为。从线下本机向线上存储桶内复制一个文件,可看到没有权限被拒绝。

aws s3 cp AWS.png s3://mys3ap02-sipdycqfuj3gkiqs9tr9szumkr68gcnn1a-s3alias/AWS10.png

返回的拒绝的错误消息是:

upload failed: .\AWS.png to s3://mys3ap02-sipdycqfuj3gkiqs9tr9szumkr68gcnn1a-s3alias/AWS10.png An error occurred (AccessDenied) when calling the CreateMultipartUpload operation: Access Denied

由此,就配置好了一个S3 Access Point,并且只允许被特定IAM用户(以及AKSK)读取对象操作。

五、跨账号访问S3 Access Point获取数据

在某些场景下,还需要提供S3跨账号访问服务,那么可在上一步的基础上,为S3存储桶策略和S3 Access Point策略分别增加跨账号授权。

注意:

  • 跨账号定义是同在AWS国内,或者同在AWS全球海外。由于AWS国内和海外两套体系,因此国内和海外账号之间不可跨账号访问;
  • 跨账号访问的时候,创建基于互联网访问的S3 Access Point比较方便。如果要求是仅限VPC内部的S3 Access Point,那么步骤还会更多一些,因为上一步实验已经创建好的仅限特定VPC的S3 Access Point一经创建是无法修改的,所以跨账号场景下,还需要使用另一个被授权账号的VPC ID来重新创建新的仅限特定VPC的S3 Access Point,且还需要在被授权的账号内应用程序所在的VPC上创建VPC Endpoint,来确保最终用户访问S3的网络流量是仅来自特定VPC的。

本文仅描述使用互联网访问的S3 Access Point的跨账号场景。实现架构如下:

1、配置S3存储桶权限授权跨账号访问

在上一步的配置S3存储桶策略的基础上进行轻微修改,调整其中存储桶所有人账号、和被授权的AWS账号、S3 Access Point名称。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws-cn:iam::被授权的AWS账号12位数字:root"
            },
            "Action": "S3:GetObject",
            "Resource": [
                "arn:aws-cn:s3:::s3accesspoint01",
                "arn:aws-cn:s3:::s3accesspoint01/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointArn": "arn:aws-cn:s3:cn-north-1:存储桶Owner的AWS账号12位数字:accesspoint/mys3ap01"
                }
            }
        }
    ]
}

以上策略表示,授权另一个AWS账号能通过本账号所属的Access Point访问进入。

2、配置S3 Access Point策略

对S3 Access Point配置如下policy,调整其中存储桶所有人账号、和被授权的AWS账号、S3 Access Point名称。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws-cn:iam::被授权的AWS账号12位数字:user/zhangsan01"
            },
            "Action": "S3:GetObject",
            "Resource": "arn:aws-cn:s3:cn-north-1:存储桶Owner的AWS账号12位数字:accesspoint/mys3ap01/object/*"
        }
    ]
}

注意,如果S3存储桶策略和S3 Access Point策略有差别,以存储桶策略为准。例如在存储桶策略上设置GetObject授权,但是在S3 Access Point的策略上授权所有访问动作,那么最终用户依然只能GetObject不能获得其他权限。

3、在另一个AWS账号验证账号访问

在被授权的账号内,分别通过AWSCLI执行cp操作,从S3存储桶向本地cp(即GetObject),并测试从本地向存储桶内复制(PutObject),来验证以上授权是否正确。

经过测试,可发现跨账号下载文件(GetObject)成功,且跨账号上传文件(PutObject)被拒绝(和Policy没有授权写入权限的行为是一致的)。

六、参考资料

https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-policies.html