如何用yq为CloudFormation中IAM角色添加唯一ManagedPolicyArns
解决CloudFormation IAM角色ManagedPolicyArns去重追加问题
我需要给多个CloudFormation.yaml文件里的多个IAM角色添加指定的ManagedPolicyArns,要求只给没有该策略的角色追加,绝对不能重复添加。使用yq v4.27.3版本,试了两个脚本要么重复添加策略,要么完全无法添加,求正确实现方式。
执行命令
yq --from-file add_policy.yq cloudformation.yaml
示例CloudFormation文件(cloudformation.yaml)
AWSTemplateFormatVersion: "2010-09-09" Parameters: MyPrefix: Description: MyPrefix Type: String Resources: MyRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn" AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com - lambda.amazonaws.com Action: - sts:AssumeRole - sts:TagSession Path: /
之前脚本的问题
1. 会重复添加的脚本
判断逻辑错误,未正确识别带!Sub标签的Fn::ImportValue结构,导致误判策略不存在:
( .Resources[] |= select( (.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "ecs-tasks.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "lambda.amazonaws.com") and (.Properties.ManagedPolicyArns | contains([{"Fn::ImportValue": "${MyPrefix}-my-policy-arn"}]) | not ) ) .Properties.ManagedPolicyArns += {"Fn::ImportValue": "${MyPrefix}-my-policy-arn" | . tag = "!Sub" } )
2. 完全无法添加的脚本
遍历和判断逻辑错误,直接用.Properties.ManagedPolicyArns[]."Fn::ImportValue"无法匹配带标签的节点,导致所有角色都被误判为已存在策略:
( .Resources[] |= select( (.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "ecs-tasks.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "lambda.amazonaws.com") and (.Properties.ManagedPolicyArns[]."Fn::ImportValue" | contains("${MyPrefix}-my-policy-arn" | . tag = "!Sub") | not) ) .Properties.ManagedPolicyArns += {"Fn::ImportValue": "${MyPrefix}-my-policy-arn" | . tag = "!Sub" } )
正确的add_policy.yq脚本
要正确识别带!Sub标签的策略节点,需结合标签匹配和值判断逻辑,脚本如下:
# 定义要添加的目标策略节点 $targetPolicy = {"Fn::ImportValue": "${MyPrefix}-my-policy-arn"} | . tag = "!Sub" .Resources[] |= # 筛选符合条件的IAM角色:类型为IAM角色且信任策略包含指定服务主体 select( .Type == "AWS::IAM::Role" and (.Properties.AssumeRolePolicyDocument.Statement[] | any( .Principal.Service[] == "ecs-tasks.amazonaws.com" or .Principal.Service[] == "lambda.amazonaws.com" )) ) | # 仅当ManagedPolicyArns中不存在目标策略时才追加 ( if (.Properties.ManagedPolicyArns | any( . tag == "!Sub" and ."Fn::ImportValue" == "${MyPrefix}-my-policy-arn" ) | not) then .Properties.ManagedPolicyArns += $targetPolicy else . # 不做任何操作 end )
脚本逻辑说明
- 先用变量
$targetPolicy定义目标策略节点,避免重复编写 - 先筛选类型为AWS::IAM::Role且信任策略包含
ecs-tasks.amazonaws.com或lambda.amazonaws.com的角色,缩小处理范围 - 判断逻辑:检查
ManagedPolicyArns数组中是否存在标签为!Sub且Fn::ImportValue值为${MyPrefix}-my-policy-arn的节点,不存在才追加 - 使用
any()函数遍历数组,确保只要有一个匹配就不执行添加操作,彻底避免重复
测试结果
- 对已存在目标策略的角色:执行脚本后无变化,不会重复添加
- 对不存在目标策略的符合条件角色:自动追加指定策略节点
内容的提问来源于stack exchange,提问作者Chip
相关产品推荐
相关产品推荐

