AWS SessionManagerで、踏み台なしのssh環境を構築する

f:id:hige_dev:20210306174802p:plain AWS SessionManagerを使うことで、踏み台サーバーが不要になるので便利!というお話。

導入手順の大きな流れとしては、

  1. EC2にSSM agentをインストール(Amazon Linuxubuntuは基本的にインストール済み)
  2. EC2にSSM用のSecurityGroupを作ってアタッチ
  3. SSM用にVPCエンドポイントを作成する
  4. AWS CLIのSession Manager プラグインをローカルにインストール

sshするのはAWSコンソール上からのみ、という場合は4は不要だけど、普通はローカルからsshしたいと思うのでそちらも記載。

概要

EC2をPublicSubnetに置くと、インターネットからアクセスされる危険性が高まるため、 f:id:hige_dev:20210306173524p:plain

基本的にEC2はPrivateSubnetに配置するのが望ましい。 が、そのままではEC2にログインもできなくなってしまうため、 f:id:hige_dev:20210306173539p:plain

PublicSubnetに踏み台サーバーを置くのが定石。 f:id:hige_dev:20210306173618p:plain

こうすることで、Privateに置いたEC2へは、踏み台以外のアクセスを拒否できるため、比較的安全な構成を構築できる。

が、踏み台サーバーそのもののセキュリティが甘ければ意味はなく、運用・保守などサーバーの維持コストもかかってしまう。

AWS Systems ManagerのSessionManagerを使うと(ややこしい)、踏み台サーバーなしでPrivateSubnetにsshできるようになるため、

  1. 踏み台サーバーが不要のため運用・保守コストがかからない
  2. (踏み台サーバーを作って放置するよりは)セキュリティ的にも安心

というメリットがある。

ややこしい名前について整理すると、

name description
AWS Systems Manager マネージドサービス
SessionManager 機能

ということになるのかな、、?

SSMを導入する手順

を書こうと思ったのだけど、セキュリティ的な問題は一次情報を見るべきだし、自分の下手な説明でセキュリティホールを作ってしまうのはやばいので、公式ドキュメントを見た方が安全。

docs.aws.amazon.com

ただ、それだけだとこの記事に意味がなくなってしまうので、セキュリティを強化するtipsを2つほど紹介しておく。

  1. SSMでsshできるIP制限
  2. ssm-userのsudo権限を削除

1. SSMでsshできるIP制限

EC2へのsshするIPを制限する場合は、SecurityGroupで特定のIPにport22を許可するが、SSMを使ったsshでは、SecurityGroupでIP制限ができない。この場合は、EC2にアタッチするロールにポリシーを追加でアタッチする。

名前はお任せだけど、つけるとしたら AllowIPListForSSMPolicy とか?

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:StartSession",
                "ssmmessages:CreateDataChannel"
            ],
            "Resource": "*",
            "Condition": {
                "ForAnyValue:IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/32",
                        "xxx.xxx.xxx.xxx/24"
                    ]
                }
            }
        }
    ]
}

CIDRを指定することで、そのIPだけを許可するのか、そのネットワークに属するIP全てを許可するのかが指定できる。

2. ssm-userのsudo権限を削除

SSMを使用すると、デフォルトでssm-userが作られる。このユーザーは、パスワードなしでrootになれるクセモノで、EC2サーバー内でユーザーの権限管理をしていても、AWSコンソールからssm-userでログインできてしまう。

すると、sudo権限がないユーザーが、AWSコンソールからssm-userでsudoを振りかざし、 sudo rm -rf /のような地獄のコマンドを打つことすらできてしまう

そうならないためにも、このssm-userは基本的に削除するべき。

対応すべき内容は、

  • ユーザーの削除
  • sudoersファイルの削除

あたりかな。

ユーザーの削除は、userdel コマンドで /home/ssm-userディレクトリも削除できる。

また、ユーザーを削除すれば問題はなさそうだけど、不要なファイルは削除するに越したことはないので、ssm-user用に作られるsudoersファイルも削除する。

$ sudo userdel ssm-user
$ sudo rm /etc/suroers.d/ssm-user

まだやるべきことあるかな、、あったら教えてください。

サーバーを作るたびにssm-userを削除するのは面倒だし、対応漏れの可能性も大いにあるので、ssm-userを削除した上でAMIを作っておいて、そこからEC2を起動する運用にするといいかも。

結局運用任せなのでミス・漏れの可能性はあるのだけれど。。(ある程度の規模ならCloudFormationとかTerraformを使うべきだけど)

おまけ: スマートな ~/.ssh/config 運用

SSMはとても便利だけど、サーバーが増えるたびに ~/.ssh/config に追加してかなきゃいけない点はちょっとスマートじゃないな、と思ってた。

そんな事思ってたら、先輩がサラッとワンライナーにしてくれた。

# ~/.ssh/config

Host i-*
  User ...
  IdentityFile ~/.ssh/id_rsa
  ProxyCommand $(PROFILE={aws configureで設定したprofile}; EC2HOST=$(echo %h | cut -d. -f2); INSTANCEID=$(aws ec2 describe-instances --profile ${PROFILE} --filters "Name=tag:Name,Values=${EC2HOST}" --query "Reservations[*].Instances[*].[InstanceId]" --output text);echo aws ssm start-session --profile ${PROFILE} --target ${INSTANCEID} --document-name AWS-StartSSHSession --parameters 'portNumber=%p')

これを設定しておくことで、 サーバーが増えても~/.ssh/configに追加せずに $ ssh {サーバー名} だけでログインできるようになる。

注意点は、EC2のタグにサーバー名を設定しておく事と、$ aws configure --profile ○○ でprofileを設定しておく事。(defaultしか使わないなら不要だけど)

超スマートで感動した。これぞプログラミング

まとめ

踏み台サーバーではなくSession Manager使うと、すごくシンプルでセキュアにsshできて、かっこいい。