RedshiftにIAM認証でつなぐ方法

# はじめに
AWSのRedshiftには普通にID/Passで接続する以外に、
IAMで作成したアクセスキー/シークレットキーで接続することができます。
このIAM認証を使ってのJDBC接続を試してみました。
SSOではなく、単純にアクセスキーのキーペアを使っての接続です。

# 接続準備
## Redshiftアカウントの作成
ここでは __rsuser__ というアカウントを作ることにします

```sql
create user rsuser password disable ;
```
passwordは __disable__ と設定します。

## ポリシーの作成

redshift:GetClusterCredentialsのResourceで
先ほど作成したRedshiftアカウントrsuserにのみ割り当てできるようにポリシーを記述します。

```json:RedshiftIAMAuthPolicy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "redshift:GetClusterCredentials",
            "Resource": [
                "arn:aws:redshift:*:*:dbuser:*/rsuser",
                "arn:aws:redshift:*:*:dbgroup:*/*",
                "arn:aws:redshift:*:*:dbname:*/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "redshift:DescribeClusters",
            "Resource": "*"
        }
    ]
}
```
省略していますが、本当はリージョンやデータベース名などを制限します。

## IAMユーザの作成
IAMでユーザを作成し、先ほど作成したポリシー(RedshiftIAMAuthPolicy)を割り当てます。
アクセスキーのキーペアを発行し、メモっておきます。

# 接続
作成したIAMユーザをRedshiftアカウントに割り当て、接続します。
JDBC文字列は以下のようになります。

*  jdbc:redshift:iam:// __クラスタ__ : __ポート__ / __データベース__ ?AccessKeyID= __アクセスキー__ &SecretAccessKey= __シークレットキー__ &DbUser= __Redshiftアカウント__

jdbc:redshift://～～ ではなく
jdbc:redshift:__iam__//～～ となることに注意してください。

## Javaサンプル

```java
import java.sql.*;
import java.util.Properties;

public class IamAuthSample{
    public static void main(String[] args){
        String jdbcURL = "jdbc:redshift:iam://hoge.xxxxxxxxx.ap-northeast-1.redshift.amazonaws.com:5439/database01?AccessKeyID=XXXXXXXXXXX&SecretAccessKey=YYYYYYYYYYYYYY&DbUser=rsuser";
        try (Connection con = DriverManager.getConnection(jdbcURL);
            Statement st = con.createStatement();
            ResultSet rs = st.executeQuery("select * from information_schema.tables;")) {
            while (rs.next()) {
                String catalog = rs.getString("table_catalog");
                String name = rs.getString("table_name");
                System.out.println("Catalog: " + catalog + ", Name: " + name);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
```
__getConnection()__に渡すのはjdbc文字列だけになることに注目です。
サンプルなのでAccessKeyIDなど接続情報をソースに直書きしていますが、
実際に使う場合は他から取得するなど工夫しましょう。

## DBeaver
[Redshiftの接続クライアントツールの比較](https://qiita.com/_konishi_/items/47732f0dc5c33b751d98)で紹介した[DBeaver](https://dbeaver.io/)で接続するときは少し工夫が必要でした。
Dbeaverのバージョンは7.0.0です。

1. 新しいドライバの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436247/1e9c64c8-79c0-6237-e367-76add07001ab.png)
メニュー ＞ ドライバーマネージャー から 新規 でドライバを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436247/fbeaa8f9-74eb-d6c3-246d-457ce863c960.png)
ドライバ名はここではRedsfhitIAMとします。
URLテンプレートには上記のJDBC文字列をそのまま入力します。
これら以外は既存のRedshiftドライバと同じ設定にします。


2. 接続の作成

メニュー ＞ データベース ＞ 新しい接続 ＞ RedshiftIAM
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436247/b3a51f3b-ff28-eb16-6465-231d0af3d6e8.png)
Host、Portなどはドライバに設定したJDBC文字列に埋め込まれているので
ここで入れる文字は意味がないのですが、何か入力しないと作成できないので適当に入力します。

* 1接続ごとにそれ用の新しいドライバを作る必要があります。
* ドライバーマネージャーで コピー をするとURLテンプレートが変更できないので、新規 で作ります。

# 参考
[IAM 認証を使用したデータベースユーザー認証情報の生成](https://docs.aws.amazon.com/ja_jp/redshift/latest/mgmt/generating-user-credentials.html)