IT未経験インターン生がAWSとAIを使ってはじめてアプリ開発に取り組んでみた話

IT未経験インターン生がAWSとAIを使ってはじめてアプリ開発に取り組んでみた話

目次

    はじめに

    ご挨拶

    初めまして、クラウドインテグレーション部所属インターン生の川辺です。今回は、IT初心者の私が、AWSを用いて初めてのアプリ開発に取り組んだ過程を記事にしてまとめてみました!アプリ開発、ブログ執筆ともに初めての経験ですので記念として、また私と同じように文系未経験からIT業界に飛び込む方々の助けになればいいなという思いを込めて寄稿させていただきます。

    作成したアプリの詳細

    今回、Amazon Bedrockを活用し、「自アカウント内のEC2インスタンス状況をリアルタイムに把握・操作できるAIエージェント」を構築しました。このエージェントは単なるチャットボットではありません。ユーザーとの対話を通じてインフラの状態を読み取り、必要に応じてEC2インスタンスの起動・停止といったアクションを自律的に実行します。

    機能概要

    ①汎用AIチャット: 日常的な会話や質問に対し、AIモデル(Claude 3.5 Sonnet)が回答します。
    ②リアルタイムなインフラ把握:「現在稼働しているEC2インスタンスは?」といった質問に対し、実際の環境をリアルタイムに調査して回答します。
    ③対話型リソース操作:インスタンスの起動・停止リクエストを自然言語で受け付け・実行します。

    システムの動作フロー

    1. 入力
      ユーザーはStreamlitで構成されたUIから、自然言語で指示を入力します。
      例:「稼働中のインスタンス一覧を教えて」「開発環境のサーバーを止めて」

    2. 思考
      Bedrock Agentが入力内容を解釈します。AI自身の内部知識で解決できる質問か、あるいは外部ツール(Action Group)を呼び出して情報を取得/操作すべきか自律的に判断します。
    3. 実行
      AWSリソースの操作が必要と判断された場合、紐づけられたAWS Lambdaが起動します。EC2 APIを介してリアルタイムな情報の取得やインスタンスのステータス変更を実施します。
    4. 回答
      Lambdaから返ってきた実行結果やデータを、AIが文脈に合わせて自然な言語に整形し、ユーザーへ回答します。

    構成イメージ

    202605_it-beginner-aws-ai-app-experience_01

    開発の背景

    今回のシステム開発には、主に2つの背景とモチベーションがあります。

    1. 生成AIへの強い関心
      私自身、昨今の生成AI技術の進化、特にLLM(大規模言語モデル)を活用した「自律型エージェント」の可能性に大きな興味を持っています。AIが単に言葉を返すだけでなく、実際のシステム(AWS環境)に対して具体的なアクションを起こす仕組みを自分の手で構築してみたいと考え、Amazon Bedrock Agentsの採用を決めました。
    2. AWSの実践的な習得
      これまで学んできたAWSクラウドコンピューティングの知識を、より実践的なアウトプットに繋げたいという思いがありました。

    Amazon Bedrockを使ったAI基盤の構築、AWS Lambdaによるサーバーレスなロジック実装、Amazon EC2の運用管理を組み合わせることで、AWSの主要サービスを横断的に活用するスキルの習得を目指しました。

    開発環境

    今回の開発で使用した環境及び技術スタックは以下の通りです。

    クラウド基盤

    ・Amazon Bedrock:生成AI基盤(エージェント機能の核)。「自分で考えて、Lambdaを叩き、EC2を操作する」というAgent機能をもった激アツAI。
    ・AWS Lambda
    ・Amazon EC2
    ・IAM

    AIモデル/フレームワーク

    ・Model:Claude 3.5 Sonnet
    ・Agent:Amzon Bedrock Agents
    ・SDK:Boto3

    フロントエンド/UI

    ・Frontend:Streamlit(Pythonベースの高速Webアプリケーション・フレームワーク)
    ・Library:streamlit-chat

    ローカル開発環境・ツール

    ・Language:Python 3.10+
    ・Editor:Visual Studio Code
    ・Version Control:Git/Github

    開発の流れ1:アプリケーションの作成

    まずは、「自アカウント内のEC2インスタンスの状況をリアルタイムで把握することのできるAIエージェント」を作成していきます。

    VPCの構築

    はじめに、AIチャットアプリを操作する基盤となる、VPCとネットワーク関連リソースを作成します。

    1. VPCの作成
      下記設定のVPCを作成します。
      入力欄 入力値
      名前タグ 任意
      IPv4 CIDRブロック 192.168.0.0/16

      ※その他はデフォルト設定

    2. サブネットの作成
      1で作成したVPCに下記設定のサブネットを作成します。

      入力欄 入力値
      VPC ID 任意
      サブネット名 pub-subnet-1c
      アベイラビリティゾーン アジアパシフィック(東京)/apne1-az1(ap-northeast-1c)
      IPv4 サブネット CIDR ブロック 192.168.0.0/24
    3. インターネットゲートウェイの作成
      VPC内のリソースがインターネットゲートウェイを介してインターネットと通信できるようにするために、インターネットゲートウェイを作成します。
      入力欄 入力値
      名前タグ 任意

      作成後、「アクション」>「VPCにアタッチ」より、1で作成したVPCにインターネットゲートウェイをアタッチします。

    4. ルートテーブルの作成
      入力欄 入力値
      名前タグ 任意
      VPC 1で作成したもの

      作成後ルートに以下を追加します。

      入力欄 入力値
      送信先 0.0.0.0/0
      ターゲット インターネットゲートウェイ(3で作成したもの)

      ※設定イメージ
      202605_it-beginner-aws-ai-app-experience_02

    5. ルートテーブルをサブネットに関連付け
      サブネットの関連付けを編集から「pub-subnet-1c」にルートテーブルを関連付けます。
      202605_it-beginner-aws-ai-app-experience_03

    EC2インスタンスの構築

    次に、Webアプリが動作するEC2インスタンスを構築します。

    1. EC2インスタンスの作成
      EC2インスタンスを下記設定で作成します。
      入力欄 入力値
      名前 任意
      Amazon マシンイメージ(AMI) Amazon Linux 2023
      インスタンスタイプ t3.micro
      キーペア 選択しなくてよい
      VPC 1で作成したもの
      サブネット pub-subnet-1c
      パブリックIP の自動割り当て 有効化
      セキュリティグループを作成
      セキュリティグループ名  任意

      インバウンドのセキュリティグループを下図のように作成してください。
      202605_it-beginner-aws-ai-app-experience_04
      ※その他はデフォルト設定
      ※作成時にキーペアを作るように警告が出ますが、キーペアなしで続行を選択して大丈夫です。

    2. IAMロールの設定
      EC2インスタンスがAWSリソースにアクセスできるように、必要な権限を持ったIAMロールを作成します。

      以下の設定でIAMロールを作成します。

      入力欄 入力値
      ユースケース EC2
      許可ポリシー AmazonBedrockFullAccess ←Bedrockへのアクセスに必要な権限が定義されたポリシー
      AmazonSSMManagedInstanceCore ←SystemManagerへのアクセスに必要な権限が定義されたポリシー
      ロール名 任意
    3. IAMロールのアタッチ
      1で作成したEC2インスタンスを開き、「アクション」>「セキュリティ」>「IAMロールを変更」から作成したIAMロールをEC2にアタッチします。
      202605_it-beginner-aws-ai-app-experience_05202605_it-beginner-aws-ai-app-experience_06

     

    Bedrockエージェントの設定

    1. エージェントの作成
      Amazon Bedrockを開きます。202605_it-beginner-aws-ai-app-experience_07

      「構築」>「エージェント」>「エージェント作成」を押下。202605_it-beginner-aws-ai-app-experience_08

       エージェント名(任意)を入力して作成します。202605_it-beginner-aws-ai-app-experience_09

    2. エージェントの設定
      エージェントの詳細を以下画像のように設定します。202605_it-beginner-aws-ai-app-experience_10

      エージェント向けの指示欄に以下の内容を入力します。

      あなたはAWSの運用管理をサポートする優秀なAIアシスタントです。
      ユーザーからの質問に対し、以下のガイドラインに従って行動してください。
      EC2情報の取得: ユーザーから「サーバーの状態はどう?」「稼働中のEC2を教えて」といった、EC2の状況確認に関する質問を受けた場合は、提供されているget_running_ec2_list関数を実行して最新情報を取得してください。
      情報の提示: 関数から取得したデータ (InstanceId,InstanceName,State)をもとに、ユーザーが見やすいような表形式、または箇条書きのリストで回答してください。
      範囲外の質問: AWSに関係のない一般的な雑談や質問には、あなたの知識の範囲で親切に答えてください。

      保存ボタンを押して設定を保存します。202605_it-beginner-aws-ai-app-experience_11

    EC2情報取得Lambda関数の作成

    本手順ではEC2の情報を取得するLambda関数を構成します。

    1. EC2情報取得Lambda関数の作成
      コンソールで「Lambda」を開きます。202605_it-beginner-aws-ai-app-experience_12

      「関数を作成」を押下。202605_it-beginner-aws-ai-app-experience_13

      下画像の設定でLambda関数を作成します。
      ※関数名は任意
      202605_it-beginner-aws-ai-app-experience_14

    2. 一般設定の編集
      1で設定したLambda関数の画面から、「設定」>「一般設定」>「編集」を押下。202605_it-beginner-aws-ai-app-experience_15

      タイムアウトを30秒に設定し、保存します。202605_it-beginner-aws-ai-app-experience_16

    3. アクセス権限の設定
      「設定」>「アクセス権限」を開き、ロール名のリンクを押下。202605_it-beginner-aws-ai-app-experience_17-1

      「アクセス許可を追加」>「ポリシーをアタッチ」を押下。202605_it-beginner-aws-ai-app-experience_18

      AmazonEC2ReadOnlyAccessポリシーを追加する。202605_it-beginner-aws-ai-app-experience_19
      「Lambda関数の設定」>「アクセス権限」のページに戻って、「リソースベースのポリシーステートメント」でアクセス権限を追加します。202605_it-beginner-aws-ai-app-experience_20-1

      以下画像のように設定します。(ソースARNには、構築手順3で設定したBedrockAgentのARNを入力する。)202605_it-beginner-aws-ai-app-experience_21

    4. コードのデプロイ
      以下のコードをコードソースに入力します。
      import json
      import boto3
      from botocore.exceptions import ClientError

      ec2 = boto3.client("ec2")


      def bedrock_response(event, body_text):
      return {
      "messageVersion": "1.0",
      "response": {
      "actionGroup": event.get("actionGroup"),
      "function": event.get("function"),
      "functionResponse": {
      "responseBody": {
      "TEXT": {
      "body": body_text
      }
      }
      }
      }
      }


      def lambda_handler(event, context):
      try:
      resp = ec2.describe_instances(
      Filters=[
      {
      "Name": "instance-state-name",
      "Values": ["running"]
      }
      ]
      )

      instances = []

      for r in resp.get("Reservations", []):
      for inst in r.get("Instances", []):
      name = ""
      for t in inst.get("Tags", []) or []:
      if t.get("Key") == "Name":
      name = t.get("Value", "")
      break

      instances.append({
      "instanceId": inst.get("InstanceId"),
      "name": name,
      "instanceType": inst.get("InstanceType"),
      "privateIp": inst.get("PrivateIpAddress"),
      "publicIp": inst.get("PublicIpAddress"),
      "availabilityZone": inst.get("Placement", {}).get("AvailabilityZone"),
      "vpcId": inst.get("VpcId"),
      "subnetId": inst.get("SubnetId"),
      })

      body = json.dumps(
      {
      "runningInstanceCount": len(instances),
      "instances": instances
      },
      ensure_ascii=False,
      indent=2
      )

      return bedrock_response(event, body)

      except ClientError as e:
      return bedrock_response(event, f"AWS ClientError: {str(e)}")

      except Exception as e:
      return bedrock_response(event, f"Unhandled error: {str(e)}")

      Deployボタンを押下。202605_it-beginner-aws-ai-app-experience_22

    5. Lambda関数をBedrockエージェントのアクショングループに登録
      作成したBedrockエージェントを開き、「エージェントビルダーで編集」を押下。202605_it-beginner-aws-ai-app-experience_23

      アクショングループで「追加」を押下。以下画像のように設定して作成します。202605_it-beginner-aws-ai-app-experience_24

      保存ボタンを押下。202605_it-beginner-aws-ai-app-experience_25

      準備ボタンを押下。202605_it-beginner-aws-ai-app-experience_26

      画面右端、テストエージェント欄で「現在稼働中のEC2インスタンスの情報を教えて」というような質問を投げてみます。

      以下画像のような回答が返ってくればしっかり設定できています!202605_it-beginner-aws-ai-app-experience_27

    フロントエンドアプリの構築

     AIと会話できるチャットアプリをEC2インスタンス上に構築します。今回はPythonで簡単にWeb UIを実装できるStreamlit(ストリームリット)を利用します。

    1. サーバーへの接続
      作成したEC2インスタンスへAWSコンソールからセッションマネージャで接続します。202605_it-beginner-aws-ai-app-experience_28-1202605_it-beginner-aws-ai-app-experience_29
    2. 必要パッケージのインストール
      パッケージとは、ソフトウェアをインストールするために必要な実行プログラム、ファイル、ライブラリ、マニュアルなどの集合体です。
      SSMで接続したコンソールから以下のコマンドを実行します。
      sudo su ec2-user
      cd
      sudo dnf update -y
      sudo dnf install -y python3-pip python3-devel
      pip install –upgrade pip
      pip install boto3
    3. アプリの作成
      以下のコマンドでアプリ配置用ディレクトリの作成とディレクトリへの移動します。
      mkdir app 
      cd app

      以下のコマンドでviエディタを開いてアプリケーションコードを作成します。

      vi app.py

      以下のコードを貼り付けます。(コードの中の”ここにエージェントIDを入力”の文字列をBedrockエージェントのエージェントIDに置き換えてから貼り付けてください。)

      import streamlit as st
      import boto3
      import uuid

      st.title("AWS運用アシスタント")

      client = boto3.client(service_name='bedrock-agent-runtime', region_name='ap-northeast-1')

      if "session_id" not in st.session_state:
      st.session_state.session_id = str(uuid.uuid4())

      if "messages" not in st.session_state:
      st.session_state.messages = []

      for msg in st.session_state.messages:
      st.chat_message(msg["role"]).write(msg["content"])

      if prompt := st.chat_input("例:動いているEC2を教えて"):
      st.session_state.messages.append({"role": "user", "content": prompt})
      st.chat_message("user").write(prompt)

      response = client.invoke_agent(
      agentId='ここにエージェントIDを入力',
      agentAliasId='TSTALIASID',
      sessionId=st.session_state.session_id,
      inputText=prompt
      )

      full_response = ""
      for event in response['completion']:
      if 'chunk' in event:
      chunk_text = event['chunk']['bytes'].decode("utf-8")
      full_response += chunk_text

      st.session_state.messages.append({"role": "assistant", "content": full_response})
      st.chat_message("assistant").write(full_response)

      202605_it-beginner-aws-ai-app-experience_30:wqで保存して終了してください。

    4. アプリの実行
      以下のコマンドを実行してアプリを起動してください。
      streamlit run app.py --server.port 8501

      202605_it-beginner-aws-ai-app-experience_31
      ブラウザからhttp://パブリックipアドレス:8501にアクセスして、以下のような画面が表示されること、チャットを入力するとAIが回答を返すことを確認してください。202605_it-beginner-aws-ai-app-experience_32-1

    以上で、「自アカウント内のEC2インスタンスの状況をリアルタイムで把握することのできるAIエージェント」のアプリケーション作成が終了しました!

    開発の流れ2:EC2起動/停止機能の組み込み

    ここからは、ハンズオン課題で作成したアプリをさらに便利にするために、アプリからEC2インスタンスの起動/停止機能を組み込んだ「インフラ運用エージェント」として進化させていく開発の流れを説明していきます。

    権限の追加

    作成した時点ではEC2及びLambda、BedrockAgentにはAmazonEC2ReadOnlyAccess(「EC2に関する情報を『見る』ことはできるが、『変更』は一切できない参照用の権限)しか与えられていません。
    ※EC2情報取得Lambda関数の作成 3.アクセス権限の設定を参照

    そこで、LambdaにEC2の起動/停止を可能にするポリシーをアタッチします!

    Lambdaへのポリシーのアタッチ

    Lambdaコンソールを開き、作成した関数を選択します。「設定タブ」>「アクセス権限」>IAMロールのリンクを押下。202605_it-beginner-aws-ai-app-experience_33

    IAMロールの許可ポリシーから「許可を追加」>「インラインポリシーを作成」を押下。202605_it-beginner-aws-ai-app-experience_34

    ポリシーエディタをJSONに変更し、以下のコードを打ち込みます。

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ec2:StartInstances",
                    "ec2:StopInstances",
                    "ec2:DescribeInstances"
                ],
                "Resource": "*"
            }
        ]
    }

    ec2:StartInstances:停止しているEC2インスタンスを「起動」させる。
    ec2:StopInstances: 動いているEC2インスタンスを「停止」させる。
    ec2:DescribeInstances:インスタンスの一覧を表示や、現在の状態(実行中か停止中か)の確認を可能にする。
    202605_it-beginner-aws-ai-app-experience_35

    Lambdaコードの変更

    Lambdaのコードを起動/停止に対応したものに変更します。
    以下のコードをコードソースに入力し、Deployを押下。

    import boto3
    from botocore.exceptions import ClientError

    ec2 = boto3.client("ec2")

    def bedrock_response(event, body_text):
        return {
            "messageVersion": "1.0",
            "response": {
                "actionGroup": event.get("actionGroup"),
                "function": event.get("function"),
                "functionResponse": {
                    "responseBody": {
                        "TEXT": {
                            "body": body_text
                        }
                    }
                }
            }
        }

    def lambda_handler(event, context):
        # Bedrock Agentが呼び出そうとしている関数名を取得
        function_name = event.get("function")
       
        try:
            # 1. 稼働中のインスタンス一覧取得 (元の機能)
            if function_name == "get_running_ec2_list":
                resp = ec2.describe_instances(
                    Filters=[{"Name": "instance-state-name", "Values": ["running"]}]
                )
                instances = []
                for r in resp.get("Reservations", []):
                    for inst in r.get("Instances", []):
                        name = next((t['Value'] for t in inst.get('Tags', []) if t['Key'] == 'Name'), "")
                        instances.append({
                            "instanceId": inst.get("InstanceId"),
                            "name": name,
                            "state": inst.get("State", {}).get("Name")
                        })
                body = json.dumps({"instances": instances}, ensure_ascii=False)
                return bedrock_response(event, body)

            # 2. インスタンスの起動
            elif function_name == "start_ec2":
                # Bedrockから渡される引数(パラメータ)を取得
                params = event.get("parameters", [])
                instance_id = next((p['value'] for p in params if p['name'] == 'instance_id'), None)
               
                if instance_id:
                    ec2.start_instances(InstanceIds=[instance_id])
                    return bedrock_response(event, f"インスタンス {instance_id} の起動リクエストを送信しました。")
                return bedrock_response(event, "インスタンスIDが指定されていません。")

            # 3. インスタンスの停止
            elif function_name == "stop_ec2":
                params = event.get("parameters", [])
                instance_id = next((p['value'] for p in params if p['name'] == 'instance_id'), None)
               
                if instance_id:
                    ec2.stop_instances(InstanceIds=[instance_id])
                    return bedrock_response(event, f"インスタンス {instance_id} の停止リクエストを送信しました。")
                return bedrock_response(event, "インスタンスIDが指定されていません。")

            else:
                return bedrock_response(event, f"未知の関数: {function_name}")

        except ClientError as e:
            return bedrock_response(event, f"AWS ClientError: {str(e)}")
        except Exception as e:
            return bedrock_response(event, f"Unhandled error: {str(e)}")

    BedrockAgentの設定

    次に、BedrockAgentを起動/停止機能を組み込んだものにアップデートしていきます。

    1. エージェントの再設定
      Amazon Bedrockを開き、作成したエージェントを選択し、エージェントビルダーで編集を押下。 
      画面をスクロールし、エージェント向けの指示欄を以下のように書き換えます。
      あなたはAWSの運用管理をサポートする優秀なAIアシスタントです。
      ユーザーの要望に対し、提供された関数を活用して以下のガイドラインに従い慎重に行動してください。

      1. EC2情報の取得:
      ユーザーから状況確認(例:「サーバーの状態は?」「稼働中のEC2を教えて」)を受けた場合は、get_running_ec2_list 関数を実行して最新情報を取得してください。取得したデータ(InstanceId, Name, State)をもとに、表形式または箇条書きで分かりやすく回答してください。

      2. EC2の操作依頼(起動・停止)を受けた場合(重要):
      ユーザーから「〜を止めて」「〜を起動して」といった指示を受けた際は、誤操作防止のため、まず以下の確認を必ず行ってください。
        ① 操作対象の「インスタンス名」と「インスタンスID」を明示する。
        ② 「本当にこのインスタンスを [起動/停止] してもよろしいですか?」とユーザーに確認を求める。
        ※この段階では、まだ操作関数(start_ec2 / stop_ec2)を実行しないでください。

      3. ユーザーの同意を得た後の実行:
      ユーザーから「はい」「お願いします」等の同意を得た場合に限り、適切な関数(start_ec2 または stop_ec2)を実行してください。
      実行後は、その結果(例:「起動リクエストを送信しました」)をユーザーに伝えてください。

      4. 補足情報の提示:
      もしユーザーが手動で操作したい様子を見せた場合や、バックアップとして案内が必要な場合は、親切に案内してください。
      5. 範囲外の質問:
      AWSに関係のない雑談や質問には、あなたの知識の範囲で親切に答えてください。
    2. アクショングループの追加
      次に、アクショングループの中にある、既存のアクショングループ(Lambdaと紐づいているもの)のリンク>「アクショングループ関数追加」を押下し、以下の二つのアクショングループ関数を作成します。
      関数1
      入力欄 入力値
      名前 start_ec2
      説明 EC2を起動する
      パラメータ instance_id (String / 必須)

      関数2

      入力欄 入力値
      名前 stop_ec2
      説明 EC2を停止する
      パラメータ instance_id (String / 必須)

      202605_it-beginner-aws-ai-app-experience_36
      完了したら、エージェントビルダーの編集を保存して終了。さらにエージェントビルダーの画面でも保存を押下します。

    テストで以下画像のように回答が返ってくればカンペキです!
    202605_it-beginner-aws-ai-app-experience_37202605_it-beginner-aws-ai-app-experience_38
    ※起動/停止機能確認用のEC2インスタンスを作成しておくと大事なEC2インスタンスを間違えて停止するリスクが小さくなり安心です。

    アプリをLinuxサービス化

    さらに、作成したアプリをLinuxサービスとして動かすことで、SSMを閉じてもアプリが動くように改良しました。

    苦労した/躓いたポイント

    開発を進める中で、私が特に骨を折った「2つの壁」について共有します。これから実装する方のショートカットになれば幸いです。

    権限周りの設定:IAMとリソースベースポリシーの沼

    今回の開発で最も時間を費やし、そして最も学びが多かったのが、AWSの「権限(IAM)」設定です。当初はそこまで難しい部分ではないだろうと流していましたが、これこそがAWSの強固なセキュリティの要であり、深い沼が待っていました。

    「権限は付与したはずなのになぜ?!」

    まず、Lambdaに「EC2を起動・停止するための権限(IAMポリシー)」を付与しました。 「これでLambda自身はEC2を操作できるようになった。単体テストも通った。準備万端だ!」

    しかし、いざアプリから実行しようとすると、「権限がありません」と拒絶されました。自分の権限は完璧なのに、なぜ動かないのか。そこでぶつかったのが、今回の開発における真のラスボス「リソースベースポリシー」でした。

    リソースベースポリシー=「受付ルール」

    調査と試行錯誤の末に理解したのは、AWSの権限には「自分の資格」のほかに、「仕事を受けるための受付ルール」が必要だということです。

    これまで設定していたIAMロールは、Lambdaさんが持っている「EC2を操作できる専門資格」に過ぎませんでした。しかし、今回の主役はBedrock Agentさん。「外部の部署(Bedrock)から、Lambdaさんに仕事を依頼する」ためには、Lambdaさんのデスクに「Bedrockさんからの依頼なら、いつでも引き受けますよ」という専用の受付ルール(リソースベースポリシー)を設定しておく必要があったのです。

    リソースベースポリシーは「双方向」で初めて成立!!

    「IAMロールを完璧にしたのに、なぜか○○から呼び出せない!」というエピソードは、AWS開発初心者における「あるある」かもしれません。
    今回の経験を通じて、AWSのセキュリティは「自分ができること(免許証)」と「相手にさせること(玄関の看板)」の両方が合致して初めて成立する、という極めて論理的で強固な設計思想を痛感しました。この「双方向の許可」が必要だと気づいた瞬間はめちゃくちゃスッキリしました。
    ※リソースベースポリシーが必要となるのは、他のサービスからLambdaを呼び出すときなどの一部の場合のみです。今回Lambdaは受動的に呼び出されたので、「呼び出す側」だけではなく「呼び出される側」にも権限が必要となりました。

    この権限は最小?

    また、「IAMに与える権限をどこまで絞るか」という点も大きな悩みの種でした。
    最初は「とりあえず動かしたい」という一心で、何でもできる強力な権限(AmazonEC2FullAccessなど)を付与していました。
    しかし、それは「家の鍵を預けるはずが、街中の建物のマスターキーを渡してしまう」ようなもので、セキュリティ上非常に危険です。
    今回はハンズオンであり、セキュリティ上の欠陥が重要な問題につながるようなことはありませんが、実務においてはその限りではないため、慎重に精査しなければならないポイントであると感じました。

    AIの設定

    AIが赤ちゃんすぎる!

    Lambdaに権限を与えても、BedrockAgentへの指示欄のプロンプトをいくら工夫しても、その関数を「実行できる」ことを教えてあげなければAIは動いてはくれません。そのためにBedrockコンソールの「Action Groups」で、stop_ec2という関数名やinstance_idというパラメータを定義するのですが、コード内の変数名と一文字でもズレると、AIは「道具の使い方がわからない」と匙を投げてしまいます。
    これに気づいた時、私はまるでおもちゃの使い方がわからない赤ちゃんだ!とAIの扱いの難しさに困惑するとともに、少しだけAIの扱い方のコツを学べた気がしました。

    おわりに

    今回、IT未経験の私が「自律型AIエージェントの構築」という、一見すると難易度の高いテーマに挑戦しました。実際に自分の手を動かしてアプリを形にする中で得られた、今の私なりの気づきをまとめます。

    権限は「信頼」をコード化したもの

    一番苦労したポイントであったIAMやリソースベースポリシーの設定。最初は単なる「作業」だと思っていましたが、実はこれがクラウドの安全を守る根幹であることを学びました。「誰が、どのルートで、どの道具を使うことを許すか」を厳格に定義していくプロセスは、まさに「システムに対する信頼関係をコードで表現している」のだと感じました。「動かない」と頭を抱えた数時間は、AWSが大切にしている「最小権限の原則」という思想を身をもって理解するために、必要な時間だったのだと思います。

    AIとシステムの「共通言語」を作る難しさ

    また、AIに実務を任せるためには、人間に対する以上に明確で論理的な指示とインターフェースが必要であることを学びました。 AIに道具を渡し、適切なプロンプトを与え、Lambdaと変数名を同期させる。この「一分の隙もない連携」がカチッとハマり、アプリが動いた瞬間の感動は、何物にも代えがたいものでした。

    IT業界に飛び込む皆さんへ

    最初は「自分にできるだろうか」という不安もありましたが、実際に手を動かし、一つひとつのエラーを解消していく過程こそが何よりの学びになりました。生成AIの力を使えば、初心者であってもこれほど強力なツールを作り上げることができます。

    「生成AI×インフラ運用」の可能性は、私たちの想像以上に広がっています。この記事が私と同じように文系・未経験からIT業界を目指す方やAWSを学び始めたばかりの方にとって、一歩を踏み出す勇気やエラーで立ち止まった時のヒントになれば、これほど嬉しいことはありません。

    最後までお読みいただき、ありがとうございました!

    アジアクエスト株式会社では一緒に働いていただける方を募集しています。
    興味のある方は以下のURLを御覧ください。