[Grafana][AWS]Cognitoを使ったGrafanaの認証

# はじめに
- 今回はAmazon Cognitoを使ったGrafanaのOAuth認証の設定手順について解説していきます。また、Grafana roleのマッピングやTeamのマッピングについても少し解説しようと思います。
- 動作環境
    - Grafana v9.3.1

# Cognitoユーザープールの作成
まずCognitoユーザープールの作成と設定を行います。
Cognitoの画面を開き、「ユーザープールを作成」をクリックします。
![Screenshot 2022-12-04 at 11.24.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/75e68486-5240-7116-9353-486d2b3d1ad4.png)

## サインインエクスペリエンスを設定
サインインオプションで「ユーザー名」と「Eメール」を選択し、ユーザー名の要件で「ユーザーが任意のユーザー名でサインインすることを許可」と「ユーザー名の大文字と小文字を区別する」を選択します。
![Screenshot 2022-12-04 at 11.28.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/fb3220e5-58bb-90c7-4a5a-303703bdf828.png)

## セキュリティ要件を設定
demoのためデフォルトのパスワードポリシーとMFAなしを選択します。ユーザーアカウントの復旧もデフォルトのままにします。
※本番環境では強力なパスワードポリシーとMFA必須をおすすめします。
![Screenshot 2022-12-04 at 11.29.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/56a2e783-9cd9-afbb-d8f3-9a234f153ec1.png)
![Screenshot 2022-12-04 at 11.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/a73e234f-d74c-5403-c5ab-9a81d5047836.png)

## サインアップエクスペリエンスを設定
ユーザーの作成はすべてCognitoユーザープールで実施したいので、セルフサービスのサインアップの「自己登録」を外します。それ以外の設定はデフォルトのままです。
![Screenshot 2022-12-04 at 11.30.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/809787f0-9a6f-9685-af04-e8f7fe1b3fac.png)
必須の属性に「追加の必須属性」として「name」を追加します。
![Screenshot 2022-12-04 at 11.32.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/8bc8aa2a-3f18-cc87-de04-90b2b0634bde.png)


## メッセージ配信を設定
Eメールの設定で「CognitoでEメールを送信」を選択します。大規模なシステムの場合はSESでのメール送信の方が向いているかと思います。
![Screenshot 2022-12-04 at 11.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/0e82cce8-289e-e5b2-739b-351b327be64e.png)

## アプリケーションを統合
「ユーザープール名」を入力します。　Cognitoのホストされたログインページを使うため、「CognitoのホストされたUIを使用」を選択します。
「Cognitoドメイン」に任意のドメイン名を入力します。`このURLは後ほどのGrafana設定で使います`。
![Screenshot 2022-12-04 at 11.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/9aba466d-12ec-100e-73bf-5fca54f63579.png)
サードパーティのアプリケーションであるGrafanaを使うため、アプリケーションタイプで「その他」を選択します。「アプリケーションクライアント名」を入力し、「クライアントのシークレットを生成する」を選択します。
「許可されているコールバックURL」に「`Grafanaのホスト/login/generic_oauth`」を入力します。今回はlocalhostでGrafanaを起動する予定なので、以下のURLになります。

```
http://localhost:3000/login/generic_oauth
```
![Screenshot 2022-12-04 at 11.37.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/129972cd-b0c4-7acd-c2e3-0199d32d320f.png)

高度なアプリケーションクライアントの設定を開き、「認証フロー」に以下の認証フローを追加します。
- ALLOW_ADMIN_USER_PASSWORD_AUTH
- ALLOW_USER_PASSWORD_AUTH
![Screenshot 2022-12-04 at 13.09.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/a627381b-a1cb-e250-ac95-43c38982fd68.png)
「OpenID接続スコープ」で以下のスコープを指定します。（「電話番号」は今回使わないので、外します）
- aws.cognito.signin.user.admin
- Email
- OpenID
- Profile
![Screenshot 2022-12-04 at 13.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/69394c5f-9dd8-7e44-9166-cee1d30b9d0c.png)


## クライアントIDとクライアントのシークレットの確認
上記手順で作成したCognitoユーザープールを開き、「アプリケーションの統合」タブをクリックします。
![Screenshot 2022-12-04 at 12.25.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/ac9b3ced-b101-e028-f85d-37cd48804776.png)

作成済みのアプリケーションクライアントを開きます。
![Screenshot 2022-12-04 at 12.26.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/8bfc33ef-7a8b-7b54-0c2e-4346df1e87c2.png)

アプリケーションクライアントに関する情報欄に表示された「クライアントID」と「クライアントシークレット」をメモしておきます。`後ほどのGrafana設定で使います。`
![Screenshot 2022-12-04 at 13.18.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/aef1360f-00e9-67e8-910c-9b9e3a8d2346.png)



# ユーザーの作成
Grafanaにログインするユーザーを作成します。上記手順で作成したCognitoユーザープールを開き、「ユーザーを作成」をクリックします。
![Screenshot 2022-12-04 at 12.16.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/73d9db4d-c1df-c69f-8839-e0043371d499.png)

「ユーザー名」と「Eメールアドレス」を入力します。仮パスワードを設定し、ユーザーを作成します。demoなのでEメール招待は送信しないようにします。
![Screenshot 2022-12-04 at 13.22.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/7a1cee96-e0b8-ad92-d2fa-a37b51336a36.png)



# Grafanaの設定
## grafana.iniの作成
ローカルPCの任意の場所に「grafana.ini」というファイルを作成し、以下の情報を記載します。client_id、client_secret、auth_url、token_url、api_urlは適宜変更してください。
```
[auth.generic_oauth]
enabled = true
name = OAuth
client_id = <クライアントID>
client_secret = <クライアントシークレット>
scopes = email profile aws.cognito.signin.user.admin openid
auth_url = https://<Cognitoドメイン>.auth.<AWSリージョン>.amazoncognito.com/oauth2/authorize
token_url = https://<Cognitoドメイン>.auth.<AWSリージョン>.amazoncognito.com/oauth2/token
api_url = https://<Cognitoドメイン>.auth.<AWSリージョン>.amazoncognito.com/oauth2/userInfo
```

## Grafanaの起動
DockerコンテナでGrafanaを起動します。grafana/grafanaのlastedを使いますが、2022/11/4時点での最新のGrafanaバージョンがv9.3.1になっています。
以下のコマンドを実行します。grafana.iniのパスのところは上記手順で作成した`grafana.iniファイルのパス`に置き換えてください。
```bash
docker run -d -p 3000:3000 -v <grafana.iniのパス>:/etc/grafana/grafana.ini --name grafana-demo grafana/grafana
```

## ログイン
ブラウザから`http://localhost:3000`にアクセスし、「Sign in with OAuth」をクリックすると、Cognitoの認証ページにリダイレクトされます。
![Screenshot 2022-12-04 at 14.00.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/68442394-22c7-4223-f1a1-a7dcdeb74eb9.png)


作成済みのtest-userのEメールアドレスと仮パスワードでログインしてみます。
![Screenshot 2022-12-04 at 14.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/fec633a5-83f0-ed5c-a7ee-343956d0e757.png)
初回ログイン時パスワードの変更とNameの設定を求められます。NameはCognitoでのユーザー作成時に設定したユーザー名とは別で設定可能です。
![Screenshot 2022-12-04 at 14.01.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/fdb75a8a-5ba5-a495-b3b6-83eb055e6ff7.png)
ログインできました！
![Screenshot 2022-12-04 at 14.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/7d8c7382-9af2-0d55-2032-1d2569b1f029.png)
![Screenshot 2022-12-04 at 14.02.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/5b0e38b0-7a53-8d26-e157-42183f09c424.png)


# Grafana roleのマッピング
Cognitoユーザープールで作成したグループ名に応じて、該当グループに所属するユーザーを特定のGrafana role（Admin、Editor、Viewer）にマッピングすることが可能です。OAuthでログインしたユーザーはデフォルトではViewerになっているので、Adminというグループを作成して、AdminのGrafana roleをマッピングしてみます。
作成済みのCognitoユーザープールを開き、「グループ」タブをクリックし、「グループを作成」をクリックします。
![Screenshot 2022-12-04 at 14.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/d74d8d3e-469d-8e85-899a-c4eea60dd25a.png)
「Admin」という名前でグループを作成します。
![Screenshot 2022-12-04 at 14.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/aa8db13d-cd3a-85da-74f2-a1db9d934ff1.png)
上記ユーザーの作成手順で作成したtest-userをグループに追加します。
![Screenshot 2022-12-04 at 14.22.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/3e7af296-cd3a-88e9-0f90-bd9f6c7c4111.png)
![Screenshot 2022-12-04 at 14.22.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/d699f67f-d8e4-ce92-940c-f3d821752d87.png)




グループ割り当て情報はid_tokenを介してGrafanaに送信されます。payloadは以下のようになっています。
```
{
    ......

	"cognito:groups": [
		"Admin"
	],

    ......
}
```
Grafanaは[JMESPath](https://jmespath.org/)を使ってクエリするので、grafana.iniファイルに下記の一行を追加します。
```
role_attribute_path = ("cognito:groups" | contains([*], 'Admin') && 'Admin' || contains([*], 'Editor') && 'Editor' || 'Viewer')
```
ユーザーがAdminグループに所属す場合はAdminのroleを付与し、Editorグループに所属する場合はEditorのroleを付与し、それ以外のグループに所属する場合はViewerのroleを付与するという設定になります。

コンテナを再起動します。
```bash
docker restart grafana-demo
```
test-userで再度ログインすると、Adminになっていることがお分かりになるかと思います。
![Screenshot 2022-12-04 at 14.34.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/899d7b79-322e-8ee7-976b-9bb0c67d49a7.png)

※ユーザーのグループ設定が変更されたら、Grafanaに再ログインすれば反映されます。

# Team Sync
Grafana roleのマッピングだけでなく、Grafana teamのマッピングもできます。Grafanaではユーザーをteamに所属させ、team単位でのダッシュボード閲覧や編集などのアクセス制御ができます。
OAuthグループ（Cognitoユーザープールのグループ）をGrafana teamにマッピングすることで、Grafanaでのteam割り当て操作が必要なくなり、より管理しやすくなりますね。roleのマッピングと似たような設定方法で、`groups_attribute_path`をgrafana.iniに追加することになります。
ただ、このTeam Syncという機能は`Grafana Enterpriseでしか使えない`らしいです。
Grafana Enterpriseを使っていないので、今回はTeam Syncに関する検証はできませんが、今後もし使う機会があったら、また共有させていただければと思います。この機能が気になる方は[Grafana公式ドキュメント](https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/generic-oauth/#team-synchronization)をご参照ください。

# 参考
- [Configure generic OAuth authentication | grafana.com](https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/generic-oauth/#team-synchronization)
- [Configure Team Sync | grafana.com](https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-team-sync/)
- [Grafana Enterprise | grafana.com](https://grafana.com/docs/grafana/latest/introduction/grafana-enterprise/)
- [AWS Cognito Authentication with Grafana Part 1: Local setup | scicoding.com](https://scicoding.com/aws-cognito-authorication/)
- [AWS Cognito Authentication with Grafana Part 2: User roles | scicoding.com](https://scicoding.com/aws-cognito-authentication-with-grafana-part-2-user-roles/)