如何用yq为CloudFormation添加带!Sub函数简写的托管策略ARN?
用yq批量给CloudFormation YAML中的Lambda/ECS角色添加托管策略(保留!Sub简写)
核心问题解决思路
yq默认会把CloudFormation的简写标签(比如!Sub)解析成完整的Fn::Sub嵌套结构,要保留简写格式,得用yq的标签指定语法。同时要覆盖两种场景:角色已有ManagedPolicyArns数组,或者完全没有这个字段。
适用yq版本
确保你用的是mikefarah/yq v4.18+(当前主流的yq版本),旧版本语法差异极大。
具体命令
单文件处理
假设要添加的策略是!Sub "arn:aws:iam::${AWS::AccountId}:policy/YourManagedPolicy",执行以下命令:
yq eval ' (.Resources[] | select( .Type == "AWS::IAM::Role" and (.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service[] == "lambda.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service[] == "ecs-tasks.amazonaws.com") )) |= ( .Properties.ManagedPolicyArns += [{"!Sub": "arn:aws:iam::${AWS::AccountId}:policy/YourManagedPolicy"}] | .Properties.ManagedPolicyArns |= unique # 可选:去重,避免重复添加同一策略 )' your-template.yaml -i
批量处理目录下所有YAML文件
for file in *.yaml; do yq eval ' (.Resources[] | select( .Type == "AWS::IAM::Role" and (.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service[] == "lambda.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service[] == "ecs-tasks.amazonaws.com") )) |= ( .Properties.ManagedPolicyArns += [{"!Sub": "arn:aws:iam::${AWS::AccountId}:policy/YourManagedPolicy"}] | .Properties.ManagedPolicyArns |= unique )' "$file" -i done
命令解释
定位目标角色:
- 筛选所有
Type为AWS::IAM::Role的资源 - 进一步匹配信任策略(AssumeRolePolicyDocument)中包含Lambda或ECS任务服务主体的角色
- 筛选所有
处理ManagedPolicyArns字段:
+= []:如果字段已存在则追加新策略,不存在则自动创建数组并添加{"!Sub": "..."}:用这种键值对形式告诉yq保留!Sub简写标签,而非转成Fn::Sub嵌套结构unique:可选操作,防止多次执行命令时重复添加同一策略
效果对比
处理前(无ManagedPolicyArns的角色)
Resources: LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole
处理后
Resources: LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - !Sub "arn:aws:iam::${AWS::AccountId}:policy/YourManagedPolicy"
错误情况(未用正确语法时)
如果直接写!Sub "...",yq会输出嵌套结构:
ManagedPolicyArns: - Fn::Sub: "arn:aws:iam::${AWS::AccountId}:policy/YourManagedPolicy"
用{"!Sub": "..."}就能避免这个问题。
注意事项
- 执行命令前一定要备份文件,或者先不加
-i参数(直接输出到控制台)验证结果 - 如果角色的信任策略中
Principal.Service是单个值(不是数组),把[]去掉即可(比如.Principal.Service == "lambda.amazonaws.com") - 可根据实际需求修改策略ARN和匹配的服务主体
内容的提问来源于stack exchange,提问作者Chip
相关产品推荐
相关产品推荐

