Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Deploy to EC2 from GitHub Actions without opening port 22

2026年09月05日に「Dev.to」が公開したITニュース「Deploy to EC2 from GitHub Actions without opening port 22」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

GitHub ActionsからEC2へ安全にデプロイする新手法を紹介する。従来のSSHと長期秘密鍵を使う代わりに、AWS Systems Manager (SSM) Run Commandを活用。これによりポート22の開放が不要となり、EC2インスタンスをプライベートサブネットに置ける。一時的な認証でセキュリティを強化し、デプロイ履歴も自動で記録される。専用のGitHub Actionsアクションで簡単に導入できる。

ITニュース解説

システムエンジニアを目指す皆さんにとって、日々の開発作業で書いたプログラムをサーバーにデプロイする(配置して動かす)作業は非常に重要だ。特にクラウド環境であるAWSのEC2(仮想サーバー)に、GitHub Actionsのような自動化ツールを使ってデプロイする場合、その方法とセキュリティは常に課題となる。この記事では、従来のデプロイ方法が抱える問題点と、それをAWS Systems Manager(SSM)のRun Command機能を使って、より安全かつ効率的に解決する方法について解説する。

まず、これまでGitHub ActionsからEC2へデプロイする際の一般的な方法として、SSHというプロトコルを使うやり方が広く行われていた。これは、サーバーにログインするための秘密の鍵ファイルをGitHub Actionsのシークレット(外部から見えないように管理される情報)に保存し、その鍵を使ってEC2インスタンスにSSH接続してコマンドを実行するというものだ。この方法は確かに機能するが、いくつかの重要な課題を抱えている。一つは、サーバーへのアクセスに必要な秘密鍵が長期間にわたって利用され続けるため、もしこの鍵が漏洩した場合のセキュリティリスクが高いことだ。もう一つは、SSH接続のためにEC2インスタンスの「ポート22」という特定のネットワークの入り口をインターネットに開放する必要がある点だ。これは、不特定多数からのアクセスを許す可能性があり、セキュリティ上の弱点となる。GitHub Actionsからの接続元IPアドレスを限定することもできるが、GitHubのIPアドレス範囲は非常に広いため、完全な対策とは言えない。

AWSは、これらの課題に対してより優れた解決策を提供している。それがSystems ManagerのRun Command機能だ。この方法では、EC2インスタンスに「SSM Agent」というソフトウェアをインストールしておく。このAgentは、自分からAWSのサービス(SSM API)に対して通信(アウトバウンド接続)を開始する。これにより、EC2インスタンスに外部から直接アクセスするためのポートを開放する必要がなくなる。つまり、ポート22を開放しなくても、AWSを通じて安全にインスタンスにコマンドを送れるようになるのだ。この仕組みの大きな利点は、EC2インスタンスがたとえインターネットから直接アクセスできないプライベートなネットワーク(プライベートサブネット)に配置されていても機能する点にある。また、サーバーへのアクセスに秘密鍵を使う必要がないため、鍵の管理や定期的な交換(ローテーション)の手間がなくなる。実行されたすべてのコマンドはAWSの監査ログサービスであるCloudTrailに記録されるため、いつ誰がどのコマンドを実行したかを後から確認できる点も、セキュリティと運用管理の観点から非常に有用だ。

筆者は、このSSM Run Commandの利点を自身のデプロイパイプラインに活用したいと考えたが、既存のGitHub Actionsが見当たらなかったという。既存のアクションの中には、コマンドを実行してもその成否を確認しないものや、エラーコードを正しく扱わないもの、あるいはログ出力に制限があり、途中で情報が途切れてしまうといった問題があったため、自身で「ankurk91/aws-ssm-run-command-action」というGitHub Actionsを開発した。

SSM Run CommandとSSHのデプロイ方法を比較すると、SSMの利点が明確になる。 まず、ネットワークの入り口となる「ポート22」の開放はSSMでは不要だが、SSHでは必須となる。これにより、SSMを使う場合、EC2インスタンスにインターネットから直接アクセスできる「パブリックIPアドレス」も通常は不要となる。SSHでは通常必要となる。 認証情報の管理について、SSHでは長期間有効な秘密鍵をGitHub Actionsのシークレットに保存する必要があるのに対し、SSMではOIDC(OpenID Connect)とIAMロールという仕組みを利用することで、短時間だけ有効な一時的な認証情報を使ってAWSにアクセスできるため、セキュリティレベルが格段に向上する。鍵の交換も、SSMではそもそも鍵が存在しないため不要だ。 EC2インスタンスをインターネットから隔離された「プライベートサブネット」に配置する場合、SSHでは通信を中継するための踏み台サーバー(Bastion)やVPN接続が必要となるが、SSMではNATゲートウェイやVPCエンドポイントといったAWSの仕組みを利用すれば特別な設定なしに機能する。 誰がどのコマンドを実行できるかといったアクセス制御も、SSHではサーバー内のauthorized_keysファイルを編集する必要があり、サーバーごとの管理が煩雑になりがちだが、SSMではAWSのIAMポリシー(アクセス権限を設定するルール)を使って、インスタンスやタグごとに細かく設定できる。 監査ログについては、SSHではサーバーのログファイル(auth.logなど)を個別に確認する必要があるが、SSMではCloudTrailとSSMのコマンド実行履歴に自動的に記録される。アクセス権の取り消しも、SSHでは全サーバーのファイルを編集する必要があるのに対し、SSMではIAMポリシーをデタッチ(解除)するだけで済む。 SSMには、リアルタイムでコマンドの出力結果を確認する機能や、ファイルを直接コピーする機能(scpやrsync)がないという二つの点でSSHに劣る。しかし、デプロイスクリプトにおいては、ログは後からS3に保存されたものを確認すれば十分であり、ビルド成果物もサーバーがS3やコンテナレジストリからプルする(取り出す)方式の方が、GitHub Actionsからプッシュするよりも効率的でセキュアであることが多い。

SSM Run CommandをGitHub Actionsで利用するには、AWS側でいくつか準備が必要だ。 まず、デプロイ先のEC2インスタンスにSSM Agentがインストールされていること。Amazon Linuxや公式のUbuntu AMI(EC2の起動イメージ)には最初から含まれていることが多い。 次に、そのEC2インスタンスに「AmazonSSMManagedInstanceCore」というAWSが管理するポリシーが付与されたIAMロールをアタッチ(割り当てる)する必要がある。これにより、SSM AgentがAWSのSSMサービスと通信するための権限が与えられる。 最後に、コマンドの実行ログを保存するためのプライベートなS3バケットを用意する。SSM自体のログ出力には約24KBというサイズ制限があるため、このS3バケットを利用することで、ログが途中で途切れることなく完全に保存される。古いログオブジェクトはライフサイクルルールを設定して自動的に削除できるため、管理の手間も少ない。

これらの準備が整えば、GitHub Actionsのワークフローは非常にシンプルになる。 まず、aws-actions/configure-aws-credentialsアクションを使って、GitHub Actionsが一時的なIAMロールを借りてAWSにアクセスするための認証を設定する。これはid-token: writeというGitHub Actionsのパーミッションと、借りるIAMロールのARN(リソースを一意に識別するID)を指定することで実現される。 次に、ankurk91/aws-ssm-run-command-actionアクションを使って、EC2インスタンス上で任意のコマンドを実行する。ec2_instance_idでターゲットのインスタンスを指定し、log_bucket_nameでログを保存するS3バケットを指定する。commandsセクションには、実行したいシェルスクリプトを記述する。例えば、アプリケーションのディレクトリに移動し、git pullで最新のコードを取得し、依存関係のインストール、データベースマイグレーションの実行、アプリケーションのビルド、プロセスマネージャーの再起動といった一連のデプロイコマンドをここに記述できる。

このワークフローでは、AWSのIAMロール以外の秘密情報はGitHub Actionsのシークレットに保存する必要がなく、ポート22を開放する必要もないため、非常に安全だ。 運用上の注意点としては、実行するスクリプトの冒頭にset -eと記述することをお勧めする。これにより、途中のコマンドが失敗した場合にシェルスクリプト全体の実行が停止し、予期せぬ成功として報告されるのを防ぐことができる。また、コマンドの実行タイムアウトはデフォルトで1時間と長いため、通常のデプロイであれば短く設定しておくことで、ハングしたコマンドが無駄に実行時間を消費するのを避けられる。コマンドの終了コードはアクションの出力として取得できるため、それに基づいて後続の処理を分岐させることも可能だ。

さらに、SSMには「ポートフォワーディング」という便利な機能もある。これは、Run Commandがサーバー上でスクリプトを実行するのに対し、ネットワーク接続が必要な場合に役立つ。例えば、データベースのマイグレーション(データベーススキーマの変更)をGitHub Actionsの実行環境から直接行いたい場合、データベースは通常プライベートなネットワークに存在するため、直接アクセスできない。このとき、EC2インスタンスを中継点として、データベースへのセキュアなトンネルを確立できるのだ。enkhjile/aws-ssm-remote-port-forwarding-actionというアクションを使えば、EC2インスタンスを経由して、プライベートなデータベース(例:RDS)にGitHub Actionsの実行環境から安全に接続し、マイグレーションを実行できる。データベースはローカルホストにあるかのように見えるため、アプリケーションの設定を変更する必要もない。この際も、EC2インスタンスやデータベースのセキュリティグループにインターネットからのインバウンドルールを追加する必要はなく、極めてセキュアな接続が実現できる。

まとめると、もし皆さんがまだGitHub ActionsからEC2へのデプロイに秘密鍵を使い、ポート22を開放しているなら、SSMへの移行はセキュリティと運用効率を大きく向上させる強力な選択肢となる。秘密鍵を削除し、不要なポートを閉じ、すべてのコマンド実行の監査ログを自動で取得できるようになるのだから、少し時間をかけてでも導入を検討する価値は十分にある。

関連コンテンツ

関連IT用語

関連ITニュース