K8sの認証をGoogle OpenIDで行う(RBAC)

Kubernetesクラスタ上の認証をGoogleをID ProviderとするOIDCにより行います．

KubernetesのRBACについては以下のスライドが参考になります．
[Kubernetes の認証・認可と RBAC - Speaker Deck](https://speakerdeck.com/tksm/kubernetes-falseren-zheng-ren-ke-to-rbac)

# 検証環境

- Kubernetesクラスタ
    - k3s v1.18.8+k3s1 (6b595318)
    - スペック
        - vCPU: 2 [core]
        - RAM: 2 [GB]
        - Storage: 30 [GB]
- クライアント
    - kubectl v1.18.8

# 手順

## [1] Google API ConsoleでTokenを発行

以下のURLにアクセスします．

https://console.developers.google.com/projectselector/apis/library

## [1.1] プロジェクトの作成

新たに「プロジェクトを作成」します．既存プロジェクトをつかう場合はこの手順をスキップしてください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/44953317-7dcd-e304-89b5-e895aced1915.png)

プロジェクト名を入力して「作成」を押します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/cb5f555f-39e0-1972-32fd-9ee78ef3a5e3.png)

### [1.2] OAuth同意画面の作成

メニューの「APIとサービス」から「OAuth同意画面」を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/21a2ddc3-f734-2ddb-eb68-4da50127dfe0.png)

UserTypeを選択して「作成」を押します．利用者が組織内に限定される場合は「内部」を選択してください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/9aa3d08c-6771-1df0-0599-a60a2b411552.png)

アプリケーション名を入力して，下部にある「保存」を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/3da0587d-fcf9-2a2a-4f22-e3b29714d76b.png)

### [1.3] OAuthクライアントIDの発行

メニューの「認証情報」を選び，「認証情報を作成」から「OauthクライアントID」を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/68a5ee9d-667a-fc6b-deb2-7dd0fd2310ef.png)

アプリケーションの種類から「テレビと入力が限られたデバイス」を選択し，名前を入力してください．そして，「作成」を押します．
過去の資料では「その他/Other」でしたが，最新のメニュー項目名は変更されているので注意が必要です．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/7c10f631-34ec-e30b-ca3b-32500e6b8cb5.png)

### [1.4] クライアントIDの取得とJSONのダウンロード

トークン一覧から作成したトークンの詳細を確認します．
メニューの「JSONをダウンロード」からJSON形式の認証情報をダウンロードします．
クライアントIDをメモしておきます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/3d5fbca2-281c-a6f4-8613-dc65554121d7.png)

## [2] Kubernetesクラスタの設定を変更

### [2.1] K3sのマスターノードの起動オプションを変更

k3sのserviceファイルをバックアップします．

```bash
sudo cp /etc/systemd/system/k3s.service /etc/systemd/system/k3s.service.org
```

k3sのserviceファイルを変更します．

```bash
sudo vi /etc/systemd/system/k3s.service
```

起動オプションに以下を追加してください．
`oidc-client-id`はGoogle API Consoleで取得したクライアントIDを付与してください．

```bash
ExecStart=/usr/local/bin/k3s \
    server \
    --kube-apiserver-arg oidc-issuer-url=https://accounts.google.com \
    --kube-apiserver-arg oidc-client-id=97...55ft9k.apps.googleusercontent.com \
    --kube-apiserver-arg oidc-username-claim=email \
    --kube-apiserver-arg authorization-mode=RBAC
```

systemdに変更を適用させます．

```bash
sudo systemctl daemon-reload
```

k3sを再起動します．

```bash
sudo systemctl restart k3s
```

## [3] .kube/configの設定を生成

k8s-oidc-helperで.kube/configのユーザ情報を生成します．

```bash
go get github.com/micahhausler/k8s-oidc-helper
```

Google API ConsoleでダウンロードしたJSONファイルを引数に渡して，k8s-oidc-helperを実行します．

```bash
k8s-oidc-helper -c client_secret_977...655ft9k.apps.googleusercontent.com.json
```

ブラウザが起動してGoogleアカウントの選択を求められるので，認証したいアカウントを選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/ef1ef7ce-7aab-48db-9be1-42ddef6b9c19.png)

コードが表示されるので，コピーしてターミナルに貼り付けてEnterを押します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/394b25dd-7fc2-4ad0-2617-eb730eedfe9e.png)

```yaml
# 以下はGoogleから取得したコードを貼り付けた結果
4/3wG2PbYtYzJ65pgniwcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Add the following to your ~/.kube/config
apiVersion: v1
clusters: []
contexts: []
current-context: ""
kind: Config
preferences: {}
users:
- name: example@gmail.com
  user:
    auth-provider:
      config:
        client-id: 977........55ft9k.apps.googleusercontent.com
        client-secret: 2...............46
        id-token: eyJhbGciOiJSUzI1NiIsxxxxxxxxxxxxxxx
        idp-issuer-url: https://accounts.google.com
        refresh-token: 1//0eqiWaqVoq7cTCxxxxxxxxxxxxxxxxxxx
      name: oidc
```

.kube/configが生成されるので，ローカルの.kube/configに追記します．

## [4] KubernetesクラスタにCustomRoleとClusterRoleBindingの作成

CustomRoleとCustomRoleBindingを作成します． `example@gmail.com` をGoogleアカウントのアドレスに置き換えてください．

```bash
$ kubectl apply -f role.yaml
clusterrole.rbac.authorization.k8s.io/admin-role created
clusterrolebinding.rbac.authorization.k8s.io/admin-binding created
```

```yaml:role.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
    name: admin-role
rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["*"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
    name: admin-binding
subjects:
    - kind: User
      name: example@gmail.com
roleRef:
    kind: ClusterRole
    name: admin-role
```

<補足> ここではClusterRoleのrulesにある`verbs`や`resouces`を `*` で設定していますが，実際には適切なアクセス制御を記述してください．

## [5] kubectlで確認

kubectlで `--user` をオプションにつけてKubernetesクラスタへアクセスできるか確認します．

```bash
$ kubectl --user=example@gmail.com get nodes
NAME       STATUS     ROLES    AGE     VERSION
k3s-test   NotReady   master   3h49m   v1.18.8+k3s1
```


# 参考資料

- [Kubernetes 1.6.1 authentication by using Google OpenID](https://cloud.google.com/community/tutorials/kubernetes-auth-openid-rbac)
- [Using RBAC Authorization | Kubernetes](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
- [youtube data api - The Option to select 'Other' for a client ID in the OAuth in the Google APIs is not available - Stack Overflow](https://stackoverflow.com/questions/62528774/the-option-to-select-other-for-a-client-id-in-the-oauth-in-the-google-apis-is)

# 追記 2020/09/10

トークンの有効期限が切れた場合，トークンの再設定が必要になるはずなので今後は以下の方法を試してみたいと思います．

- [kubectl で OpenID Connect ID トークンをリフレッシュする - Qiita](https://qiita.com/superbrothers/items/3c4e3fc651e9b3e9ef02)