AWS CloudFormation의 AWS::EKS::Cluster에서 OIDC 공급자 URL을 가져오려면 어떻게 해야 합니까?

최종 업데이트 날짜: 2020년 8월 20일

AWS::EKS::Cluster에서 OpenID Connect(OIDC) 공급자 URL을 가져오려고 합니다. 그런 다음, 이 URL을 AWS Identity and Access Management(IAM) 역할에서 AWS CloudFormation을 사용하는 서비스 계정 신뢰 관계에 대해 사용하려고 합니다.

간략한 설명

AWS::EKS::Cluster는 OIDC 공급자 URL을 가져오기 위한 반환 값을 제공하지 않습니다. 기존 Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터에서 클러스터 OIDC 공급자 URL을 가져오려면 AWS CloudFormation 내에서 AWS Lambda 지원 사용자 지정 리소스를 사용해야 합니다. 그런 다음, 해당 클러스터에서 반환한 값을 사용하여 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 Command Line Interface(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 리전으로 바꿉니다.


이 문서가 도움이 되었습니까?


결제 또는 기술 지원이 필요합니까?