🪣

RCPs (Resource Control Policies) で S3 のHTTP通信をブロックするガードレールを敷く

に公開

こんにちは、Finatextの @s_tajima です。

2026年現在、インターネットの世界では、HTTPSの通信を行うのが当たり前になりました。
Googleによる透明性レポートによる統計情報も、それを示しています。
https://transparencyreport.google.com/https/overview

AOSSLという言葉もありましたが、今や誰もこの言葉を使っていないこともそれを証明していると思います。

言うまでもなく、暗号化のされていないHTTPの通信というのは、盗聴や改ざんのリスクにさらされていて様々なリスクがあります。一方で、驚くべきことに、2026年においても、AWSではS3を始め、いくつかのサービスは引き続きHTTPでのアクセスができてしまいます。

一応、今までもバケットポリシーやSCPsでHTTP通信を制限することはできましたが、これらの方法は理想的なものではありませんでした。今回は、AWSが2024年にリリースしたRCPs (Resource Control Policies)の機能を使い、より洗練された方法で組織全体のS3(等)のHTTP通信をブロックする方法についてお伝えします。

※本記事での HTTP という表現は、HTTPSでの暗号化された通信を含まない、平文の通信のみを意味します。

AWSでのHTTP通信の例

まず最初に、S3バケットに対して実際にHTTP通信ができる様子をお見せします。
具体的な方法としては、APIを呼び出す際のEndpoint URLを、httpにするだけです。

AWS CLIを使う場合は、以下のように --endpoint-url を指定することで実現できます。

$ aws s3api get-object --bucket s-tajima-http-test --key test.txt --endpoint-url http://s3.ap-northeast-1.amazonaws.com/ /dev/stdout
test

Wiresharkで観測すると、実際にHTTPで通信されていることもわかります。

Resource Control Policies (RCPs) とは

今回は、このS3バケットへのHTTPの通信を、Resource Control Policies (RCPs)という機能で制限する方法を紹介するのですが、最初に簡単にRCPsについて紹介します。

RCPs は、AWS Organizations 上で管理される「リソースに対するガードレール用ポリシー」です。
例えば、特定リージョン以外での利用を禁止したり、インターネットからのアクセスを禁止したり、今回のように「HTTPS で暗号化されていない HTTP 通信は許可しない」といった制約を、対象リソース(S3バケットやSQSのQueueなど)に対して一括で適用できます。
これにより、各アカウントの個別設定やバケットポリシーの書き方に依存せず、組織全体として一貫したセキュリティポリシーを適用できるのが特徴です。

似た仕組みとして AWS Organizations の SCPs (Service Control Policies) がありますが、SCPs は「アカウント内のプリンシパル(ユーザ / ロールなど)が最大どの操作まで実行できるか」を制限するもので、プリンシパル側の最大アクセス許可 を定義します。
一方で RCPs は、「組織内のリソースがどのように利用されてよいか」を制御する、リソース側の最大アクセス許可 です。どれだけ強い権限を持つロールが存在していても、RCPs で禁止されている条件下では、そのリソースに対する操作は失敗します。

このように、SCPs と RCPs はどちらも組織レベルのガードレールとして機能する仕組みですが、前者は「誰(プリンシパル)」、後者は「何(リソース)」に対する制御で役割が異なります。本記事では、この RCPs を使って S3 への HTTP 通信を組織横断でブロックする方法を見ていきます。

HTTP通信を防ぐためのRCPsの設定

今回は、RCPsで以下のようなポリシーを設定しました。

{
  "Version" : "2012-10-17",
  "Statement" : [
    {
      "Effect" : "Deny",
      "Principal" : "*",
      "Action" : [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "NotResource" : [
        "arn:aws:s3:::BUCKET_NAME/*", // 除外したいバケット
      ],
      "Condition" : {
        "StringNotEquals" : {
          "aws:ResourceAccount" : [
            "123456789012", // 除外したいAWS Account ID
          ]
        },
        "BoolIfExists" : {
          "aws:SecureTransport" : "false"
        }
      }
    }
  ]
}

この設定により、

  • s3:GetObjectとs3:PutObjectのHTTPでの通信を制限する。
  • この制限を、AWS Organizationレベルで導入し、新規のAWSアカウントやS3バケットに対しても自動的に制限が入る。
  • ただし、AWSアカウントのIDやS3バケットを個別に指定し、制限の対象から除外できる。

というのを実現しています。

このポリシーを設定すると、今まで通っていたHTTPのアクセスが、以下のように制限されるようになります。

$ aws s3api get-object --bucket s-tajima-http-test --key test.txt --endpoint-url http://s3.ap-northeast-1.amazonaws.com/ /dev/stdout

An error occurred (AccessDenied) when calling the GetObject operation: User: arn:aws:iam::872515287518:user/http-test is not authorized to perform: s3:GetObject on resource: "arn:aws:s3:::s-tajima-http-test/test.txt" with an explicit deny in a resource control policy

今までの手段との違い

RCPsの登場前にも、S3バケットへのHTTPの通信を制限する手段は存在していました。
一方で、これらの方法は機能的にはイマイチな点があったので、その点についてもふれておきます。

バケットポリシー

一番古くから存在する方法が、このバケットポリシーに設定する方法です。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/example-bucket-policies.html#example-bucket-policies-HTTP-HTTPS

この方法は、当然のことながら1つひとつすべてのバケットで設定をする必要があり、大規模な環境では対応が大変という課題がありました。

SCPs

もう一つの方法は、SCPs (Service Control Policies) を使う方法です。
https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_policies_scps.html

この方法は、Organization全体に一括で制限を入れられるという観点では、バケットポリシーよりも有用でした。
一方で、SCPsでの制限は、組織内のプリンシパルに対してのみ有効です。これはつまり、Organization外のプリンシパルからのクロスアカウントアクセスにおいては、制限が有効にならず、HTTPでの通信ができてしまうという問題がありました。

RCPsでのブロックを有効化する前の事前調査

万が一、既存のワークロードでHTTPの通信があると、制限を有効化したタイミングでシステムの稼働に影響がでてしまうので、事前に影響の有無を確認しておく必要があります。
影響の確認方法はいくつかの手段があるので、それらの方法を紹介します。

S3のサーバーアクセスログでの確認

S3のサーバーアクセスログを見るのが一番確実な方法です。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/ServerLogs.html

ログの中の、 TLS version のフィールドの値を確認し、 - (TLS wasn't used) の行がなければHTTP通信をしていないと判断できます。

CloudTrail & IAM Access Analyzerの確認

基本的には、S3のサーバーアクセスログを使って確認すればよいのですが、Organization内全体での制限を有効化する場合に、すべてのバケットにおいてログが出力できていないケースがあるかもしれません。

そんな場合でも、CloudTrailを使えば、代替した調査をすることができます。
具体的には、CloudTrailの tlsDetails のフィールドを参照します。
https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-event-reference-record-contents.html

このフィールドが空になっているレコードがなければ、HTTP通信をしていないと判断できます。

ただし、CloudTrailで確認できるのは、組織内のプリンシパルからのアクセスのみです。つまり、Organization外のプリンシパルからのクロスアカウントアクセスに関するログは記録されていません。(SCPsと同じような制約です。)

そこで、 IAM Access Analyzer の External Access Analyzer も組み合わせて使うことで、クロスアカウントアクセスが可能になっているバケットの特定をセットで行います。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access-analyzer-resources.html#access-analyzer-s3

これにより、クロスアカウントアクセスが可能なバケットがなければ、CloudTrailによる調査のみで完結でき、もしクロスアカウントアクセスが可能なバケットがあれば、S3のサーバーアクセスログを有効にして確認するという対応ができます。

最後に

RCPsを活用することで、今回紹介したS3だけでなく、以下のドキュメントにあるように、SQS等他のサービスのHTTP通信も制限することができるようになります。(弊社では実際にはS3以外も対象とした設定を有効にしています。)
https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html

以上、RCPsを使ってS3へのHTTP通信を制限する方法のご紹介でした。

Finatext Tech Blog

Discussion