使用 AWS CloudFormation 引用创建 yaml

Posted

技术标签:

【中文标题】使用 AWS CloudFormation 引用创建 yaml【英文标题】:create yaml with AWS CloudFormation references 【发布时间】:2021-01-05 13:50:55 【问题描述】:

我需要一个 python 代码来创建下面的 yaml 代码。

    Tags:
    - Key: key1
      Value: !Ref 'AWS::StackName'
    - Key: Key2
      Value: !Ref 'AWS::StackId'

这是我所拥有的,但不能解决问题。

def generate_resource(ami, source_data):
    resource = 
         "Type": "AWS::EC2::Instance",
         "Properties": 
             "ImageId": ami["ImageId"],
             "InstanceType": ami["InstanceType"],
             "PrivateIpAddress": ami["PrivateIpAddress"],
             "KeyName": ami["KeyName"]
             "SubnetId":  "Ref": "SubnetId" ,
             "SecurityGroupIds":  "Ref":  "SecurityGroupId" , 
             "Tags": [
                  "Key": "key1", "Value": "!Ref 'AWS::StackName'",
                  "Key": "key2", "Value": "!Ref 'AWS::StackId'"
             ]
         
     

此代码的yaml 输出格式不正确,因此它只是将!Ref 'AWS::StackName' 复制为值。

import os, sys
import lib.aws as aws, lib.cft as cft, lib.inventory as inventory 

BUCKET_NAME = 'testbucket'


def generate_cft(commit_hash, file_dict, dry_run):
    return (
        "# Autogenerated CFT for commit hash " + commit_hash + "\n" + 
        cft.generate(inventory.read(file_dict["path"]))
    )


def upload_cft(commit_hash, file_dict, cft_text):
    target_key = commit_hash + "/" + file_dict["name"].split("_")[0] +    ".yaml"

    aws.upload(BUCKET_NAME, target_key, cft_text)


def show_cft(file_dict, cft_text):
    print(file_dict["path"] + " generates the following cft:")
    print("")
    print(cft_text)
    print("")


def generate_and_upload(commit_hash, file_dict, dry_run):
    cft_text = generate_cft(commit_hash, file_dict, dry_run)

    aws.validate_cft(cft_text)

    if dry_run: 
        show_cft(file_dict, cft_text)
    else:
        upload_cft(commit_hash, file_dict, cft_text)


def generate_and_upload_all(commit_hash, dry_run):
    for file_dict in inventory.list():
        print("generating cft for " + file_dict["path"])
        generate_and_upload(commit_hash, file_dict, dry_run)


if __name__ == "__main__":
    if not os.getcwd().endswith("ci"):
        print("Please run this script from the ci directory")
        exit()

    commit_hash = sys.argv[1] if len(sys.argv) >= 2 else "test"
    generate_and_upload_all(commit_hash, False)

【问题讨论】:

我当然希望一个特殊的值不能使解析器神奇地从一个字符串变成一个引用——想想所有正在寻找的损害安全问题可以通过故意将这种形式的数据作为输入输入软件来解决! 也就是说,一般而言:序列化程序的存在是为了以符合格式规范的方式准确描述内存中的结构。使数据以用户想要的特定方式表示通常不是序列化程序的工作。如果您查看avoid references in pyyaml 等相关问题,您会发现当结构包含对同一个 Python 对象的多个引用时,pyyaml 确实 使用引用,但这并不意味着用户可以配置那些参考的名字。 您没有包含任何代码,因此很难为您提供帮助。顺便说一句,这些是 CloudFormation 模板的 AWS 特定功能,您可能必须在通用 JSON 到 YAML 转换之外显式地对它们进行预处理/后处理,可能使用自定义序列化。 @CharlesDuffy 好的,谢谢,对不起。 @jarmod 我已经更新了帖子并添加了资源的代码。上面的 yaml 代码是我需要 python 代码生成的。谢谢 【参考方案1】:

是的!!!!我玩弄了代码并弄明白了。这是 CFT 创建期间的语法错误。现在,当我使用生成的 CFT 创建堆栈时,标签值将替换为实际的“StackId”。感谢大家的帮助和指导。

def generate_resource(ami, source_data):
resource = 
    "Type": "AWS::EC2::Instance",
    "Properties": 
        "ImageId": ami["ImageId"],
        "InstanceType": ami["InstanceType"],
        "PrivateIpAddress": ami["PrivateIpAddress"],
        "KeyName": ami["KeyName"],
        "SubnetId":  "Ref": "SubnetId" ,
        "SecurityGroupIds":  "Ref":  "SecurityGroupId" , 
        "Tags": [
             "Key": "Name", "Value": ami["Name"] ,
             "Key": "BootUpDependsOn", "Value": ami["BootUpDependsOn"],
             "Key": "WaitTimeAfterBootUp", "Value": ami["WaitTimeAfterBootUp"],
             "Key": "Key1", "Value":  "Ref": "AWS::StackName" ,
             "Key": "Key2", "Value":  "Ref": "AWS::StackId" 
        ]
    

【讨论】:

以上是关于使用 AWS CloudFormation 引用创建 yaml的主要内容,如果未能解决你的问题,请参考以下文章

在 AWS CloudFormation 模板中引用 !Ref DynamoDB 表名

在 CloudFormation 模板中引用 AWS Parameter Store 的安全字符串

在 AWS CloudFormation 模板中,如何使用自己的 Id 标记 EC2 实例而不会出现循环引用错误?

Cloudformation + OpsWorks

AWS CloudFormation:使用 resolve 具有动态引用的嵌套子会导致错误并且不执行解析以从 Parameter Store 获取值

AWS Cloudformation的相关概念