如何根据 IAM 角色 CloudFormation 模板中的参数提供不同的条件

Posted

技术标签:

【中文标题】如何根据 IAM 角色 CloudFormation 模板中的参数提供不同的条件【英文标题】:How do I supply different conditions based on a parameter in an IAM Role CloudFormation Template 【发布时间】:2020-01-03 06:41:50 【问题描述】:

我正在为我将通过 STS 代入的 IAM 角色编写 CloudFormation 模板。我需要添加一个键等于一个值的条件,其中键和值都取决于“阶段”参数。我已经能够根据参数以编程方式更改值,但是我所有基于 Stage 更改键的尝试都失败了。

我已经尝试使用地图和 !FindInMap 来获取正确的键,并尝试使用 !If 来构造两种情况的条件。

第一种情况……

Mappings:
  Constants:
    beta:
      Id: "beta.example.com"
      Endpoint: "beta-link.example.com/api/oauth2/v2:aud"
    prod:
      Id: "example.com"
      Endpoint: "link.example.com/api/oauth2/v2:aud"

AssumeRolePolicyDocument:
  Statement:
    Action:
      - "sts:AssumeRoleWithWebIdentity"
    Condition:
      StringEquals:
        !FindInMap [Constants, !Ref Stage, Endpoint]:
          - !FindInMap [Constants, !Ref Stage, Id]

...我收到一个错误:map keys must be strings; received a map instead

第二种情况……

AssumeRolePolicyDocument:
  Statement:
    Action:
      - "sts:AssumeRoleWithWebIdentity"
    Condition:
      !If
        - !Equals [!Ref Stage, prod]
        - StringEquals:
          "link.example.com/api/oauth2/v2:aud": "example.com"
        - StringEquals:
          "beta-link.example.com/api/oauth2/v2:aud": "beta.example.com"

...我遇到另一个错误:Template format error: Conditions can only be boolean operations on parameters and other conditions

简而言之,如何指定键和值都依赖于参数的条件?

【问题讨论】:

【参考方案1】:

我连续挣扎了大约 8 个小时,终于找到了这个问题的答案。 只是为了观众我想总结一下这个问题:

问题陈述:作为一名基础架构工程师,我想为 AWS::IAM::Role 编写一个 cloudformation 资源,它定义了一个带有 Condition 子句的 AssumeRolePolicyDocument,其中需要对密钥进行参数化。还有一个问题是我们可以使用带有条件键的内在函数吗?

回答:是的,可以使用开箱即用的样式。 AssumeRolePolicyDocument 是一个字符串类型,符合 AWS Cloudformation documentation 的“AWS::IAM::Role”。因此,不要使用 YAML 样式数据到 AssumeRolePolicyDocument 属性,只需使用 Fn::Sub 传递原始 JSON 格式的 Assumerole 策略并使用变量替换密钥,没有任何问题或警告。以下是您可以使用的示例。这是一个我试图解决的复杂用例,但它展示了如何使用 !SUB、!Select 等替换 IAM Condition 子句下的键。

  ExampleAppRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !Sub $Environment-ExampleAppRole
      AssumeRolePolicyDocument: 
                            Fn::Sub: 
                              - |
                                
                                  "Version": "2012-10-17",
                                  "Statement": [
                                    
                                      "Effect": "Allow",
                                      "Principal": 
                                        "Federated": "arn:aws:iam::$AWS::AccountId:oidc-provider/oidc.eks.$AWS::Region.amazonaws.com/id/$id"
                                      ,
                                      "Action": "sts:AssumeRoleWithWebIdentity",
                                      "Condition": 
                                        "StringEquals": 
                                          "$clusterid": "$serviceaccount"
                                        
                                      
                                    
                                  ]
                                
                              - 
                                clusterid: !Join ["",[!Sub "oidc.eks.$AWS::Region.amazonaws.com/id/",!Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]],":sub"]]
                                id: !Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]]
                                Region: !Sub $AWS::Region
                                serviceaccount: system:serviceaccount:default:awsiamroleexample
      Path: /
      ManagedPolicyArns:
        - !Ref SnsPublishAccessPolicy

在 cmets 部分告诉我你的想法。

【讨论】:

我无法让这个策略发挥作用。我有完全相同的用例,模板化 EKS OIDC 提供程序。似乎使用 Lambdas 和 CustomResource 是更规范的方法。我感谢你的努力。我同样花了 8 多个小时试图解决这个问题。 谢谢!你为我节省了 8 个小时的奋斗时间。 谢谢!这帮助很大。如果您使用 python cft_flip 将上述内容翻转为 json,则可以在 json 中执行相同操作 - github.com/awslabs/aws-cfn-template-flip 这个答案为我节省了几个小时!荣誉【参考方案2】:

我认为不允许在 IAM 策略条件元素中使用内部函数,我还没有看到任何示例。条件元素只需要一组预定义的键。我认为您可以尝试以下模板,它有点冗长,但应该可以。模板由cloudkast提供支持

    
   "AWSTemplateFormatVersion":"2010-09-09",
   "Description":"Template created by CloudKast",
   "Parameters":  

   ,
   "Mappings":  

   ,
   "Conditions":  
      "Prod":  
         "Fn::Equals":[  
              
               "Ref":"Stage"
            ,
            "prod"
         ]
      ,
      "Dev":  
         "Fn::Equals":[  
              
               "Ref":"Stage"
            ,
            "dev"
         ]
      
   ,
   "Resources":  
      "ProdRole":  
         "Properties":  
            "AssumeRolePolicyDocument":  
               "Version":"2012-10-17",
               "Statement":[  
                    
                     "Sid":"Stmt1567153169873",
                     "Action":[  
                        "sts:AssumeRoleWithWebIdentity"
                     ],
                     "Effect":"Allow",
                     "Resource":"arn:aws:iam::namespace::relativeid"
                  
               ]
            ,
            "RoleName":"ProdRole"
         ,
         "Type":"AWS::IAM::Role",
         "Condition":"Prod"
      ,
      "DevRole":  
         "Properties":  
            "AssumeRolePolicyDocument":  
               "Version":"2012-10-17",
               "Statement":[  
                    
                     "Sid":"Stmt1567153169873",
                     "Action":[  
                        "sts:AssumeRoleWithWebIdentity"
                     ],
                     "Effect":"Allow",
                     "Resource":"arn:aws:iam::namespace::relativeid"
                  
               ]
            ,
            "RoleName":"DevRole"
         ,
         "Type":"AWS::IAM::Role"
      
   ,
   "Outputs":  

   

【讨论】:

以上是关于如何根据 IAM 角色 CloudFormation 模板中的参数提供不同的条件的主要内容,如果未能解决你的问题,请参考以下文章

如何创建 IAM 策略以根据子网名称标签控制对 Amazon EC2 资源的访问?

如何使用 Terraform 创建没有代入角色策略的 AWS IAM 角色?

如何将 IAM 角色分配给用户或组

如何使用 python boto3 将新角色权限附加到 aws 中的 iam_role?

如何在 EMR 上使用 MrJob 0.4.2 设置 IAM 角色

是否可以从另一个账户使用 IAM 角色访问 Redshift?如何?