AWS SSM Send Commandで複数EC2に一括スクリプト実行する構成設計|マルチAZ運用自動化の実践

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > AWS(Amazon Linux) > AWS SSM Send Commandで複数EC2に一括スクリプト実行する構成設計|マルチAZ運用自動化の実践
複数のEC2インスタンスに同じ変更を適用しなければならない場面は、マルチAZ運用では毎週のように起きます。20台・50台のインスタンスを1台ずつSSHで叩いていては、作業時間もヒューマンエラーのリスクも上がり続けるだけです。

AWS Systems Manager(SSM)のaws ssm send-commandを使えば、SSH接続・踏み台サーバー不要で複数のEC2インスタンスに対して一括でシェルスクリプトを実行できます。タグフィルターと組み合わせると、マルチAZ構成の全インスタンスを一度に対象にできるため、定期メンテナンスや設定変更の自動化に最適です。

この記事では、aws ssm send-commandの設計前提から基本構文、マルチAZ環境での実践的な活用パターンまでを、実際のCLI出力例を交えて解説します。

この記事のポイント

・aws ssm send-command でタグ指定した複数EC2に同時実行できる
・IAMロールとSSM Agentで踏み台不要・SSH不要のセキュア実行が可能
・MaxConcurrency/MaxErrorsでリスクをコントロールできる
・get-command-invocationでインスタンス単位に結果確認できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜaws ssm send-commandを使うのか|SSH一斉接続との根本的な違い

マルチAZ構成のEC2インスタンスに同じ作業を行う場合、従来のSSHベースの手順はいくつかの問題を抱えています。

・プライベートサブネットのインスタンスには踏み台サーバーが別途必要になる
・インスタンスごとにSSHの接続設定(鍵・ポート・セキュリティグループの22番許可)が必要
・並列実行のためのツール(Ansible・SSH並列ループ)を別途用意しなければならない

AWS SSM Run Command(aws ssm send-command)は、SSM AgentがインストールされたEC2インスタンスに対して、AWSのコントロールプレーン経由でコマンドを配信する仕組みです。SSH接続を使わないため、パブリックIPが不要で22番ポートも開ける必要がありません。

比較軸 SSH一斉実行 aws ssm send-command
踏み台サーバー 必要(プライベートサブネット) 不要
22番ポート開放 必要 不要
認証方式 SSH鍵 IAMロール
マルチAZ対象指定 手動でIPリスト タグフィルター
実行結果の一元管理 なし(各ターミナル) CloudWatch Logs / S3

前提設計|SSM Agentの確認とIAMロール最小権限の設定

1. SSM Agentの動作確認とインスタンスのオンライン確認

Amazon Linux 2・Amazon Linux 2023ではSSM Agentがデフォルトでインストールされています。まずEC2インスタンス上でAgentが動いているか確認しましょう。

# SSM Agentのステータス確認 $ sudo systemctl status amazon-ssm-agent * amazon-ssm-agent.service - amazon-ssm-agent Loaded: loaded (/usr/lib/systemd/system/amazon-ssm-agent.service; enabled) Active: active (running) since Wed 2026-09-10 09:14:23 UTC; 3 weeks 4 days ago Main PID: 812 (amazon-ssm-agen)

次に、AWS CLIでインスタンスが「Online」状態かを確認します。Online状態でないインスタンスにはsend-commandが届かないため、事前確認が重要です。

# SSMに登録されているインスタンス一覧(オンライン状態のみ表示) $ aws ssm describe-instance-information \ --filters "Key=PingStatus,Values=Online" \ --query "InstanceInformationList[*].{ID:InstanceId,IP:IPAddress,Status:PingStatus}" \ --output table \ --region ap-northeast-1 ------------------------------------------------------------------- | DescribeInstanceInformation | +------------------------+---------------+---------+ | ID | IP | Status | +------------------------+---------------+---------+ | i-0a1b2c3d4e5f6789 | 10.0.1.45 | Online | | i-0f9e8d7c6b5a4321 | 10.0.2.67 | Online | | i-0c1d2e3f4a5b6c7d | 10.0.3.89 | Online | | i-0d4e5f6a7b8c9012 | 10.0.1.102 | Online | | i-0e5f6a7b8c9d0ef3 | 10.0.2.114 | Online | | i-0f6a7b8c9d0e1f24 | 10.0.3.128 | Online | +------------------------+---------------+---------+

2. IAMロールの最小権限設計(AmazonSSMManagedInstanceCore)

EC2インスタンスにIAMインスタンスプロファイルを付与します。AWS管理ポリシーAmazonSSMManagedInstanceCoreを使うのが最小権限の基本設計です。

・AmazonSSMManagedInstanceCore:Run Command・Session Manager・Patch Manager・State Managerの実行に必要な最小ポリシー
・S3バケットへの実行ログ保存が必要な場合は、対象バケットへのs3:PutObject権限を追加する
・CloudWatch Logsへの転送が必要な場合は、logs:CreateLogGroupとlogs:PutLogEventsを追加する

Terraformでロールを定義する場合は以下のようになります。

# Terraform: SSM実行用IAMロール定義(最小権限) resource "aws_iam_role" "ssm_ec2" { name = "ssm-ec2-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } }] }) } resource "aws_iam_role_policy_attachment" "ssm_core" { role = aws_iam_role.ssm_ec2.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } resource "aws_iam_instance_profile" "ssm_ec2" { name = "ssm-ec2-instance-profile" role = aws_iam_role.ssm_ec2.name }

3. VPCエンドポイント設計(インターネット非公開環境)

プライベートサブネット内のEC2インスタンスからSSMを使う場合、インターネット経由を避けるためにVPCエンドポイントを設定します。以下の3つのエンドポイントが必要です。

・com.amazonaws.ap-northeast-1.ssm:Run Command・SSM管理トラフィック
・com.amazonaws.ap-northeast-1.ssmmessages:Session Manager用
・com.amazonaws.ap-northeast-1.ec2messages:EC2との通信

S3ログ保存を使う場合はGateway型のS3エンドポイントも追加します。各エンドポイントのセキュリティグループはEC2のセキュリティグループからのインバウンド443番(HTTPS)を許可する設定にします。VPCエンドポイントとSSM Agentの構成設計を含むAWS環境全般の基礎については、AWSをLinuxエンジニアが学ぶための基礎講座も参考にしてください。

aws ssm send-commandの基本構文と一括実行手順

1. ターゲット指定|インスタンスIDとタグフィルター

aws ssm send-commandのターゲット指定は2通りあります。

方法1:インスタンスIDを直接指定

# 2台のインスタンスを直接指定してdf -hを実行 $ aws ssm send-command \ --instance-ids "i-0a1b2c3d4e5f6789" "i-0f9e8d7c6b5a4321" \ --document-name "AWS-RunShellScript" \ --parameters 'commands=["df -h"]' \ --region ap-northeast-1

方法2:タグフィルターで対象を動的に指定(マルチAZ設計に推奨)

# Env=prod タグのついた全インスタンスを対象に一括実行 $ aws ssm send-command \ --targets "Key=tag:Env,Values=prod" \ --document-name "AWS-RunShellScript" \ --parameters 'commands=["df -h","free -m"]' \ --region ap-northeast-1

タグフィルターを使うと、インスタンスを増減してもコマンドを変える必要がありません。マルチAZ構成でAZをまたいだ全台に同一操作をする場合はこちらが推奨です。複数のタグを指定するとAND条件になります。

2. コマンドの送信とパラメータ設計

実際にディスク使用率の確認スクリプトをマルチAZ全台に送信する例を見てみましょう。

$ aws ssm send-command \ --targets "Key=tag:Env,Values=prod" \ "Key=tag:Role,Values=web" \ --document-name "AWS-RunShellScript" \ --parameters 'commands=["echo "=== $(hostname) ==="","df -h /","free -m"]' \ --timeout-seconds 60 \ --max-concurrency "50%" \ --max-errors "1" \ --output-s3-bucket-name "my-ssm-logs-bucket" \ --output-s3-key-prefix "run-command/prod-web/2026-10-08" \ --region ap-northeast-1 { "Command": { "CommandId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "DocumentName": "AWS-RunShellScript", "ExpiresAfter": "2026-10-08T16:14:23.000000+00:00", "Status": "Pending", "TargetCount": 6, "CompletedCount": 0, "ErrorCount": 0 } }

実行時の主要パラメータの意味を整理します。

・--document-name AWS-RunShellScript:任意のシェルスクリプトを実行するAWS提供ドキュメント
・--parameters commands=[...]:実行コマンドをJSON配列で指定(複数行スクリプトも可能)
・--timeout-seconds:コマンドの最大実行時間(秒)。長時間処理は適切に延ばす
・--max-concurrency:同時実行数。50%と指定するとターゲット数の半分ずつ順番に実行
・--max-errors:エラーが許容できる上限数。この数を超えると残りの実行を中断する

3. 実行結果の確認(get-command-invocation)

CommandIdを使ってインスタンス単位の実行結果を確認します。

# 特定インスタンスの実行結果(標準出力・標準エラー)を確認 $ aws ssm get-command-invocation \ --command-id "a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ --instance-id "i-0a1b2c3d4e5f6789" \ --region ap-northeast-1 { "CommandId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "InstanceId": "i-0a1b2c3d4e5f6789", "Status": "Success", "StatusDetails": "Success", "StandardOutputContent": "=== ip-10-0-1-45.ap-northeast-1.compute.internal ===\nFilesystem Size Used Avail Use% Mounted on\n/dev/xvda1 30G 8.2G 22G 28% /\n total used free\nMem: 7786 4123 2108\n", "StandardErrorContent": "" }

全インスタンスの実行状況を一覧確認するにはlist-command-invocationsを使います。

# 全インスタンスの実行ステータスを一覧表示 $ aws ssm list-command-invocations \ --command-id "a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ --query "CommandInvocations[*].{Instance:InstanceId,Status:Status}" \ --output table \ --region ap-northeast-1 -------------------------------------------- | ListCommandInvocations | +------------------------+------------------+ | Instance | Status | +------------------------+------------------+ | i-0a1b2c3d4e5f6789 | Success | | i-0f9e8d7c6b5a4321 | Success | | i-0c1d2e3f4a5b6c7d | Success | | i-0d4e5f6a7b8c9012 | Success | | i-0e5f6a7b8c9d0ef3 | Success | | i-0f6a7b8c9d0e1f24 | Success | +------------------------+------------------+

マルチAZ冗長設計での活用パターン

1. 複数AZにまたがるタグベースの一括実行設計

マルチAZ構成では、各インスタンスにEnv・Role・AZなどのタグを統一して付与しておくと、send-commandのターゲット設計が柔軟になります。

・全AZの全台に一括適用する場合:--targets "Key=tag:Env,Values=prod"
・特定AZだけ先行実行して様子見する場合:--targets "Key=tag:Env,Values=prod" "Key=tag:AZ,Values=ap-northeast-1a"
・特定ロールだけ対象にする場合:--targets "Key=tag:Role,Values=web"

タグを2つ指定するとAND条件になるため、「prod環境のwebサーバーだけ」という絞り込みが1コマンドで実現できます。インスタンスの増減があっても、タグが正しく付いていれば対象リストは自動で変わります。

2. MaxConcurrencyとMaxErrorsでリスクをコントロールする

本番のマルチAZ構成に対して一括でスクリプトを実行するときは、想定外の失敗が全台に波及しないよう、--max-concurrencyと--max-errorsを必ず設定してください。

・--max-concurrency:同時に実行するインスタンス数。1(1台ずつ順次)から100%(全台同時)まで指定可能。本番は25%~50%が目安
・--max-errors:許容できるエラー数の上限。0にすると1台でも失敗した時点で残りの実行をキャンセル。1~2が実務上の標準

冗長設計を崩さないために、--max-concurrency "25%"を指定してAZ間でローリング的に展開するのがおすすめです。AZをまたいだ冗長構成の設計パターン全般はAWSマルチAZ冗長設計の実践ガイドも参照してください。

3. 実行ログのS3保存とCloudWatch Logsへの転送設計

マルチAZの全インスタンスに一括実行した場合、標準出力・標準エラーをS3またはCloudWatch Logsに保存しておくと、事後のトラブルシュートが楽になります。

# S3とCloudWatch Logs両方に出力を保存するセキュリティパッチ適用例 $ aws ssm send-command \ --targets "Key=tag:Env,Values=prod" \ --document-name "AWS-RunShellScript" \ --parameters 'commands=["yum update -y --security 2>&1"]' \ --timeout-seconds 600 \ --max-concurrency "25%" \ --max-errors "1" \ --output-s3-bucket-name "my-ssm-logs-bucket" \ --output-s3-key-prefix "security-patch/2026-10-08" \ --cloud-watch-output-config \ 'CloudWatchOutputEnabled=true,CloudWatchLogGroupName=/ssm/run-command/prod' \ --region ap-northeast-1

CloudWatch Logsに転送すると、インスタンスID単位のログストリームが自動作成され、マネジメントコンソールから各台の出力を直接確認できます。S3保存と組み合わせることで、長期保管とリアルタイム確認の両方に対応できます。

トラブルシュート|よくあるエラーと対処法

「An error occurred (InvalidInstanceId) when calling the SendCommand operation」

原因:対象インスタンスがSSMに登録されていない(SSM AgentがOfflineかIAMロール未設定)
対処:aws ssm describe-instance-informationでPingStatus=Onlineを確認。IAMインスタンスプロファイルにAmazonSSMManagedInstanceCoreが付与されているか確認する

Status: Failed / StatusDetails: executionTimedOut

原因:スクリプトが--timeout-secondsの設定時間内に終了しなかった
対処:--timeout-secondsを増やすか、スクリプトをより短い単位に分割する。yum updateなど長時間処理は600秒以上に設定する

タグフィルターで対象が0件になる

原因:タグキー/バリューの大文字小文字が一致していない、またはタグが付与されていない
対処:aws ec2 describe-instances --filters "Name=tag:Env,Values=prod" --query "Reservations[*].Instances[*].InstanceId"でタグが付いているインスタンスを事前確認する

プライベートサブネットのインスタンスがOnlineにならない

原因:VPCエンドポイントが未設定か、エンドポイントのセキュリティグループが443番ポートを許可していない
対処:VPCエンドポイント(ssm・ssmmessages・ec2messages)の作成とセキュリティグループのインバウンド443番許可を確認する。エンドポイントは各サブネットに1つずつ配置する必要がある

本記事のまとめ

やりたいこと コマンド・設定
SSM Agentの状態確認 sudo systemctl status amazon-ssm-agent
SSMオンライン状態のインスタンス一覧 aws ssm describe-instance-information --filters "Key=PingStatus,Values=Online"
タグ指定で一括スクリプト実行 aws ssm send-command --targets "Key=tag:Env,Values=prod" --document-name "AWS-RunShellScript" --parameters 'commands=["cmd"]'
インスタンス単位の実行結果確認 aws ssm get-command-invocation --command-id "..." --instance-id "i-xxx"
全インスタンスのステータス一覧 aws ssm list-command-invocations --command-id "..."
コマンド実行のキャンセル aws ssm cancel-command --command-id "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
実行ログのS3保存付き一括実行 aws ssm send-command --targets "Key=tag:Env,Values=prod" --document-name "AWS-RunShellScript" --parameters 'commands=["cmd"]' --output-s3-bucket-name "bucket"
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
AWSをゼロから体系的に学べる入門講座を用意しています。
>> AWS Amazon Linux サーバー構築入門はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。