You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在CloudFormation中正确传递LaunchUserData参数至EC2的UserData

问题描述

我有一个用于创建EC2实例的CloudFormation模板,需要关联一个UserData脚本,该脚本通过LaunchUserData参数赋值。当前模板片段如下:

AWSTemplateFormatVersion: '2010-09-09'
Description: Create an AMI from an EC2 instance.
Parameters:
  LaunchUserData:
    Description: Base64-encoded user data to launch EC2 instances.
    Type: String
  GitSSHKey:
    Description: Git SSH key
    Type: String
Resources:
  LaunchEc2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      UserData: ...

LaunchUserData是一个bash脚本,里面会引用栈的参数和资源,示例脚本如下:

#!/bin/bash

GIT_SSH_KEY=${GitSshKey};

echo "$GIT_SSH_KEY" | base64 -d > $HOME/.ssh/id_rsa;

echo ${AWS:Region};

我希望通过以下CLI命令创建栈:

GIT_SSH_KEY="somesshkey"
LAUNCH_USERDATA=$(jq -Rs . < $PWD/templates/launch)
STACK_ID=$(aws cloudformation create-stack \
--stack-name test \
--template-body file://$CLOUD_FORMATION_FILE \
--parameters \
    ParameterKey=GitSSHKey,ParameterValue="$GIT_SSH_KEY" \
    ParameterKey=LaunchUserData,ParameterValue="$LAUNCH_USERDATA" \
--output text \
--query 'StackId');

要求脚本在EC2实例中执行时,其中的${}变量能被替换为当前栈的参数和资源值,最终执行的脚本应该是这样:

$ curl http://169.254.169.254/latest/user-data

#!/bin/bash

GIT_SSH_KEY=somesshkey;

echo "$GIT_SSH_KEY" | base64 -d > $HOME/.ssh/id_rsa;
echo us-east-1;

需要注意脚本还可能引用其他CloudFormation资源,请问如何在不将脚本硬编码到模板中的前提下,正确将LaunchUserData参数传递给UserData?

解决方案

要实现脚本变量的动态替换,同时不硬编码脚本到模板,需要结合CloudFormation的Fn::Sub函数和参数传递来处理,具体步骤如下:

1. 修改CloudFormation模板的UserData配置

把UserData字段改成用Fn::Sub函数处理传入的脚本参数,同时加上CloudFormation要求的Base64编码:

Resources:
  LaunchEc2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      UserData:
        Fn::Base64:
          !Sub
            - ${LaunchUserDataContent}
            - LaunchUserDataContent: !Ref LaunchUserData

Fn::Sub会自动把脚本里的变量(比如${GitSSHKey}、${AWS::Region})替换成栈对应的参数值或内置资源值,Fn::Base64是UserData的必填要求。

2. 修正脚本中的变量格式

CloudFormation的Fn::Sub识别的变量有固定格式:

  • 栈参数直接写参数名,比如模板里的GitSSHKey,脚本里对应写${GitSSHKey}
  • CloudFormation内置变量要写完整名称,比如区域是${AWS::Region}(注意是双冒号,不是单冒号)

修改后的示例脚本:

#!/bin/bash

GIT_SSH_KEY=${GitSSHKey};

echo "$GIT_SSH_KEY" | base64 -d > $HOME/.ssh/id_rsa;

echo ${AWS::Region};

3. 调整CLI命令的参数传递

不需要用jq做JSON转义,直接读取脚本内容传递即可:

GIT_SSH_KEY="somesshkey"
# 直接读取脚本文件内容
LAUNCH_USERDATA=$(cat $PWD/templates/launch)
STACK_ID=$(aws cloudformation create-stack \
--stack-name test \
--template-body file://$CLOUD_FORMATION_FILE \
--parameters \
    ParameterKey=GitSSHKey,ParameterValue="$GIT_SSH_KEY" \
    ParameterKey=LaunchUserData,ParameterValue="$LAUNCH_USERDATA" \
--output text \
--query 'StackId')

如果脚本里有特殊字符(比如双引号、反斜杠),可以先做base64编码再传递,模板里用Fn::Base64+Fn::Sub+Fn::DecodeBase64组合处理,但上述方式对大多数bash脚本已经够用。

4. 验证效果

栈创建完成后,登录EC2实例执行curl http://169.254.169.254/latest/user-data,就能看到脚本中的变量已经被替换为实际值,和预期结果一致。

内容的提问来源于stack exchange,提问作者Constantin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:27:03