1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBM BobでSSH先サーバーの aws login --remote を通す方法: URLが表示されない問題の回避

1
Posted at

IBM BobでSSH先サーバーの aws login --remote を通す方法

背景

IBM BobからSSHでリモートサーバーへ接続し、そのサーバー上でAWS CLIを使いたい場面がありました。

ローカル端末ではなくSSH先のサーバーからAWSへアクセスしたいので、AWS CLIの認証もSSH先で完了させる必要があります。

AWS CLIには、このようなリモート環境向けに aws login --remote があります。

aws login --remote

このコマンドはブラウザを自動で開かず、代わりに認証用URLを表示します。人間がそのURLを手元のブラウザで開き、ログイン後に表示された認証コードをCLIへ貼り付ける、という流れです。

なぜSSH先でAWS CLI認証したかったのか

今回やりたかったのは、QuarkusのネイティブアプリをAWS Lambda向けにビルドしてデプロイすることです。

手元の環境はApple SiliconのmacOSでした。この環境でQuarkusのローカルnative buildを実行すると、基本的にはmacOS用arm64バイナリが生成されます。

一方、AWS Lambdaで必要なのはLinux用のarm64またはx86_64バイナリです。そのため、macOS上で直接作ったネイティブバイナリは、そのままLambdaでは動きません。

file target/*-runner

macOSで直接ビルドした場合は、たとえば次のように表示されます。

Mach-O 64-bit executable arm64

Lambda向けには、次のようなLinux用ELFバイナリが必要です。

ELF 64-bit LSB executable, ARM aarch64

この差を避けるには、Quarkusのコンテナビルドを使うのが基本です。

./mvnw package -Dnative -Dquarkus.native.container-build=true

ただし、今回はリモートのLinuxサーバー上でビルドやデプロイ作業を行いたかったため、SSH先サーバーからAWSへアクセスできるようにする必要がありました。

そもそも、なぜQuarkus Nativeを使いたかったのか

今回QuarkusのネイティブアプリをAWS Lambdaに載せたかった理由は、主に起動速度です。

データ連携のバッチ処理を使う程度なら、小さいVMを借りるよりもコストは安くなるのではないか?と思い検証しようと考えました。

Javaアプリを通常のJVMモードでLambdaに載せると、コールドスタート時にJVMの起動、クラスロード、フレームワーク初期化が発生します。QuarkusはJVMモードでも起動が速いフレームワークですが、Native Imageにするとさらに起動時間を短くできます。

一般的には、JVMモードではコールドスタートが数百ミリ秒から数秒程度になることがあります。一方、Native Imageでは数十ミリ秒から数百ミリ秒程度に収まるケースがあります。

もちろん実際の差は、以下の条件で変わります。

  • Lambdaのメモリサイズ
  • 初期化するライブラリの量
  • VPC接続の有無
  • 使用するAWS SDKやDBクライアント
  • arm64かx86_64か
  • SnapStartやProvisioned Concurrencyの有無

そのため、「必ず何倍速い」とは言えませんが、コールドスタートを小さくしたい用途ではQuarkus Nativeは有力な選択肢です。

今回も、Lambdaでの起動速度を重視してQuarkus Nativeを使うことにしました。

そこで、BobからSSH先で aws login --remote を実行する手順を整えました。

やりたいこと

Bobに以下の流れを実行させます。

  1. BobがSSHでリモートサーバーへ接続する
  2. SSH先で aws login --remote を実行する
  3. 表示された認証URLを人間に見せる
  4. 人間がブラウザでURLを開いて認証する
  5. 表示された認証コードをBob経由でSSH先のCLIへ渡す
  6. SSH先サーバーからAWS CLIが使えるようになる

最初に試した方法

まずは素直にSSH越しに実行します。

ssh user@host 'aws login --remote'

しかし、Bob経由では対話的なコマンドがうまく扱えないことがあります。

そこで疑似TTYを強制します。

ssh -tt user@host 'AWS_PAGER= AWS_CLI_AUTO_PROMPT=off aws login --remote'

-tt はSSHで疑似TTYを強制的に割り当てるオプションです。

通常のターミナルなら、これで次のようにURLが表示されます。

Browser will not be automatically opened.
Please visit the following URL:
https://...
Please enter the authorization code displayed in the browser:

Bobで起きた問題

BobのRun表示では、次の行で止まったように見えることがありました。

Browser will not be automatically opened.

本来はこの次にURLが表示されるはずですが、Bobの画面ではURLが見えません。

つまり、aws login --remote は進んでいるように見えるものの、人間が開くべきURLが取得できない状態です。

tmux を使う案

このような対話コマンドは、リモート側で tmux に逃がしておくと扱いやすいです。

ssh user@host "tmux new-session -d -s aws-login 'AWS_PAGER= AWS_CLI_AUTO_PROMPT=off aws login --remote'"

出力はあとから取得できます。

ssh user@host 'tmux capture-pane -pt aws-login -S -200'

ただし、tmux はリモートサーバーにインストールされていないことがあります。

今回の目的では、追加インストールなしで実現したかったため、別の方法を使いました。

追加インストールなしの回避策

aws login --remote の出力を一時ファイルへ保存し、認証コード入力にはFIFOを使います。

まず、SSH先で aws login --remote をバックグラウンド起動します。

ssh user@host 'set -eu; d=/tmp/aws-login-bob; rm -rf "$d"; mkdir -m 700 "$d"; mkfifo "$d/code"; nohup sh -c '"'"'exec 3<> "$1/code"; AWS_PAGER= AWS_CLI_AUTO_PROMPT=off aws login --remote <&3 > "$1/output" 2>&1; echo $? > "$1/exit"'"'"' sh "$d" >/dev/null 2>&1 & echo $! > "$d/pid"; echo "$d"'

出力を確認します。

ssh user@host 'sed -n "1,200p" /tmp/aws-login-bob/output'

ここで認証URLが見えるようになります。

Browser will not be automatically opened.
Please visit the following URL:
https://...
Please enter the authorization code displayed in the browser:

人間がURLをブラウザで開き、認証コードを取得します。

取得したコードをSSH先の待機中プロセスへ渡します。

ssh user@host "printf '%s\n' 'AUTHORIZATION_CODE' > /tmp/aws-login-bob/code"

認証結果を確認します。

ssh user@host 'sed -n "1,240p" /tmp/aws-login-bob/output'

AWS CLIとして認証できているか確認します。

ssh user@host 'aws sts get-caller-identity'

最後に一時ファイルを削除します。

ssh user@host 'rm -rf /tmp/aws-login-bob'

仕組み

この方法では、SSH先に一時ディレクトリを作っています。

/tmp/aws-login-bob/
├── code    # 認証コード入力用のFIFO
├── output  # aws login --remote の出力
├── pid     # バックグラウンドプロセスID
└── exit    # 終了コード

aws login --remote の標準出力と標準エラーを output に保存します。

一方で、標準入力にはFIFOである code をつなぎます。

そのため、Bobは別コマンドで output を読んでURLを人間に提示できます。また、人間が取得した認証コードを code に書き込むことで、待機中の aws login --remote に入力できます。

Bob Skillにする

この手順はBobのSkillにしておくと(自分にとって)便利なのではと思いました。

例えば、以下の場所にSkillを作成します。

~/.bob/skills/aws-remote-login/SKILL.md

Skillの流れは以下のようにします。

  1. まず ssh -ttaws login --remote を試す
  2. URLが見えない場合は /tmp/aws-login-bob 方式に切り替える
  3. /tmp/aws-login-bob/output からURLを取得して人間に提示する
  4. 人間が取得した認証コードを /tmp/aws-login-bob/code に流し込む
  5. aws sts get-caller-identity で確認する
  6. /tmp/aws-login-bob を削除する

これでBobに次のように頼めます。

SSH先でAWS remote loginして

注意点

SSH認証方式の考え方

SSH接続時の認証情報は、できるだけBobの画面、コマンド履歴、プロセス一覧に出さないようにします。

安全性の優先順位としては、以下の順で考えます。

  1. SSH公開鍵認証を使う
  2. 人間がSSHのパスワードプロンプトへ直接入力する
  3. .env + sshpass -e を使う
  4. sshpass -p 'password' のような直書きは避ける

本来の推奨はSSH公開鍵認証です。

ただし今回は、検証環境で一時的にパスワード認証を使う前提とし、コマンドラインへパスワードを直接書かないために .env + sshpass -e を使います。

.env を使う前提

この方法は、以下の前提で使います。

  • 検証環境または一時的な作業である
  • .env はGit管理しない
  • .env の内容を記事、ログ、スクリーンショットに載せない
  • Bobに .env の中身を表示させない
  • 作業後に .env または認証情報を削除する
  • 可能になった時点でSSH公開鍵認証へ切り替える

.env はコマンドライン直書きよりはましですが、平文ファイルに秘密情報を置く点は変わりません。公開鍵認証の代替ではなく、あくまで一時的な緩和策として扱います。

.env の例

SSH_USER=user
SSH_HOST=example.com
SSHPASS=your_password

.env は必ず .gitignore に追加します。

.env

必要に応じて権限も絞ります。

chmod 600 .env

.env を使ったSSH実行例

sshpass -e は、環境変数 SSHPASS からパスワードを読みます。

set -a
. ./.env
set +a

sshpass -e ssh "${SSH_USER}@${SSH_HOST}" 'aws sts get-caller-identity'

unset SSHPASS

aws login --remote を実行する場合も、パスワードをコマンドに直接書かず、.env から読み込ませます。

set -a
. ./.env
set +a

sshpass -e ssh "${SSH_USER}@${SSH_HOST}" 'AWS_PAGER= AWS_CLI_AUTO_PROMPT=off aws login --remote'

unset SSHPASS

避けたい例

以下のようにパスワードをコマンドへ直接書くのは避けます。

sshpass -p 'password' ssh user@example.com

この形式だと、Bobの表示、シェル履歴、プロセス一覧などにパスワードが残る可能性があります。

投稿時の注意

Qiitaなどに投稿する場合は、スクリーンショットやログに含まれる以下の情報を必ずマスクします。

  • IPアドレス
  • ユーザー名
  • パスワード
  • 認証URL
  • 認証コード
  • AWSアカウントID
  • ARN

まとめ

IBM BobからSSH先サーバーで aws login --remote を実行すると、BobのRun表示では認証URLが見えないことがあります。

まずは ssh -tt を試します。

ssh -tt user@host 'AWS_PAGER= AWS_CLI_AUTO_PROMPT=off aws login --remote'

それでもURLが見えない場合は、追加インストール不要の一時ファイル/FIFO方式が使えます。

この手順をBob Skill化しておくと、SSH先サーバーからAWSへアクセスしたいときに再利用しやすくなります。

ということでgithubに置きました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?