今すぐやめようssh! AWS Session Managerを検証・導入してみた

この記事は アソビュー! Advent Calendar 2019 - Qiita 17日目の記事です。

アソビューにてバックエンドおよびSREを担当している寺岡(@toda_kk)と申します。よろしくお願いします!

最近はリングフィットアドベンチャーをやり始め、スクワットをする度に「いいぞ!」「すごいぞ!」と褒められることで自己肯定感を高めています。

はじめに

さて、SREの業務というと、どの企業でも多岐にわたるかと思います。インフラアーキテクチャの設計および構築、モニタリング環境の整備、開発フローや運用業務の効率化……などなど、ビジネス上あまり目立たないけれど実は大事な役割を担っていたりします*1

そんな中で、今回は開発や運用の効率化のためにAWSのSession Managerという機能を検証・導入した話を取り上げたいと思います。

Session Managerとは?

AWS Systems Manager Session Managerとは、マネジメントコンソールやAWS CLIを介してEC2インスタンスを管理するための機能です。IAMポリシーでアクセス制御を設定できるなど、セキュリティ面での向上が期待できます。

その他、サービスの特徴や導入のメリットについては公式ドキュメントをご参照いただきたいのですが、多くの場合はEC2インスタンスに対するssh接続の代替となる機能として認識されることが多いのではないかと思います。

課題感

弊社ではインフラリソースとしてAWSを利用しており、特に最近はECSやEKSの導入をはじめアプリケーションのコンテナ化を進めています。

しかしながら、サービス開始当初から動いている一部のアプリケーションについてはまだコンテナ化が追いついておらず、EC2インスタンス上で直接 jarファイルを実行してアプリケーションを起動しているケースがあります*2

こうしたケースでは、サービスの再実行やインフラリソースの整備などでインスタンスにsshして作業することが少なくありません。そんな中で、日々の業務のなかで下記の点で課題が発生していました。

  • EC2インスタンスにssh接続するための秘密鍵の管理が必要になる。
  • 誰がどういった作業を実施したのかロギングしづらい。

ssh認証の秘密鍵(pemファイル)の管理

EC2インスタンスへのssh認証方式として、多くの場合はパスワードを使用する方式と公開/秘密鍵を使用する方式を用いると思います。特にEC2をそのまま使う場合、 hoge.pem のようなファイル形式で秘密鍵を使った認証を選択する場合が多いのではないでしょうか。どちらの方式を選択するにせよ、パスワードや秘密鍵をどのように管理するかというところが運用上の課題になるでしょう。

秘密鍵をどういう単位で生成するのか、個々のインスタンスで別にするのか、VPC内で同一にするのかなど、さまざまな方針があると思います。

しかしいずれにせよ、どのインスタンスがどの秘密鍵とひもづくのか、またどの秘密鍵をどのメンバーに共有しているのかなどの管理が煩雑になりがちです。スタートアップ創業当初で限られたメンバーでサービス開発をしているフェーズあれば大きな問題にはならないかもしれませんが、サービスや組織が大きくなるに連れてセキュリティ面を強化することは必須の課題となってきます。そうしたときに、ひとつの課題としてインスタンスにおける認証方法の管理という点が浮上してくることでしょう。

作業のロギング(監査ログの取得)

またセキュリティの強化を考えた場合、機密性(Confidentiality)を確実にすると共に責任追跡性(Accountability)を担保することも重要となってきます。そこで、インスタンス上でどのような作業を行ったのか、さらにいえば誰がどのような操作を行ったのか、という監査ログを取得することが必要になってくると思います。

Linux上であれば auditd を用いるのが一般的かと思いますが*3、企業によってはEC2上でWindows OSを動かしている場合もあるでしょう。このような場合も含めて、OS上の監査ログ取得の選択肢としてはさまざまな方針が考えられるかと思いますが、多くの場合はログの連携や確認が容易にできないといったケースもあるのではないでしょうか。

検証と導入

こうした課題に対して、弊社では解決策の一つとしてSession Managerの検証および導入を行いました。なお、今回の検証にあたっては下記の記事を大いに参考に実施しました*4

dev.classmethod.jp

導入の手順

導入の手順は非常に簡単で、下記の3ステップを実施するだけで完了します。

  • Session Manager自体の設定を行う。
  • EC2インスタンスの amazon-ssm-agent を最新化する。
  • EC2インスタンスにIAMポリシーを設定する*5

Session Managerの設定

まず、対象となるAWSアカウントでSession Managerを使えるように設定を行います。今回はマネジメントコンソール上から設定する方法を紹介します。

といっても、実はSession Manager自体の設定について手順は多くはありません。とりあえず導入するだけなら、下記のように設定するだけでOKです。

Session Managerの設定
Session Managerの設定

なお、Session Managerでセッションを開始すると通常は ssm-user というユーザー名が表示されるのですが、 Enable Run As support for Linux instances の設定を有効にしておくと任意のOSユーザーでSession Managerの利用が可能となります。

EC2インスタンスの設定

次に、対象のEC2インスタンスでSession Managerからセッションを開始できるようにするための設定を行います。

まずは、EC2インスタンス上で amazon-ssm-agent をインストール or 最新化しておきます。Amazon Linux 2 を利用している場合はデフォルトでインストールされていますが、古いインスタンスだと 2 ではなく以前の Amazon Linux で運用していることもあるかと思います。そのような場合は、新たにインストールしておく必要があります。

そして、Session Managerを利用するために必要となるIAMポリシーを設定します。AWSではあらかじめ AmazonSSMManagedInstanceCore というポリシーが用意されており AmazonSSMRoleForInstancesQuickSetup というロールにアタッチされています。このロールをそのままEC2インスタンスに適用することもできますが、Systems Managerの機能を全て許可する設定になっているので本番適用するのは控えた方が良さそうです。

Session Managerを導入するための最低限のIAMポリシーとしては、いろいろと試してみたところ下記のようになるようです。この記述を元に、用途に合わせて設定を変更していただくのが良いかと思います。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:UpdateInstanceInformation",
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        }
    ]
}

監査ログの取得

Session Managerを導入するための手順は、上記で完了となります。この程度であれば、マネジメントコンソールからでもAWS CLIからでもサクッと導入できちゃいますね!

加えて、Session Managerで実行した操作のログを取得する方法を紹介します。

といっても、上述したSession Managerの設定にある項目を有効化するだけ済みます。めっちゃ簡単やんけ。

Session Manager監査ログの有効化
Session Manager監査ログの有効化

CloudWatch Logsにログ出力するように設定すると、指定したロググループに対してセッション終了後にログストリームが作成されます。

セッション履歴からCloudWatch Logsを確認できる
セッション履歴からCloudWatch Logsを確認できる

下図のように、Session Managerから作成されたログストリームの名前にはプレフィックスとしてIAMユーザー名が付きます。そのため、どのメンバーがどのような操作を実行したのかが簡単に追えるようになります。

ログストリームにIAMユーザー名が付く
ログストリームにIAMユーザー名が付く

今回はCloudWatch Logsに連携するように設定しましたが、設定画面にあるようにS3にログを送信することもできます。用途に応じて使い分けられると良さそうです。

ちなみに、CloudWatch Logsに連携する場合はEC2インスタンスに設定するIAMポリシーに下記のような権限を加える必要があります。ただ、通常はインスタンス上のOSログやアプリケーションログなどをCloudWatch Logsに出力している場合が多いかと思いますので、特別にポリシーを変更する必要はないかもしれません。

        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*"
        }

さらなる検証

Session Managerを導入することで、はじめに挙げた2つの課題を解決することができました!

まず、開発メンバーに対してpemファイルを配布する機会を減らし管理しやすくすることができました。特に新たに、ジョインしたメンバーに対しては、pemファイルを配布せずにEC2インスタンスの管理をお願いする準備を整えることができました。

また、どのメンバーがEC2インスタンス上でどういった操作をしたのか記録できるようになりました。こうした形でセキュリティ面の強化を着実に進めることができたと思います。

導入手順としては以上となりますが、弊社ではさらなる検証を実施しました。

ひとつは、EC2インスタンスに設定するセキュリティグループについてです。上記の導入手順ではセキュリティグループの設定はありませんでした。Session Managerの利用においてセキュリティグループは関係ないのでしょうか?

続いて、AWS公式がサポートしている session-manager-plugin についてです。これはAWS CLIを通じてSession Managerを介しEC2インスタンスへのセッションを開始するためのツールですが、今回の目的にどの程度適しているのかを検証してみました。

必要なセキュリティグループについて

Session Managerはsshの代替となるものではありますが、実際にはsshを実行しているわけではありません。詳細は公式ドキュメントを参照していただきたいのですが、sshしているわけではないのでセキュリティグループのインバウンドで 22ポート を開放する必要はありません

ところで、インバウンドで 22 以外のポートを閉じてしまうとSession Managerでも接続できなくなるのではないでしょうか? そこで、どの程度ポートを開けておく必要があるのか検証してみました。

結論としては、インバウンドのポートは全て閉じた状態でもSession Manager経由で接続できます

なお、当たり前ですがアウトバウンドのポートを全て閉じてしまうとSession Managerでも接続できませんでした。正確には、セッションは開始できるものの、出力を受け付けないためインスタンス上でなにが起きているのか把握できない状態となってしまっていました。アウトバウンドは基本的に全て許可にするケースが多いかと思いますが、Session Manager導入にあたって特別に設定変更する必要はないかと思います。

session-manager-pluginについて

基本的にSession Managerを利用する際にはマネジメントコンソールからセッションを開始します。ただし、ブラウザ上からコマンドを叩くのはぶっちゃけちょっと面倒ですし、人によってはつらい前世の記憶が呼び起こされることになるでしょう。

そこで、AWS CLIからセッションを開始する方法として session-manager-plugin というツールが公式でサポートされています。ローカルのマシンにインストールすることでCLIからSession Managerを利用できます。導入の手順などは公式ドキュメントをご参照ください。

ツールのインストール後は下記コマンドを実行するだけでセッションを開始できます。便利ですね!

# インスタンスのパブリックIPではなくインスタンスIDを指定するので注意!
aws ssm start-session --target [instance-id]

これで全部ええやん!……と思いきや、ひとつ問題が発生しました。

弊社ではAWSアカウントを複数所持しており、例えば本番環境と開発環境を分離するなどの目的でマルチアカウントで運用しています。そのため、マネジメントコンソールを利用する際には、まず大元となるAWSアカウントにログインして、そのあと別アカウントのロールとしてスイッチロールする形で運用しています。また、スイッチ先のロールはメンバーの権限に合わせて admin / developer / operator などを設定しており、IAMユーザーもそのように作成しています。

そこで問題になるのがスイッチロールの際にはスイッチ元のIAMユーザー名は引き継がれないという点です。

上述の通り、Session Managerを介した操作のログはCloudWatch Logsに出力しており、ログストリームのプレフィックスにIAMユーザー名が付くことで監査ログとして機能できると考えていました。しかし session-manager-plugin からスイッチロールした先のAWSアカウント上のインスタンスに対してセッションを開始すると、ログストリームのプレフィックスに一律で botocore-session という文字列が付与されてしまい、どのメンバーが操作したのか追いづらくなってしまいます。

スイッチロールした際のユーザー名
スイッチロールした際のユーザー名

ログストリームのプレフィックスにも付いてしまう
ログストリームのプレフィックスにも付いてしまう

plugin内部の処理を見てみると、どうやらセッション開始の度に botocore-session-XXXXXXXXXX という形式でIAMユーザーを作成している? ように見えます*6。そのため、ログストリームにそのユーザー名が入るようになってしまっているようです*7

Session Managerの導入後にこのような問題が発覚してしまいました。とはいえ、単にEC2インスタンス上の作業を記録する目的としては、上記の通りCloudWatch Logsへのログ出力で十分と考えることもできます。弊社ではひとまずこの状態まで持っていくことをゴールとして、Session Managerの導入と開発メンバーへの共有を進めました。

おわりに

以上、Session Managerを導入することで、開発メンバーに対してpemファイルを配布する機会を減らし管理しやすくすることができました。特に新たに、ジョインしたメンバーに対してはpemファイルを配布せずにEC2インスタンスの管理をお願いする準備を整えることができました。

また、どのメンバーがEC2インスタンス上でどういった操作をしたのか記録できるようになりました。こうした形でセキュリティ面の強化を着実に進めることができたと思います。

このようにアソビューSREチームでは、開発チームとの連携を強化したり運用を改善するための施策をたくさん進めております! とはいえ、手が足らずに思うように実行できていないのも事実です。

そこで、下記の通り新たなメンバーを積極的に募集中ですので、ぜひ応募いただけると嬉しいです!

hrmos.co

みんなどんどん応募してくれよな!!

*1:このアドベントカレンダーでもCloudFormationの話EKSの話など、SREチームのメンバーが書いた記事がいくつかあります。

*2:アソビューでは開発言語としてJavaを利用しているアプリケーションが多いです。Javaを選択する理由についてはこちらの記事をご参照ください。

*3:弊社では実施しませんでしたが、Amazon Linux上でauditdを使って監査ログを取得する際は、こちらの記事が参考になるかと思います。EC2でファイル監査を設定する(auditd設定編) | ナレコムAWSレシピ

*4:クラスメソッド様、いつもありがとうございます!

*5:正確には「IAMポリシーをアタッチしたIAMロールをインスタンスプロファイルとして設定する」ということになるでしょうが、記述の簡略化のため上記のように表現しています。

*6:この辺りはまだしっかりと検証できていない部分です。また私が調べた限りでは、この辺りの詳細について解説したページは見当たりませんでした。どなたかご存知の方がいらっしゃれば、ご教示いただけると助かります!

*7:公式ドキュメントのこの辺りを参照すれば解決しそうな気がしますが、まだ十分に検証できていません。