特定の IP アドレス または CloudShell からのみ S3 バケットにアクセス可能に制限する方法を教えてください

特定の IP アドレス または CloudShell からのみ S3 バケットにアクセス可能に制限する方法を教えてください

Clock Icon2024.11.22

困っていること

特定の IP アドレス または CloudShell からのみ S3 バケットへのアクセスを制限する方法を教えてください。

S3 バケットポリシーで aws:SourceIpaws:ViaAWSService を使用して、特定の IP アドレス または CloudShell からのみアクセス可能にしようとしましたが、 CloudShell からアクセスする際に AccessDenied エラーが発生しアクセスできません。

<バケットポリシーの例>

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAccessFromNonSpecificIPsOrCloudShell",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::hogehoge-bucket",
                "arn:aws:s3:::hogehoge-bucket/*"
            ],
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "203.0.113.0/24"
                    ]
                },
                "Bool": {
                    "aws:ViaAWSService": "false"
                }
            }
        }
    ]
}

どう対応すればいいの?

S3 バケットポリシー側で CloudShell からのアクセスを識別することはできません。
そのため、 CloudShell を利用する際の IAM ロールに許可したい IP アドレスを指定した信頼ポリシーを設定することでアクセスを制限します。

IAM ロールの作成

まず、 CloudShell を利用する際に使用するための IAM ロールを作成します。

許可ポリシーには S3 と CloudShell にアクセスできるようにポリシーをアタッチします。最小権限の原則に従い、S3 へのアクセスにはオブジェクトの取得のみできれば良いので s3:GetObject のみを設定し、加えて CloudShell へのアクセスに必要なポリシーを設定します。

<許可ポリシーの例>

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"

            ],
            "Resource": [
                "arn:aws:s3:::hogehoge-bucket/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudshell:*"
            ],
            "Resource": "*"
        }
    ]
}

次に、ここがアクセス制限のポイントになりますが、信頼ポリシーには aws:SourceIp で IP アドレスを指定することで、スイッチロール可能な IP アドレスを制限します。

<信頼ポリシーの例>

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAssumeRoleFromSpecificIPs",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<アカウントID>:user/hogehoge"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "203.0.113.0/24" // ←許可したい IPアドレスを指定
                }
            }
        }
    ]
}

S3 バケットポリシーの設定

次に、先ほど作成した IAM ロールからのみアクセスを許可するように S3 バケットポリシー側を設定します。

<バケットポリシーの設定例>

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAccessFromNonSpecificRoles",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::hogehoge-bucket",
                "arn:aws:s3:::hogehoge-bucket/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::<アカウントID>:role/CloudShellAccessRole" // ←先ほど作成した IAM ロールの ARN を指定
                }
            }
        }
    ]
}

CloudShell から S3 にアクセスして確認

あとは作成した IAM ロールにスイッチロールして CloudShell を立ち上げることで、 S3 バケットにアクセスできることを確認します。

<CloudShell でのコマンド実行例>

[cloudshell-user@ip-203-0-113-0 ~]$ aws sts get-caller-identity
{
    "UserId": "AROAUFMHGPF**********:hogehoge",
    "Account": "<アカウントID>",
    "Arn": "arn:aws:sts::<アカウントID>:assumed-role/CloudShellAccessRole/hogehoge"
}
[cloudshell-user@ip-203-0-113-0 ~]$ aws s3 cp test.txt s3://hogehoge-bucket/
upload: ./hello.txt to s3://hogehoge-bucket/test.txt

スイッチロールできない場合は、 IP アドレスが IAM ポリシー側で許可したものと一致しているか、checkip.amazonaws.com にアクセスして自分の IP アドレスをご確認ください。

また、 AccessDenied エラーが発生する場合は、 IAM ポリシーの設定やバケットポリシーの設定に誤りがないかトラブルシューティングします。

アクセス拒否エラーメッセージをトラブルシューティングする - AWS Identity and Access Management

補足: なぜ CloudShell からのアクセスに対して aws:SourceIPaws:ViaAWSService は利用できないのか

aws:ViaAWSService に対応する AWS サービスは aws:CalledVia に対応するサービスと同一で、 CloudFormation や Athena 等、一部のサービスに限られます。そのため、CloudShell からのアクセスに対して aws:ViaAWSServicefalse と判定されます。

AWS グローバル条件コンテキストキー - AWS Identity and Access Management

いずれかのサービスがプリンシパルの認証情報を使用してリクエストを実行したときにアクセスを許可または拒否するには、 aws:ViaAWSService 条件キーを使用します。この条件キーは、AWS サービスをサポートします。

それならば CloudShell からのアクセスについても IP アドレスで制限しようと考えますが、 AWS から公開されている IP アドレス範囲 には CloudShell に限定した IP アドレスの範囲はなく、逆に IP アドレスによってアクセス元のサービスを特定する方法もないため 、IP アドレスで制限することは実質的に困難です。

また、 代替案 として aws:UserAgent で CloudShell からのアクセスを識別する方法が以前に公式ドキュメントより案内されていましたが、執筆時点ではこの記載は削除されており、また User-Agent はリクエスタ側で改ざんが可能である性質を考慮すると、この方法は現時点では推奨されないものと考えます。

参考資料

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.