こんにちは、Red Hatでソリューションアーキテクトをしている北村です。
今回はAWS環境でOpenShiftを構築・利用する際の認証情報の扱いについて考えていきます。
みなさんはOpenShift上のコンテナからAWSを操作する時、どのような形で権限を付与していますか?よくあるパターンとしてIAMユーザーのアクセスキーとシークレットキーをSecretで環境変数としてアタッチすることが多いかと思います。
しかしAWSでのベストプラクティスでは、システム上での認証はIAMユーザーでなくIAMロールやAWS STS(Security Token Service)による一時的な形での付与を推奨されています。また企業のセキュリティ規約上、システムリソースにIAMユーザーを使うことを明示的にNGにしていることもあるかと思います。
そこで、OpenShift上のコンテナに対して、IAMユーザーの認証情報ではなく、STSを使った一時的な認証情報を渡す方法についてご紹介します。
まずは今回のキーコンポーネントであるCloud Credential Operatorの説明から。
Cloud Credential Operator(CCO)
Cloud Credential Operator(CCO)はOpenShiftの管理Operatorで、IPIインストールした場合はデフォルトでクラスターにインストールされています。 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にプロジェクションして認証に使用できます。以下は、それがどのように機能するかを示す図です。
手順
今回は、以下の2つの作業を行います。
- STSを使ってAWS IPIインストールを実施
- Podに対してSTSで一時的な認証情報を付与してS3バケット一覧を取得する
ちなみにSTSを使ったROSAのインストール方法については、以前に弊社の石川がまとめています。STSのメリットなどもわかりやすくまとまっていますので、ぜひ参照ください。
前提条件
- ocコマンド
- AdministratorAcccess権限を持つIAMユーザー
- OpenShiftサブスクリプション
STS を使ったAWS IPIインストール
まずはhttps://console.redhat.com/openshift/install/aws/installer-provisionedからpull-secretをダウンロードします。
次に今回デプロイするOpenShiftのリリースイメージから、AWS CredentialsRequestオブジェクトを抽出します。そのためにhttps://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable-4.9/release.txtにアクセスし、Pull From 行からイメージのIDを取得しRELEASE_IMAGEに格納します
$ export RELEASE_IMAGE="quay.io/openshift-release-dev/ocp-release@sha256:1c13f0926c37c122eb5c86afd754c007f38977c8fc32d7da090490f556945afd"
以下コマンドでAWS CredentialsRequestオブジェクトを抽出します。
0000から始まる5つのファイルが普通にIPIインストールした際にデプロイされるCredentialsRequestリソースのyamlになります。
$ mkdir credreqs ; oc adm release extract --cloud=aws --credentials-requests $RELEASE_IMAGE --to=./credreqs $ ls credreqs/ 0000_30_machine-api-operator_00_credentials-request.yaml 0000_50_cloud-credential-operator_05-iam-ro-credentialsrequest.yaml 0000_50_cluster-image-registry-operator_01-registry-credentials-request.yaml 0000_50_cluster-ingress-operator_00-ingress-credentials-request.yaml 0000_50_cluster-storage-operator_03_credentials_request_aws.yaml
次にリリースイメージからOpenShiftインストールバイナリーを抽出します。
$ oc adm release extract --command=openshift-install $RELEASE_IMAGE
install-config.yamlを作成します。
Pull Secretには先ほどダウンロードしたpull-secretの中身をペーストしてください。
$ ./openshift-install create install-config ? Platform aws INFO Credentials loaded from the "default" profile in file "/home/username/.aws/credentials" ? Region ap-northeast-1 ? Base Domain xxxx.com ? Cluster Name sts-test-cluster-1 ? Pull Secret [? for help] ************************* INFO Install-Config created in: .
作成されたinstall-config.yamlに、credentialsModeをManualでデプロイするための設定を挿入します。
$ echo "credentialsMode: Manual" >> install-config.yaml
インストールマニフェストを作成します。
$ ./openshift-install create manifests INFO Credentials loaded from the "default" profile in file "/home/username/.aws/credentials" INFO Consuming Install Config from target directory INFO Manifests created in: manifests and openshift
次にOpenShift Container Platform リリースイメージ内の CCO コンテナーイメージから ccoctl バイナリーを展開します。
ここでは冒頭でダウンロードしたpull-secretを~/.pull-secretとして保存していることを前提としています。
$ CCO_IMAGE=$(oc adm release info --image-for='cloud-credential-operator' $RELEASE_IMAGE) $ oc image extract $CCO_IMAGE --file="/usr/bin/ccoctl" -a ~/.pull-secret $ chmod 775 ccoctl
ccoctlを使ってAWSリソースを作成します。
以下のコマンドでは次の操作を一気に実行します。
- ServiceAccount署名キー(Private/Public)を生成
- S3バケットを作成し、OIDC設定をバケットにアップロード
- S3バケット設定を信頼するIAM Identity Providerを設定
- 先述で抽出したcredreqsディレクトリ内のAWSCredentialsRequestごとにIAMロールを作成
- インストーラーが必要とするファイルをoutputディレクトリにdump
$ ccoctl aws create-all \ --name sts-test-1 \ --region ap-northeast-1 \ --credentials-requests-dir ./credreqs \ --output-dir ./outputs
実行結果
2022/02/25 08:38:07 Generating RSA keypair 2022/02/25 08:38:16 Writing private key to outputs/serviceaccount-signer.private 2022/02/25 08:38:16 Writing public key to outputs/serviceaccount-signer.public 2022/02/25 08:38:16 Copying signing key for use by installer 2022/02/25 08:38:18 Bucket sts-test-1-oidc created 2022/02/25 08:38:19 OpenID Connect discovery document in the S3 bucket sts-test-1-oidc at .well-known/openid-configuration updated 2022/02/25 08:38:19 Reading public key 2022/02/25 08:38:19 JSON web key set (JWKS) in the S3 bucket sts-test-1-oidc at keys.json updated 2022/02/25 08:38:21 Identity Provider created with ARN: arn:aws:iam::XXXXXXXXXXXX:oidc-provider/sts-test-1-oidc.s3.ap-northeast-1.amazonaws.com 2022/02/25 08:38:21 Role arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-machine-api-aws-cloud-credentials created 2022/02/25 08:38:21 Saved credentials configuration to: outputs/manifests/openshift-machine-api-aws-cloud-credentials-credentials.yaml 2022/02/25 08:38:22 Updated Role policy for Role sts-test-1-openshift-machine-api-aws-cloud-credentials 2022/02/25 08:38:22 Role arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-cloud-credential-operator-cloud-credential- created 2022/02/25 08:38:22 Saved credentials configuration to: outputs/manifests/openshift-cloud-credential-operator-cloud-credential-operator-iam-ro-creds-credentials.yaml 2022/02/25 08:38:22 Updated Role policy for Role sts-test-1-openshift-cloud-credential-operator-cloud-credential- 2022/02/25 08:38:23 Role arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-image-registry-installer-cloud-credentials created 2022/02/25 08:38:23 Saved credentials configuration to: outputs/manifests/openshift-image-registry-installer-cloud-credentials-credentials.yaml 2022/02/25 08:38:23 Updated Role policy for Role sts-test-1-openshift-image-registry-installer-cloud-credentials 2022/02/25 08:38:24 Role arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-ingress-operator-cloud-credentials created 2022/02/25 08:38:24 Saved credentials configuration to: outputs/manifests/openshift-ingress-operator-cloud-credentials-credentials.yaml 2022/02/25 08:38:24 Updated Role policy for Role sts-test-1-openshift-ingress-operator-cloud-credentials 2022/02/25 08:38:24 Role arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-cluster-csi-drivers-ebs-cloud-credentials created 2022/02/25 08:38:24 Saved credentials configuration to: outputs/manifests/openshift-cluster-csi-drivers-ebs-cloud-credentials-credentials.yaml 2022/02/25 08:38:24 Updated Role policy for Role sts-test-1-openshift-cluster-csi-drivers-ebs-cloud-credentials
AWSのIAMを見ると、たしかにIAMユーザーでなくIAMロールが作成されていることがわかります。
IAM Identity Providerも構築されていることが確認できます。
outputsにdumpされたmanifestディレクトリ内のファイルを./manifest配下にコピーします。
$ cp outputs/manifests/* manifests/
同じくtlsディレクトリも直下のディレクトリにコピーします。
$ cp -a outputs/tls .
先ほどマニフェストを作成した際にinstall-config.yamlが消えてしまっている場合は、再度以下のコマンドを実行します。
入力値は.openshift_install_state.jsonに保存されているため、特に対話なしにファイルが作成されます。
$ ./openshift-install create install-config
以上の作業を行なった後、クラスターのデプロイを実施します。
$ ./openshift-install create cluster
インストール後デプロイされたAWSの認証情報のSecretを確認すると、たしかにIAMロールの情報が格納されていることがわかります。
(通常のインストールでは、この情報がIAMユーザーのものになります)
$ oc get secrets -n openshift-image-registry installer-cloud-credentials -o json | jq -r .data.credentials | base64 -d [default] role_arn = arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-openshift-image-registry-installer-cloud-credentials web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
STSによる一時的な認証情報を付与してPodをデプロイ
さて、STSを使ってOpenShiftがデプロイできましたので、次はその上でデプロイするPodに対してSTSを使った一時的なCredentials付与を実施します。
実施する手順は大きく以下の4つです。
- CredentialsRequestリソースのyamlファイルを作成
- ccoctlで上記yamlファイルをもとにIAMロールの作成とデプロイ用マニフェスト(kind: secret)を作成
- 作成されたSecretマニフェストをデプロイ
- Secretとサービスアカウントのトークンを要求する設定を行なったPodをデプロイ
まずCredentialsRequestを作成します。以下はS3の一覧を取得するための権限を持つIAMを作成するためのものです。
Secretのデプロイ先を「default」に、またPodに付与するService Accountを「default」にすることを前提として記述しています。
$ mkdir -p sts-test-resource/cred-reqs $ cd sts-test-resource $ vi 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: default providerSpec: apiVersion: cloudcredential.openshift.io/v1 kind: AWSProviderSpec statementEntries: - effect: Allow action: - s3:ListAllMyBuckets resource: "*" serviceAccountNames: - default
次にccoctlでIAMロールの作成とsecretマニフェストの作成を行います。
※identity-provider-arnにはAWSコンソールのIAM→IDプロバイダから確認してください。
$ ccoctl aws create-iam-roles \ --identity-provider-arn arn:aws:iam::XXXXXXXXXXXX:oidc-provider/sts-test-1-oidc.s3.ap-northeast-1.amazonaws.com \ --output-dir ./outputs \ --name sts-test-1 \ --region ap-northeast-1 \ --credentials-requests-dir ./cred-reqs/
上記コマンドで作成されたoutputsディレクトリ配下のマニフェストをデプロイします
$ oc create -f ./outputs/manifest/default-s3-access-secret-credentials.yaml
最後にデプロイする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を設定(詳細はこちらを参照)
$ vi pod.yaml
apiVersion: v1 kind: Pod metadata: 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-25 08:38:19 sts-test-1-oidc 2022-02-25 09:13:08 sts-test-cluster-1-5rtrx-image-registry-ap-northeast-1-abcdefg
無事にS3バケットの情報が取得できました。
ちなみにマウントされたawsのCredentialsファイルを見てみましょう
sh-4.2# cat /var/run/secrets/aws/credentials [default] role_arn = arn:aws:iam::XXXXXXXXXXXX:role/sts-test-1-default-s3-access-secret web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
たしかにIAMロールで認証設定されていますね。
ということで、IAMユーザーではなくSTSでの一時的な認証付与を行なったPodの作成方法についてご紹介しました。
CCOの機能を最大限活用するにはIAMユーザーでの運用が望ましいですが、セキュリティ的な側面からIAMユーザー認証が使えない際は、この手法を検討してみてはいかがでしょうか?