はじめに
今まで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
で実行するように変更したりすれば、キーペアの根絶も可能かと思うので、なるべくキーペアを使わない運用にシフトできれば幸せになれるかと思います。