AWS CloudFormation の AWS::EKS::Cluster から OIDC プロバイダーの URL を取得するにはどうすればよいですか?

最終更新日: 2020 年 8 月 20 日

AWS::EKS::Cluster から OpenID Connect (OIDC) プロバイダーの URL を取得したいと考えています。その後、AWS CloudFormation を使用して、サービスアカウントの信頼関係のために AWS Identity and Access Management (IAM) ロールの URL を使用したいと考えています。

簡単な説明

AWS::EKS::Cluster では、OIDC プロバイダーの URL を取得するための戻り値が提供されません。既存の Amazon Elastic Kubernetes Service (Amazon EKS) クラスターからクラスター OIDC プロバイダーの URL を取得するには、AWS CloudFormation で AWS Lambda-backed カスタムリソースを使用する必要があります。その後、クラスターからの戻り値を使用して IAM ロールを作成できます。IAM ロールを使用すると、OIDC との信頼関係を確立できます。

注意: 以下の解決方法は Python 3.7 を使用しており、Kubernetes バージョン 1.14 以降に適用できます。

解決方法

次の例では、Amazon EKS クラスターのサービスアカウントを IAM ロールに関連付ける方法を示します。IAM ロールは、Amazon EKS ポッドに対するきめ細かなアクセス許可と、Amazon EKS クラスターのサービスアカウントに対する AWS API への安全なアクセスを提供します。その後、スタックによって Amazon EKS クラスターの OIDC 値に関連付けられた IAM ロールが作成されます。

1.    次の例に基づいて、CustomLambdaEksOidc.template という AWS CloudFormation テンプレートを作成します。

Parameters:
  EKSClusterName:
    Type: String
    Description: Provide the name for EKS Cluster
Resources:
  ClusterName:
      Type: Custom::ClusterName
      Properties:
        ServiceToken: !GetAtt LambdaFunction.Arn
        cluster_name:
          Ref: EKSClusterName
  MyIAMRole:
      Type: AWS::IAM::Role
      DependsOn: ClusterName
      Properties:
        AssumeRolePolicyDocument: !Sub |
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Principal": {
                  "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${ClusterName.oidc}"
                },
                "Action": "sts:AssumeRoleWithWebIdentity",
                "Condition": {
                  "StringEquals": {
                    "${ClusterName.oidc}:aud": "system:serviceaccount:default:my-serviceaccount"
                  }
                }
              }
            ]
          }
  LambdaIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'eks:DescribeCluster'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |
          import cfnresponse
          import boto3
          import json
          def lambda_handler(event, context):
              print("Received event: " + json.dumps(event, indent=2))
              oidc_response = ''
              responseData = {}
              try:
                  if event['RequestType'] == 'Delete':
                      print("Request Type:",event['RequestType'])
                      print("Delete Request - No Physical resources to delete")
                  elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
                      print("Request Type:",event['RequestType'])
                      cluster_name = event['ResourceProperties']['cluster_name']
                      oidc_response_url = fetchClusterOIDC(cluster_name)
                      oidc_response=oidc_response_url.split("https://")[1]
                      responseData['oidc'] = oidc_response
                  print("Sending response to custom resource for event type " + event['RequestType'])
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
                  return oidc_response
              except Exception as e:
                  print('Failed to process:', e)
                  responseStatus = 'FAILURE'
                  responseData = {'Failure': 'Something bad happened.'}
                  cfnresponse.send(event, context, cfnresponse.FAILED, responseData, "CustomResourcePhysicalID")
          def fetchClusterOIDC(cluster_name):
              print("Getting Cluster OIDC value for cluster name "+ cluster_name)
              oidc = ''
              client = boto3.client('eks')
              try:
                  response = client.describe_cluster(
                      name=cluster_name
                  )
                  if response['ResponseMetadata']['HTTPStatusCode'] == 200:
                      print("Success response recieved for describing cluster "+ cluster_name)
                      oidc = (response['cluster']['identity']['oidc']['issuer'])
                      print('OIDC output recieved '+ oidc + ' for Cluster Name ' + cluster_name)
                  return oidc
              except Exception as e:
                  print('Failed to fetch Cluster OIDC value for cluster name ' + cluster_name, e)
      Handler: index.lambda_handler
      MemorySize: 1024
      Role: !GetAtt LambdaIAMRole.Arn
      Runtime: python3.7
      Timeout: 300
Outputs:
  OIDC:
    Description: EKS Cluster OIDC Value
    Value:
      Fn::GetAtt:
      - ClusterName
      - oidc

2.    CustomLambdaEksOidc.template ファイルを使用して AWS CloudFormation スタックを起動するには、AWS CloudFormation コンソールまたは AWS コマンドラインインターフェイス (AWS CLI) を使用します。

AWS CLI を使用するには、次のコマンドを実行します。

aws cloudformation create-stack --stack-name lambda-eks-oidc --template-body file://CustomLambdaEksOidc.template --parameters ParameterKey=EKSClusterName,ParameterValue=demo-newsblog --capabilities CAPABILITY_NAMED_IAM --region us-east-1

注意: AWS CloudFormation スタックを起動するときは、demo-newsblog を Amazon EKS クラスター名に置き換えます。us-east-1 を AWS リージョンに置き換えます。


この記事はお役に立ちましたか?


請求に関するサポートまたは技術的なサポートが必要ですか?