안녕하세요.이토 쿠니히코입니다.*1
Nizi Project から韓国ドラマやK-POP を聞くようになった kunitoo です。
Webアプリケーションを書いていると、アイコン画像やPDFなどファイルをアップロードして保存したいというケースに遭遇すると思います。私が関わってきたプロジェクトではファイル添付する要件が十中八九入っていました。
ファイル添付を実現する Ruby のライブラリは様々ありますが、Rails 5.2 から標準でファイルをアップロードして Active Record モデルにファイルを添付する機能の Active Storage が利用できるようになっています。
今回は Rails を AWS ECS で動作させる場合に Active Storage + S3 を Rails サーバーを介して利用する際に秘匿情報を秘匿して利用する設定方法について書いていきます。
簡単な設定方法
Rails ガイド Active Storage の概要 2 セットアップ に Amazon S3サービスを利用する設定方法について以下のように記載されています。
# config/storage.yml amazon: service: S3 access_key_id: "" secret_access_key: "" region: "" bucket: ""
一番簡単な設定方法としては、IAM で S3 にフルアクセスできるユーザーを作成し、アクセスキーを発行して、その access_key_id
, secret_access_key
を YAML に記載するという方法があります。
しかし、この方法はセキュリティとしてあまりよろしくありません。 よろしくない点としては以下があります。
- IAM ユーザーのAWS S3 アクセスできる権限が強すぎるため、Active Storage に利用するバケット以外にもアクセスできてしまう
- IAM のアクセスキーは流用することができるため、今回利用したい Rails サーバー(ECS) 以外からもアクセスすることができ、キーが漏れると悪用される可能性がある
秘匿情報を秘匿した設定方法
今回はアクセスキーを作成せずに、ECS に必要な必要最低限の権限を付加することで、安全に Active Storage を利用する方法を紹介します。 設定のポイントは以下です。
以下に Terraform を使って実行可能な具体的な設定を記載します。
S3 Bucket を private で作成する
Active Storage で利用する S3 を private で作成します。 これにより、外部からのアクセスを防ぎます。 この状態ではどこからもアクセスができません。
resource "aws_s3_bucket" "images" { bucket = "${local.server_subdomain}images.example.com" acl = "private" }
S3 Bucket にアクセス可能な必要最低限の IAM ポリシーを作成する
ここのポイントは Rails ガイドにも記載されている、s3:ListBucket、s3:PutObject、s3:GetObject、s3:DeleteObject の4つのパーミッションを付与することと、resources に bucket/ とbucket を指定する点です。
はじめはすべてのオブジェクト (bucket/) の指定だけで動作するかと思ったのですが、 バケット全体 (bucket) の指定がないと Active Storage で purge をする際に失敗します。
data "aws_iam_policy_document" "allow_s3_policy" { statement { actions = ["s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject"] resources = [ "${aws_s3_bucket.images.arn}/*", "${aws_s3_bucket.images.arn}" ] } } resource "aws_iam_policy" "allow_s3_policy" { name = "${var.environment}_allow_s3" description = "allow s3 bucket" policy = "${data.aws_iam_policy_document.allow_s3_policy.json}" }
ECS Task ロールに IAM ポリシーをアタッチする
ここのポイントはタスク実行ロールではなくタスクロールにIAMポリシーを設定する点です。
参考のため、ECS task definition を定義する部分までを載せていますが、aws_iam_role_policy_attachment
が重要な点です。
resource "aws_iam_role_policy_attachment" "ecs_task_role_allow_s3" { role = aws_iam_role.ecs_task_role.name policy_arn = aws_iam_policy.allow_s3_policy.arn } resource "aws_iam_role" "ecs_task_role" { name = "${var.environment}EcsTaskRole" path = "/" assume_role_policy = "${data.aws_iam_policy_document.ecs_assume_role_policy.json}" } data "aws_iam_policy_document" "ecs_assume_role_policy" { statement { principals { type = "Service" identifiers = ["ecs-tasks.amazonaws.com"] } actions = ["sts:AssumeRole"] } } resource "aws_ecs_task_definition" "server" { family = "${var.environment}-server" container_definitions = data.template_file.server_container_definitions.rendered execution_role_arn = aws_iam_role.ecs_task_execution.arn task_role_arn = aws_iam_role.ecs_task_role.arn network_mode = "awsvpc" cpu = 256 memory = 512 requires_compatibilities = ["FARGATE"] }
Active Storage の設定
ポリシーを設定することで Rails の設定から access_key_id
, secret_access_key
は不要になり以下を書いておくだけでよくなります。
# config/storage.yml amazon: service: S3 region: ap-northeast-1 bucket: <%= ENV.fetch("AWS_S3_BUCKET_NAME") %>
まとめ
AWS ECS で Rails サーバーを動かす際の Active Storage の設定を IAM ポリシーを適切に設定することで、アクセスキー管理せず、より安全に S3 を利用できるようになりました。
また、具体的な設定方法として Terraform で示しました。
(いくつか記載していないリソースがあるのでそのままでは動作しませんが、実際に構築し動作させたものをベースに記載しています)
AWS で Active Storage を使う際の参考になればと思います。
*1:こんにちは。伊藤邦彦です。