1
1

Windowsで、パブリックIPを固定していないEC2インスタンスへ、.ssh/configを毎回書き換えずにssh接続したい

Posted at

こねくり回してようやく解決したので、備忘録。

目的

パブリックIPアドレスが固定されていないEC2インスタンスにVS Codeでgit pull/pushするときに、
毎回.ssh/configを書き換えたくない。
すなわち、
パブリックIPアドレスが固定されていないEC2インスタンスに、毎回.ssh/configを書き換えずにssh接続したい。

環境

Windowsで個人開発をしていて、EC2インスタンスをプライベートなGitサーバ兼デプロイサーバとして使っています。
インスタンスは常時起動ではなく、必要な時だけ起動するので、そのたびにパブリックIPアドレスが変わります。

この上でローカルからリモートへgit経由でアクセスしようとすると、毎回

git remote set-url origin https://[毎回違うパブリックIP]/[.gitの場所]

とリモートアドレスを書き換えるか、.ssh/configに設定を書き込んだ上で、URLを毎回書き換える必要があります。面倒!
有料のElastic IPをアタッチすればIPは固定されるけど、少額とはいえもったいない。

そこで無料のEC2 Instance Connectorの出番です。
AWS CLI経由でsshができるので、これを使う設定を.ssh/configに書き込んで、
VS Codeのコマンドからgit pull/pushしたりRemote SSHで直接アクセスできるようにします。

準備

EC2 Instance Connector経由で、AWS CLIを使ってインスタンスに接続できるのが前提です。
AWS: EC2 Instance Connect Endpoint を使用して Linux インスタンスに接続する をベースに、とても丁寧で救われたこちらの解説記事を参考にしました。

IAMに付与する許可ポリシーが一番のハマりポイントだと思います(私はハマった)。
AWS: EC2 Instance Connect Endpoint を使用するための IAM アクセス許可の付与 に記載されているJSONを適宜編集します。
既知で単一のエンドポイントにだけ接続したい場合は次の通り:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "EC2InstanceConnect",
			"Action": "ec2-instance-connect:OpenTunnel",
			"Effect": "Allow",
			"Resource": "arn:aws:ec2:ap-northeast-1:[アカウントID]:instance-connect-endpoint/[エンドポイントID]",
			"Condition": {
				"NumericEquals": {
					"ec2-instance-connect:remotePort": "22"
				},
				"NumericLessThanEquals": {
					"ec2-instance-connect:maxTunnelDuration": "3600"
				}
			}
		},
		{
			"Sid": "SSHPublicKey",
			"Effect": "Allow",
			"Action": "ec2-instance-connect:SendSSHPublicKey",
			"Resource": "*",
			"Condition": {
				"StringEquals": {
					"ec2:osuser": "ami-user"
				}
			}
		},
		{
			"Sid": "Describe",
			"Action": [
				"ec2:DescribeInstances",
				"ec2:DescribeInstanceConnectEndpoints"
			],
			"Effect": "Allow",
			"Resource": "*"
		}
	]
}

ami-usernameAWS: IAM への EC2 Instance Connect のアクセス許可の付与 にある通り、

  • インスタンスのOSがAL2023またはAmazon Linux 2の場合 ec2-user
  • Ubuntuでは ubuntu

です(ただしami-usernameのままでも動いた)。
このページにもポリシーのJSONがありますが、これだけだとOpenTunnel許可がないよ、と怒られます。

ポリシーを付与した後、コマンドプロンプトないしPowerShellから

aws ec2-instance-connect ssh --instance-id [インスタンスID] \
--eice-options maxTunnelDuration=3600,endpointId=[エンドポイントID] \
--os-user [インスタンス上のユーザ名]

でインスタンスに接続できれば、準備完了です。

手順

Windows上のAWS CLIでssh接続できるようになったわけですが、ここから AWS: EC2 Instance Connect Endpoint を使用して Linux インスタンスに接続する に従って

ssh -i [ssh鍵] [インスタンス上のユーザ名]@[インスタンスID] \
    -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id [インスタンスID]'

を実行すると、

2024-03-06 14:51:13,755 - awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"AccessDeniedException","Message":"User: arn:aws:iam::[アカウントID]:user/[接続に使うIAMユーザ] is not authorized to perform: ec2-instance-connect:OpenTunnel on resource: arn:aws:ec2:ap-northeast-1:[アカウントID]:instance-connect-endpoint/[エンドポイントID] because no identity-based policy allows the ec2-instance-connect:OpenTunnel action"}

AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE: Failed to upgrade HTTP connection to Websocket.
kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535

と再び怒られてしまいます。もー!

1. IAMに許可ポリシーを追加する

OpenTunnelその他を許可するインラインポリシーを新しく作り、ユーザに付与します。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "SecureInstanceConnect",
			"Effect": "Allow",
			"Action": [
				"ec2-instance-connect:OpenTunnel",
				"ec2-instance-connect:SendSSHPublicKey",
				"ec2-instance-connect:SendSerialConsoleSSHPublicKey"
			],
			"Resource": [
				"arn:aws:ec2:ap-northeast-1:322811116193:instance/[インスタンスID]",
				"arn:aws:ec2:ap-northeast-1:322811116193:instance-connect-endpoint/[エンドポイントID]"
			]
		}
	]
}

これで再び

ssh -i [ssh鍵] [インスタンス上のユーザ名]@[インスタンスID] \
    -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id [インスタンスID]'

を実行して、インスタンスに接続できればOKです。

2. 上記を.ssh/configに書き込む

.ssh/config

Host [お好きな名前]
	HostName  [インスタンスID]
	User [EC2上のユーザ名]
	Port 22
	IdentitiesOnly yes
	IdentityFile [ssh鍵]
	StrictHostKeyChecking no
	ProxyCommand "C:\Program Files\Amazon\AWSCLIV2\aws.exe" ec2-instance-connect open-tunnel --instance-id [インスタンスID]

を追記します。
awsPATHを通していない場合はフルパスで書く必要があります。
WindowsだとデフォルトでC:\Program Filesにインストールされます。この空白で引っかかるので、パス全体をquoteで囲む必要があります。

StrictHostKeyCheckingno にすると、IPが変わった後の質問を回避できます。
ただしセキュリティ的には良くないとGitHub Copilot先生が教えてくれました。

最後に

ssh [お好きな名前]

でインスタンスに接続できるか確認します。無事接続できたら完了です。

これで、パブリックIPアドレスが固定されていないEC2インスタンスを、.ssh/config/に保存された他の接続先と同じように扱えるようになりました。お疲れ様でした。
それでは楽しいsshライフを!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1