如何从 AWS CloudFormation 中的 AWS::EKS::Cluster 获取 OIDC 提供商 URL?

上次更新时间:2020 年 8 月 20 日

我想要从 AWS::EKS::Cluster 获取 OpenID Connect (OIDC) 提供商 URL。然后,我想要将 AWS Identity and Access Management (IAM) 角色中的 URL 用于使用 AWS CloudFormation 的服务账户信任关系。

简短描述

AWS::EKS::Cluster 未提供返回值来获取 OIDC 提供商 URL。您必须在 AWS CloudFormation 中使用 AWS Lambda 支持的自定义资源,这样才能从现有 Amazon Elastic Kubernetes Service (Amazon EKS) 集群中获取集群 OIDC 提供商 URL。然后,您可以使用从群集返回的值来创建 IAM 角色。IAM 角色可让您与 OIDC 建立信任关系。

注意:以下解决方法使用 Python 3.7,并且适用于 Kubernetes 版本 1.14 及更高版本。

解决方法

以下示例演示如何将 Amazon EKS 集群中的服务账户与 IAM 角色相关联。IAM 角色提供对 Amazon EKS pod 的精细权限,并为 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 堆栈时,请使用您的 Amazon EKS 群集名称替换 demo-newsblog。使用您的 AWS 区域替换 us-east-1


这篇文章对您有帮助吗?


您是否需要账单或技术支持?