# 防止 IAM 角色从 VPC 外部访问S3存储桶

<figure><img src="https://3752289132-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LTfg4e0NhLEbwi6WFJp%2Fuploads%2FTznzcm2iZlhac5AKL4PV%2Fimage.png?alt=media&#x26;token=1939c14c-7970-4994-8157-fb7ba4b731da" alt=""><figcaption></figcaption></figure>

您可以看到，到 S3 存储桶的流量是通过 VPC 网关端点传输的，该端点用于 VPC 内的应用程序，而不是通过公共互联网。这是一种最佳做法！不过，我们还需要确保只有我们授权的 IAM 角色才能访问 S3 存储桶，而且只能从我们的 VPC 访问。

## S3存储桶策略

拷贝下面的存储桶策略，替换`<BUCKET_NAME>` 为你自己的存储桶名称，替换`<VPC_ENDPOINT_ID>` 为你的VPC终端ID。

```
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "DenyInsecureConnections",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ],
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        },
        {
            "Sid": "Access-to-specific-VPCE-only",
            "Principal": "*",
            "Action": [
                "s3:GetObject*",
                "s3:PutObject*",
                "s3:DeleteObject*"
            ],
            "Effect": "Deny",
            "Resource": "arn:aws:s3:::<BUCKET_NAME>/*",
            "Condition": {
                "StringNotEquals": {
                    "aws:sourceVpce": "<VPC_ENDPOINT_ID>"
                }
            }
        }
    ]
}

```

## VPC Endpoint

如果没有 S3 的 VPC 端点，从 EC2 实例到 S3 的网络连接会通过互联网网关出VPC，然后返回 AWS 网络，从其公共端点到达 S3。有了 VPC 端点，这些网络流量就会保留在 AWS 私有网络中。

打开 [VPC Endpoints ](https://console.aws.amazon.com/vpc/home?region=us-west-2#Endpoints:sort=tag:Name) 控制台，选择需要修改的VPC端点，在策略中添加 [Condition ](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html)，可以参考[VPC端点策略(VPC endpoint policies)示例策略](https://github.com/aws-samples/data-perimeter-policy-examples/tree/main/vpc_endpoint_policies)进行设计，如果是EC2代入role进行访问的，则设置可以访问的角色是哪一个。

VPC端点的策略建议设置如下：

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:ListBucket",
                "s3:GetBucketPolicy",
                "s3:GetObjectAcl",
                "s3:PutObjectAcl",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ],
            "Condition": {
                "Bool": {
                    "aws:PrincipalIsAWSService": "true"
                },
                "StringEquals": {
                    "aws:PrincipalOrgID": "<my-org-id>",
                    "aws:ResourceOrgID": "<my-org-id>"
                },
                "ArnEquals": {
                    "aws:PrincipalArn": "<THE_ROLE_ARN>"
                }
            }
        }
    ]
}

```

## 从预期的网络才能访问S3存储桶

为了实现控制目标，您可以编写一个AWS服务控制策略（SCP），以确保您的应用程序的临时凭证只能在您期望的网络空间内访问您的S3存储桶。根据提供的信息，您可以使用SCP来限制对S3的访问，以确保只有在特定网络空间内的应用程序才能访问该存储桶。

以下是一个示例SCP，用于实现您的控制目标：

在上面的示例中，这个SCP将拒绝所有对S3存储桶的操作，除非请求来自于指定的IP地址范围（您期望的网络空间）。您需要将示例中的"your-s3-bucket-name"替换为您的S3存储桶名称，并根据您的网络空间配置正确的IP地址范围。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::your-s3-bucket-name",
                "arn:aws:s3:::your-s3-bucket-name/*"
            ],
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "192.168.1.0/24",  // 期望的网络空间IP范围
                        "10.0.0.0/16"
                    ]
                }
            }
        }
    ]
}
```
