Amazon Web Services ブログ

AWS Amplify Hosting でサーバーサイドレンダリングのための IAM Compute Roles

今日、AWS Amplify Hosting は、AWS Amplify アプリケーションの IAM Compute Roles を導入しました。これにより、コンピュート実行時から AWS サービスへの安全なアクセスを可能にし、サーバーサイドレンダリング機能を拡張できるようになりました。IAM Compute Roles を使えば、開発者はサーバーサイドレンダリングアプリに特定の権限を付与でき、Amplify が他の AWS サービスへの承認された呼び出しを行えるようになります。この新機能により、セキュリティのベストプラクティスを維持しながら、開発プロセスを加速できます。

主な機能

IAM Compute Roles を使えば、以下のことができるようになりました。

  1. Next.js API ルートから AWS Secrets ManagerAWS Systems Manager Parameter Store を使用して、ランタイムで機密設定データにアクセスできます。
  2. SSR アプリを Amazon RDSAmazon DynamoDB などの AWS データベースに直接接続できます。
  3. AWS Identity and Access Management (IAM) ポリシーを使用して、コンピューティング環境に細かい権限を定義できます。
  4. サーバーサイドコードから任意の AWS サービスに対して、安全な認証済みの呼び出しができます。

チュートリアル

始める前に、IAM コンピューティング ロールを作成し、それを Amplify Next.js アプリケーションに関連付ける次の手順に従ってください。

前提条件

始める前に、以下がインストールされていることを確認してください。

IAM Compute Roles の作成

Amplify Hosting の SSR コンピューティングサービスが、ロールの権限と信頼関係に基づいて、AWS リソースに安全にアクセスできるように、IAM ロールを作成しましょう。この例では、Amazon Simple Storage Service (Amazon S3) バケットに安全にアクセスします。

  1. AWS マネジメントコンソールにサインインし、IAM コンソールに移動します
  2. Access Management タブの下で、Roles を選択し、Create role を選びます
  3. Custom trust policy を選択し、Amplify がこのロールを引き受けることができるように、以下のポリシーを入力します:
{
    "Version": "2012-10-17",
    "Statement": [ 
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [ 
                    "amplify.amazonaws.com"
                ] 
            },
            "Action": "sts:AssumeRole"
        }
    ] 
}
JSON
  1. AWS 管理の AmazonS3ReadOnlyAccess 権限ポリシーをロールに追加し、Next を選択します
  2. ロールに amplify-compute-role という名前を付け、Create Role を選択します

Amplify が他の AWS サービスに接続するために引き受けることができるコンピュートロールを正常に作成しました。

セキュリティのベストプラクティス: 最小特権の原則を実施し、特定のユースケースに必要な権限のみを付与してください。

Amazon S3 バケットの作成

Next.js アプリが IAM Compute Roles を使用して安全にアクセスできる、プライベートの Amazon S3 バケットを設定します。Amazon S3 オブジェクトを公開したり、アクセスキーを管理するのではなく、Amplify Hosting の IAM Compute Roles を使って Amazon S3 からプライベートコンテンツを安全に取得します。

  1. AWS マネジメントコンソールにサインインし、Amazon S3 コンソールに移動します
  2. Create bucket を選択し、一意のバケット名を入力します
  3. ACL を無効にし、Block all public access を有効にしたままにします。

  1. デフォルトの設定のままで、Create bucket を選択します。
  2. バケットへ移動し、Upload を選択します。
  3. 画像 (例: amplify-logo.png) をアップロードします。

セキュリティの検証: S3 バケットが完全にロックダウンされていることを確認するには、次の get-public-access-block AWS CLI コマンドを実行してください:

// Note: Replace amplify-compute-role-demo with your specific bucket name 
 aws s3api get-public-access-block --bucket amplify-compute-role-demo
Bash

出力結果は次のようになるはずです。

{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": true,
        "RestrictPublicBuckets": true 
    }
}
JSON

これらの設定は以下を保証します。

  • パブリック ACL の作成はできません
  • 既存のパブリック ACL は無視されます
  • パブリックバケットポリシーはブロックされます
  • バケットへのパブリックアクセスが制限されます

Next.js アプリの作成

次に、API ルートを使用して Amazon S3 バケットからプライベートコンテンツの画像にセキュアにアクセスできる Next.js アプリを作成します。

  1. 新しい Next.js 15 アプリを TypeScript と Tailwind CSS で作成します。
npx create-next-app@latest compute-role-demo --typescript --tailwind --eslint 
 cd compute-role-demo
Bash
  1. JavaScript 用の AWS SDK の S3 Client パッケージをインストールします。
npm install @aws-sdk/client-s3
Bash
  1. Amazon S3 Image API のルートを作成します。Amplify Hosting へのアプリケーションのデプロイ
// app/api/image/route.ts

import { S3Client, GetObjectCommand, S3ServiceException } from "@aws-sdk/client-s3";
import { NextResponse } from 'next/server';

const s3Client = new S3Client({});

const BUCKET_NAME = 'amplify-compute-role-demo';
const IMAGE_KEY = 'amplify-logo.png';

export async function GET() {
  console.log(`[S3 Image Request] Starting - Bucket: ${BUCKET_NAME}, Key: ${IMAGE_KEY}`);
  
  try {
    console.log('[S3 Image Request] Creating GetObjectCommand...');
    const command = new GetObjectCommand({
      Bucket: BUCKET_NAME,
      Key: IMAGE_KEY
    });

    console.log('[S3 Image Request] Sending request to S3...');
    const response = await s3Client.send(command);
    console.log('[S3 Image Request] Received S3 response:', {
      contentType: response.ContentType,
      contentLength: response.ContentLength,
      metadata: response.Metadata
    });

    console.log('[S3 Image Request] Converting response to byte array...');
    const buffer = await response.Body?.transformToByteArray();

    if (!buffer) {
      console.error('[S3 Image Request] No buffer received from S3');
      throw new Error('No image data received from S3');
    }

    console.log('[S3 Image Request] Successfully processed image:', {
      bufferSize: buffer.length,
      contentType: response.ContentType
    });

    return new NextResponse(buffer, {
      headers: {
        'Content-Type': response.ContentType || 'image/png',
        'Cache-Control': 'public, max-age=31536000, immutable'
      }
    });

  } catch (error) {
    if (error instanceof S3ServiceException) {
      console.error('[S3 Image Request] AWS S3 Error:', {
        message: error.message,
        code: error.name,
        requestId: error.$metadata?.requestId,
        statusCode: error.$metadata?.httpStatusCode
      });
    } else {
      console.error('[S3 Image Request] Unexpected error:', error);
    }

    return NextResponse.json({
      success: false,
      error: 'Failed to load content'
    }, { 
      status: 500 
    });
  } finally {
    console.log('[S3 Image Request] Request completed');
  }
}
TypeScript
  1. クライアントコンポーネントを作成します。
// app/components/S3Component.tsx

'use client';

import { useState } from 'react';
import Image from 'next/image';

export default function S3Component() {
  const [imageError, setImageError] = useState(false);
  const [isRevealed, setIsRevealed] = useState(false);

  return (
    <div className="absolute inset-0 top-[88px] flex items-center justify-center">
      <div className="w-full max-w-2xl rounded-2xl mx-4">
        <div className="flex flex-col items-center justify-center min-h-[400px] p-8">
          {!isRevealed ? (
            <button
              onClick={() => setIsRevealed(true)}
              className="px-8 py-4 bg-[rgb(117,81,194)] text-white text-lg rounded-xl 
                       hover:bg-[rgb(107,71,184)] transition-colors"
            >
              <span className="flex items-center gap-2">
                Access Private S3 Bucket
                <span className="text-xl"></span>
              </span>
            </button>
          ) : (
            <div className="space-y-8 w-full">              
              {!imageError && (
                <div className="relative h-64 w-full">
                  <Image 
                    src="/api/image"
                    alt="Amplify Logo"
                    fill
                    unoptimized
                    priority
                    onError={() => setImageError(true)}
                    className="object-contain"
                    sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
                  />
                </div>
              )}
              
              <div className="text-center">
                <p className="text-gray-400 text-sm">
                  This content is securely served from S3 using an IAM Compute Role.
                </p>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
TypeScript
  1. ホームページを更新して、クライアントコンポーネントをレンダリングします。
import S3Component from './components/S3Component';

export default function HomePage() {
  return (
    <div className="relative min-h-screen bg-[rgb(0,0,0)]">
      <h1 className="text-2xl font-bold text-white py-8 text-center relative z-10">
        Amplify Hosting Compute Role Demo
      </h1>
      <S3Component />
    </div>
  );
}
TypeScript
  1. 変更を git リポジトリにプッシュします。
    1. 新しい GitHub リポジトリを作成します
    2. 変更内容を Git ブランチに追加してコミットします
    3. リモート オリジンを追加し、変更内容をアップストリームにプッシュします
git add .
git commit -m "initial commit"
git remote add origin https://github.com/<OWNER>/amplify-compute-role-demo.git
git push -u origin main
Bash

Amplify Hosting へのアプリケーションのデプロイ

  1. AWS マネジメントコンソールにサインインし、Amplify コンソールに移動します。
  2. Create new app を選び、リポジトリソースとして GitHub を選択します。
  3. Amplify が GitHub アカウントにアクセスできるように認証します。
  4. 作成したリポジトリとブランチを選択します。
  5. アプリの設定を確認し、Next を選択します。
  6. 全体の設定を確認し、Save and Deploy を選択します。

IAM Compute Roles を Amplify アプリに割り当てる

  1. Amplify コンソールでアプリを選択し、「App settings > IAM roles」に進みます

  1. コンピュート ロールのセクションで Edit を選択します

  1. ロールメニューから amplify-compute-role を選択し、Save を選んでください
  2. ブランチごとに固有のコンピュートロールを使うようにブランチ上書きを設定することもできます。これは開発、ステージング、プロダクションなど、さまざまな Git 環境間で特に役立ちます。

Next.js アプリへのアクセス

Amplify コンソールのアプリの Overview タブに移動し、ブラウザ上で Amplify が生成したデフォルトの URL を開いてください。

次に、Access Private S3 ボタンを選択してください。Amazon S3 バケットにアップロードされた画像が表示されるはずです。

ホスティングコンピューティングのログのレビュー

アプリのホームページから、[Hosting] > [Monitoring] に移動し、Hosting compute logs タブを選択してください。

Amazon CloudWatch の Log Streams URL に移動し、最新のログストリームを確認してください。ログには Amazon S3 からの画像リクエストが含まれるはずです:

おめでとうございます! Amplify Hosting の Next.js SSR アプリケーションに、IAM Compute Roles を正常に作成して割り当てました。これで、プライベート Amazon S3 バケットからコンテンツを安全に取得できるようになりました! 🚀

クリーンアップ

  1. AWS Amplify アプリを削除するには、[ アプリ設定 ] > [ 全般設定 ] に移動し、[ アプリの削除 ] を選択します。
  2. Amazon S3 バケットを削除するには、S3 コンソールから [ バケットを選択 ] > [ 削除を選択 ] > 削除を確認するためにバケット名を入力します。
  3. IAM ロールを削除するには、IAM コンソールから [ ロールを選択 ] > amplify-compute-role 名を探し > [ 削除を選択 ] > 削除を確認するためにロール名を入力します。

まとめ

AWS Amplify Hosting は現在、サーバーサイドレンダリング (SSR) アプリケーションの IAM Compute Roles をサポートし、AWS サービスへのセキュアなアクセスの課題を解決しています。以前は、開発者が環境変数を介して手動で認証情報を管理していました。しかし、IAM Compute Roles を使えば、開発者は SSR アプリに直接 IAM アクセス許可を割り当てられるため、サービスの統合が簡単になり、セキュリティが強化されます。

SSR アプリに IAM Compute Roles を追加するには今日、Amplify ドキュメントをご覧ください。

本記事は「IAM Compute Roles for Server-Side Rendering with AWS Amplify Hosting」を翻訳したものです。

著者について

Photo of author

Jay Raval

Jay Raval is a Solutions Architect on the AWS Amplify team. He’s passionate about solving complex customer problems in the front-end, web and mobile domain and addresses real-world architecture problems for development using front-end technologies and AWS. In his free time, he enjoys traveling and sports. You can find Jay on X @ _Jay_Raval_

Photo of author

Matt Auerbach

Matt Auerbach is a NYC-based Product Manager on the AWS Amplify Team. He educates developers regarding products and offerings, and acts as the primary point of contact for assistance and feedback. Matt is a mild-mannered programmer who enjoys using technology to solve problems and making people’s lives easier. B night, however … well he does pretty much the same thing. You can find Matt on X @ mauerbac. He previously worked at Twitch, Optimizely & Twilio.

翻訳者について

Photo of author

稲田 大陸

AWS Japan で働く筋トレが趣味のソリューションアーキテクト。普段は製造業のお客様を支援しています。年明け 4 kg 太ったので、ダイエットに励んでいます。好きな AWS サービスは Amazon Location Service と AWS Amplify で、日本のお客様向けに Amazon Location Service の解説ブログなどを執筆しています。