Cloudflare Zero Trust と Amazon Cognito の Single Logout (SLO) について考える

# セッション管理
以下の記事にある通り、Cloudflare Zero Trust の ID 認証先に Amazon Cognito を OIDC で連携することができます。

https://qiita.com/khayama/items/dcd5b2fc51b7435e1765

その際には、それぞれのユーザセッションはそれぞれの Cookie にて管理されます。

- Cloudflare Zero Trust
    - `CF_Authorization` Cookie で管理されます。

https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/

- Amazon Cognito
    - `cognito`、`cognito-fl` Cookie が使用されます。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html

https://repost.aws/questions/QUXFeyaZ5LSveYWDn6q-anSw/what-is-the-point-of-using-the-logout-endpoint-when-aws-cognito-is-stateless

# 考えられるログアウトフロー
それぞれのログアウトエンドポイントにアクセスすることで、それぞれが管理する Cookie を削除できます。

- Cloudflare Zero Trust
    - `returnTo` パラメータがサポートされているものの、リダイレクト先が制限されています。
    - Ref. [Cloudflare Access logout page customization / redirect - Zero Trust / Access - Cloudflare Community](https://community.cloudflare.com/t/cloudflare-access-logout-page-customization-redirect/223470)

https://developers.cloudflare.com/cloudflare-one/identity/users/session-management/#log-out-as-a-user

- Amazon Cognito
    - Amazon Cognito では `Allowed sign-out URLs` を定義の上で `logout_uri` パラメータを指定することで、別のログアウトエンドポイントにリダイレクトさせることができます。

https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html

以上を踏まえると、以下のようなフローが考えられます。

```mermaid:
graph TB

subgraph Cloudflare Zero Trust
    subgraph CFLogout [Logout endpoint]
        1["(your-application-domain)/cdn-cgi/access/logout"]
        2["(your-team-name).cloudflareaccess.com/cdn-cgi/access/logout"]
    end
    CFCookie[CF_Authorization Cookie]
    CFLogout --> |Delete|CFCookie
end

subgraph Amazon Cognito
    subgraph ACLogout [Logout endpoint]
        3["(Your-User-Pool-Domain).auth.(Your-User-Pool-Region).amazoncognito.com/logout"]
    end
    ACCookie[cognito, cognito-fl Cookie]
    ACLogout --> |Delete|ACCookie
    ACLogout --> |"[o] Redirect with</br>logout_uri=Allowed sign-out URLs"|CFLogout
end

A[こちらのURLを踏みリダイレクトをさせることで両方の Cookie を削除できる] --> ACLogout
B[リダイレクト先が制限されているため、片方の Cookie のみの削除となる] --> CFLogout
CFLogout -.-> |"[x] Redirect"|ACLogout
```

# App Launcher への Bookmark 追加
Cloudflare Zero Trust の App Launcher では、ユーザーは単一のダッシュボードからアクセス可能なすべてのアプリケーションを開くことができます。

- `https://<your-team-name>.cloudflareaccess.com/`

https://developers.cloudflare.com/cloudflare-one/applications/app-launcher/

そこに以下の手順で、 Cloudflare Zero Trust と Amazon Cognito の双方からログアウトができる Bookmark を追加することで、従業員が容易にログアウトできるようにします。

https://developers.cloudflare.com/cloudflare-one/applications/bookmarks/

`Application URL ` に以下のリンクを設定し、`Enable App in App Launcher` を有効にします。

```shell:
https://<Your-User-Pool-Domain>.auth.<Your-User-Pool-Region>.amazoncognito.com/logout?
client_id=<Your-User-Pool-App-Client>&
logout_uri=https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/logout?returnTo=https://<your-team-name>.cloudflareaccess.com/
```

Amazon Cognito では `https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/logout?returnTo=https://<your-team-name>.cloudflareaccess.com/` を `Allowed sign-out URLs` に追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9484c961-73e5-4a22-4daf-e68c8a3203a6.png)

# 動作確認

App Launcher `https://<your-team-name>.cloudflareaccess.com/` にアクセスして Login ボタンを押すと、Amazon Cognito でログインする選択肢が提示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/c1872539-ef80-1074-59b3-1bc94774dd68.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/8f499aec-d11c-8202-8001-b165dfb66cda.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/90576616-3ee3-d059-410f-91545a6ac1ff.png)

Amazon Cognito ユーザプールで認証します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/8f8a32f9-81d6-7618-6a6e-0eec33fd1988.png)

認証後は、以下の Single Logout 用のブックマークを押すことで、App Launcher ログイン画面 `https://<your-team-name>.cloudflareaccess.com/` に `returnTo` し、再度 Amazon Cognito ユーザプールでの認証が求められることが確認できます。

これで両方の Cookie を削除できたことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/5967cde7-6ab1-0267-0a67-66c7bb1106ea.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/c1872539-ef80-1074-59b3-1bc94774dd68.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/8f8a32f9-81d6-7618-6a6e-0eec33fd1988.png)


# 参考：再認証時に必要な対話操作を強制する
特定の IdP に対しては、`prompt` オプションによって再認証時に必要な対話操作を強制することで同等のフローを実現する方法もあります。

https://qiita.com/khayama/items/c045723728e127e2874f

Amazon Cognito に関しては、そうした `prompt` オプションは存在しないようです。

https://stackoverflow.com/questions/58154256/aws-cognito-how-to-force-select-account-when-signing-in-with-google

# 参考：OpenID Connect SLO
今回はそれぞれのプロバイダで用意されているログアウトエンドポイントに、リダイレクトを組み合わせる形の実装となりました。

ただ OpenID Connect (OIDC) の枠組みの中で Single Logout (SLO) の仕組みも標準化されているため、今後は各プロバイダがこうした仕組みをサポートするかを優先的に確認するとよいでしょう。

- OpenID Connect Front-Channel Logout 1.0：

https://openid.net/specs/openid-connect-frontchannel-1_0.html

- OpenID Connect Back-Channel Logout：

https://openid.net/specs/openid-connect-backchannel-1_0.html