Skip to Content

ステップ3:Cognitoによる認証・ユーザー管理システムの構築

今回のステップの概要とライブ配信アプリとの関連について

このステップでは、ステップ2で基本的な認証機能を実装したCognitoシステムを拡張し、配信者・視聴者・管理者の役割分担高度なユーザー管理機能を実装します。具体的には、IAMロールとポリシーによる権限管理、配信者専用管理画面の作成、視聴者認証によるパーソナライズ機能を構築します。

ライブ配信アプリケーションにとって、高度な認証・ユーザー管理システムは「会場への入場券チェックとVIP席の区別をする仕組み」のような役割を果たします。コンサート会場で一般席、VIP席、関係者席があるように、ライブ配信でも「視聴者」「プレミアム会員」「配信者」「管理者」など、ユーザーの種類に応じて異なる権限と機能を提供する必要があります。これにより、有料配信、限定配信、年齢制限付きコンテンツなど、多様なビジネスモデルに対応できます。

このステップで学ぶこと

リソースの関わりと構成説明

ステップ3で作成するリソースは、ライブ配信アプリケーションの高度なユーザー管理機能を構築するものです。それぞれのリソースがライブ配信アプリケーションにどのように関わるのかを説明します。

Cognitoグループとライブ配信アプリの関わり

Cognitoグループ「ユーザー役割管理」は、ライブ配信アプリケーションの「会場の座席区分システム」のような役割を果たします。一般視聴者、プレミアム会員、配信者、管理者など、それぞれの役割に応じて異なる機能にアクセスできます。これにより、配信者のみが配信開始・停止でき、プレミアム会員のみが特別なチャット機能を使用でき、管理者のみがユーザー管理を行えるなど、きめ細かい権限制御が可能になります。

IAMロールとライブ配信アプリの関わり

IAMロール「権限管理システム」は、ライブ配信アプリケーションの「警備員の権限証明書」のような役割を果たします。各ユーザーの役割に応じて、どのAWSリソースにアクセスできるかを厳密に制御します。配信者はIVSチャンネルの操作権限、管理者はユーザー管理権限、視聴者はチャット参加権限のみを持つことで、セキュリティを確保しながら必要な機能を提供できます。

API Gatewayとライブ配信アプリの関わり

API Gateway「セキュアなAPI管理」は、ライブ配信アプリケーションの「受付カウンター」のような役割を果たします。フロントエンドからのリクエストを受け取り、認証状態と権限を確認してから、適切なLambda関数やAWSサービスに処理を転送します。これにより、不正なアクセスを防ぎながら、ユーザーに必要な機能を安全に提供できます。

実際の手順

実際の手順では、たくさんの設定値を入力することになります。 本文中に設定値が指定されていない場合は、デフォルト値のまま作業を進めてください。

1. Cognitoグループによる役割ベースアクセス制御

ユーザーの役割に応じたグループを作成し、権限を管理します。

Note

AWSでの役割

Cognitoグループは、ユーザーの役割に基づいてアクセス制御を行う機能です。

特徴:

  • ユーザーを複数のグループに所属させることが可能
  • グループごとにIAMロールを割り当て可能
  • 動的な権限変更(グループの追加・削除)が可能
  • JWTトークンにグループ情報が自動的に含まれる

オンプレミスでの対応

オンプレミス環境では「LDAP + Active Directory」が対応します。

  • ディレクトリサービスでのユーザーグループ管理
  • アプリケーションレベルでの権限チェック実装
  • データベースでのユーザー・ロール・権限テーブル設計

1-1. Cognitoグループの作成

  1. AWSマネジメントコンソールでCognitoユーザープールにアクセスします
  2. 「グループ」タブを選択し、「グループを作成」をクリックします
  3. 以下のグループを作成します:

Streamersグループ(配信者)

  • グループ名: Streamers
  • 説明: 配信を行うユーザー
  • 優先度: 1 (最高優先度)

PremiumViewersグループ(プレミアム視聴者)

  • グループ名: PremiumViewers
  • 説明: 有料機能を利用できる視聴者
  • 優先度: 2

Viewersグループ(一般視聴者)

  • グループ名: Viewers
  • 説明: 一般的な視聴者
  • 優先度: 3

Administratorsグループ(管理者)

  • グループ名: Administrators
  • 説明: システム管理者
  • 優先度: 0 (最高権限)

Cognitoグループ作成画面

1-2. IAMロールの作成と割り当て

各グループに対応するIAMロールを作成します:

Streamersロール

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ivs:CreateChannel", "ivs:DeleteChannel", "ivs:UpdateChannel", "ivs:GetChannel", "ivs:ListChannels", "ivs:GetStream", "ivs:StopStream", "ivs:GetStreamKey", "ivs:ListStreamKeys", "ivschat:CreateChatToken", "ivschat:SendMessage", "ivschat:DisconnectUser" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::live-streaming-metadata-*/*" } ] }

注意: IVSでは配信の開始は配信者がストリームキーを使用して映像をプッシュすることで自動的に行われるため、StartStreamアクションは存在しません。配信の停止にはStopStreamアクションを使用します。

PremiumViewersロール

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ivschat:CreateChatToken", "ivschat:SendMessage" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:GetObject" ], "Resource": "arn:aws:s3:::live-streaming-premium-content/*" } ] }

Viewersロール

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ivschat:CreateChatToken" ], "Resource": "*", "Condition": { "StringEquals": { "ivschat:ChatRoomArn": "arn:aws:ivschat:*:*:room/public-*" } } } ] }
Tip

【解説】IAMポリシーの最小権限の原則

IAMポリシーでは「最小権限の原則」に従い、各役割に必要最小限の権限のみを付与します。配信者は配信関連の操作権限、視聴者はチャット参加権限のみを持ちます。

条件(Condition)を使用することで、さらに細かい制御が可能です。例えば、一般視聴者は公開チャットルームのみアクセス可能に制限できます。

この設計により、セキュリティインシデントが発生した場合でも、被害を最小限に抑えることができます。

2. API GatewayによるセキュアなAPI設計

ユーザー認証と権限チェックを行うAPIを構築します。

2-1. API Gatewayの基本設定

  1. AWSマネジメントコンソールで「API Gateway」サービスにアクセスします
  2. 「REST API」を選択し、「構築」をクリックします
  3. 以下の設定を行います:
    • API名: live-streaming-api
    • 説明: ライブ配信アプリケーション用API
    • エンドポイントタイプ: リージョン

2-2. Cognitoオーソライザーの設定

  1. 作成したAPIの「オーソライザー」タブを選択します

  2. 「オーソライザーを作成」をクリックし、以下を設定:

    • 名前: CognitoAuthorizer
    • オーソライザータイプ: Cognito
    • Cognitoユーザープール: 先ほど作成したユーザープールを選択
    • トークンソース: Authorization (HTTPヘッダー名)
    • トークン検証: オプションで正規表現を入力可能
  3. 「オーソライザーを作成」をクリックします

  4. 作成後、ユーザープールからIDトークンを取得してオーソライザーをテストできます

2-3. API リソースの作成

以下のAPIエンドポイントを作成します:

配信管理API(配信者専用)

  • POST /streams/start - 配信開始
  • POST /streams/stop - 配信停止
  • GET /streams/status - 配信状態確認
  • GET /streams/analytics - 配信統計取得

チャット管理API

  • POST /chat/token - チャットトークン取得
  • POST /chat/moderate - メッセージモデレーション
  • GET /chat/history - チャット履歴取得

ユーザー管理API(管理者専用)

  • GET /users - ユーザー一覧取得
  • PUT /users/{userId}/group - ユーザーグループ変更
  • DELETE /users/{userId} - ユーザー削除

3. 配信者専用管理画面の実装

配信者が配信を管理できる専用画面を作成します。

3-1. 配信者ダッシュボードのHTML作成

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>配信者ダッシュボード</title> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1000.0.min.js"></script> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; } .dashboard { max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } .card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .card h3 { margin-top: 0; color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; } .status-indicator { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 8px; } .status-live { background-color: #dc3545; } .status-offline { background-color: #6c757d; } .control-button { padding: 12px 24px; margin: 10px 5px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold; } .btn-start { background-color: #28a745; color: white; } .btn-stop { background-color: #dc3545; color: white; } .btn-primary { background-color: #007bff; color: white; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin: 20px 0; } .stat-item { text-align: center; padding: 15px; background-color: #f8f9fa; border-radius: 5px; } .stat-number { font-size: 24px; font-weight: bold; color: #007bff; } .stat-label { font-size: 14px; color: #666; margin-top: 5px; } .chat-moderation { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 5px; padding: 10px; background-color: #f9f9f9; } .message-item { padding: 8px; margin: 5px 0; background: white; border-radius: 4px; border-left: 4px solid #007bff; } .message-user { font-weight: bold; color: #007bff; } .message-time { font-size: 12px; color: #666; float: right; } .message-actions { margin-top: 5px; } .btn-small { padding: 4px 8px; font-size: 12px; margin-right: 5px; } .btn-warning { background-color: #ffc107; color: black; } .btn-danger { background-color: #dc3545; color: white; } </style> </head> <body> <div class="dashboard"> <!-- 配信状態カード --> <div class="card"> <h3>配信状態</h3> <div id="stream-status"> <span class="status-indicator status-offline"></span> <span id="status-text">オフライン</span> </div> <div style="margin: 20px 0;"> <div><strong>チャンネル名:</strong> <span id="channel-name">-</span></div> <div><strong>配信URL:</strong> <span id="stream-url">-</span></div> <div><strong>ストリームキー:</strong> <span id="stream-key">-</span></div> </div> <div> <button id="start-btn" class="control-button btn-start" onclick="startStream()">配信開始</button> <button id="stop-btn" class="control-button btn-stop" onclick="stopStream()" disabled>配信停止</button> <button class="control-button btn-primary" onclick="refreshStatus()">状態更新</button> </div> </div> <!-- 配信統計カード --> <div class="card"> <h3>配信統計</h3> <div class="stats-grid"> <div class="stat-item"> <div class="stat-number" id="current-viewers">0</div> <div class="stat-label">現在の視聴者数</div> </div> <div class="stat-item"> <div class="stat-number" id="peak-viewers">0</div> <div class="stat-label">最大視聴者数</div> </div> <div class="stat-item"> <div class="stat-number" id="stream-duration">00:00</div> <div class="stat-label">配信時間</div> </div> <div class="stat-item"> <div class="stat-number" id="chat-messages">0</div> <div class="stat-label">チャットメッセージ数</div> </div> </div> <button class="control-button btn-primary" onclick="exportAnalytics()">統計データをエクスポート</button> </div> <!-- チャット管理カード --> <div class="card"> <h3>チャット管理</h3> <div class="chat-moderation" id="chat-messages-list"> <!-- チャットメッセージがここに表示されます --> </div> <div style="margin-top: 15px;"> <button class="control-button btn-primary" onclick="refreshChat()">チャット更新</button> <button class="control-button btn-warning" onclick="clearChat()">チャットクリア</button> </div> </div> <!-- 設定カード --> <div class="card"> <h3>配信設定</h3> <div> <label> <input type="checkbox" id="chat-enabled" checked> チャット機能を有効化 </label> </div> <div> <label> <input type="checkbox" id="moderation-enabled" checked> 自動モデレーションを有効化 </label> </div> <div> <label> 配信品質: <select id="stream-quality"> <option value="720p">720p (推奨)</option> <option value="1080p">1080p (高品質)</option> <option value="480p">480p (低帯域)</option> </select> </label> </div> <button class="control-button btn-primary" onclick="saveSettings()">設定保存</button> </div> </div> <script> // AWS SDK設定 AWS.config.region = 'us-east-1'; let currentUser = null; let streamStartTime = null; let statsInterval = null; // ページ読み込み時の初期化 window.onload = function() { checkAuthentication(); refreshStatus(); startStatsUpdater(); }; // 認証状態チェック function checkAuthentication() { // Cognitoの認証状態を確認 const userPool = new AmazonCognitoIdentity.CognitoUserPool({ UserPoolId: 'YOUR_USER_POOL_ID', ClientId: 'YOUR_CLIENT_ID' }); currentUser = userPool.getCurrentUser(); if (!currentUser) { alert('ログインが必要です'); window.location.href = 'login.html'; return; } // ユーザーのグループを確認 currentUser.getSession((err, session) => { if (err) { alert('セッションの取得に失敗しました'); return; } const groups = session.getIdToken().payload['cognito:groups'] || []; if (!groups.includes('Streamers') && !groups.includes('Administrators')) { alert('配信者権限がありません'); window.location.href = 'viewer.html'; return; } console.log('認証成功:', currentUser.getUsername()); }); } // 配信開始 async function startStream() { try { const response = await fetch('/api/streams/start', { method: 'POST', headers: { 'Authorization': `Bearer ${await getAccessToken()}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ channelName: 'live-streaming-channel', quality: document.getElementById('stream-quality').value }) }); if (response.ok) { streamStartTime = new Date(); document.getElementById('start-btn').disabled = true; document.getElementById('stop-btn').disabled = false; updateStreamStatus('live'); alert('配信を開始しました'); } else { alert('配信開始に失敗しました'); } } catch (error) { console.error('配信開始エラー:', error); alert('配信開始でエラーが発生しました'); } } // 配信停止 async function stopStream() { try { const response = await fetch('/api/streams/stop', { method: 'POST', headers: { 'Authorization': `Bearer ${await getAccessToken()}`, 'Content-Type': 'application/json' } }); if (response.ok) { streamStartTime = null; document.getElementById('start-btn').disabled = false; document.getElementById('stop-btn').disabled = true; updateStreamStatus('offline'); alert('配信を停止しました'); } else { alert('配信停止に失敗しました'); } } catch (error) { console.error('配信停止エラー:', error); alert('配信停止でエラーが発生しました'); } } // 配信状態更新 function updateStreamStatus(status) { const statusIndicator = document.querySelector('.status-indicator'); const statusText = document.getElementById('status-text'); if (status === 'live') { statusIndicator.className = 'status-indicator status-live'; statusText.textContent = 'ライブ配信中'; } else { statusIndicator.className = 'status-indicator status-offline'; statusText.textContent = 'オフライン'; } } // 統計データ更新 function startStatsUpdater() { statsInterval = setInterval(async () => { if (streamStartTime) { updateStreamDuration(); await updateViewerStats(); await updateChatStats(); } }, 5000); // 5秒間隔で更新 } // 配信時間更新 function updateStreamDuration() { if (streamStartTime) { const now = new Date(); const duration = Math.floor((now - streamStartTime) / 1000); const hours = Math.floor(duration / 3600); const minutes = Math.floor((duration % 3600) / 60); const seconds = duration % 60; document.getElementById('stream-duration').textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } } // 視聴者統計更新 async function updateViewerStats() { try { const response = await fetch('/api/streams/analytics', { headers: { 'Authorization': `Bearer ${await getAccessToken()}` } }); if (response.ok) { const data = await response.json(); document.getElementById('current-viewers').textContent = data.currentViewers || 0; document.getElementById('peak-viewers').textContent = data.peakViewers || 0; } } catch (error) { console.error('統計取得エラー:', error); } } // チャット統計更新 async function updateChatStats() { try { const response = await fetch('/api/chat/history', { headers: { 'Authorization': `Bearer ${await getAccessToken()}` } }); if (response.ok) { const data = await response.json(); document.getElementById('chat-messages').textContent = data.messageCount || 0; displayRecentMessages(data.recentMessages || []); } } catch (error) { console.error('チャット履歴取得エラー:', error); } } // 最新チャットメッセージ表示 function displayRecentMessages(messages) { const container = document.getElementById('chat-messages-list'); container.innerHTML = ''; messages.slice(-10).forEach(message => { // 最新10件を表示 const messageElement = document.createElement('div'); messageElement.className = 'message-item'; messageElement.innerHTML = ` <div> <span class="message-user">${message.username}</span> <span class="message-time">${new Date(message.timestamp).toLocaleTimeString()}</span> </div> <div>${message.content}</div> <div class="message-actions"> <button class="control-button btn-small btn-warning" onclick="warnUser('${message.userId}')">警告</button> <button class="control-button btn-small btn-danger" onclick="banUser('${message.userId}')">BAN</button> </div> `; container.appendChild(messageElement); }); } // アクセストークン取得 async function getAccessToken() { return new Promise((resolve, reject) => { currentUser.getSession((err, session) => { if (err) { reject(err); } else { resolve(session.getAccessToken().getJwtToken()); } }); }); } // その他の機能(簡略化) function refreshStatus() { console.log('配信状態を更新中...'); } function exportAnalytics() { alert('統計データをエクスポートします'); } function refreshChat() { updateChatStats(); } function clearChat() { if (confirm('チャットをクリアしますか?')) { alert('チャットをクリアしました'); } } function saveSettings() { alert('設定を保存しました'); } function warnUser(userId) { alert(`ユーザー ${userId} に警告を送信しました`); } function banUser(userId) { if (confirm(`ユーザー ${userId} をBANしますか?`)) { alert(`ユーザー ${userId} をBANしました`); } } </script> </body> </html>
Tip

【解説】配信者ダッシュボードの設計思想

配信者ダッシュボードは、配信中でも直感的に操作できるUIを重視しています。重要な情報(配信状態、視聴者数)を一目で確認でき、配信開始・停止などの主要操作を大きなボタンで提供します。

リアルタイム更新機能により、配信者は配信を中断することなく、視聴者の反応やチャットの様子を把握できます。これにより、より質の高いインタラクティブな配信が可能になります。

チャットモデレーション機能は、配信者が健全なコミュニティを維持するために重要です。不適切な投稿に対して迅速に対応できる機能を提供しています。

4. 視聴者認証によるパーソナライズ機能

視聴者のログイン状態に応じた機能制限とパーソナライズを実装します。

4-1. 視聴者画面の認証機能強化

既存のviewer.htmlを拡張し、ユーザーグループに応じた機能を提供します:

// ユーザーグループに応じた機能制御 function initializeUserFeatures(userGroups) { // プレミアム機能の有効化 if (userGroups.includes('PremiumViewers')) { enablePremiumFeatures(); } // 管理者機能の有効化 if (userGroups.includes('Administrators')) { enableAdminFeatures(); } // 配信者機能の有効化 if (userGroups.includes('Streamers')) { enableStreamerFeatures(); } } // プレミアム機能の有効化 function enablePremiumFeatures() { // 特別なチャットスタイル document.body.classList.add('premium-user'); // 高画質視聴オプション addQualitySelector(); // チャット履歴表示 enableChatHistory(); } // 画質選択機能 function addQualitySelector() { const qualitySelector = document.createElement('select'); qualitySelector.innerHTML = ` <option value="auto">自動</option> <option value="1080p">1080p</option> <option value="720p">720p</option> <option value="480p">480p</option> `; qualitySelector.addEventListener('change', (e) => { player.setQuality(e.target.value); }); document.querySelector('.video-section').appendChild(qualitySelector); }

このステップで何をしたのか

このステップでは、Amazon CognitoとIAMを使用してライブ配信アプリケーションに高度なユーザー管理機能を実装しました。具体的には、配信者・視聴者・管理者の役割に基づくアクセス制御、API GatewayによるセキュアなAPI設計、配信者専用の管理ダッシュボード、視聴者グループに応じたパーソナライズ機能を構築しました。また、最小権限の原則に基づいたIAMポリシーにより、セキュリティを確保しながら必要な機能を提供できる環境を整備しました。

ライブ配信アプリでどのような影響があるのか

この構成により、ライブ配信アプリケーションは単純な配信プラットフォームから、多様なユーザー層に対応できる本格的なサービスに進化しました。有料配信、限定配信、年齢制限付きコンテンツなど、様々なビジネスモデルに対応できます。配信者は専用ダッシュボードで配信を効率的に管理でき、視聴者は自分の会員レベルに応じた機能を利用できます。管理者は全体のユーザー管理とコンテンツ管理を行えるため、健全で持続可能なプラットフォーム運営が可能になります。これは、NetflixやAmazon Prime Videoのような大規模な配信プラットフォームと同等のユーザー管理機能を、個人や小規模組織でも実現できることを意味します。

技術比較まとめ表

技術領域AWSオンプレミス
ユーザー認証Cognito + IAM
マネージド認証とアクセス制御
独自認証システム + LDAP
データベース設計と実装が必要
API管理API Gateway + Lambda
サーバーレスでスケーラブル
Express.js/Spring Boot
サーバー運用とスケーリング管理
権限管理IAMロール + ポリシー
細かい粒度でのアクセス制御
データベースベースのRBAC
権限チェック機能の実装

学習において重要な技術的違い

1. 認証・認可の分離

  • AWS:Cognitoで認証、IAMで認可を分離、それぞれに特化した機能を提供
  • オンプレミス:認証と認可を統合したシステム設計、複雑な権限管理ロジック

2. スケーラビリティの対応

  • AWS:CognitoとAPI Gatewayが自動スケーリング、ユーザー数に制限なし
  • オンプレミス:認証サーバーの負荷分散設計、データベースのスケーリング対策

3. セキュリティの管理

  • AWS:AWSがインフラレベルのセキュリティを担保、アプリケーションレベルに集中
  • オンプレミス:インフラからアプリケーションまで全レイヤーのセキュリティ対策

4. 運用・監視

  • AWS:CloudWatchによる認証ログとメトリクスの自動収集
  • オンプレミス:独自のログ収集・監視システムの構築と運用

実践チェック:画面キャプチャで証明しよう

下記のチェック項目について、実際にAWSマネジメントコンソールで設定ができていることを確認し、各項目ごとに該当画面のスクリーンショットを撮影して提出してください。

  • Cognitoユーザープールで4つのグループ(Administrators、Streamers、PremiumViewers、Viewers)が作成されている

  • 各グループに適切なIAMロールが割り当てられ、最小権限の原則に基づいたポリシーが設定されている

  • API GatewayでCognitoオーソライザーが設定され、認証が必要なエンドポイントが保護されている

  • 配信者専用ダッシュボードでログイン・認証機能が正常に動作している

  • ユーザーグループに応じて異なる機能(プレミアム機能、管理者機能)がアクセス制御されている

  • API経由でのユーザー管理操作(グループ変更、権限確認)が正常に動作している

提出方法: 各項目ごとにスクリーンショットを撮影し、まとめて提出してください。 ファイル名やコメントで「どの項目か」が分かるようにしてください。

構成図による理解度チェック

ステップ2の構成図に、このステップで作成したリソースを追記して、現在のインフラ構成を完成させましょう。

なぜ構成図を更新するのか?

認証・認可システムの追加により、システム全体のセキュリティ境界が明確になります。どのユーザーがどのリソースにアクセスできるか、どの経路で認証・認可が行われるかを理解することで、セキュリティ設計の全体像を把握できます。また、トラブルシューティング時に、認証・認可のどの段階で問題が発生しているかを特定しやすくなります。

  • 認証フローの理解: ユーザーログインから各機能へのアクセスまでの流れ
  • 権限境界の理解: 各ユーザーグループがアクセスできるリソースの範囲
  • セキュリティ制御点の理解: API Gateway、IAM、Cognitoでの多層防御

構成図の書き方

ステップ2で作成した構成図をベースに、以下のリソースを追記してみましょう。

  1. Cognitoグループ: ユーザーの役割分類、各グループの権限範囲
  2. IAMロール・ポリシー: 各グループに対応する権限設定、リソースアクセス制御
  3. API Gateway: セキュアなAPI管理、認証・認可のゲートウェイ機能
  4. セキュリティ境界: 各ユーザーグループがアクセスできる範囲の明示

💡 ヒント: ユーザーグループごとに異なる色を使用し、それぞれがアクセスできるリソースを色分けして表現すると、権限の違いが明確になります。

理解度チェック:なぜ?を考えてみよう

AWSの各リソースや設計には、必ず”理由”や”目的”があります。 下記の「なぜ?」という問いに自分なりの言葉で答えてみてください。 仕組みや設計意図を自分で説明できることが、真の理解につながります。 ぜひ、単なる暗記ではなく「なぜそうなっているのか?」を意識して考えてみてください。

Q. なぜCognitoグループとIAMロールを組み合わせて権限管理を行うのでしょうか?それぞれの役割の違いと組み合わせることのメリットを説明してください。

Q. なぜAPI Gatewayでオーソライザーを設定するのでしょうか?Lambda関数内で認証チェックを行う方法と比較して、どのような利点があるか説明してください。

Q. なぜ「最小権限の原則」が重要なのでしょうか?ライブ配信アプリケーションにおいて、過度な権限付与がどのようなリスクを生むか具体例で説明してください。

今回のステップで利用したAWSサービス名一覧

  • Amazon Cognito グループ:役割ベースアクセス制御(RBAC)、ユーザーの役割に応じた権限管理
  • IAM ロール・ポリシー:最小権限の原則に基づいたリソースアクセス制御
  • API Gateway:セキュアなAPI管理、認証・認可のゲートウェイ機能
  • AWS Lambda:ユーザー管理機能、サーバーレスでの権限チェック処理
Last updated on