OpenShiftのOAuthサーバーを認証プロバイダーとして使用して、Libertyへのアクセスを認証する方法

# はじめに
当記事では、OpenShiftのOAuthサーバーを認証プロバイダとして使用して、コンテナ上のLibertyを認証する方法を記述します。
環境はOpenShift4.6です。
前提として、ある程度JakartaEE/J2EE 等の知識があることを想定しています。


以下の2パターンのうち、１のパターンについて記述します。
この方法は、２に至る前のテスト接続の確認としても有用です。

1. OAuthのための設定値を静的に設定する
1. オペレータからアプリケーションをデプロイし、オペレータからサービスアカウントの作成、および、設定値を動的に設定する。

LibertyからOpenShift上のOAuthサーバーを使用する方法は、以下の記事を参考にしています。

https://openliberty.io/blog/2020/01/17/openshift-oauth-server-social-login-liberty-20001.html

サービスアカウントをOauthクライアントとして使用する方法は、以下の記事を参考にしています。

https://docs.openshift.com/container-platform/4.6/authentication/using-service-accounts-as-oauth-client.html


# Oauthのための設定値を静的に設定する
Oauthのための設定値を静的に設定する方法は、アプリケーションが動作するOpenShiftのインスタンスが決まっている状況に有用です。

## 手順概要
Oauthのための設定値を静的に設定する手順の概要は、下記になります。

1. アプリケーションを保護および、Basic Registryを使用した認証のテスト
1. Service Accountの作成
1. Service Accountにredirecturiの設定
1. Service AccountにClusterRoleおよびClusterRoleBindingを設定
1. Service Accountのトークンを取得
1. Libertyのserver.xmlに、oauth2loginを設定
1. APIサーバーの証明書をLibertyが使用するJVMのtruststoreにインポート

## 1 アプリケーションを保護および、Basic Registryを使用した認証のテスト
まずは、アプリケーションの保護、および、Basic Registryを使用した認証をテストします。

詳細の説明は省きますが、
Webアプリケーションで使用するweb.xmlやLibertyで使用するserver.xmlに、アプリケーションの保護設定および認証設定を行い、稼働をテストします。

この設定により、Libertyで稼働するWebアプリケーションのリソースにアクセスした際に、認証を求められます。
その認証時には、Basic Registryで指定したユーザーおよび、パスワードによって、認証することができます。

```web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="DownloadApps" version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">

 <!-- SECURITY ROLES -->
 <security-role>
    <role-name>downloader</role-name>
 </security-role>

 <!-- SECURITY CONSTRAINTS -->
 <security-constraint>
    <web-resource-collection>
      <web-resource-name>all</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>downloader</role-name>
    </auth-constraint>
 </security-constraint>

 <!-- AUTHENTICATION METHOD: Basic authentication -->
 <login-config>
    <auth-method>BASIC</auth-method>
 </login-config> 

 <display-name>DownloadApps</display-name>
</web-app>
```

```server.xml
    <webApplication location="DownloadApps.war" contextRoot="/">
        	<application-bnd>
    		<security-role name="downloader">
    		    <special-subject type="ALL_AUTHENTICATED_USERS" />
    			<group name="admin"/>
    		</security-role>
    	</application-bnd>
    </webApplication>
    <basicRegistry>
    	<user password="secret" name="test"></user>
    	<group name="admin">
    		<member name="test"></member>
    	</group>
    </basicRegistry>
```

## 2 Service Accountの作成
OAuth認証をするためのOAuth ClientにOpenShift上のService Accountを使用します。
そのServcie AccountをOpenShiftで作成します。

```yaml
kind: ServiceAccount
apiVersion: v1
metadata:
  name: sample-sa
  namespace: default
```

画面例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/f6e2356f-0d33-45c9-86b3-73d56ffe2dee.png)



## 3 Service AccountのAnnotationsにredirecturiの設定
Servcie AccountのAnnotationsに、LibertyのSocial Login用のリダイレクトURIを指定します。

|key|value|
|:-:|:-:|
|serviceaccounts.openshift.io/oauth-redirecturi.first| https://xxxx:9443/ibm/api/social-login/redirect/openshiftLogin|

FQDNのxxxの部分は、環境に応じて指定してください。

画面例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/ed1b4a8c-2eed-6677-10dc-78fd98d38cc7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/0f0cc6db-54b3-6ed0-5678-e66df1744734.png)


## 4 Service AccountにClusterRoleおよびClusterRoleBindingを設定
tokenreviewsとsubjectaccessreviewsをcreateできるClusterRoleを作成します。

```yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: auth-tokenreviews
rules:
  - verbs:
      - create
    apiGroups:
      - authentication.k8s.io
    resources:
      - tokenreviews
      - subjectaccessreviews
```

Cluster Role Bindingを作成し、Cluster RoleとService AccountをBindします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/f293d084-8166-502f-3c7f-ae395b6648d4.png)


## 5 サービスアカウントのトークンを取得
作成したサービスアカウントのトークンを取得します。
このトークンを、libertyのserver.xmlのoauth2Login のclientSecretとuserApiTokenに設定します。

```
oc sa get-token <service_account_name>
```

## 6 Libertyのserver.xmlに、oauth2loginを設定

ibertyのserver.xmlに、oauth2loginを設定します。


```server.xml
    <variable name="serviceAccountName" defaultValue="system:serviceaccount:<namespace>:<serviceaccount>"  />
    <variable name="token" defaultValue="XXXXXX"/>
    <variable name="authEndpointUrl" defaultValue="https://oauth-openshift.apps.<FQDN>/oauth/authorize"  />
    <variable name="tokenEndpointUrl" defaultValue="https://oauth-openshift.apps.<FQDN>/oauth/token"  />
    <variable name="userApiUrl" defaultValue="https://api.<FQDN>:6443/apis/authentication.k8s.io/v1/tokenreviews"  />
    <oauth2Login id="openshiftLogin"
      scope="user:info"
      clientId="system:serviceaccount:default:${serviceAccountName}"
      clientSecret="${token}"
      authorizationEndpoint="${authEndpointUrl}"
      tokenEndpoint="${tokenEndpointUrl}"
      userNameAttribute="username"
      groupNameAttribute="groups"
      userApiToken="${token}"
      userApiType="kube"
      userApi="${userApiUrl}">
  </oauth2Login>
```

```server.xml
    <webApplication location="DownloadApps.war" contextRoot="/">
        <application-bnd>
    		<security-role name="downloader">
    		    <special-subject type="ALL_AUTHENTICATED_USERS" />
    		</security-role>
    	</application-bnd>
    </webApplication>
```

## 7 APIサーバーの証明書をLibertyが使用するJVMのtruststoreにインポート

OpenShiftのAPIサーバーの証明書を、Libertyが使用するJVMのtruststoreにインポートしないと、
LibertyからOpenShiftのAPIサーバーにアクセスしたときにSSL Handshakeのエラーが発生します。


```:エラーの例
[ERROR   ] CWPKI0823E: SSL HANDSHAKE FAILURE:  A signer with SubjectDN [CN=*.apps.xxx.com] was sent from the host [oauth-openshift.apps.xxx.com:443].  The signer might need to be added to local trust store [/opt/ol/wlp/output/defaultServer/resources/security/key.p12], located in SSL configuration alias [defaultSSLConfig].  The extended error message from the SSL handshake exception is: [PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target].
[ERROR   ] CWPKI0828E: The trustDefaultCerts attribute is enabled but trust was not established by using the default truststore. The extended error message from the SSL handshake exception is: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.
[ERROR   ] CWWKS5451E: The social login feature encountered a problem while obtaining token information from the token endpoint that is configured for the social login configuration [openshiftLogin]. CWWKS5476E: An error occurred while making a request to the provided URL [https://oauth-openshift.xxx.com/oauth/token]. PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

```

### APIサーバーの証明書をLibertyが使用するJVMのtruststoreにインポートする方法
OpenShiftのコンソールにアクセスし、ブラウザを使用して証明書をダウンロードします。

Firefoxの場合、ブラウザのURL横の鍵アイコンを押下し、証明書を表示し、ダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/0e4077ac-e02d-a1cf-1e0a-0d7c97f0232c.png)
PEM（CERT）というリンクから、証明書をダウンロードできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/b36e5add-f769-13a5-563b-426fe36fe63e.png)

```
keytool.exe -list -keystore C:/DownloadApps/target/liberty/wlp/usr/servers/defaultServer/resources/security/key.p12 -storepass XXXX
```

```
keytool.exe -importcert -keystore C:/DownloadApps/target/liberty/wlp/usr/servers/defaultServer/resources/security/key.p12 -storepass xxxx -file "C:\Downloads\apps-xxx-com.pem
```

同様に、LibertyのuserApiに指定する下記のようなページにアクセスし、同様に証明書のダウンロードとインポートを行います。
https://api.xxxx.com:6443/apis/authentication.k8s.io/v1/tokenreviews

この証明書のインポートの部分は、もしかすると、もう少しスマートな方法があるかもしれません。

## 期待の動き

1. Libertyの任意のアプリケーションURLにアクセスします
1. OpenShiftの認証ページにリダイレクトされます。
1. OpenShiftのクレデンシャルでログインします。
1. LibertyのアプリケーションURLにダイレクトされます。

OpenShiftの認証ページ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/c70d4228-34b7-f64a-bfac-4fe1ff1fddd0.png)


## まとめ
この記事では、OAuthのための設定値を静的に設定し、OpenShiftのOAuthサーバーを認証プロバイダとして使用して、Libertyを認証する方法を記しました。

誰かの助けになれば、幸いです。