SORACOM Napterで複数SIMからSSH先を選択して接続できるスクリプト作った

この記事はBeeX Advent Calendar 2020の12/15の記事です。

SORACOM NapterはオンデマンドでデバイスへのテンポラリかつセキュアなSSH接続を開けるサービスで、コロナ禍で現場に行くのが難しくなった中、自分の中でますます活躍の場が増えてるサービスです。

soracom.jp

SORACOM Napterの通常の使い方

この記事見ている人なら知らない人はいないと思いますが、通常の使い方を復習すると、

SIM選んで、オンデマンドリモートアクセスを選択して、

空けるポートや、許可するグローバルIP、空けておく時間を設定して、

これでSSHするためのポートが設定したグローバルIP向けに開きます。

とてもシンプルかつ便利なサービスで、かなり利用しています。

更に欲しくなってきたモノ

開発の中で欠かせないものになってきて、以下のような状態になってきました。

  • 管理対象のSIM付きデバイスが増えてきて、切り替えての開発作業が増えてきた
  • 既存の接続を使い回したいときシェルの履歴ではどれがどのSIMへの接続だかわからなくなった
  • 開発中はターミナルから出ないで作業したい(マウス使いたくない)

作成したスクリプト

ということでブラウザを開かずに手元から管理先のSIM選んでSSHできるスクリプトを作成しました。

前提条件

Linuxの基本コマンド以外で必要なものは以下となります。

  • jq
  • SORACOM CLI
  • fzfpeco (任意なので無くてもOK)

SORACOM CLIは公式サイトを参考にインストールと認証して使えるようにしておいてください。

スクリプト

特に名前に指定は無いですが、記事では便宜上 napter_selector.sh として保存します。

※ところどころawk使ってて読みにくくてすみません・・

#!/bin/bash
set -eu

#################################
# 定数パラメータ
#################################
readonly USER=pi
readonly PORT=22
readonly DURATION_SEC=1800

# Global IPを取得
readonly GLOBAL_IP=$(curl -s checkip.soracom.io)

# fzfやpecoを設定するとフィルタリングに利用できます
#readonly FILTER_CMD=fzf

#################################
# 既存接続を選択
#################################
port_mappings=""
existing_port_mappings=$(
  soracom port-mappings list | \
  jq -r '.[]|[.hostname,.port,.destination.imsi] | @csv' | \
  tr -d '"' | \
  awk -F, -v u="${USER}" '{print $1":"$2":"$3}')

for mapping in ${existing_port_mappings}
do
  # 既存の接続にNameタグを付与
  imsi=$(echo ${mapping} | awk -F: '{print $3}')
  name_tag=$(soracom subscribers get --imsi ${imsi} | jq -r '.tags.name' | tr -d ' ')
  port_mappings="${port_mappings} ${mapping}:$name_tag"
done

if [ -n "${port_mappings}" ];then
  # 既存のSSH接続から選択または新規作成(new)
  port_mappings="new ${port_mappings}"
  echo "Select existing connection or Select [new] to create a connection:"
  select p in ${port_mappings}
  do
    if [ "${REPLY}" = "q" ]; then
      echo "QUIT."
      exit -1
    fi
    if [ "${p}" = "new" ]; then
      # newを選択した場合は新規接続を作成
      break
    fi
    if [ ! -n "${p}" ]; then
        echo "invalid selection."
        continue
    fi
    ssh_cmd=$(echo ${p} | awk -F: -v u="${USER}" '{print "ssh -o StrictHostKeyChecking=no -p "$2" "u"@"$1}')
    # 既存のSSH接続を利用して接続処理
    echo ${ssh_cmd}
    ${ssh_cmd}
    exit 0
  done
fi

#################################
# 新規に接続を作成する場合
#################################
# IMSIとNameタグ見ながら選択接続を開くSIMを選択
subscribers=$(soracom subscribers list | jq -r '.[] | [.tags.name,.imsi] | join("@")' | tr -d ' ') 
if [ -v ${FILTER_CMD:+""} ];then
  echo "Select sim to create new connection:"
  select subscriber in ${subscribers}
  do
    if [ -n "${subscriber}" ]; then
        break
      else
        echo "invalid selection."
    fi
  done
else
  subscriber=$(echo ${subscribers} | tr ' ' '\n' | ${FILTER_CMD})
fi


# 選択したSubscriberのIMSIを使ってリモートアクセスを設定
imsi=$(echo ${subscriber} | awk -F@ '{print $2}')
ssh_cmd=$(soracom port-mappings create --body \
  "{\"destination\":{\"imsi\":\"${imsi}\",\"port\":${PORT}},\"duration\":${DURATION_SEC},\"source\":{\"ipRanges\":[\"${GLOBAL_IP}/32\"]}}" | \
  jq -r '[.hostname,.port] | @csv' | tr -d '"' | awk -F, -v u="${USER}" '{print "ssh -o StrictHostKeyChecking=no -p",$2,u"@"$1}')

# SSHで接続
echo ${ssh_cmd}
${ssh_cmd}
exit 0

使い方

以下のようにスクリプトを起動します。

./napter_selector.sh

スクリプト起動時に既にオープンしている既存のSSH接続があれば、その一覧が表示されます。一覧にはURLやポート、SIMに設定したNameタグが表示されます。

以下の画像の場合は3つの既存接続があるので、2~4番号選択すると、選択された接続先にSSH接続します。1の new を選択すると新規のSSH接続を作る処理に遷移します。

f:id:yomon8:20201214111324p:plain

新規接続の作成処理です。SIMとNameタグの一覧が表示されるので選択すると、デフォルトでは現在のGlobal IPのみを許可したSSH接続が選択したSIMに対してオープンします。

f:id:yomon8:20201214111807p:plain

オプション

以下のようにスクリプトの中でパラメータを設定しています。環境に合った値に変更して使ってください。

# 定数パラメータ
readonly USER=pi
readonly PORT=22
readonly DURATION_SEC=1800

# Global IPを取得
readonly GLOBAL_IP=$(curl -s checkip.soracom.io)

# fzfやpecoを設定するとフィルタリングに利用できます
#readonly FILTER_CMD=fzf
パラメータ デフォルト 内容
USER pi SSH接続で利用するユーザ
PORT 22 デバイス側のSSHポート
DURATION_SEC 1800(30分) Napterのアクセスが可能な時間
GLOBAL_IP (自身のGlobal IPを取得) SSH接続を許可するグローバルIP
FILTER_CMD (コメントアウト) フィルターコマンドの設定(以下で説明)
  • FILTER_CMDオプション

以下は fzf をインストールした環境で readonly FILTER_CMD=fzf と設定した場合の画面です。

f:id:yomon8:20201214110858p:plain

github.com

peco でも同じようなことが可能です。

f:id:yomon8:20201214102231p:plain

github.com

所感

自分用に作ったツールですが、それなりに汎用的になってきたので、もしかしたら使える人もいるかと思って公開しました。

このツールを作る前は既存のBashのヒストリーから既存のSSH接続先の履歴探したり、再度接続先をオープンするのが面倒なので長めの接続オープン時間を設定していたりしていて、あまり良くないなーと感じてました。簡単なツールですが、これ作ってからはその辺りが軒並み解消できています。

自分は開発や作業中はLinuxターミナル出たく無い派なので、CLI出してくれたSORACOMさんには感謝です。