踏み台EC2を廃止してSession Manager接続に置き換えました

Daichi Harada
Sep 14 · 9 min read

こんにちは、エウレカ SRE チームの原田です。

今年エウレカでは、公開鍵認証で接続するEC2の踏み台サーバを廃止し、代わりに各サーバへの接続をIAMで認証できるSSM Session Managerへのリプレースを行いました。本記事ではそのモチベーションや、実装のポイントを紹介していきたいと思います。

旧来の踏み台サーバ

旧来の踏み台サーバ

エウレカで長く運用されていた踏み台サーバ (Gateway) は以下のようなものでした。

課題

機能上は上記で全く問題なかったのですが、運用の観点で以下のような課題を感じていました。

日常的な変更のリードタイムと労力が大きい

入退社時にSSH鍵とユーザーの登録が必要で、変更発生頻度が高い上に、その都度 設定変更→ packer build → terraform反映 → サーバのローテーション(手作業) を行う必要があったため、変更反映のリードタイムと労力が大きい

鍵の管理が大変

サーバーの秘密鍵はAnsible Vaultで暗号化した状態でGitリポジトリに保管していたため、平文コミットの可能性が拭えなかったり、ローテーションの対応が必要であるなど、管理上考えることが多く悩ましい

サーバー設定の複雑・肥大化

各ユーザーのPermission設定やサーバ上での監査ログ収集などの要件が多く、AnsibleのPlaybookが複雑化、肥大化していた。また、変更のリードタイムの長さから、こういった設定を変更する際のデバッグがしづらい

SSM Session Manager とは

Session Manager は AWS Systems Managerの機能で、AWSコンソールまたはAWS CLIのコマンド経由で、SSM Agentを経由してサーバに接続することができます。

GUI ベースでSSH可能
aws ssm start-session --target <instance_id>

接続制御をIAMに集約できるので鍵の管理や踏み台ホストの管理が不要になることや、接続ログもCloudTrailで取れるなど前述の課題をうまく解決してくれそうだったので導入することにしました。

新アーキテクチャ

Session Managerを活用して、最終的に以下のような構成で運用しています。

EC2への接続

チームごとのアクセス可否制御をIAM Policyで表現する

チーム毎にサーバへのアクセス可否を設定する必要があったため、各チームごとに接続できるサーバをresource句で定義したRoleを定義し、AWS SSOで各チームにアサインしました。

具体的にはssm:StartSessionのconditionで制御を行います。 以下のようなIAM Policyを各チーム向けのIAM Roleにアタッチしておきます。

statement {
effect = "Allow"
actions = ["ssm:StartSession"]
resources = [
"arn:aws:ec2:*:*:instance/*",
]
condition {
test = "StringLike"
variable = "ssm:resourceTag/Name"
values = ["hoge-server", "fuga-server"] // allowed server names
}
}

オートスケール構成だとinstance arnが事前に確定しないため、resource句での制御はできません。代わりにStringLike conditionを使ったTagでの制御を行っています。なお、Tagを変更するとこの制限を突破できてしまうので、別途SCP (Service Control Policy) などでTagの変更が確実にDenyされていることを保証する必要があります。

MySQL / Elasticsearch / Redis への接続

Private Subnetに配置しているこれらのデータソースに接続するには、引き続き踏み台となるホストが必要となります。EC2での管理は辞めたかったので、ECS on FargateでSSM Agentがインストールされたコンテナを動かしてそれを踏み台とし、各種データソースに接続 / クエリしてもらうようにしています。

具体的な構築方法は以下の記事を参考にさせていただきました。

実は、この踏み台サーバーのリプレース中に特に何もインストールしてないコンテナにもStartSessionができる「ECS Exec」がリリースされています。今から構築するならこちらを使うのがよさそうです。ただしデフォルトだと 各コンテナの ECS Exec セッションの最大数 が 2 に設定されているので、複数人でつなぎに行く踏み台として使う場合ここの引き上げ申請は必要そうです。

ローカル用 Database GUI Client のサポート

DatabaseにSequel, DataGripなどのGUIクライアントから接続したい要望がありました。これまでは踏み台のSSH情報 + MySQLの認証情報で接続していたのですが、新しい踏み台はそのままだとSSHの接続情報はないためうまく接続できません。

SSH over SSM を使うことをまず検討したのですが、鍵の管理や全員の ~/.ssh/config をもれなく変更してもらうのはやや大変と感じました。

別のアプローチを探したところ、以下のRedditのスレッドで議論されているような socatでのtcpリレーを踏み台上で実行し、ローカルから SSM Sessions ManagerのPort Forwarding機能 を使う方針ですすめることにしました。

動作イメージを図にすると以下のようになり、事前にローカルでSSM Port Forwardのコマンドを実行しておくことで、localhostの:3306に接続すると各Databaseの:3306につながるようになります。

接続用のスクリプト / ドキュメント整備

開発者全員に使ってもらうものなので、必要以上に裏側を意識しなくても使えるような工夫として、ローカルから接続してもらう際gatewayのinstance idやポート番号をいちいち入れずに使えるスクリプトを用意したり、接続方法のドキュメントを充実させたりしています。

接続用スクリプト
接続方法の解説ドキュメント ( 一部 )

導入してどうなったか

入退社時にAWS SSOへの自動登録/解除が行われるため、そこと連動することで踏み台サーバ関連の反映リードタイムや労力がゼロとなり、かなり楽になりました。また各サーバへの接続用の鍵管理がなくなり、全てAWS SSOのアサインとIAM Policyでかけるようになったことで随分スッキリとしました。

今後改善できそうなポイントとしては、GUIクライアント利用時のPort Forwardスクリプト実行の手間が増えてしまったので、この部分の省力化することを考えています。AWS CLI v2とAWS SSOの統合 を使うと改善できそうだったり、鍵やssh config変更の手間はあるものの SSH over SSM をやる方針も再度検討してみたいと思っています。

Eureka Engineering

Learn about Eureka’s engineering efforts, product…

Eureka Engineering

Learn about Eureka’s engineering efforts, product developments and more.

Daichi Harada

Written by

SRE

Eureka Engineering

Learn about Eureka’s engineering efforts, product developments and more.