AWS Session Manager
AWS Session Manager は AWS Systems Manager の機能で、AWS CLI を経由して EC2 インスタンス、オンプレミスインスタンス、仮想マシン (VM) にログインできるようにしてるというものです。
IAMベースで認証するのでセキュリティーグループを神経質に設定してインバウンドポートを開いたり、パブリックIPアドレスを開放する必要がなくなるというメリットがあります。
また、ハイブリットアクティベーション機能を利用することで Fargate のようなマネージドインスタンスに SSM ログインしターミナルセッションを開くことができます。面倒な SSH 鍵の登録などは不要です。
とはいえSSHしたいときもある
とはいえ、運用の都合でSSHしたいこともあります。ということで、AWS Sesstion Manager を経由してFargate コンテナへのSSH 接続を試してみました。
Dockerコンテナの準備
まず大前提として Fargate に SSH するにはデプロイするコンテナに SSH できる必要があります。それに加えて、SSMエージェントをインストールインストールしハイブリットアクティベーション可能なコンテナを作ります。
FROM ubuntu:18.04
COPY run.sh /run.sh
RUN apt-get update \
&& apt-get -y install curl openssh-server \
&& curl https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/debian_amd64/amazon-ssm-agent.deb -o /tmp/amazon-ssm-agent.deb \
&& dpkg -i /tmp/amazon-ssm-agent.deb \
&& cp /etc/amazon/ssm/seelog.xml.template /etc/amazon/ssm/seelog.xml
RUN mkdir /var/run/sshd
RUN sed -i 's/#\?PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
COPY path/to/id_rsa.pub /root/authorized_keys
RUN mkdir ~/.ssh && \
mv ~/authorized_keys ~/.ssh/authorized_keys && \
chmod 0600 ~/.ssh/authorized_keys
EXPOSE 22
CMD ["bash", "run.sh"]
#!/bin/bash
/usr/sbin/sshd &
amazon-ssm-agent -register -code "${SSM_AGENT_CODE}" -id "${SSM_AGENT_ID}" -region "${AWS_DEFAULT_REGION}"
amazon-ssm-agent
作成した Docker Image は ECR に登録して利用しますが詳細は端折ってます。
ハイブリットアクティベーションのセットアップ
ハイブリッド環境の IAM サービスロールを作成する
作成するハイブリットアクティベーションにアタッチするロールを作成します。インスタンスと System Manager の通信を許可する設定が入ってます。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {"Service": "ssm.amazonaws.com"},
"Action": "sts:AssumeRole"
}
}
aws iam create-role \
--role-name SSMServiceRole \
--assume-role-policy-document file://ssm-trust.json
aws iam attach-role-policy \
--role-name SSMServiceRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
SSM アクティベーションを作成する
aws ssm create-activation --description my-fargate-task \
--iam-role "SSMServiceRole" \
--registration-limit 1000 \
--default-instance-name my-fargate-task
{
"ActivationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ActivationCode": "yyyyyyyyyyyyyyyyyyyy"
}
Activation ID, Code は後の工程で利用するのでメモしておきます。
パラメータストアに登録
作成した ActivationId, ActivationCode をパラメータストアに登録します。これらの情報は Fargate Task 起動時に読み込まれます。
aws ssm put-parameter --overwrite --name "my-activation-id" \
--value "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--type "SecureString"
aws ssm put-parameter --overwrite --name "my-activation-code" \
--value "yyyyyyyyyyyyyyyyyyyy" \
--type "SecureString"
Task Definition 作成
起動タイプに Fargate を選択して、コンテナの定義を下記の通り設定します。
環境変数
Task Definition 起動時に ssm-agent を起動するのでパラメータストアから先程登録した ActivationId, ActivationCode を環境変数に読み込ませます。
ポートマッピング
SSHログインするのでポートは 22 をマッピングしておきます。
Fargate Task 起動
Task Role に SSMの読み込みポリシーをアタッチ
タスク起動時にパラメータストアから ssm-agent 起動のための値を読み込む必要があるので、以下のようなポリシーを作成し、 ecsTaskExecutionRole
等にアタッチしておきます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DescribeSSMParameter",
"Effect": "Allow",
"Action": [
"ssm:GetParameters",
"secretsmanager:GetSecretValue",
"kms:Decrypt"
],
"Resource": "*"
}
]
}
Fargate Task 起動
Fargate Task を起動します。
起動していることが確認できました。
セキュリティグループは インバウンドトラフィックはVPC内部での通信のみ許可、アウトバウンドはVPC内部のトラフィックに加えて 443 ポートのトラフィックを許可しました。
また、ECR からの Image 取得、Fargate と System Manager との通信許可のため Private Link を設定しています。
Cloud Watch からログを確認してみると ssm-agent の起動が確認できます。mi-*
となっているのがインスタンスIDで 、後に SSM および SSH ログインする際に利用します。
また、aws ssm describe-instance-information
で ssm-agent が起動しているインスタンスの情報を閲覧することができます。
aws ssm describe-instance-information
{
"InstanceInformationList": [
{
"InstanceId": "mi-0abfaba2ca9885629",
"PingStatus": "Online",
"LastPingDateTime": "2020-05-24T17:55:55.927000+09:00",
"AgentVersion": "2.3.978.0",
"IsLatestVersion": false,
"PlatformType": "Linux",
"PlatformName": "Ubuntu",
"PlatformVersion": "18.04",
"ActivationId": "63dd7755-c64b-477c-b2ad-25e46a964363",
"IamRole": "SSMServiceRole",
"RegistrationDate": "2020-05-24T17:23:55.481000+09:00",
"ResourceType": "ManagedInstance",
"Name": "my-fargate-task",
"IPAddress": "169.254.172.42",
"ComputerName": "ip-10-0-1-86.ap-northeast-1.compute.internal"
}
]
}
SSMログインする
SSMログインできるか試してみます。
Fargaet にSSMログインするには System Manager → マネージドインスタンス → 設定 → インスタンス枠 が 「高度なインスタンス枠を使用する」設定になっている必要があるので事前に設定を変更しておきます。
以下のようにして SSM ログインすることができます。
aws ssm start-session --target mi-0abfaba2ca9885629
Starting session with SessionId: me-0c78ed24d7770a19c
$ whoami
ssm-user
SSHログインする
ssh_config を修正します。proxy command で start-session コマンドを経由して SSH するような設定になっています。
host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
IdentityFile path/to/id_rsa
UseKeychain yes
AddKeysToAgent yes
SSH 接続してみましょう。
ssh root@mi-0abfaba2ca9885629
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.14.158-129.185.amzn2.x86_64 x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
Last login: Sun May 24 15:10:15 2020 from 127.0.0.1
root@ip-10-0-1-86:~#
Sesstion Manager を使って Fargate に SSH できるようになりました。
所感
そもそも Session Manager を使うと IAM で認証できるから、SSH する必要もなくて SSH 鍵の管理もしなくていいというのがメリットなはずなのに、開発してると結局 SSH しなきゃいけないタイミングが出てきてしまうのがモヤッとしてます。
System Manager 側で SSH をサポートするもっと便利な機能を提供してくれないかなーと感じています。
とはいうものの Public なインスタンスを作らなくて良いのはセキュリティの面ではメリットではないかと思います。