ROSA(Red Hat OpenShift Service on AWS)環境でPodにSTSによる一時的な認証を付与する

# はじめに
みなさんはOpenShift上のコンテナからAWSを操作する時、どのような形で権限を付与していますか？よくあるパターンとしてIAMユーザーのアクセスキーとシークレットキーをSecretで環境変数としてアタッチすることが多いかと思います。

しかしAWSでのベストプラクティスでは、システム上での認証はIAMユーザーでなくIAMロールやAWS STS(Security Token Service)による一時的な形での付与を推奨されています。また企業のセキュリティ規約上、システムリソースにIAMユーザーを使うことを明示的にNGにしていることもあるかと思います。

そこで、OpenShift上のコンテナに対して、IAMユーザーの認証情報ではなく、STSを使った一時的な認証情報を渡す方法についてご紹介します。

ここでは、Red Hat OpenShift Service on AWS(ROSA)環境にてSTSによる認証を付与されたPodからAWSリソースにアクセスできるまでの手順をまとめます。
前提条件としてすでにSTSを使ったROSA環境をデプロイできていることを想定しているため、もしこれからSTSを使ったROSAのインストールを実施する場合は以下の赤帽エンジニアブログを参照ください。

[AWS STSを使ったROSAのデプロイ](https://rheb.hatenablog.com/entry/2021/09/22/AWS_STS%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9FROSA%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)

また、AWS IPIインストール時の手順は、OpenShiftの構築手順と含めて以下の赤帽エンジニアブログに上げています。
[AWS STSを使って一時的な認証情報を扱うOpenShift on AWS環境を構築する](https://rheb.hatenablog.com/entry/2022/02/26/AWS_STS%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E4%B8%80%E6%99%82%E7%9A%84%E3%81%AA%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E3%82%92%E6%89%B1%E3%81%86OpenShift_on_AWS%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89)


それでは、まずはキーコンポーネントとなるCloud Credential Operatorの説明から。

# Cloud Credential Operator（CCO）
Cloud Credential Operator（CCO）はOpenShiftの管理Operatorで、デフォルトでクラスターにインストールされています。 CCOはクラウドの認証情報をCredentialsRequestというカスタムリソースで管理しており、このリソース内に記述したIAMポリシー情報や利用先のNamespace情報を元に、自動的に該当のIAMユーザーの作成とSecretの作成を実施してくれる便利なツールです。 IAMユーザーの利用で問題なければ、上記を活用して簡単にAWSアクセス用のリソースが準備できるのでぜひご利用してみてください。

今回はSTSを使うということなのでOpenShift上のこちらの機能は活用できませんが、CCOはccoctlというバイナリツールを提供しており、それを使うことでCredentialsRequestからSTSを使う場合のSecret yamlファイルを作成することができます。 ちなみにOpenShiftのSTSによるインストールはバージョン4.8からGAになりました。

以下はCCOのgithubにある、STSを使った一時的なCredential付与の概要です。


> OpenShiftは、AWS Security Token Service(STS)で様々なコンポーネントの一時的なクレデンシャルを使用するように設定できます。これにより、認証フローが有効になり、コンポーネントがIAMロールを引き受けることができるため、資格情報が短命になります。また、AWS IAM OpenID Connect（OIDC）IDプロバイダーを使用して、Credentialsのリクエストと更新を自動化します。OpenShiftは、AWS IAMによって信頼されているServiceAccountトークンに署名できます。このトークンは、Podにプロジェクションして認証に使用できます。以下は、それがどのように機能するかを示す図です。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/f584af0e-d464-1ce5-1db6-d7e37f3ad5ad.png)
https://github.com/openshift/cloud-credential-operator/blob/master/docs/sts.md

# ROSA環境におけるSTS利用手順
## 前提条件
* Linux環境
* ROSAをAWS STSを使った方法でインストール済
* ocコマンド
* AdministratorAccessのIAMユーザー

## pull-secretのダウンロード
まずは[こちら](https://console.redhat.com/openshift/install/aws/installer-provisionedからpull-secret)からpull-secretをダウンロードして実行フォルダに格納してください。


## ccoctlバイナリのダウンロード
まずccoctlコマンド実行のための準備を行います。
ROSA環境にcluster-adminでログインしている状態で以下のコマンドを実行します。
今のROSA環境にインストールされているCCOのイメージを取得し、バイナリとしてダウンロードします。
```
$ CCO_IMAGE=$(oc adm release info --image-for='cloud-credential-operator')
$ oc image extract $CCO_IMAGE --file="/usr/bin/ccoctl" -a ./pull-secret.txt
$ chmod 775 ccoctl
```

以下コマンドを実行すると正常にダウンロードできているか確認できます。

```
$ ccoctl aws --help
Creating/updating/deleting cloud credentials objects for AWS cloud


Usage:
  ccoctl aws [command]


Available Commands:
  create-all               Create all the required credentials objects
  create-iam-roles         Create IAM roles
  create-identity-provider Create IAM identity provider
  create-key-pair          Create a key pair
  delete                   Delete credentials objects

Flags:
  -h, --help   help for aws

Use "ccoctl aws [command] --help" for more information about a command.
```
## IDプロバイダーのARNを確認
AWSコンソールにログインして、`IAM`→`IDプロバイダ`からROSA構築時に作成されたIDプロバイダを選択し、表示されたARNをメモしておきます。
![スクリーンショット 2022-02-28 16.18.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/ddb8a09b-0f6c-4b7a-f1bd-5d539656ebb5.png)

## CredentialsRequestリソースのyamlファイルを作成
次に、デプロイしたいIAMロールの権限情報を記載したCredentialsRequestリソースのyamlファイルを作成します。
今回はPodからS3バケットの一覧を取得するコマンドを実施したいので、その操作に必要な権限を定義します。
以下は、Secretのデプロイ先Projectを「sts-test」に、またPodに付与するService Accountを「default」にすることを前提として記述しています。

```
$ mkdir -p sts-test-resource/cred-reqs
$ cd sts-test-resource
$ vi cred-reqs/s3-access-secret.yaml
```

```cred-reqs/s3-access-secret.yaml
apiVersion: cloudcredential.openshift.io/v1
kind: CredentialsRequest
metadata:
  name: sts-test-cr
  namespace: openshift-cloud-credential-operator
spec:
  secretRef:
    name: s3-access-secret
    namespace: sts-test
  providerSpec:
    apiVersion: cloudcredential.openshift.io/v1
    kind: AWSProviderSpec
    statementEntries:
    - effect: Allow
      action:
      - s3:ListAllMyBuckets
      resource: "*"
  serviceAccountNames:
  - default
 ```

## ccoctlコマンドの実行
取得・作成した内容をもとに、ccoctlコマンドを実行してIAMロールの作成とsecretマニフェストの作成を行います。
`--identity-provider-arn`には先述の手順で取得したIDプロバイダーのARNを入力します。

```
$ ccoctl aws create-iam-roles \
--identity-provider-arn arn:aws:iam::XXXXXXXXXXXX:oidc-provider/rh-oidc.s3.us-east-1.amazonaws.com/1ql0oja8ndd2h0s03c9lhmdrtfqev56q \
--output-dir ./outputs \
--name sts-test-rosa \
--region ap-northeast-1 \
--credentials-requests-dir ./cred-reqs/
```

実施すると、IAMロールが新規に作成されます。
![スクリーンショット 2022-02-28 16.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/f25700d1-b79b-7409-6f85-6f888f286fd9.png)


ポリシーを確認するとCredentialsRequestで指定したポリシーがアタッチされています。
![スクリーンショット 2022-02-28 16.26.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/355b1dc5-f309-8024-0713-6e86567a97da.png)

信頼関係を見てみると、ROSAインストール前に構築したIDプロバイダーをプリンシパルとして、`sts-test`Namespaceの`default`サービスアカウントに権限を付与することが読み取れます。
![スクリーンショット 2022-02-28 16.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/953f2602-f73d-d704-5cc9-d7fa05cd1bf3.png)

またoutputsディレクトリに、デプロイするためのマニフェストが出力されています。

```
$ cat outputs/manifests/sts-test-s3-access-secret-credentials.yaml
apiVersion: v1
stringData:
  credentials: |-
    [default]
    role_arn = arn:aws:iam::XXXXXXXXXXXX:role/sts-test-rosa-sts-test-s3-access-secret
    web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
kind: Secret
metadata:
  name: s3-access-secret
  namespace: sts-test
```

## Secretのデプロイ
outputsディレクトリに出力されたyamlをデプロイします。

```
$ oc new-project sts-test
$ oc create -f outputs/manifests/sts-test-s3-access-secret-credentials.yaml
```

これでPodからSTSの認証情報を取得する準備が整いました。


## Podのデプロイ
最後にデプロイするPodのyamlファイルを作成していきます。

* デプロイしたSecretを/var/run/secrets/awsにVolumeMount
* awscli実行時の認証ファイルに/var/run/secrets/aws/credentialsを使うようAWS_CONFIG_FILE環境変数を設定
* サービスアカウントのトークンを/var/run/secrets/openshift/serviceaccountに格納するようbound-sa-tokenvolumesを設定（詳細は[こちら](https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.6/html/authentication_and_authorization/bound-sa-tokens-configuring_bound-service-account-tokens)を参照）

```
$ vi pod.yaml
```

```pod.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
  labels:
    run: running-aws
  name: running-aws
spec:
  containers:
  - command:
    - tail
    - -f
    - /dev/null
    image: amazon/aws-cli
    name: running-aws
    resources: {}
    env:
    - name: AWS_CONFIG_FILE
      value: /var/run/secrets/aws/credentials
    volumeMounts:
    - name: aws-credentials
      mountPath: /var/run/secrets/aws
      readOnly: true
    - name: bound-sa-token
      mountPath: /var/run/secrets/openshift/serviceaccount
      readOnly: true
  volumes:
  - name: aws-credentials
    secret:
      defaultMode: 420
      secretName: s3-access-secret
  - name: bound-sa-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: openshift
          expirationSeconds: 3600
          path: token
```

上記のPodをデプロイします。

```
$ oc create -f pod.yaml
```

実際にPodにログインしてawsコマンドを叩いてみます。

```
$ oc rsh running-aws
sh-4.2# aws s3 ls
2022-02-28 05:46:27 sts-test-rosa-vlwl8-image-registry-ap-northeast-1-tcfkpstrpeww
```

無事にS3バケットの情報が取得できました。


# 最後に

ということで、ROSA環境におけるSTSでの一時的な認証付与を行なったPodの作成方法についてご紹介しました。

CCOの機能を最大限活用するにはIAMユーザーでの運用が望ましいですが、セキュリティ的な側面からIAMユーザー認証が使えない際は、この手法を検討してみてはいかがでしょうか？