微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

作为另一个角色运行嵌套的 cloudformation 堆栈

如何解决作为另一个角色运行嵌套的 cloudformation 堆栈

我正在尝试构建一个将部署 EKS 集群、节点组和工作负载的 cloudformation 模板。

使用以下 lambda layer,我创建了一个可以与 EKS 集群交互的函数;但是,这仅在函数承担创建集群的用户的角色时才有效。

我发现的一个问题是,由于 AWS 管理信任策略,因此无法在 SSO 环境中承担 SSO 用户的角色。 如果我在创建集群之前担任另一个角色并让 lambda 担任该角色,则该函数会起作用。

遗憾的是,无法传入用于创建集群的特定角色,RoleArn 仅提供控制平面与其他 AWS 服务交互的权限。

我想知道是否可以创建一个嵌套的堆栈结构来做这样的事情?

  1. 在主栈中创建一个角色
  2. 然后调用嵌套模板承担新角色
  3. 在子堆栈中将创建 EKS 集群
  4. 在主堆栈中将创建和调用一个 lambda 函数

这在技术上可行吗?

作为参考,这是该函数当前正在执行的操作。

def update_kubeconfig(clusterName,role):
  runcmd("aws eks update-kubeconfig --name {} --kubeconfig /tmp/kubeconfig --role-arn {}".format(clusterName,role))
def getPods():
  runcmd("kubectl get pod --kubeconfig /tmp/kubeconfig")

update_kubeconfig('eks-cluster-1','arn:aws:iam::3088564456:role/cluster-admin')

解决方法

我能够通过在主堆栈中创建和调用一个 lambda 函数来解决这个问题,该函数在承担 eks 集群管理员的角色后创建了一个子堆栈。

为了避免在子堆栈中创建 IAM 角色,我在主堆栈中创建了所有这些角色,然后将 ARN 传递到子堆栈中。

如果其他人需要做类似的事情,我希望这可能对其有用

主栈

  EKSClusterRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - eks.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonEKSClusterPolicy'
DeployCloudformationStackLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AllowRolePassAndCF
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                  - 'iam:PassRole'
                  - 'iam:GetRole'
                  - 'cloudformation:CreateStack'
                  - 'cloudformation:CreateChangeSet'
                  - 'eks:DescribeCluster'
                Resource: '*'
EKSClusterAdminRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS: !GetAtt DeployCloudformationStackLambdaRole.Arn
            Action: sts:AssumeRole
      Policies:
        - PolicyName: RunKubeCtlCommands
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'eks:*'
                  - 'cloudformation:CreateStack'
                  - 'cloudformation:CreateChangeSet'
                  - 'serverlessrepo:CreateCloudFormationTemplate'
                  - 'serverlessrepo:GetCloudFormationTemplate'
                  - 's3:GetObject'
                  - 'lambda:PublishLayerVersion'
                  - 'lambda:CreateFunction'
                  - 'lambda:GetLayerVersion'
                  - 'lambda:GetFunction'
                  - 'lambda:InvokeFunction'
                  - 'lambda:GetFunctionConfiguration'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'iam:PassRole'
                  - 'iam:GetRole'
                Resource: 
                  - !GetAtt EKSClusterRole.Arn
                  - !GetAtt DeployCloudformationStackLambdaRole.Arn
  TriggerStack:
    Type: "Custom::TriggerStack"
    DependsOn: DeployCloudformationStack
    Properties:
      ServiceToken: !GetAtt DeployCloudformationStack.Arn
      cfStackName: "eksDeploy"
      assumeRoleARN: !GetAtt EKSClusterAdminRole.Arn
      templateUrl: !Sub 'https://test-${AWS::Region}-public-lambda.s3.amazonaws.com/DeployEKS.yml'
      stackParameters: 
        - ParameterKey: EksClusterName
          ParameterValue: "test-cluster"
        - ParameterKey: EksClusterRole
          ParameterValue: !GetAtt EKSClusterRole.Arn
        - ParameterKey: EksSubnets
          ParameterValue: "subnet-256faaf,subnet-6e205960"
        - ParameterKey: EksClusterAdminRole
          ParameterValue: !GetAtt EKSClusterAdminRole.Arn
        - ParameterKey: KubeLambdaRole
          ParameterValue: !GetAtt DeployCloudformationStackLambdaRole.Arn
  DeployCloudformationStack:
    Type: AWS::Lambda::Function
    Properties:
      Description: Deploy cloudformation stack
      Handler: index.lambda_handler
      Runtime: python3.8
      Role: !GetAtt DeployCloudformationStackLambdaRole.Arn
      MemorySize: 128
      Timeout: 30
      Code:
        ZipFile: |
          import cfnresponse
          import json,os,boto3,logging
          from botocore.exceptions import ClientError
          def lambda_handler(event,context):
            print("Received event: " + json.dumps(event,indent=2))
            payload = ""
            result = cfnresponse.SUCCESS
            logger = logging.getLogger()
            logger.setLevel(logging.INFO)
            try:
             if event['RequestType'] == 'Create':
               payload = deployStack(event['ResourceProperties'])
            except ClientError as e:
             logger.error('Error: %s',e)
             result = cfnresponse.FAILED   
            cfnresponse.send(event,context,result,payload)
          
          def deployStack(input):
              
              sts = boto3.client('sts').assume_role(RoleArn=input['assumeRoleARN'],RoleSessionName="lambda_assume_role")
              
              client = boto3.client('cloudformation',aws_access_key_id=sts['Credentials']['AccessKeyId'],aws_secret_access_key=sts['Credentials']['SecretAccessKey'],aws_session_token=sts['Credentials']['SessionToken']
              )
              response = client.create_stack(StackName=input['cfStackName'],TemplateURL=input['templateUrl'],Parameters=input['stackParameters'],TimeoutInMinutes=60,Capabilities=['CAPABILITY_IAM','CAPABILITY_NAMED_IAM','CAPABILITY_AUTO_EXPAND'])

子栈

AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Parameters:
  KubeLambdaRole:
    Default: arn:*
    Type: String
  EksClusterRole:
    Default: arn:*
    Type: String
  EksSubnets:
    Description: Subnet IDs
    Type: CommaDelimitedList
  EksClusterName:
    Default: pebble-oceans
    Type: String
  EksClusterAdminRole:
    Default: arn:*
    Type: String
Resources:
  KubeCtlLayer:
    Type: AWS::Serverless::Application
    Properties:
      Parameters: 
        LayerName: kubelayer
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:903779448426:applications/lambda-layer-kubectl
        SemanticVersion: 2.0.0
  EKS:
    Type: 'AWS::EKS::Cluster'
    Properties:
      Name: !Ref EksClusterName
      Version: '1.19'
      RoleArn: !Ref EksClusterRole
      ResourcesVpcConfig:
        SubnetIds: !Ref EksSubnets
  TriggerKubectl:
    Type: "Custom::TriggerKubectl"
    DependsOn: 
    -  KubeLambda
    -  EKS
    Properties:
      ServiceToken: !GetAtt KubeLambda.Arn
      clusterName: !Ref EksClusterName
      roleArn: !Ref EksClusterAdminRole
      region: !Ref "AWS::Region"
  KubeLambda:
    Type: AWS::Lambda::Function
    Properties:
      Description: Copies images into ECR
      Handler: index.lambda_handler
      Runtime: python2.7
      Layers: 
        - !GetAtt KubeCtlLayer.Outputs.LayerVersionArn
      Role: !Ref KubeLambdaRole
      MemorySize: 512
      Timeout: 300
      Code:
        ZipFile: |
          import cfnresponse
          import json,logging
          from botocore.exceptions import ClientError
          from subprocess import Popen,PIPE,STDOUT
          
          def lambda_handler(event,indent=2))
            payload = ""
            result = cfnresponse.SUCCESS
            logger = logging.getLogger()
            logger.setLevel(logging.INFO)
            try:
             if event['RequestType'] == 'Create':
               clusterName=event['ResourceProperties']['clusterName']
               roleArn=cluster=event['ResourceProperties']['roleArn']
               region=cluster=event['ResourceProperties']['region']
               update_kubeconfig(clusterName,region,roleArn)
               payload = getPods()
            except ClientError as e:
             logger.error('Error: %s',payload)
          
          def update_kubeconfig(clusterName,role):
            runCmd("aws eks update-kubeconfig --name {} --region {} --role-arn {} --kubeconfig /tmp/kubeconfig".format(clusterName,role))
          
          def getPods():
            runCmd("kubectl get pod --kubeconfig /tmp/kubeconfig")
          
          def runCmd(cmd):
            my_env = os.environ.copy()
            my_env["PATH"] = my_env["PATH"] + ":/opt/awscli:/opt/kubectl"
            p = Popen(cmd,shell=True,stdin=PIPE,stdout=PIPE,stderr=STDOUT,close_fds=True,env=my_env)
            output = p.stdout.read()
            print output

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。