为什么此CloudFormation模板脚本不起作用?

时间:2019-07-01 16:25:19

标签: python json amazon-web-services amazon-cloudformation

我正在尝试在AWS CloudFormation上创建一个具有EC2实例和2个S3存储桶的堆栈。我的脚本试图将策略分配给允许访问存储桶的EC2实例,但是无论我做什么,都不会分配权限。另外,根本不执行用户数据。

我尝试彻底测试EC2是否确实没有权限:CLI确认没有。我用制作文本文件的简单脚本替换了用户数据,但实际上并没有创建。 AWS Designer不提出任何投诉,并显示正确的模板结构。堆栈描述运行并执行没有错误,除了对S3存储桶的访问和用户数据不起作用(无警告)之外。

经过大量的手动编辑和非常仔细的检查文档之后,我意识到我应该使用更高级别的语言来完成此操作。因此,我尝试使用templateGenerator将脚本导入简单的python Troposphere脚本中。这会导致以下错误(到目前为止,其他任何地方都未创建其他错误,所有内容都默默地出错了,JSON语法验证器也没有任何抱怨):

TypeError: <class 'troposphere.iam.PolicyType'>: MickStorageS3BucketsPolicy.PolicyDocument is <class 'list'>, expected (<class 'dict'>,)

但是,很明显,我的PolicyDocument是字典类型的,而且我不明白如何将其解释为列表。我已经盯着这个看了好几个小时了,我可能对这个问题视而不见了,但是在这一点上,我真的很感谢任何帮助!!!!

安全组和入站流量设置正常运行,我的dockerized flask应用运行良好(在EC2上),但无法访问存储桶(尽管我必须通过SSH手动启动它,因为用户数据无法执行,我还尝试使用ec2元数据中的CFN-init段(在命令下)执行此操作,但是即使我尝试通过SSH连接后手动运行CFNinit,也不会执行任何操作。

这是我写的cloudformation模板:

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Attach IAM Role to an EC2",
  "Parameters" : {
    "KeyName" : {
      "Description" : "EC2 Instance SSH Key",
      "Type" : "AWS::EC2::KeyPair::KeyName",
      "Default" : "MickFirstSSHKeyPair"
    },
    "InstanceType" : {
      "Description" : "EC2 instance specs configuration",
      "Type" : "String",
      "Default" : "t2.micro",
      "AllowedValues" : ["t2.micro", "t2.small", "t2.medium"]
    }
  },
  "Mappings" : {
    "AMIs" : {
      "us-east-1" : {
        "Name" : "ami-8c1be5f6"
      },
      "us-east-2" : {
        "Name" : "ami-c5062ba0"
      },
      "eu-west-1" : {
        "Name" : "ami-acd005d5"
      },
      "eu-west-3" : {
        "Name" : "ami-05b93cd5a1b552734"
      },
      "us-west-2" : {
        "Name" : "ami-0f2176987ee50226e"
      },
      "ap-southeast-2" : {
        "Name" : "ami-8536d6e7"
      }     
    }
  },
  "Resources" : {
    "mickmys3storageinstance" : {
      "Type" : "AWS::S3::Bucket",
      "Properties" : {

      }
    },
    "mickmys3processedinstance" : {
      "Type" : "AWS::S3::Bucket",
      "Properties" : {

      }
    },

    "MickMainEC2" : {
      "Type" : "AWS::EC2::Instance",
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "config" : {
            "files" : {

            },
            "commands" : {

            }

          }
        }
      },
      "Properties" : {
        "UserData": {
            "Fn::Base64" : "echo 'Heelo ww' > ~/hello.txt" 
        },
        "InstanceType" : {
          "Ref" : "InstanceType"
        },
        "ImageId" : {
          "Fn::FindInMap" : [
            "AMIs",
            {
              "Ref" : "AWS::Region"
            },
            "Name"
          ]
        },
        "KeyName" : {
          "Ref" : "KeyName"
        },
        "IamInstanceProfile" : {
          "Ref" : "ListS3BucketsInstanceProfile"
        },
        "SecurityGroupIds" : [
          {
            "Ref" : "SSHAccessSG"
          },
          {
            "Ref" : "PublicAccessSG"
          }
        ],
        "Tags" : [
          {
            "Key" : "Name",
            "Value" : "MickMainEC2"
          }
        ]
      }
    },
    "SSHAccessSG" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Allow SSH access from anywhere",
        "SecurityGroupIngress" : [
          {
            "FromPort" : "22",
            "ToPort" : "22",
            "IpProtocol" : "tcp",
            "CidrIp" : "0.0.0.0/0"
          }
        ],
        "Tags" : [
          {
            "Key" : "Name",
            "Value" : "SSHAccessSG"
          }
        ]
      }
    },
    "PublicAccessSG" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Allow HTML requests from anywhere",
        "SecurityGroupIngress" : [
          {
            "FromPort" : "80",
            "ToPort" : "80",
            "IpProtocol" : "tcp",
            "CidrIp" : "0.0.0.0/0"
          }
        ],
        "Tags" : [
          {
            "Key" : "Name",
            "Value" : "PublicAccessSG"
          }
        ]
      }
    },
    "ListS3BucketsInstanceProfile" : {
      "Type" : "AWS::IAM::InstanceProfile",
      "Properties" : {
        "Path" : "/",
        "Roles" : [
          {
            "Ref" : "MickListS3BucketsRole"
          }
        ]
      }
    },
    "MickStorageS3BucketsPolicy" : {
        "Type" : "AWS::IAM::Policy",
        "Properties" : {
            "PolicyName" : "MickStorageS3BucketsPolicy",

            "PolicyDocument" : {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "ListObjectsInBucket",
                        "Effect": "Allow",
                        "Action": [
                        "s3:ListBucket"
                        ],
                        "Resource": [
                            "arn:aws:s3:::mickmys3storageinstance", "arn:aws:s3:::mickmys3storageinstance/*"
                        ]
                    },  
                    {
                        "Sid": "AllObjectActions",
                        "Effect": "Allow",
                        "Action": ["s3:*Object"],
                        "Resource": [
                            "arn:aws:s3:::mickmys3storageinstance", "arn:aws:s3:::mickmys3storageinstance/*"
                        ]
                    }
                ]
            },
            "Roles" : [
                {
                    "Ref" : "MickListS3BucketsRole"
                }
            ]           
        }
    },
    "MickListS3BucketsRole" : {
      "Type" : "AWS::IAM::Role",
      "Properties" : {
        "AssumeRolePolicyDocument": {
          "Version" : "2012-10-17",
          "Statement" : [
            {
              "Effect" : "Allow",
              "Principal" : {
                "Service" : ["ec2.amazonaws.com"]
              },
              "Action" : [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path" : "/"
      }
    }
  },
  "Outputs" : {
    "EC2" : {
      "Description" : "EC2 IP address",
      "Value" : {
        "Fn::Join" : [
          "",
          [
            "ssh ec2-user@",
            {
              "Fn::GetAtt" : [
                "MickMainEC2",
                "PublicIp"
              ]
            },
            " -i ",
            {
              "Ref" : "KeyName"
            },
            ".pem"
          ]
        ]
      }
    }
  }
}

这是我的对流层脚本,在导入以上内容时会产生错误:

from troposphere import Ref, Template
import troposphere.ec2 as ec2

from troposphere.template_generator import TemplateGenerator
import json
with open("myStackFile.JSON") as f:
    json_template = json.load(f)
template = TemplateGenerator(json_template)
template.to_json()


print(template.to_yaml())

我希望角色分配正确,用户数据也要执行。我希望对流层能够导入JSON,因为据我所知,它具有正确的语法和正确的类输入。我已经手工检查了许多小时,很多时间,我不确定如何继续使用CloudFormation脚本查找问题。将来(我会建议任何人都这样做),我将不再手动编辑JSON(或更糟糕的是,YAML)文件,而不会单独使用更高级别的工具。

感谢您的任何帮助/指标!

亲切的问候

1 个答案:

答案 0 :(得分:0)

由于忘记了#!/bin/bash,因此未执行您的用户数据。来自documentation

  

用户数据外壳程序脚本必须以#!开头。字符和要读取脚本的解释器的路径(通常为/ bin / bash)。有关shell脚本的重要介绍,请参见Linux Documentation Project(tldp.org)上的BASH编程方法。

对于存储桶权限,我认为问题是您在策略中指定了CloudFormation资源名称,而不是实际的存储桶名称。如果要将存储桶实际命名为mickmys3storageinstance,则需要:

"mickmys3storageinstance" : {
  "Type" : "AWS::S3::Bucket",
  "Properties" : {
    "BucketName": "mickmys3storageinstance"
  }
},

否则,您应该在策略中使用RefFn::Sub来获取实际的存储桶名称。

                {
                    "Sid": "ListObjectsInBucket",
                    "Effect": "Allow",
                    "Action": [
                    "s3:ListBucket"
                    ],
                    "Resource": [
                        {"Fn::Sub": "${mickmys3storageinstance.Arn}"},
                        {"Fn::Sub": "${mickmys3storageinstance.Arn}/*"}
                    ]
                },