Comment obtenir une URL de fournisseur OIDC à partir d'AWS::EKS::Cluster dans AWS CloudFormation ?

Dernière mise à jour : 20/08/2020

Je souhaite récupérer l'URL de fournisseur OpenID Connect (OIDC) à partir d'AWS::EKS::Cluster. Je souhaite ensuite utiliser l'URL dans un rôle AWS Identity and Access Management (IAM) pour une relation d'approbation de compte de service à l'aide d'AWS CloudFormation.

Brève description

AWS::EKS::Cluster ne fournit pas de valeur de retour afin d'obtenir l'URL de fournisseur OIDC. Vous devez utiliser des ressources personnalisées basées sur AWS Lambda dans AWS CloudFormation pour obtenir l'URL de fournisseur OIDC du cluster à partir d'un cluster Amazon Elastic Kubernetes Service (Amazon EKS) existant. Vous pouvez ensuite utiliser la valeur renvoyée par le cluster pour créer un rôle IAM. Le rôle IAM vous permet d'établir une relation d'approbation avec OIDC.

Remarque : la résolution suivante utilise Python 3.7 et s'applique à la version 1.14 de Kubernetes, ainsi qu'aux versions ultérieures.

Résolution

L'exemple suivant montre comment associer un compte de service dans un cluster Amazon EKS à un rôle IAM. Le rôle IAM fournit des autorisations précises aux pods Amazon EKS et un accès sécurisé à l'API AWS pour les comptes de service du cluster Amazon EKS. La pile crée ensuite un rôle IAM associé à la valeur OIDC du cluster Amazon EKS.

1.    Créez un modèle AWS CloudFormation intitulé CustomLambdaEksOidc.template, fondé sur l'exemple suivant :

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.    Pour lancer une pile AWS CloudFormation avec le fichier CustomLambdaEksOidc.template, utilisez la console AWS CloudFormation ou l'interface de ligne de commande AWS (CLI AWS).

Pour utiliser l'interface de ligne de commande AWS, exécutez la commande suivante :

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

Remarque : lorsque vous lancez votre pile AWS CloudFormation, remplacez demo-newsblog par le nom de votre cluster Amazon EKS. Remplacez us-east-1 par votre région AWS.


Cet article vous a-t-il été utile ?


Besoin d'aide pour une question technique ou de facturation ?