AWS EventBridgeとSSMのRun Commandを活用したEC2インスタンスのApache自動起動

## はじめに
AWS Systems Manager (SSM) の Run Command は、AWS環境内のEC2インスタンスなどをリモート操作できる強力なツールです。

Run Commandの基本的な使い方については、前回の記事でも詳しく説明していますので、興味がある方はぜひご覧ください。

https://qiita.com/free-honda/items/f2a2e922a826c2b45a18

https://qiita.com/free-honda/items/071fc55d2c8f2aee57c3

この記事では、EventBridgeを使用してEC2インスタンスの起動を検知し、Lambda関数をトリガーとしてSSMコマンドを実行します。

さらに、指定のインスタンスにApacheのサービスを自動起動させる自動化の流れを解説します。

## 前提条件
この手順では、AWSの各種サービスを活用して、インスタンスの起動を動的に検知し、Apacheサービスの起動を自動化するフローを構築します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/54b7714e-219a-4f1e-915e-efa520cbedc7.png)

:::note info 
**IAM Roleの設定:** 
EC2インスタンスには「AmazonSSMManagedInstanceCore」ポリシーがアタッチされたIAMロールが必要です。
Lambda関数には「AmazonSSMFullAccess」ポリシーがアタッチされたIAMロールが必要です。

**SSMエージェントのインストール:** 
最新のAmazon LinuxやWindows ServerにはSSMエージェントがプリインストールされていますが、インストールされていない場合は手動でのインストールが必要です。

**AWS CLIのセットアップ:** 
コマンドを実行するマシンにAWS CLIがインストールされ、適切に設定されていることを確認してください。 
:::

IAMロールに必要なポリシーが付与されていないと処理が正しく動作しないことがあるため、実装時には十分に確認してください。

## 構成/検証の流れ
ここでは、すでにEC2インスタンスが構築されていることを前提とします。

インスタンスの構築やIAMロールの設定に関しては、前回の記事でも解説していますので、こちらも参考にしてください。

https://qiita.com/free-honda/items/071fc55d2c8f2aee57c3

## Apache HTTP Serverのインストール手順
使用するLinuxディストリビューションによって異なりますが、ここではAmazon Linux 2 / CentOS / RHELの場合の手順を紹介します。

まず、パッケージリストを更新し、Apacheをインストールします。

```bash
sudo yum update -y
sudo yum install httpd -y
```

Apacheサービスを起動し、ファイアウォールでHTTPおよびHTTPSのトラフィックを許可します。

**※ここでは、後続の検証のために、あえてApacheサービスの自動起動設定は行っていません。**

```bash
sudo systemctl start httpd
# HTTP (ポート 80) を許可
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# HTTPS (ポート 443) を許可
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 変更を保存します
sudo service iptables save
```

サーバーのIPアドレスまたはドメイン名をブラウザに入力します。デフォルトのApacheのテストページが表示されれば、インストールは成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/7c483841-c6a4-f2b1-eb65-92fd4daae51f.png)

:::note warn
デフォルトのApacheのテストページが表示されない場合は、セキュリティグループのインバウンドルールで「HTTP(80):0.0.0.0/0」を許可する必要があります。
:::

### EventBridgeルールの作成
まず、EC2インスタンスの起動を検知するために、EventBridgeルールを設定します。

AWS Management ConsoleからEventBridgeに移動し、新しいルールを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/3b1e923f-5003-ec8e-e880-78a45a773798.png)


イベントソースを「EC2」から選択し、イベントタイプを「EC2インスタンスの状態変更通知」とします。

次に、EC2インスタンスの起動（state: running）を検知するため、以下のカスタムイベントパターンJSONを使用します。

```json
{
  "source": [
    "aws.ec2"
  ],
  "detail-type": [
    "EC2 Instance State-change Notification"
  ],
  "detail": {
    "instance-id": [
      "i-xxx"
    ],
    "state": [
      "running"
    ]
  }
}

```

このように「state: running」と設定することで、特定のインスタンスの起動イベントをキャプチャできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/95b3450f-8a03-9153-60cd-c0eaf1d60695.png)


設定内容に問題がないことを確認したら、ルールを作成します。

## Lambda関数の作成

次に、EventBridgeからトリガーされるLambda関数を作成します。AWS Lambdaに移動し、新しい関数を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/4c8316f1-ddad-8d87-609d-7fa56a5b3ec9.png)

:::note warn
Lambda関数に使用する実行ロールには、「AmazonSSMFullAccess」ポリシーを必ずアタッチしてください。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c68d85de-372a-ff4e-b086-a70945e8edd9.png)

次に、既存のLambda関数にApacheの自動起動コマンドを追加し、起動が成功した場合にメッセージを/tmp/instance_status.txtに記録する処理を追加します。

```py
import boto3
import datetime

def lambda_handler(event, context):
    # SSMクライアントの作成
    ssm = boto3.client('ssm')
    
    # インスタンスIDを取得
    instance_id = event['detail']['instance-id']
    
    # 現在のタイムスタンプを取得
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    # Apacheサービスの自動起動と成功メッセージの記録コマンド
    commands = [
        "sudo systemctl start httpd",  # Apacheの起動コマンド (Amazon Linuxの場合)
        "if systemctl is-active --quiet httpd; then",  # Apacheが起動しているか確認
        f"echo '{timestamp} - Apacheサービスが正常に起動しました' >> /tmp/instance_status.txt",  # 起動成功時のメッセージ
        "else",
        f"echo '{timestamp} - Apacheサービスの起動に失敗しました' >> /tmp/instance_status.txt",  # 起動失敗時のメッセージ
        "fi"
    ]
    
    # SSM Run Commandを使用してApacheを起動し、メッセージを出力
    response = ssm.send_command(
        InstanceIds=[instance_id],
        DocumentName="AWS-RunShellScript",
        Parameters={'commands': commands},
    )
    
    return {
        'statusCode': 200,
        'body': response
    }
```

このLambda関数は、EC2インスタンスが起動した際にApache（httpd）サービスを自動的に開始します。

また、起動結果は/tmp/instance_status.txtにタイムスタンプ付きで記録されます。


### Lambdaトリガーの設定

Lambda関数を作成した後、EventBridgeルールのターゲットとしてこの関数を指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/8801274c-02b8-424d-61f4-2f7ecf8f0645.png)

これにより、EC2インスタンスの起動が検知されるたびに、Lambda関数が自動で呼び出されます。

## 検証方法

EC2インスタンスを起動または再起動して、EventBridgeがインスタンスの状態変化を検知し、LambdaをトリガーとしてSSM Run Commandを実行し、Apacheが自動的に起動されるか確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/32c00148-5e68-8753-c42b-47177e422579.png)

検証結果として、/tmp/instance_status.txtに以下のようにタイムスタンプ付きのメッセージが出力されていることが確認できました。

```bash
[ec2-user@ip-10-0-7-121 ~]$ cd /tmp/
[ec2-user@ip-10-0-7-121 tmp]$ cat instance_status.txt 
2024-10-12 10:35:15 - Apacheサービスが正常に起動しました
[ec2-user@ip-10-0-7-121 tmp]$ sudo systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Sat 2024-10-12 10:35:16 UTC; 1min 55s ago
     Docs: man:httpd.service(8)
 Main PID: 3214 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─3214 /usr/sbin/httpd -DFOREGROUND
           ├─3219 /usr/sbin/httpd -DFOREGROUND
           ├─3220 /usr/sbin/httpd -DFOREGROUND
           ├─3221 /usr/sbin/httpd -DFOREGROUND
           ├─3222 /usr/sbin/httpd -DFOREGROUND
           └─3223 /usr/sbin/httpd -DFOREGROUND

Oct 12 10:35:16 ip-10-0-7-121.ap-northeast-1.compute.internal systemd[1]: Starting The Apache HTTP Server...
Oct 12 10:35:16 ip-10-0-7-121.ap-northeast-1.compute.internal systemd[1]: Started The Apache HTTP Server.
[ec2-user@ip-10-0-7-121 tmp]$
```

OS起動後、デフォルトのApacheのテストページが正常に表示されることも確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1cdb0b3d-783b-b019-84bf-834cbc32a0ad.png)


Apacheのhttpd.serviceも正常に起動していることが確認でき、検証は成功です！

## おわりに
この記事では、EC2インスタンスの起動イベントをEventBridgeで検知し、LambdaをトリガーとしてSSM Run Commandを実行してApacheを自動的に起動する手順を紹介しました。

この方法を使うことで、インスタンス起動時のApacheサービスの管理が簡単になります。

少し難しい内容でしたが、期待通りの結果が得られ、非常に有意義な検証となりました！

## 参考文献

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-run-lambda-schedule.html