はじめに
社内環境にアクセスするためのJump Serverに、Pomeriumゲートウェイ+Okta認証を通して接続する必要があり、毎回の手動認証に手間を感じていました。
そこで、Playwright + TOTP(Time-based One-Time Passwordを用いて、OktaのMFA認証を自動化し、Pomerium経由のTCP接続を自動起動する仕組みを構築したので紹介します。
解決したかった課題
- Pomeriumを起動すると、Oktaログイン→MFA認証→トンネル確立の流れが手動
- 特に毎回手でOkta Verifyコードを入力するのが面倒
- 開発/運用チームのメンバーも手動対応しており、属人化していた
技術スタック
-
Playwright
: ブラウザ自動操作(Oktaログイン処理) -
otplib
: TOTPコード生成(Okta Verifyコード自動入力) -
child_process.spawn
: Pomeriumバイナリの起動 -
chromium
(via Playwright): headlessブラウザ操作 - Node.js (TypeScript)
処理フローの全体像
- Node.jsからPomeriumバイナリをspawn
- stderrから認証URLを取得
- PlaywrightでそのURLにアクセス
- ユーザー名+パスワードを入力してログイン
- Okta Verifyに切り替え、TOTPコードを自動入力
- 認証完了でPomeriumがトンネルを確立
コード解説
1️⃣ Pomerium起動とURLの取得
public initPomerium(): Promise<void> {
const pomeriumProcess = spawn(pomeriumPath, [
"tcp", pomeriumHost,
"--listen", `:${pomeriumPort}`,
]);
pomeriumProcess.stderr.on("data", async (chunk) => {
const message = chunk.toString();
if (message.includes("listening on")) {
Logger.success(`Pomerium is ready on port ${pomeriumPort}`);
resolve();
} else if (message.includes("https")) {
const match = message.match(/https?:\/\/[^\s]+/g);
if (match) {
await Playwright.loginPomerium(match[0]);
}
} else {
reject(new Error(`Failed to start Pomerium: ${message}`));
}
});
}
-
stderrから
https://
で始まるURLを抽出 → Pomeriumのログインページ - Macでは
chmod
とxattr
で初回実行制限を解除しているのもポイント
2️⃣ PlaywrightによるOktaログイン自動化
public async loginPomerium(url: string) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(url);
await page.getByRole("textbox", { name: "Username" }).fill(credentials.SSH_USERNAME);
await page.getByRole("textbox", { name: "Password" }).fill(credentials.JUMP_SERVER_PASSWORD);
await page.getByRole("button", { name: "Sign in" }).click();
await page.getByRole("link", { name: "Select to enter a code from" }).click();
const otpInput = await page.getByRole("textbox", { name: "Enter code from Okta Verify" });
const mfaOtp = Okta.generateOTP(); // otplibなどを使って生成
await otpInput.fill(mfaOtp);
await page.getByRole("button", { name: "Verify" }).click();
}
- ログインページ→Okta Verifyへの遷移→TOTP入力→認証完了の流れを再現
-
Okta.generateOTP()
はotplib
等で事前に設定されたシークレットから生成できます
import { totp } from "otplib";
export const Okta = {
generateOTP(): string {
return totp.generate(process.env.OKTA_MFA_SECRET || "");
}
};
TOTPのセットアップはこちら:
成果と今後の展望
- Oktaログイン~MFA認証の自動化で、Pomeriumトンネル確立を完全自動化
- 毎回の認証手間がゼロに。10秒以内にSSHが使える状態に!
- 今後はGitHub Actionsなどから自動でVPN経由ジョブを走らせる応用も検討
PomeriumやOktaの認証処理が面倒…という方は、Playwright+TOTPによる自動化をぜひ試してみてください!