Amazon Web Services ブログ

STS を用いた Red Hat OpenShift Service on AWS (ROSA) ワークロードのためのきめ細かい IAM ロール

この記事は Fine-grained IAM roles for Red Hat OpenShift Service on AWS (ROSA) workloads with STS (記事公開日: 2022 年 5 月 17 日) を翻訳したものです。

Red Hat OpenShift Services on AWS (ROSA) は、Red Hatと Amazon Web Services (AWS) に共同でサポートされ、Red Hat SRE チームにより管理されるフルマネージドな OpenShift サービスです。お客さまをクラスターライフサイクル管理から解放し、OpenShift クラスターの維持ではなく、アプリケーションの構築に集中できるようにします。

ROSA は AWS Security Token Service (AWS STS) と統合されました。AWS STS は、AWS Identity and Access Management (IAM) フェデレーションによって認証された AWS ユーザーが AWS リソースへの一時的なセキュリティ認証情報を要求できるようにする AWS サービスです。一時的なセキュリティ認証情報はそのライフサイクルが短い点を除いて IAM ユーザーに割り当てられる通常の長期的なアクセスキーの認証情報と同じように機能します。また、一時的なセキュリティ認証情報はユーザーごとに保持されておらず、代わりに必要に応じて動的に生成されてユーザーに提供されます。一時的なセキュリティ認証情報が失効した場合は、ユーザーは単に新しいものを要求します。

IAM は OpenID Connect (OIDC) ID プロバイダーを用いたフェデレーティッドアイデンティティをサポートしています。この機能によりお客様はサポートされた ID プロバイダーから受け取る妥当な OIDC JSON web token (JWT)を用いて AWS API 呼び出しを認証させることができます。Pod はこのトークンを要求して AWS STS AssumeRoleWithWebIdentity API を用いることで一時的な IAM ロールのセキュリティ認証情報を受け取ることができます。

現在、rosa create cluster --sts オプションを用いることで、AWS STS サービスを利用した ROSA クラスターを作成できます。詳細は後ほど記載しますが、クラスター作成の間に、operator IAM ロールと OpenID Connect (OIDC) ID プロバイダーが作成されます。operator IAM ロールとエンドポイントが ROSA クラスター内の OpenShift リソースに対応づけられ、OIDC が認証に用いられます。

この記事では、クラスター作成時に作られる OIDC ID プロバイダーを使う方法とサービスアカウントの IAM ロール (IRSA) と共に使う方法を解説します。IRSA により Kubernetes サービスアカウントに IAM ロールを関連づけることができ、サービスアカウントは認証やきめ細かいアクセス権限のために pod により利用されます。

IRSA を用いる利点は最小特権の推奨と認証情報の分離であり、すなわち pod 内のコンテナは pod が属するサービスアカウントに関連づけられた IAM ロールのセキュリティ認証情報だけを取得できることです。また、AWS CloudTrail を介してアクセスとイベントのロギングを利用することで、より良い監査を実現できます。

チュートリアル

以下の段落では、STS が有効化された ROSA が Kubernetes pod に Amazon Simple Storage Services (Amazon S3) バケットへのアクセスを提供するためにサービスアカウントの IAM ロールを用いる方法を解説します。このガイドは STS を有効化した ROSA クラスターの作成については解説しません。STS を用いた ROSA クラスターの作成方法の詳細はドキュメントを参照してください。

前提条件

  • AWS アカウント
  • AWS CLIrosa CLI 及び oc CLI
  • AWS アカウントで有効化された ROSA
  • STS が有効化された ROSA クラスター

ステップ 1. 変数を設定する

ROSA STS クラスターのデプロイメント時に作成された既存の OIDC エンドポイントを再利用します。そのために、後ほど用いる項目をひとそろいの変数として作成しておき、oc CLI を用いた OpenShift クラスターへの接続に進みます。

$ export ROSA_CLUSTER_NAME=<cluster-name>
$ export SERVICE="s3"
$ export AWS_REGION=<aws-region-id>
$ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
$ export APP_NAMESPACE=iam-app
$ export APP_SERVICE_ACCOUNT_NAME=iam-app-$SERVICE-sa

ステップ 2. クラスターの OIDC エンドポイント URL を取得する

oc CLIを用いて ROSA クラスターに接続し、既存の OIDC エンドポイントの詳細を取得します。このドキュメントoc CLI を使ってクラスターに接続する方法が詳しく書かれています。接続できたら、エンドポイントの詳細を取得します。

$ export OIDC_PROVIDER=$(oc get authentication.config.openshift.io cluster -ojson | jq -r .spec.serviceAccountIssuer | sed 's/https:\/\///')

ステップ 3. アプリケーションの名前空間とサービスアカウントを作成する

$ oc new-project $APP_NAMESPACE
$ oc create serviceaccount $APP_SERVICE_ACCOUNT_NAME -n $APP_NAMESPACE

ステップ 4. アプリケーション用のサービスアカウントの IAM ロールを作成する

$ cat <<EOF > ./trust.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:${APP_NAMESPACE}:${APP_SERVICE_ACCOUNT_NAME}"
        }
      }
    }
  ]
}
EOF
$ export APP_IAM_ROLE="iam-app-${SERVICE}-role"
$ export APP_IAM_ROLE_ROLE_DESCRIPTION='IRSA role for APP $SERVICE deployment on ROSA cluster'
$ aws iam create-role --role-name "${APP_IAM_ROLE}" --assume-role-policy-document file://trust.json --description "${APP_IAM_ROLE_ROLE_DESCRIPTION}"
$ APP_IAM_ROLE_ARN=$(aws iam get-role --role-name=$APP_IAM_ROLE --query Role.Arn --output text)

ステップ 5. IAM ポリシーを IAM ロールにアタッチ

必要な Amazon S3 ポリシーを新規に作成された IRSA ロール にアタッチして適用します。

補足:要望に応じたユーザーのカスタムもしくは特定のポリシーを選んでアタッチしてください。

$ POLICY_ARN=$(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3FullAccess`].Arn' --output text)
$ aws iam attach-role-policy --role-name "${APP_IAM_ROLE}" --policy-arn "${POLICY_ARN}" > /dev/null

ステップ 6. 作成された IAM ロールをサービスアカウントに関連づける

この時点では、作成された IAM ロールの Amazon リソースネーム(ARN) は、まだサービスアカウントのアノテーションに設定されていません。次のコマンドを使って IAM ロールをサービスアカウントに関連づけてください。

$ export IRSA_ROLE_ARN=eks.amazonaws.com/role-arn=$APP_IAM_ROLE_ARN
$ oc annotate serviceaccount -n $APP_NAMESPACE $APP_SERVICE_ACCOUNT_NAME $IRSA_ROLE_ARN

サービスアカウントについて表示します。

$ oc describe serviceaccount $APP_SERVICE_ACCOUNT_NAME -n $APP_NAMESPACE
 Name:                iam-app-s3-sa
 Namespace:           iam-app
 Labels:              <none>
 Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<APP_IAM_ROLE>
 Image pull secrets:  iam-app-s3-sa-dockercfg-wk7tz
 Mountable secrets:   iam-app-s3-sa-token-pqpkd
                      iam-app-s3-sa-dockercfg-wk7tz
 Tokens:              iam-app-s3-sa-token-pqpkd
                      iam-app-s3-sa-token-vngcg
 Events:              <none>

ステップ 7. アプリケーションのデプロイメント

次に、ROSA クラスターにサンプルアプリケーションをデプロイします。単純にするため、awscli という名前の単一のコンテナを含む Deployment をデプロイします。このコンテナは AWS CLI バイナリがプリインストールされており、きめ細かい IAM ロールを用いた ROSA からクラウドサービスへのアクセスを実行できます。

$ cat <<EOF | oc create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: ${APP_NAMESPACE}
  name: awscli
  labels:
    app: awscli
spec:
  replicas: 1
  selector:
    matchLabels:
      app: awscli
  template:
    metadata:
      labels:
        app: awscli
    spec:
      containers:
        - image: amazon/aws-cli:latest
          name: awscli
          command:
            - /bin/sh
            - "-c"
            - while true; do sleep 10; done
          env:
            - name: HOME
              value: /tmp
      serviceAccount: ${APP_SERVICE_ACCOUNT_NAME}
EOF

AWS クライアントか SDK が AWS API に接続する時、~/.aws/config ファイルや AWS_ACCESS_KEY_ID 環境変数といった様々な異なる場所にあるセキュリティ認証情報を探します。Web アイデンティティを使っている時、AWS クライアントか SDK は AWS_WEB_IDENTITY_TOKEN_FILEAWS_ROLE_ARN の環境変数を探します。Python Boto3 SDK については次のドキュメントを参照してください。

OpenShift クラスターで動作している EKS Pod Identity Webhook は IAM ロールが定義されたサービスアカウントが pod にアタッチされていると、これらの変数を稼働している pod に設定します。ROSA クラスターで稼働しているデモンストレーションのワークロードにおいて、これらの変数が pod に挿入されていることを次のコマンドで見ることができます。

$ oc describe pod $(oc get pod -l app=awscli -o jsonpath='{.items[0].metadata.name}') | grep "^\s*AWS_"
 AWS_ROLE_ARN: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<APP_IAM_ROLE>
 AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token

pod の volume セクションの TokenExpirationSeconds の値にも注目してください。

Volumes:
  aws-iam-token:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  86400

ステップ 8. S3 バケットを作成する

ROSA クラスターの外側で、各自のワークステーションで AWS CLI を用いて S3 バケットを作成します。

$ export S3_BUCKET_NAME=$ROSA_CLUSTER_NAME-iam-app
$ aws s3api create-bucket --bucket $S3_BUCKET_NAME --region $AWS_REGION --create-bucket-configuration LocationConstraint=$AWS_REGION > /dev/null

ステップ 9. ソリューションを確認する

ソリューションを確認するため稼働している pod へのリモートシェルを開始させます。そして、AWS CLI を使って S3 バケットに書き込む手順に進みます。

$ oc rsh $(oc get pod -l app=awscli -o jsonpath='{.items[0].metadata.name}')

awscli を使ってバケットを一覧表示します。

sh-4.2$ aws s3 ls

ファイルを作成し、それを S3 バケットにアップロードします。そして、S3 バケットの内容を確認します。

sh-4.2$ echo "Hello from ROSA" > /tmp/rosa.txt
sh-4.2$ aws s3 cp /tmp/rosa.txt s3://<S3_BUCKET_NAME>/rosa.txt
upload: ../tmp/rosa.txt to s3://<S3_BUCKET_NAME>/rosa.txt
sh-4.2$ aws s3 ls s3://<S3_BUCKET_NAME> --recursive --human-readable --summarize
2022-01-17 13:50:58   39 Bytes rosa.txt

Total Objects: 1
   Total Size: 39 Bytes

まとめ

この記事では、pod にきめ細かいアクセス制御を提供してAWS APIにより安全にアクセスするために ROSA クラスターでサービスアカウントのIAM ロールを用いたロールベースのアクセス制御(RBAC)を使う方法を紹介しました。Red Hat OpenShift Service on AWS (ROSA) や他の AWSでの Red Hat ソリューションについて更に知りたい方は、AWS の Red Hat パートナーのページを参照ください。

翻訳はパートナーソリューションアーキテクトの市川が担当しました。原文はこちらです。