OCI Bastionを少し楽に使う方法

# 概要
パブリッククラウドに立てたサーバーへアクセスするため、VPNを利用したり踏み台サーバーを立てたりするかと思います。
Oracle Cloud Infrastructure (OCI)にはBastionサービスというセキュアなリモートアクセスサービスがあり、SSH/RDP以外の通信を含めリモートからサーバーへのアクセスが可能です。

[OCI Bastion](https://www.oracle.com/jp/security/cloud-security/bastion/)

[よくある質問](https://www.oracle.com/jp/security/cloud-security/bastion/faq/)

ただ、このサービスを使うためにSSHポートフォワーディングのセッションの生成とコマンド取得する作業があり煩わしいので、少し楽に使えるようWindowsバッチを作成しました。

# 何がいいの?
- セキュアなBastionサービスが利用できます
    - Bastionサービスは無料です
    - コマンドの有効期間は最長3時間なので有効期間後は紛失や漏洩しても悪用リスクがありません（一日中接続する必要のある用途には向きません）
    - SSH/RDP以外にも対応しており、例えばOracle Client(Port:1521)も可能です
- リモートアクセスしたいときにバッチを実行すればBastionサービス利用に必要なコマンドが出力されますので、そのまま実行すればリモートアクセス環境を確立できます
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/8d5f2cc6-41bd-2e5c-bc6b-c450ac333163.png">

# 構成
PC内のクライアントソフトは同じPC内のSSHポートフォワードと通信します。
PC内のSSHポートフォワードはOCIのBastionとSSHセッションを確立し通信を転送します。
OCI内VMから見るとBastion Endpointから接続したように見えます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/8207f9ff-c21a-5a45-d124-1500c7441307.png">

# Bastion利用
## ハンズオン
以下のサイトを参考にBastion経由の接続を行ってください。
セッションタイプはSSHポート転送セッションを使用します。管理対象SSHセッションは使用しません。
[BastionサービスでパブリックIPを持たないリソースにアクセスする](https://oracle-japan.github.io/ocitutorials/intermediates/bastion/)

## バッチ作成
ハンズオンで実施したセッションの作成とSSHコマンドのコピーは、リモートアクセスするたびに必要となります。この部分をバッチ実行で省力化したいと思います。
今回はクライアント側はWindowsを前提としています。

### 初回のみ実行
- OCI CLIインストール
  以下のサイトを参考にOCI CLIインストールします

　[OCIコマンドライン・インタフェース(CLI)をすばやくインストールして構成](https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/cliinstall.htm)

  インストールの確認には以下のコマンドを実行してエラーにならないことを確認するとよいかと思います。
```
oci os ns get
```
- jqダウンロード
  OCI CLIのJSON形式のOutputから抽出するためにjqを使用します。
  https://jqlang.github.io/jq/
  jq-windows-amd64.exeは、jq.exeに名前変更してください。

- 各パラメータ確認
  以下のパラメータを確認します。
    - Bastion OCID 
 OCIコンソールナビゲーションメニューからアイデンティティとセキュリティ>>要塞>>対象要塞>>要塞情報内のOCIDをコピー
    - <font color="red">接続先サーバーPrivate IP</font>
    -  <font color="gray">~~接続先サーバーOCID~~</font>
        - <font color="gray">~~Linux/Windows:~~</font>
   <font color="gray">~~OCIコンソールナビゲーションメニューからコンピュート>>インスタンス>>対象インスタンス>>インスタンス情報内のOCIDをコピー~~</font>
        - <font color="gray">~~Oracle DBサーバー(DBCS):~~</font>
   <font color="gray">~~OCIコンソールナビゲーションメニューからOracle Database>>Oracleベース・データベース>>対象インスタンス>>DBシステム情報内のOCIDをコピー~~</font>

### リモートアクセス時に実行
以下の環境情報に必要な情報を設定します
- TARGETSERVER=<font color="red">接続先サーバーPrivate IP</font><font color="gray">  ~~接続先サーバーOCID~~</font>
- TARGETPORT=接続先サーバーポート
- TARGETPORTL=クライアントから接続先ポートに指定するローカルポート
Windows側で使っていないポートを指定します
- PUBKEYF=Bastion側に設定するSSHパブリックキー
- PRIKEYF=上記SSHキーに対応するプライベートキー
- BASTIONID=Bastion OCID

LinuxにSSHで接続する場合の例です。

<font color="red">oci bastion session create-port-forwardingの--target-resource-idを--target-private-ipに変更しました</font>

```bastion-session-create.bat
@echo off
rem Bastion session作成およびコマンド情報取得

echo Set environment
rem 環境情報
set TARGETSERVER=【接続先サーバーPrivate IP】
set TARGETPORT=22
set TARGETPORTL=3222
set PUBKEYF=c:\path\to\ssh-key.key.pub
set PRIKEYF=c:\path\to\ssh-key.key

set BASTIONID=【Bastion OCID】
set DATASTATUS=FAIL

echo Step1
rem Bastion session作成
oci bastion session create-port-forwarding --bastion-id %BASTIONID% --ssh-public-key-file %PUBKEYF% --target-port %TARGETPORT% --target-private-ip %TARGETSERVER% --session-ttl 10800 --wait-for-state SUCCEEDED > %temp%create-port-forwarding-result.json

for /f "usebackq" %%A in (`type %temp%create-port-forwarding-result.json ^| jq -r ".data.status"`) do set DATASTATUS=%%A

if not %DATASTATUS%==SUCCEEDED (
    echo Try again
    exit /b
)

echo Step2
rem Bastion sessionコマンド情報取得
for /f "usebackq" %%B in (`type %temp%create-port-forwarding-result.json ^| jq -r ".data.resources[0].identifier"`) do set IDENTIFIER=%%B

oci bastion session get --session-id %IDENTIFIER% >%temp%bastion-session-result.json
for /f "usebackq delims=" %%C in (`type %temp%bastion-session-result.json ^| jq -r ".data.\"ssh-metadata\".command"`) do set COMMANDTEMP=%%C

set LINE0=%PRIKEYF% -N -L %TARGETPORTL%
call echo %%COMMANDTEMP%:^<privateKey^> -N -L ^<localPort^>=%LINE0%%%
```
バッチを実行して正常完了するとコマンドが作成されます。

```
C:\Path\to>bastion-session-create.bat
Set environment
Step1
Action completed. Waiting until the work request has entered state: ('SUCCEEDED',)
Step2
ssh -i c:\path\to\ssh-key.key -N -L 3222:【接続先サーバーIP】：22 -p 22 ocid1.bastionsession.oc..@host.bastion.ap-tokyo-1.oci.oraclecloud.com
↑このコマンドを実行します
```
作成されたコマンドを実行するとBastion間をのSSHセッションが確立しますので、その後にクライアントソフト(SSH,RDPやOracle Client等)にて
- 宛先サーバー：localhost
- 宛先ポート：ローカルポート(この例では3222)

を指定して接続します。

TCP/IP通信状態は以下のようになります。
```
C:\path\to>netstat -an
....
PCとBastion間のSSH Forwardingセッション
  TCP         (PCのIP):56977   (BastionのIP):22      ESTABLISHED
....
PCクライアントソフトとPC内Forwardingポート間セッション
  TCP         127.0.0.1:3222         0.0.0.0:0              LISTENING
  TCP         127.0.0.1:3222         127.0.0.1:56994        ESTABLISHED
  TCP         127.0.0.1:56994        127.0.0.1:3222         ESTABLISHED
....

```