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

时间:2019-08-30 01:34:39

标签: yaml amazon-cloudformation amazon-iam openid-connect

我正在为IAM角色编写CloudFormation模板,该模板将通过STS承担。我需要添加一个条件,其中键等于一个值,键和值都取决于“ Stage”参数。我已经能够根据参数通过编程方式更改该值,但是我所有基于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

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

2 个答案:

答案 0 :(得分:0)

我不认为允许在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":{  

   }
}

答案 1 :(得分:0)

我连续奋斗了大约8个小时,终于找到了解决这个问题的办法。 仅针对观众,我想总结一下问题:

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

答案:是的,可以使用开箱即用的样式。 AssumeRolePolicyDocument 是适用于'AWS :: IAM :: Role'的AWS Cloudformation documentation的字符串类型。因此,与其使用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

在评论部分让我知道您的想法。