はじめに
今までEC2インスタンスを運用するときにはEC2インスタンス作成時にSSHキーペアを作成してSSHで接続、データ転送する際にはSCP等で転送するようなことをやっておりましたが、Systems Managerの機能を使うことでキーペアを使わなくて済むため、今回はSystems Managerサービスの1機能となるSession Managerを使ってキーペアを根絶してみようと思います。
なぜキーペアを根絶したいのか
そもそもキーペアとは何かというと、EC2にSSH接続する際に必要となる鍵情報となります。
キーペア自身には鍵情報を定期的に更新したりする機能は無いので、意図的に更新作業など行わなければ、同じキーペアファイルで永続的に対象のEC2にログインすることができるものとなります。
キーペアでEC2に接続するためには、作業を行うクライアントやサーバにキーペアを置く必要があるので、キーペアを運用していかないといけないリスクや、キーペアが誤って公開されてしまったときのリスクと向かい合わなければならず、持たなくて済むなら持ちたくないものです。
AWS Systems Manager Session Managerについて
AWS Systems ManagerのSession Manager機能を使えばユーザのアクセス制御はIAMで行うことができ、ログインしてCLI操作を行うだけであればキーペアも不要でセキュリティグループでSSHを許可する必要も無いことから、AWSでEC2に接続する際にはぜひとも使ったほうが良い機能だと思います。
ただ、Session ManagerはSSHとは当然異なるため、SSHを使うことを前提とするサービス(例えばAnsible)等を利用したりサーバ間通信でSCP等を利用している場合は、単純にSSHをSession Managerに置き換えると問題が発生してしまうので、今回の記事を参照してよく検討するようにしてください。
Ansibleに限って言えば、Run Commandで用意されているAnsible用ドキュメントを使うことでキーペアを持つことを回避することができるのでキーペア根絶の参考にしてください。
- AnsibleをAWS Systems Managerから実行するCI/CDを構築する。(その1:Systems ManagerからのAnsible実行)
- AWS Systems ManagerでAnsible実行を行う前提でのPlaybook構成検討
また、今回はEC2の説明に限りますが、Session Managerと連携するためのSSMエージェントをLinuxサーバ等にインストールすることで、オンプレサーバへの接続も管理することが可能です。
Session Managerによる接続手順
以下より大きく3つの項目に区切ってSession Managerを使ったEC2への接続について紹介していこうと思います。
最初にSession Managerを使った接続手順を説明する「接続編」、EC2のネットワーク構成ごとの接続手順を説明する「構成編」、Session Managerを使ったSSHプロキシ等の手順を説明する「応用編」を説明していきます。
接続編
EC2がSession Managerと連携できるようになっていれば、AWSマネジメントコンソールもしくはCLIから接続できます。
事前作業
Session Manager経由でEC2接続するためにはSSMエージェントの準備とEC2からSession Managerへの通信を許可するIAMロールの設定が必要となります。
以下よりSSMエージェントインストールの方法とIAMロールの作成を行っていきます。
SSMエージェントの準備
Session Manager経由でのEC2接続の仕組みとして、Session Managerと連携するためのSSMエージェントというサービスを使ってSSMエージェントからSession Managerに接続を行うことで、Session Manager側からEC2を管理・接続できるようになるという仕組みとなります。
SSMエージェントはAWSが提供している比較的最近のマシンイメージ(AMI)を使用しているようであれば、すでに実装済みとなるため特に作業は不要ですが、独自のAMIを使用したり、古いAMIを使用したい場合はEC2にSSMエージェントを個別にインストールする必要があります。
以下、x86_64のAmazon Linux 2023に対してSSMエージェントをインストール&サービス起動する場合の例。
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo systemctl enable --now amazon-ssm-agent
その他OSへのインストール方法は以下参照。
SSMエージェントの設定
Session ManagerでEC2に接続を行うと、デフォルトでは「/var/lib/amazon/ssm/[インスタンスID]/document/orchestration」に作業ログや一時ファイルが置かれ、ログアウトしてもそのまま残り続けます。
EC2へログインしてのコマンド実行程度であればすぐに枯渇するようなことも無いかと思いますが、SSMエージェントはRun Command等でも使われ、ログだけではなく実行ファイルも置かれることから、特にRun CommandでAnsibleを実行する場合、Playbookのファイルが毎回まるごとダウンロードされるため、何度も実行しているとそれだけでディスク容量やiノードが逼迫してしまいます。
ディスクやiノード枯渇を防ぐため、以下の作業を行い、作業ログや一時ファイルがサーバ上に残らないようにしましょう。
IAMロールの準備
EC2からSession Managerへ通信することから、EC2にIAMロールを付与し、EC2からSession Managerへの接続を許可する必要があります。
あらかじめIAMポリシーとして作成されている、AmazonSSMManagedInstanceCoreに、Session Managerに必要な権限が付与されているため、こちらのポリシーを使ってIAMロールを作成します。
IAMダッシュボードより、「ロール」→「ロールを作成」で以下のようにIAMロールを作成します。
| 項目 | 設定 | 備考 |
|---|---|---|
| 信頼されたエンティティタイプ | AWSのサービス | |
| ユースケース | EC2 | |
| 許可ポリシー | AmazonSSMManagedInstanceCore | |
| ロール名 | ec2instance-role | 任意の名前を入力 |
| 説明 | デフォルトのまま | 任意の説明を入力 |
| タグ | 空欄 | 今回は設定せず |
作成したらEC2ダッシュボードより「インスタンス」からIAMロールを付与するEC2を選択し、「アクション」→「セキュリティ」→「IAMロールを変更」で作成したIAMロールを選択し、「IAMロールの更新」でIAMロールを付与します。
AWSマネジメントコンソールからのEC2接続
EC2のネットワーク構成的にSession Managerに接続できる状態になっている前提で進めます。
EC2ダッシュボードより「インスタンス」から接続を行いたいEC2を選択し、「接続」→「セッションマネージャー」タブの「接続」を押下します。
正常に接続できれば、SSH接続したときと同じように操作ができる画面が表示されます。
また、別の方法として、Systems Managerダッシュボード画面の「セッションマネージャー」→「セッション」タブから「セッションの開始」で接続したいEC2を選択し、「Start session」を押下しても接続することができます。
AWS CLIからのEC2接続
クライアントPCからSession Managerで接続するためにはaws ssm start-sessionコマンドで接続したいEC2のインスタンスIDを指定して実行することでSession Manager経由でEC2に接続することができます。
以下、i-07e03a71e09e5921bのインスタンスIDを持つEC2に接続した場合の表示例。
aws ssm start-session --target i-07e03a71e09e5921b
Starting session with SessionId: xxxxx-xxxxxxxxxxxxxxxxx
sh-5.2$ exec /bin/bash
[ec2-user@ip-10-1-1-144 bin]$ cd ~/
[ec2-user@ip-10-1-1-144 ~]$ timestamp=$(date '+%Y-%m-%dT%H:%M:%SZ')
[ec2-user@ip-10-1-1-144 ~]$ echo $timestamp
2023-10-14T12:11:18Z
[ec2-user@ip-10-1-1-144 ~]$
前準備は必要ですが、前述の通り、セキュリティグループでSSHポートを許可する必要もなく、キーペアも作成する必要が無いため、簡単にセキュアな接続構成を準備することができます。
以下からはEC2のネットワーク構成ごとのSession Manager接続方法を説明します。
構成編
Session ManagerはVPC外のサービスとなるため、実際にクライアントPCからSession Manager経由でEC2に接続する場合の構成としては以下のような構成となります。
Session Managerは大雑把に言うとEC2への接続をプロキシしてくれるようなサービスとなるため、EC2自身もSession Managerサービスと連携できるようにしないとSession Manager経由で接続することができないので、上述のIAMロールの設定でEC2からSession Managerへ接続できるように権限を付与する必要がありました。
EC2のネットワーク構成としては以下のようなパターンが考えられるかと思いますので、それぞれのパターンごとに説明していきます。
- パブリックサブネットに所属したEC2にSession Manager接続する場合
- プライベートサブネットに所属したEC2にSession Manager接続する場合(NATゲートウェイあり)
- プライベートサブネットに所属したEC2にSession Manager接続する場合(NATゲートウェイなし)
パブリックサブネットに所属したEC2にSession Manager接続する場合
EC2が直接グローバルIPアドレスを持っているパブリックサブネットに所属している場合、EC2はインターネット経由(厳密にはAWSのグローバルIPネットワーク網内での通信となるためインターネット網とは異なりますが)でSession Managerと連携できるため、EC2でSSMエージェントが動作していれば何もせずともSession Manager経由で接続することができます。
プライベートサブネットに所属したEC2にSession Manager接続する場合(NATゲートウェイあり)
グローバルネットワークとNATゲートウェイ経由で接続しているEC2インスタンスの場合、NATゲートウェイ経由でEC2からSession Managerに対して接続できることから、パブリックサブネット所属のEC2の時と同様、EC2でSSMエージェントが動作していればSession Manager経由で接続することができます。
プライベートサブネットに所属したEC2にSession Manager接続する場合(NATゲートウェイなし)
グローバルネットワークと全く繋がっていないセグメントに所属するEC2インスタンスに接続する場合、そのままではEC2からSession Managerへ接続するための経路がなく、Session Managerと連携することができないため、Session Managerと裏から接続するためのVPCエンドポイントを作ってあげる必要があります。
VPCエンドポイントを作成することで、通常、AWSのグローバルネットワーク経由で繋ぐ必要があるSession Managerとの接続を内部のプライベートネットワークから直接Session Managerへ接続することができるようになります。
以下よりVPCエンドポイントの作成方法を説明します。
VPCエンドポイントとは
EC2から内部のプライベートネットワークでSession Managerと接続するには、PrivateLinkといった機能を使用してVPCエンドポイントを設定する必要があります。
ざっくり言うと、該当のプライベートネットワークにSession Managerサービスと直接接続している仮想ネットワークインタフェース(ENI)を作成することで、裏からSession Managerに繋げられるようにします。
もう少しPrivateLinkについて説明すると、例えばSession Managerというパブリックに公開されているサーバがあったとして、内部のサーバと通信するためにネットワークインタフェースを増設してプライベートセグメントにも接続できるようにするような機能となります。
セキュリティグループの作成
VPCエンドポイントを作成する前に、VPCエンドポイントを設定する際に一緒に作成されるネットワークインタフェース(ENI)に付与するセキュリティグループを作成しておきます。
Session Managerとの通信は443ポートで行われるため、インバウンドの443ポートを許可する設定を行います。
なぜEC2からSession Managerへの通信に対するセキュリティグループ設定なのにアウトバウンドの443ポートではなくインバウンドの443ポートを指定するのかと言うと、セキュリティグループを付与する対象はENIとなり、ENIから見た場合は、EC2からENIに入ってくる通信(インバウンド)となるため、インバウンドの許可となります。
以下にENIから見た際のセキュリティグループのイメージ。
VPCエンドポイントの作成
VPCダッシュボードより「Endpoints」→「エンドポイントを作成」から各エンドポイントを作成していきます。
サービスとしては以下のサービスを指定する必要があり、まとめて選択するようなことはできないことから、最大で以下6つ分のVPCエンドポイントを作成します。
| サービス名 | 必須有無 | 説明 |
|---|---|---|
| com.amazonaws.region.ec2messages | 必須 | |
| com.amazonaws.region.ssm | 必須 | |
| com.amazonaws.region.ssmmessages | 必須 | |
| com.amazonaws.region.kms | オプション | 暗号化オプションを使う場合に必要 |
| com.amazonaws.region.logs | オプション | CloudWatch Logsへログ転送する場合に必要 |
| com.amazonaws.region.s3 | オプション | S3へログ転送する場合に必要 |
オプションと記載した3つについては、Session Managerの設定によって追加で設定する必要があり、もしSession Managerの設定で有効にしているのにVPCエンドポイントの設定が行われていないと接続できないので注意してください。
なお、Session Managerの設定はSystems Managerダッシュボードより、「セッションマネージャー」→「設定」タブの「編集」から設定できます。
VPCエンドポイントの設定は以下のように設定します。
| 項目 | 設定 | 備考 |
|---|---|---|
| 名前タグ | ※任意 | 任意の名前を指定 |
| サービスカテゴリ | AWSのサービス | |
| サービス | ※上記のサービスを指定 | |
| VPC | ※VPCエンドポイントを作成するVPCを指定 | |
| DNS名を有効化 | チェック | DNSが有効でないと作成に失敗するため、指定する |
| DNSレコードのIPタイプ | IPv4 | |
| サブネット | ※EC2が存在するプライベートサブネットを指定 | |
| IPアドレスタイプ | IPv4 | |
| セキュリティグループ | session_manager_sg | 先程作成したセキュリティグループを指定 |
| ポリシー | フルアクセス | 今回はフルアクセスで指定 |
| タグ | 空欄 | 今回はタグは作成しない |
上記VPCエンドポイントを作成することで、EC2からSession Managerへ接続できるようになります。
EC2からSession Managerへ接続する際にはDNSで内部に作られたENIのアドレスを問い合わせてVPCエンドポイント経由で接続することになるため、特にルーティング等は不要です。
応用編
「接続編」、「構成編」までの手順で、キーペアを使わずに様々なネットワーク構成のEC2に接続することができるようになったので、一般的な使い方をする分にはここまでの手順で支障がないかと思います。
ここからは応用として、Session Managerを使ったポートフォワードを行ってみようと思います。
Session Managerを使ったポートフォワード
SSHにはクライアントとサーバ間で接続したSSHのセッション(SSHトンネル)を使って、任意のポートの通信をフォワーディングするSSHポートフォワード機能がありますが、Session Managerにも同じようにポートフォワードする機能があります。
Session Manager接続するEC2へのポートフォワード
Session Managerを使って接続するEC2の他のポートにフォワーディングする場合、EC2に以下のコマンドで接続することでフォワーディングすることができます。
aws ssm start-session \
--target [インスタンスID] \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["[リモートポート番号]"], "localPortNumber":["[ローカルポート番号]"]}'
上記コマンドを実行することで待ち受け状態となるので、例えばリモートポートをポート80、ローカルポートをポート8880とした場合、別のターミナルやブラウザを開いてcurlコマンドやWebブラウザからhttp://localhost:8880/のようにしてクライアント自身にアクセスすると、Session Managerで接続しているEC2上で動作しているWebサービスに接続できる仕組みとなります。
Starting session with SessionId: xxxxx-xxxxxxxxxxxxxxxxx
Port 8880 opened for sessionId xxxxx-xxxxxxxxxxxxxxxxx.
Waiting for connections...
なお、Session Managerで接続したEC2がプロキシのような役割になってポート80にアクセスするようなイメージとなるため、クライアントからのポート80への通信許可をセキュリティグループで行う必要はありません。
以下参考にしたURL
Session Manager接続するEC2経由で他ホストへのポートフォワード
先程はSession Managerで接続しているEC2へのポートフォワードでしたが、以下のコマンドで接続することでSession Managerで接続したEC2から更に先に存在するサービスにアクセスすることができるようになります。
aws ssm start-session \
--target [インスタンスID] \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["[ホスト名またはIPアドレス]"],"portNumber":["[リモートポート番号]"], "localPortNumber":["[ローカルポート番号]"]}'
指定しているdocument-nameが異なるのと、parametersにhostの指定が加わったこと以外は変わりません。
ちなみに、ホスト指定をlocalhostにすればSession Managerで接続しているEC2自身を指定することになるので、先程のAWS-StartPortForwardingSessionのドキュメントを使った場合と同じ動作となります。
そのため、わざわざ2つのポートフォワード用コマンドを使い分けるのではなく、AWS-StartPortForwardingSessionToRemoteHostのコマンドだけ使うようにしても良いかと思います。
上記Webサービスへのアクセスは、Session Managerで接続しているEC2を送信元ホストとしてWebサービスにアクセスすることになるため、セキュリティグループでEC2からアクセスできるように許可を行ってください。
Session Manager経由でのSSH接続
先程のSession Managerを使ったポートフォワードの応用となりますが、ポートフォワードでEC2のSSHポートに接続することで、セキュリティグループでSSHを許可しなくてもSSH接続できるようになります。
ポートは許可する必要はありませんが、当然SSH接続するためのキーペアもしくはパスワードは必要となるので今回の記事としては本末転倒ですが、SCPやSFTPでデータ転送したいといった場合の参考にしてください。
また、クライアント側の~/.ssh/configに以下のようなプロキシコマンドを登録することで、SSHコマンドを実行した際に、裏でSession Managerの接続をした上でSession Managerトンネル経由でSSHできるようになります。
# SSH over Session Manager
host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
以下、プロキシコマンド登録したクライアントからSSHでEC2に接続した場合のコマンド例。
ssh ec2-user@[インスタンスID] -i [キーペアファイル]
おわりに
キーペアを根絶するためにはいくつか課題はあるため、システムによっては根絶ができない場合もあるかと思いますが、そのような場合でもSession Managerを組み合わせることでSSHのリスクを軽減できることがわかるかと思います。
運用で回避可能であれば、例えばEC2へのデータ転送はS3経由で行ったり、AnsibleはRun Commandで実行するように変更したりすれば、キーペアの根絶も可能かと思うので、なるべくキーペアを使わない運用にシフトできれば幸せになれるかと思います。






