Не удается отправить параметры из дочернего шаблона CloudFormation в другой дочерний шаблон

#templates #amazon-web-services #amazon-cloudformation

#шаблоны #amazon-веб-сервисы #aws-cloudformation

Вопрос:

Я создаю чудовищный шаблон CloudFormation, который использует AWS::CloudFormation::Stack ресурс для создания других вложенных стеков. Целью этого является классическое разделение обязанностей и управления.

Общая цель состоит в том, чтобы создать среду приложения с нуля (начиная с VPC и заканчивая экземплярами приложений).

Пока что большая часть этого работает. Но я столкнулся с проблемой, связанной со ссылками на выходные данные шаблона CF подсети и шаблона CF securitygroup для использования при создании экземпляров EC2.

Это работает следующим образом:

Главный шаблон -> Создает VPC -> Вызывает дочерний шаблон для создания подсетей -> Вызывает дочерний шаблон для создания групп безопасности -> Вызывает дочерний шаблон для создания экземпляров EC2

Мне нужно передать выходные данные из шаблонов подсети и группы безопасности в шаблон экземпляра EC2, чтобы экземпляры могли быть подготовлены в правильной части архитектуры. Ссылка на идентификатор VPC и пары ключей передаются нормально, но идентификатор подсети и securitygroupID — нет.

Вот часть главного шаблона, которая вызывает шаблоны группы безопасности / подсети:

 "DevNetworkStack": {
        "Type": "AWS::CloudFormation::Stack",
        "DependsOn": [
            "SNVPC",
            "SNIGW"
        ],
        "Properties": {
            "TemplateURL": {
                "Fn::FindInMap": [
                    "TemplateURLs",
                    "DevNetworkStack",
                    "URL"
                ]
            },
            "TimeoutInMinutes": "30",
            "Parameters": {
                "VPCID": {
                    "Ref": "SNVPC"
                },
                "SNIGW": {
                    "Ref": "SNIGW"
                }
            }
        }
    },
    "DevSecurityGroupsStack": {
        "Type": "AWS::CloudFormation::Stack",
        "DependsOn": "DevNetworkStack",
        "Properties": {
            "TemplateURL": {
                "Fn::FindInMap": [
                    "TemplateURLs",
                    "DevSecurityGroupsStack",
                    "URL"
                ]
            },
            "TimeoutInMinutes": "30",
            "Parameters": {
                "VPCID": {
                    "Ref": "SNVPC"
                }
            }
        }
},
  

Они работают нормально. Они создаются, и все в порядке. Шаблоны предлагают такие выходные данные:

 "Outputs": {
     "DevAdminSubnetID": {
        "Description": "DevAdminSubnetID",
        "Value": {
            "Ref": "DevAdminSubnet"
        }
},
  

 "Outputs": {
     "DevAdminSecurityGroupID": {
        "Description": "DevAdminSecurityGroupID",
        "Value": {
            "Ref": "DevAdminSecurityGroup"
        }
},
  

Я вижу выходные данные в консоли CF.

Теперь следующий шаблон пытается использовать идентификатор группы безопасности и идентификатор подсети. Но это не работает.

Главный шаблон вызывает следующий дочерний шаблон как:

 "DevAdminStack": {
       "Type": "AWS::CloudFormation::Stack",
        "DependsOn": [
            "DevNetworkStack",
            "DevSecurityGroupsStack",
            "EC2DevRoleInstanceProfile",
            "S3DevUserDataBucket",
            "S3DevHomeDirsDataBucket"
        ],
        "Properties": {
            "TemplateURL": {
                "Fn::FindInMap": [
                    "TemplateURLs",
                    "DevAdminStack",
                    "URL"
                ]
            },
            "TimeoutInMinutes": "30",
            "Parameters": {
                "AdminKeyPair": {
                    "Ref": "AdminServersKeyPair"
                },
                "VPCID": {
                    "Ref": "SNVPC"
                },
                "DevAdminSecurityGroupID": [
                    {
                        "Fn::GetAtt": [
                            "DevSecurityGroupsStack",
                            "Outputs.DevAdminSecurityGroupID"
                        ]
                    }
                ],
                "DevAdminSubnetID": [
                    {
                        "Fn::GetAtt": [
                            "DevNetworkStack",
                            "Outputs.DevAdminSubnetID"
                        ]
                    }
                ]
            }
        }
}
  

…и дочерний шаблон выглядит следующим образом (удалены некоторые части для краткости, потому что я только тестирую прямо сейчас)

 {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Dev-Admin",
"Mappings": {
    "RegionMap": {
        "DevAdminServer": {
            "AMI": "ami-6fc9770e",
            "InstanceType": "t2.micro"
        }
    }
},
"Parameters": {
    "AdminKeyPair": {
        "Type": "AWS::EC2::KeyPair::KeyName"
    },
    "VPCID": {
        "Type": "AWS::EC2::VPC::Id"
    },
    "DevAdminSecurityGroupID": {
        "Type": "AWS::EC2::SecurityGroup::Id"
    },
    "DevAdminSubnetID": {
        "Type": "AWS::EC2::Subnet::Id"
    }
},
"Resources": {
    "DevAdminServer": {
        "Type": "AWS::EC2::Instance",
        "Metadata": {
            "Comment": "Sets up administrative tools for the server",
            "AWS::CloudFormation::Init": {
                "config": {
                    "packages": {
                        "yum": {}
                    },
                    "files": {},
                    "services": {}
                }
            }
        },
        "Properties": {
            "ImageId": {
                "Fn::FindInMap": [
                    "RegionMap",
                    "DevAdminServer",
                    "AMI"
                ]
            },
            "SecurityGroupIds": [
                {
                    "Ref": "DevAdminSecurityGroupID"
                }
            ],
            "SubnetId": {
                "Ref": "DevAdminSubnetID"
            },
            "InstanceType": {
                "Fn::FindInMap": [
                    "RegionMap",
                    "DevAdminServer",
                    "InstanceType"
                ]
            },
            "KeyName": {
                "Ref": "AdminKeyPair"
            },
            "Tags": [
                {
                    "Key": "Application",
                    "Value": {
                        "Ref": "AWS::StackId"
                    }
                }
            ],
            "UserData": {
                "Fn::Base64": {
                    "Fn::Join": [
                        "",
                        []
                    ]
                }
            }
        }
    }
  }
}
  

Но при создании этого ресурса происходит сбой с ошибкой:

Значением параметров свойства должен быть объект со свойствами String (или простого типа)

Я знаю, что проблема в последних двух переменных (subnetID и securitygroupID), потому что я удалил их, и подготовка дочернего шаблона работает просто отлично.

Что я делаю не так?

Ответ №1:

Значения DevAdminSecurityGroupID и DevAdminSubnetID определены как массивы JSON [] в вашем главном шаблоне, но они должны быть строками (после Fn::GetAtt расширения встроенной функции):

             "DevAdminSecurityGroupID":
                {
                    "Fn::GetAtt": [
                        "DevSecurityGroupsStack",
                        "Outputs.DevAdminSecurityGroupID"
                    ]
                },
            "DevAdminSubnetID":
                {
                    "Fn::GetAtt": [
                        "DevNetworkStack",
                        "Outputs.DevAdminSubnetID"
                    ]
                }