プライベートSubnetsのEKS managed worker nodeに手軽にSSHログインする方法 

## TL;DR;

プライベートsubnetsなど、閉じたネットワークにEKS Managed Worker Nodeを動かしていて、手元のローカルマシンから直接SSHできないけど、わざわざアクセス可能なネットワーク内にEC2とか立てたくない人のためのお手軽にWorker Nodeに手軽にSSHログインする方法


- 中継用PodをクラスタにデプロイしてそのPod経由でWorker Node (EC2)にSSHログインする
- ここでは[kubectl-plugin-ssh-jump](https://github.com/yokawasa/kubectl-plugin-ssh-jump)を紹介

## （前提条件） EKS Managed Node GroupのSSH設定

前提条件としてSSHログインのためにEKS Node Group作成時にSSHアクセス設定が必要となる。以下簡単に、利用ツール別の設定マニュアルを紹介する

- CloudFormationの場合: [AWS::EKS::Nodegroup RemoteAccess](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-remoteaccess.html)でssh鍵とソースとなるSecurity Groupを設定する 
- eksctlの場合: eksctlの[EKS Managed Nodegroups設定例](https://eksctl.io/usage/eks-managed-nodes/)のようにssh鍵とソースとなるSecurity Groupを設定する

## 中継用Podを経由してWorker NodeにSSHログイン

kubectl pluginの[ssh-jump]([https://github.com/yokawasa/kubectl-plugin-ssh-jump)を利用して、中継用PodをクラスタにデプロイしてそのPod経由でWorker Node (EC2)にSSHログインする手順を紹介する

kubectl plugin管理ツールの[krew](https://krew.sigs.k8s.io/docs/user-guide/setup/install/)を使ってssh-jumpをインストールする。これで準備完了。

```
kubectl krew install ssh-jump
```

ログインしたいノード名もしくはIPアドレスを取得

```
kubectl get no -o custom-columns=Hostname:.metadata.name,Internal-IP:'{.status.addresses[?(@.type=="InternalIP")].address}'

Hostname                                           Internal-IP
ip-10-110-19-10.ap-northeast-1.compute.internal    10.110.19.10
ip-10-110-19-88.ap-northeast-1.compute.internal    10.110.19.88
ip-10-110-38-34.ap-northeast-1.compute.internal    10.110.38.34
```

ここでは`ip-10-110-19-10.ap-northeast-1.compute.internal`にログインする。 kubectlのssh-jumpコマンド （pluginコマンド）の`-i`オプションにPEMキー（~/.ssh/yokawasa.pem）を指定し、ログイン先ホストに`ip-10-110-19-10.ap-northeast-1.compute.internal`を指定して実行する

```
kubectl ssh-jump -u ec2-user \
  -i ~/.ssh/yokawasa.pem \
  ip-10-173-62-96.ap-northeast-1.compute.internal
```

登録した鍵に問題がなければ、次のようなログインメッセージが出力されます

```
Last login: Thu Aug  6 01:57:57 2020 from ip-10-110-19-10.ap-northeast-1.compute.internal
 
       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|
 
https://aws.amazon.com/amazon-linux-2/
4 package(s) needed for security, out of 7 available
Run "sudo yum update" to apply all updates.
```

## 中身解説

上述のとおり、ssh-jumpプラグインコマンドは、EKSクラスタにssh jump用のPodを一時的にたてて、そこを踏み台にWorker NodeにSSHアクセスする。具体的には次のようなステップをコマンド内で実行している。

中継用Pod（sshjump）を立ち上げる

```
kubectl run sshjump --image=corbinu/ssh-server --port=22 --restart=Never
```
 
中継用PodにSSHログインするための一時公開・秘密鍵を作成

```
ssh-keygen -t rsa -f $HOME/.kube/kubectlssh/id_rsa_sshjump -N '' > /dev/null
```
 
バックグラウンドで中継用Podに2222->22でポートフォワードする

```
kubectl port-forward sshjump 2222:22 2>/dev/null &
```

中継用Podに上記ステップで作成した一時公開鍵を登録（中継用Podにはssh serverが動いている）

```
cat $HOME/.kube/kubectlssh/id_rsa_sshjump.pub | \
    kubectl exec -i sshjump -- /bin/bash -c "cat > /root/.ssh/authorized_keys"
```

中継用Podを経由して、ターゲットノードにSSHログイン 

```
ssh -i ~/.ssh/yokawasa.pem -p 22 ec2-user@ip-10-110-19-10.ap-northeast-1.compute.internal \
  -o "ProxyCommand ssh root@127.0.0.1 -p 2222 -i $HOME/.kube/kubectlssh/id_rsa_sshjump　-o \"StrictHostKeyChecking=no\" \"nc %h %p\""
```

使い終わったら中継用Podを削除し、 ポートフォワードも停止

```
kubectl delete pod sshjump
kill -3 <Portforward command PID> 2>/dev/null
```

## まとめ

これはEKSクラスタの操作権限さえあれば手軽にできる手法であり、毎回アクセス元（＋そのサーバー管理）を意識することなく、必要なときにオンデマンドで一時的に作って終わったら破棄できるところがポイント。是非プライベートsubnetsなど、閉じたネットワークでのSSHログインシナリオの際にはご活用いただけたらと。