OCI Bastion経由でプライベート・サブネット内のAutonomous DBに接続する

__初めに__
冒頭ですが、この記事は次のシリーズ記事の1つです。
シリーズ１：[OCI Bastion サービス](https://qiita.com/letian/items/10152a4fec813c1b7d98#bastion-%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9)
シリーズ２：[プライベート・サブネット内の Oracle DB/ADB に接続](https://qiita.com/liu-wei/items/10152a4fec813c1b7d98#4-%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%82%B5%E3%83%96%E3%83%8D%E3%83%83%E3%83%88%E5%86%85%E3%81%AE-oracle-dbadb-%E3%81%AB%E6%8E%A5%E7%B6%9A)

プライベート・サブネットにADBを作成した場合、ADBへのアクセスはプライベート・エンドポイントを介して行います。VPNを設定しない場合、OCI Bastionサービスを利用すると、踏み台サーバを構築せずにOn-Pのクライアントからプライベート・サブネット内のADBに接続できます。OCI Bastionサービスは<font color=blue>無料</font>で利用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/0153c151-78e2-b45a-06e9-17fb9a22d433.png)

__検証環境__

|項目|内容|コメント|
|--|--|--|
|ADBタイプ|Data Warehouse|ATPにも適用|
|クライアントOS|Windows Server 2019|
|DB接続ツール|SQL Developer Ver 21.4|SQL PlusでもOK|
|SSHソフト|OpenSSH||

__ステップ__
- [1. 事前準備](#1-事前準備)
- [2. Bastionの作成](#2-bastionの作成)
- [3. セッションの作成](#3-セッションの作成)
- [4. NSGにイングレス・ルールを追加する](#4-nsgにイングレスルールを追加する)
- [5. ADBのホスト名をローカルで識別可能にするため](#5-adbのホスト名をローカルで識別可能にするため)
  - [方法1. ホストファイルを編集する](#方法1-ホストファイルを編集する)
  - [方法2. tnsnames.oraを編集する](#方法2-tnsnamesoraを編集する)
- [6. SSHトンネルの作成](#6-sshトンネルの作成)
- [7. ADBに接続する](#7-adbに接続する)
- [付録](#付録)
  - [トラブル・シューティング](#トラブルシューティング)
  - [Bastionの制限](#bastionの制限)

# 1. 事前準備
__ADB Walletをダウンロード__
OCIコンソールからダウンロードした後（詳細は省略）、それをクライアント側に保存します。

__ADBの「プライベート・エンドポイントIP」を確認__
ADBの詳細ページから、「プライベート・エンドポイントIP」を取得できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/84d51c11-84b9-1095-1aa6-4b2481555037.png", width="350">

# 2. Bastionの作成
Identity & Security -> Bastion -> Create Bastion

|項目|内容|
|--|--|
|要塞名|適当な名前を入力|
|ターゲットVCNとサブネット|ADBが所属するVCNとサブネットを選択|
|CIDRブロック許可リスト|このテストではCIDRブロックの許可リストを「0.0.0.0/0」に設定しているが、運用時には範囲を絞り込むことが推奨される。例えば、 接続元（クライアント）のIPアドレスのみを許可するように。|

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/77b6a1a8-59c9-e87a-42e6-859fbd41307e.png", width="500">

__注意__
1. このテストでは、CIDRブロックの許可リストを「0.0.0.0/0」に設定しています。運用時には範囲を絞り込むことが推奨されます。例えば、接続元（クライアント）のIPアドレス範囲のみを許可するのが良いでしょう。
2. OCI Bastionを作成する際には、<strong>ターゲット</strong>のVCNとサブネットを指定する必要がありますが、<strong>Bastion自体</strong>に対し、<strong>配置場所を指定する必要はありません</strong>（誤解されることがよくあります）。

Bastionがアクティブの状態になると、「<font color=blue>プライベート・エンドポイントIP</font>」は次の画面から確認できます。このIPはターゲット・サブネット内で自動的に割り当てられます。次のステップで、このIPをNSGのイングレス・ルールに追加します。「CIDRブロック許可リスト」を編集したい場合は、「<strong>編集</strong>」ボタンをクリックすれば大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/9ad98d1d-fa95-f7ef-578d-e1056ca6c3af.png)

# 3. セッションの作成
Bastion -> Sessions -> Create session
|項目|内容|
|--|--|
|セッション・タイプ|"<font color=blue>SSH port forwarding session</font>"を選択|
|ターゲット・ホストに接続する方法|"IPアドレス"を選択 (デフォルト)|
|IPアドレス|ADBの「プライベート・エンドポイントIP」|
|ポート|<font color=blue>1522</font>
|SSHキー|既存のキーファイルを利用するか、新しいキーペアを作成する。|

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/cc2012de-0fde-1da8-0a92-02057070fac0.png", width="500">
セッションはアクティブの状態になりましたら、次のように、3ドットのメニューをクリックしてSSHコマンドをコピーします。このコマンドは、[「STEP 6. SSHトンネルの作成」](#6-sshトンネルの作成)で使用されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/639cc802-3236-6da3-55e9-a29db10c0599.png">
デフォルトでは、セッションは3時間有効ですが、Bastionを作成する際にはこの期間を変更することが可能です。

# 4. NSGにイングレス・ルールを追加する
プライベートADBを作成する時、ネットワーク・セキュリティ・グループ（NSG）がアタッチされます。ADBにアクセスするため、TCPポート1522を入力ルールに追加するのは必要です。

まだ行っていない場合は、次のようにルールを追加してください。"<strong>Source CIDR</strong>"は、Bastionの「プライベート・エンドポイントIP」です（Bastionの情報ページに表示されます）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/ef57190b-a6cb-c4c5-dd41-cfd25c24a3e8.png)

# 5. ADBのホスト名をローカルで識別可能にするため
次の2つの方法があり、どちらもOKです。
## 方法1. ホストファイルを編集する
接続クライアントに、次のファイルを編集します。

__ファイル名__
Windows OS: C:\Windows\System32\drivers\etc\hosts
Linux OS: /etc/hosts

追加内容: 127.0.0.1 <プライベート・エンドポイントURL>
例：127.0.0.1 xxxxxxxx.adb.ap-tokyo-1.oraclecloud.com

## 方法2. tnsnames.oraを編集する
ファイルtnsnames.oraに記載されているホスト名は、ADBの「プライベート・エンドポイントURL」です。 BastionサービスのSSHポート転送を使用するため、ローカル（DBクライアン側）からADBへのSSHトンネルを作成します。それで、ホスト名を<font color=blue>localhost</font>に変更する必要があります。

__重要<font color=red> !!</font>__
ホスト名の編集は、<font color=blue>Linux OS</font>で実施してください（例えば、<font color=blue>vi, sed</font>コマンド）。Windowsでホスト名を編集して保存したら、tnsnames.oraファイル内のサービス名が識別されませんので、ご注意ください。

以下のようにホスト名を変更してください。
編集前：host=<font color=Magenta>\<Private Endpoint URL></font>　例：`host=xxxxxxxx.adb.ap-tokyo-1.oraclecloud.com`
編集後：host=<font color=blue>localhost</font>

編集後のイメージは、以下のようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/f0ed01fb-d5ab-513e-4e2a-b48c68b23950.png)

以下は、Oracle Linuxでの実施例です（解凍+編集+圧縮）。
```bash
[opc@linux8 ~]$ pwd
/home/opc
[opc@linux8 ~]$ mkdir wallet_local
[opc@linux8 ~]$ unzip Wallet_adw02.zip -d ./wallet_local
Archive:  Wallet_adw02.zip
  inflating: ./wallet_local/README
  inflating: ./wallet_local/cwallet.sso
  inflating: ./wallet_local/tnsnames.ora
  inflating: ./wallet_local/truststore.jks
  inflating: ./wallet_local/ojdbc.properties
  inflating: ./wallet_local/sqlnet.ora
  inflating: ./wallet_local/ewallet.p12
  inflating: ./wallet_local/keystore.jks
[opc@linux8 ~]$ cd wallet_local
[opc@linux8 wallet_local]$ sed -i 's/host=[a-z0-9]*.adb.ap-tokyo-1.oraclecloud.com/host=localhost/' tnsnames.ora
[opc@linux8 wallet_local]$ zip Wallet_adw02_local.zip *
  adding: cwallet.sso (stored 0%)
  adding: ewallet.p12 (stored 0%)
  adding: keystore.jks (deflated 13%)
  adding: ojdbc.properties (deflated 49%)
  adding: README (deflated 56%)
  adding: sqlnet.ora (deflated 9%)
  adding: tnsnames.ora (deflated 73%)
  adding: truststore.jks (deflated 28%)
[opc@linux8 wallet_local]$
```
利用中のリージョンにより、リージョン・コード(ap-tokyo-1)を置き換えてください。

名前を区別するため、Wallet_adw02_local.zipを名付けます。当ディレクトリの全ファイルを一つのZipファイルに圧縮します。圧縮後、接続元のクライアントに転送してください。

# 6. SSHトンネルの作成
クライアント側でSSHコマンドを実行してトンネルを作成します。この例は、OpenSSHを利用します。まだインストールされていない場合、PowerShellを起動して、以下のコマンドでインストールしてください（管理者ユーザで実行）。
コマンド：`Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'`
```powershell
PS C:\Windows\system32> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'


Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed

Name  : OpenSSH.Server~~~~0.0.1.0
State : Installed



PS C:\Windows\system32>
```

__SSHトンネルを作成するコマンド__:
```bash
ssh -i <privateKey> -N -L <localPort>:<Private_IP_of_ADB>:1522 -p 22 <bastion_ocid>@host.bastion.ap-tokyo-1.oci.oraclecloud.com
```

* `<privateKey>`を秘密キーのパスとファイル名に置き換える。
　Windowsの例（PowerShell）：`$home\.ssh\id_rsa`
* `<localPort>`を<font color=blue>1522</font>に置き換える。
* `<Private_IP_of_ADB>`は自動に実のIPが埋められるので、変更する必要がない。

PowerShllのコマンド例：
```powershell
ssh -i $home\.ssh\id_rsa -N -L 1522:10.0.1.130:1522 -p 22 <bastion_ocid>@host.bastion.ap-tokyo-1.oci.oraclecloud.com
```
※、接続成功の場合、コマンドプロンプトを返さない。

# 7. ADBに接続する
* SQL Developerを開き、接続を新規作成
<strong>Database Type</strong>: デフォルトのOracleを指定
<strong>Connection Type</strong>: <font color=blue>Cloud Wallet</font>を指定
<strong>Configuration File</strong>:（ZIPファイルのままでよい。）
ホストファイルを編集した場合：元のWalletファイルを指定
ホストファイルを編集していない場合：<font color=blue>tnsnames.oraを編集した</font>Walletファイルを指定（次のスクリーンショットのように）。
<strong>Service</strong>: 必要に応じて、XXXX_high, XXXX_medium, XXXX_lowの選択肢から指定
「<font color="blue">テスト</font>」ボタンを押し、接続をテストします。接続成功を確認したら、「<font color="blue">接続</font>」ボタンを押し、接続を立てます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/1e3439a0-7bb0-785a-fc26-4d7df2bf368d.png)

__SQL Plusを使いたい場合__
クライアント側からSQL Plusを利用しプライベートADBへの接続も可能です。上記ステップ以外、<font color=blue>sqlnet.ora</font>の編集も必要です。別のトピックとなりますので、ここで割愛させていただきます。興味のある方は以下の記事をご参照ください。接続元は"OCI Cloud Shell"ですが、作業の流れは同様です。（SQL Plusの場合、tnsnames.oraの修正も必要ですが、最後にWalletファイルの圧縮は不要です。）
[OCI Cloud Shell上のSQL PlusからADBに接続する](https://qiita.com/liu-wei/items/38b968cee3a9619c63e5)

# 付録
## トラブル・シューティング
ADBへの接続が失敗した場合、以下の原因は一般的です。ご参考ください。

- 無効なユーザーまたはパスワード。
- ユーザー・ロールの指定は間違った。
- ADBインスタンスはまだ起動していない。
- リスナー・ポート（TCP 1522）は、Ingressルールに追加されていない。
- SSHトンネルは未作成か、作成が失敗した。
トンネル作成失敗、或いはタイムアウトの時、以下のメッセージが表示される。
`Connection to host.bastion.ap-tokyo-1.oci.oraclecloud.com closed by remote host.`
- tnsnames.oraの編集が間違ったため、サービス名が識別できない。（Linux OSで編集）
- Bastionのセッション期限が切れた（デフォルトは３時間）。
セッション期限が切れた後、SSHトンネルを作成しようとしたら、以下のエラーが発生する。
`<bastion_ocid>@host.bastion.ap-tokyo-1.oci.oraclecloud.com: Permission denied (publickey)`
対策：セッションを再作成する。

## Bastionの制限

|項目|内容|
|--|--|
|最大Bastion数|テナンシ毎に<font color=blue>5つ</font>|
|最大セッション数|Bastionあたり<font color=blue>20</font>セッション|
|最大セッション存続時間|<font color=blue>3時間</font>|
|最小セッション存続時間|30分|
|データ転送制限|データ転送の制限はありません。<br>ただし、SSH接続あたりの接続速度は<font color=blue>16 Mbps</font>に制限されます。|

以上です。


__関連記事__
[オラクル・クラウドの個人ブログ一覧](https://qiita.com/liu-wei/items/10152a4fec813c1b7d98)
[OCI Cloud Shell上のSQL PlusからAutonomous DBに接続する](https://qiita.com/liu-wei/items/38b968cee3a9619c63e5)
[SQL Developerで様々なDBに接続する方法](https://qiita.com/liu-wei/items/08f2e2f6d90c08549cbf)
[Oracle Base DBのサービス名を取得する](https://qiita.com/liu-wei/items/ecab5bc23efd13410dac)
[OCI データベース・ツールでオラクルDBへの接続方法](https://qiita.com/liu-wei/items/1d4ed7477a28b794a56c)
[OCI Bastion経由でプライベート・サブネット内のOracle DBに接続する](https://qiita.com/liu-wei/items/36f2108992ce71d7bafc)
[OCI Bastion経由でMySQL Database Serviceに接続する](https://qiita.com/liu-wei/items/e86e01ac3d61999aa811)