IAMベースのアクセス管理で踏み台のセキュリティを強化する

IAMベースのアクセス管理で踏み台のセキュリティを強化する

なぜ踏み台サーバーにセキュリティが必要?

みなさま。「踏み台サーバー」の管理をしていますか?

本ブログの読者にはインフラ実装における踏み台サーバーの管理をご経験されている方も多くいらっしゃると思います。

踏み台サーバーは「要塞ホスト」とも呼ばれ、情報処理推進機構(IPA)の用語集においてはその特徴が以下のように紹介されています。

bastion host (要塞ホスト) DMZに設置されるインターネットサーバー等、攻撃の脅威にさらされていることを前提に、セキュリティを高める努力が施されているホスト。不要なサービスを動作させず、専用サーバーとして構築されることが推奨される。ホストにおけるアクセスコントロール機能、ロギング機能を実装し、必要な修正プログラムを適用する。

https://www.ipa.go.jp/security/ciadr/crword.html#B

踏み台サーバー(要塞ホスト)は、構成上外部インターネットとの接点となっており、この説明の通り攻撃の脅威に晒されている可能性が高く、運用に関わる皆様もセキュアな構成にするべく日々模索されているものかと存じます。

今回は踏み台サーバー利用のシナリオを考え、AWSのサービスを使って既存の踏み台サーバーをよりセキュアにするにはどうすれば良いかを探っていきたいと思います。

利用例と課題

利用例1:秘密鍵の配布を絞る

例えば、踏み台サーバーの利用例としては

  • 接続用の秘密鍵は関係者のみに配布

とすることで、関係者のみが踏み台サーバーにアクセスできるようにします。

そして、秘密鍵を使ったSSHアクセスをできるようにするため、AWSでのSecurity Groupでは22ポートからのアクセスを許可します。

図に表すとこのような形でしょうか?

しかし、これだと

  • 秘密鍵が漏洩した時、関係者以外でも自由にアクセスできるようになる

という懸念があります。

また、パスフレーズ設定を入れていたとしても、例えば退職者がパスフレーズ含めて秘密鍵を保持し続けていた場合は自由にアクセスし続けることができてしまいます。

改良を考えてみましょう。

利用例2:アクセス元IPアドレスを絞る

1の例は秘密鍵の所有の有無だけでアクセス管理をしようとしており、正直極端だったかもしれません。心許ない設計でした。そこで、

  • アクセス許可するIPアドレスを制限する

という工夫を加えて、秘密鍵を持っている、かつ、許可された拠点からのアクセスのみを許可するようにします。

AWSであれば、Security Groupの22ポートの許可の際に”From”の指定を定義する形です。

これにより、関係者が所定の拠点(例えば会社のオフィスなど)からのみアクセスする前提であれば、関係者のみのアクセスに絞り込めることが期待できます。

そしてIPアドレスでの絞り込みによりSecurity Groupのレイヤーで遮断されるので、関係拠点以外から攻撃を受ける懸念が取り除かれます。

この際の課題を考えてみますと、拠点が多い場合、Security Groupにて記述すべき許可設定も増えてきます。そして、管理が追いつかなくなった結果、「削除されるべき設定が残り、許可されるべきでない者がアクセスできるようになってしまっていた」というシナリオも考えられます。

また、Security Groupのルールには上限があり、それに達してしまうと緩和申請の必要が生じます。

これは運用のあり方次第なので、必ずしも課題を抱えているとは言えませんが他の実装例を考えてみます。

利用例3:SSH Over Session Manager

2の例とは「別のパターン」となりますが、今回の本題として3つ目のパターンを紹介します。

1のパターンに対して

  • 接続用の秘密鍵は関係者のみに配布

までは同様でありつつも、

  • Security Groupでの22ポート(SSH)の許可を削除

を行います。

図で表すとこのような形です。

これにより踏み台サーバーはインフラ構成上は外部インターネットから一切ポートが開いていない構成を実現できます。

そして、ポートが開いていない状況からどのように踏み台にアクセスするかというと、小見出しの通りAWS Systems Managerにおける”Session Manager”の仕組みを利用します。

(参考:https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html

図で表すとこのような形です。

これによってポートが解放されていなくても、IAMによってアクセス管理された形で踏み台サーバーに接続することができます。

では、そのための設定方法を見ていきます。

SSH Over Session Manager

設定1:踏み台サーバーをSystems Managerの管理下に置く

EC2インスタンスに対してSession Managerで接続できるようにするためには、踏み台サーバーがSystems Managerの管理下に入っている必要があります。

細かい設定方法自体は公式ドキュメントに任せるものとして割愛しますが、ウィザードに沿って設定ができる 「高速セットアップ」(QuickSetup)のうちの「ホスト管理」(Host Management)がおすすめです。

(参考:https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/quick-setup-host-management.html

設定を終えましたら、該当の踏み台インスタンスは次のように専用のロールが付与され、

「フリートマネージャー」画面にも表示されており、Systems Managerの管理下に入ったことがわかります。

なお、この時点で Session Managerを使った接続ができるようになります。AWSマネジメントコンソール画面から「セッションを開始」でできます。

この時点でもサーバー内の操作、ログ閲覧などの目的であれば、ブラウザ上で完結するので非常に魅力的です。

ただし、この場合はブラウザ上で完結するため、ローカル環境との接続ができず、例えばログファイルを自PC内にダウンロードするなどもできません。

そのため、以下のように設定を加えていきます。

設定2:Session Manager開始用のssh設定

今回は既存の踏み台サーバーに対して、Session Managerベースのアクセスできるようにするのですが、この実装以前には

$ ssh -i <踏み台用の秘密鍵> <OSユーザー名>@<踏み台のIPアドレス>

のようなコマンドでアクセスしたり、 ~/.ssh/configファイル内に

Host bastion-test(※踏み台サーバー接続用のエイリアス名)
    User <OSユーザー名>
    HostName <踏み台のIPアドレス>
    Port 22
    IdentityFile <踏み台用の秘密鍵>

のような設定を入れた上で

$ ssh bastion-test

と実行して接続していたかと思います。

今回はこれに代わる形で、macOSであれば ~/.ssh/configファイル内に

# SSH over Session Manager
Host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

という記述を加えます。

(参考:https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html

また、

Host <踏み台サーバーのインスタンスID>
    User ec2-user
    HostName <踏み台サーバーのインスタンスID>
    Port 22
    IdentityFile ~/.ssh/bastion-test.pem

という記述も入れておきます。

これにより

$ ssh <踏み台サーバーのインスタンスID>

と実行することで、該当のインスタンスに対してSession Managerを介してSSH接続が行われるようになります。

その際には、Session Manager用のクレデンシャルが必要なので、次でIAMユーザーを作成します。

設定3:IAMユーザーを作成

Session Managerを介してSSH接続を行うためにはローカルのPC内にAWSアクセスキーの設定が入っている必要があります。

公式ドキュメントの

https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html#ssh-connections-permissions

でのサンプルを参考に以下のような権限を付与した形で、IAMユーザーを作成します。

具体的には

(1)・・・使用しているリージョン

(2)・・・AWSアカウントID

(3)・・・対象となるEC2インスタンス

のように指定をして、ポリシーを付与することで、該当の踏み台サーバーへのSession Manager開始できるIAMユーザーになります。

このIAMユーザーのアクセスキーをSession Manager開始時に使用します。

以上で必要な設定は完了しました。これらを使って、次に接続をしてみましょう。

接続確認

確認1:従来のSSH接続

さて、今回の構成を採用するに伴い、踏み台サーバーのSSH(22)ポートは完全に閉じてしまっています。

従来のSSHでの接続が遮断されているか確認します。

設定2:Session Manager開始用のssh設定での内容を踏まえると bastion-testのホストに対して接続していたわけですが、接続試行をすると

$ ssh bastion-test
ssh: connect to host xxx.xxx.xxx.xxx port 22: Operation timed out

一向に応答がなかったのちタイムアウトになりました。(一部表示をマスクしています)

これはセキュリティグループ上ポートを閉じてしまっているからで、「秘密鍵を持っていてもそれだけでは接続できない」という期待通りの表示です。

確認2:SSH Over Session Manager

次に今回の目的であるSession Managerを介した接続を試みます。

Session Managerでの接続をする際にはAWSアクセスキーのクレデンシャル情報が読み込まれている必要がありますので、上記で作成したIAMユーザーのシークレットアクセスキーを使って

$ export AWS_ACCESS_KEY_ID=<IAMユーザーのアクセスキーID>
$ export AWS_SECRET_ACCESS_KEY=<IAMユーザーのシークレットアクセスキー>
$ export AWS_DEFAULT_REGION=ap-northeast-1

というように実行した上で、

ssh <踏み台サーバーのインスタンスID>

を実行します。すると、

$ ssh i-xxxxxxxxxxxxxxxxx
Last login: xxx Sep xx 11:20:04 2021 from localhost

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-0-0-137 ~]$

無事接続されました。(一部表示をマスクしています)

これによって、例えば、次のように踏み台サーバー内にテストファイルが置かれていて、

[ec2-user@ip-10-0-0-137 tmp]$ pwd
/tmp
[ec2-user@ip-10-0-0-137 tmp]$ cat test.txt
これは踏み台サーバー内で書かれたテストファイルです

その状態で、ローカル側から

$ scp i-xxxxxxxxxxxxxxxxx:/tmp/test.txt .
test.txt                                                                                                  100%   76     4.9KB/s   00:00

というようにscpコマンドにダウンロードすると、

$ cat test.txt
これは踏み台サーバー内で書かれたテストファイルです

ローカルの環境内でその中身を確認できるようになりました。

このように、踏み台サーバーでの許可ポートは全て閉じていながらも、従来の操作感のままSSH接続が実現できました。

確認3:IAMユーザーを失効させた場合の動作確認

上記のようにSecurity Groupでの許可ポートを全て閉じることができ、より一層のセキュリティ向上は期待できるのですが、「操作感が同じのまま設定することが増えた」という具合であまり旨味を感じないこともあるかもしれません。

ですが、今回の設定により

  • AWS IAMベースでのアクセス管理機構が備わった

ということも注目すべき利点かと思います。

従来の構成ですと、例えば退職などにより特定の担当者のアクセス許可を取り下げたい時、該当の秘密鍵を失効させるために、踏み台サーバー内でのオペレーションが必要となっていました。

また、何らかの経緯で不正なアクセスが疑われる時にも、攻撃が目下行われている可能性がある踏み台サーバー内に入って操作をする必要がありました。攻撃の影響次第では踏み台サーバーでのリソースが枯渇して、接続すらできないシナリオも考えられます。

それが今回の仕組みを入れることで、IAMユーザーの権限を失効させるだけで、特定のユーザーのアクセスを遮断できます。

例えば、上記までの動作確認に使っていたIAMユーザーに、全ての権限を失効させるポリシーを適用します。

このうえで、再度アクセスを試行します。

すると

$ ssh i-xxxxxxxxxxxxxxxxx

An error occurred (AccessDeniedException) when calling the StartSession operation: User: arn:aws:iam::xxxxxxxxxxxx:user/bastion-test-cli is not authorized to perform: ssm:StartSession on resource: arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-xxxxxxxxxxxxxxxxx with an explicit deny
kex_exchange_identification: Connection closed by remote host

期待通り、接続が拒否された旨の表示になりました。

まとめ

以上の通り、AWS IAMというマネージドサービス側の操作だけで、特定の担当者のアクセス権を失効できるのは、セキュリティの運用面で非常にメリットが大きいように思います。

また、Session Managerを介したSSH接続を行うことで

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html

にて紹介されているように、他のAWSマネージドサービスと連携して、実行ログ記録や監査の仕組みもAWSサービス側で実現できることも期待できます。

aws cliがローカル端末に入っている必要があるなど、若干敷居が高いところがあるかもしれませんが、既存サーバーに対する追加のセキュリティ施作として参考になれば幸いです。

・・・ちなみに、動作検証を行なっているうちに似たような検証は以前、当ブログにて投稿されていたのを思い出しました。。(今回は「踏み台サーバーにどうセキュリティを追加するか」という話なので被りじゃないはず…!)

Session Manager 使えば踏み台サーバーが不要に デロイト トーマツ ウェブサービス株式会社(DWS)公式ブログ

Session Managerを使った接続時のトラブルシューティングなども書かれていますので、ぜひこちらもご覧いただければと思います。