使用Cloudformation在S3存储桶中创建文件夹

时间:2016-04-28 14:39:26

标签: amazon-s3 amazon-cloudformation

我能够使用cloudformation创建一个S3存储桶,但想在S3存储桶中创建一个文件夹。比如

<mybucket>--><myfolder>

请告诉我用于在存储桶中创建文件夹的模板......两者都应该在同一时间创建...

我使用AWS lambda如下

stackname = 'myStack'
client = boto3.client('cloudformation')
response = client.create_stack(
    StackName= (stackname),
    TemplateURL= 'https://s3.amazonaws.com/<myS3bucket>/<myfolder>/nestedstack.json',
    Parameters=<params>
)

4 个答案:

答案 0 :(得分:17)

AWS未提供正式的CloudFormation资源来在S3存储桶中创建对象。但是,您可以使用AWS SDK创建Lambda-backed Custom Resource来执行此功能,实际上gilt/cloudformation-helpers GitHub存储库提供了现成的自定义资源。

与任何自定义资源设置一样有点冗长,因为您需要首先部署Lambda函数和IAM权限,然后将其作为堆栈模板中的自定义资源引用。

首先,将Lambda::Function和关联的IAM::Role资源添加到您的堆栈模板中:

"S3PutObjectFunctionRole": {
  "Type": "AWS::IAM::Role",
  "Properties": {
    "AssumeRolePolicyDocument": {
      "Version" : "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": [ "lambda.amazonaws.com" ]
          },
          "Action": [ "sts:AssumeRole" ]
        }
      ]
    },
    "ManagedPolicyArns": [
      { "Ref": "RoleBasePolicy" }
    ],
    "Policies": [
      {
        "PolicyName": "S3Writer",
        "PolicyDocument": {
          "Version" : "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "s3:DeleteObject",
                "s3:ListBucket",
                "s3:PutObject"
              ],
              "Resource": "*"
            }
          ]
        }
      }
    ]
  }
},
"S3PutObjectFunction": {
  "Type": "AWS::Lambda::Function",
  "Properties": {
    "Code": {
      "S3Bucket": "com.gilt.public.backoffice",
      "S3Key": "lambda_functions/cloudformation-helpers.zip"
    },
    "Description": "Used to put objects into S3.",
    "Handler": "aws/s3.putObject",
    "Role": {"Fn::GetAtt" : [ "S3PutObjectFunctionRole", "Arn" ] },
    "Runtime": "nodejs",
    "Timeout": 30
  },
  "DependsOn": [
    "S3PutObjectFunctionRole"
  ]
},

然后,您可以使用Lambda函数作为自定义资源来创建S3对象:

"MyFolder": {
  "Type": "Custom::S3PutObject",
  "Properties": {
    "ServiceToken": { "Fn::GetAtt" : ["S3PutObjectFunction", "Arn"] },
    "Bucket": "mybucket",
    "Key": "myfolder/"
  }
},

除了BodyBucket之外,您还可以通过添加Key参数来使用相同的自定义资源来编写基于字符串的S3对象(请参阅docs )。

答案 1 :(得分:11)

使用AWS CloudFormation模板无法做到这一点。

应该提到的是,文件夹在Amazon S3中实际上并不存在。而是将对象的路径添加到对象的名称(key)之前。

因此,存储在名为bar.txt的文件夹中的文件foo实际上存储的密钥为:foo/bar.txt

您还可以将文件复制到不存在的文件夹,并自动创建文件夹(实际上并非如此,因为文件夹本身不存在)。但是,管理控制台将提供此类文件夹的外观,并且路径将建议将其存储在此类文件夹中。

底线:无需预先创建文件夹。只要使用就好像它已经存在一样。

答案 2 :(得分:0)

我们(至少到目前为止)无法在s3存储桶中创建子文件夹。

您可以尝试使用以下命令:

 aws s3 mb s3://yavdhesh-bucket/inside-folder

然后尝试使用命令列出存储桶中的所有文件夹:

aws s3 ls s3://yavdhesh-bucket

您会发现未创建子文件夹。

只有一种创建子文件夹的方法,即通过在不存在的子文件夹或子目录(相对于存储桶)中创建/复制文件

例如,

aws s3 cp demo.txt s3://yavdhesh-bucket/inside-folder/

现在,如果您列出子文件夹中的文件,它应该可以工作。

 aws s3 ls s3://yavdhesh-bucket/inside-folder/

它应该列出该子文件夹中存在的所有文件。

enter image description here

希望有帮助。

答案 3 :(得分:0)

我最终得到了一个小的python脚本。它应该手动运行,但是会自动同步。适用于不想创建Lambda支持的自定义资源的懒惰人。

import subprocess
import json

STACK_NAME = ...
S3_RESOURCE = <name of your s3 resource, as in CloudFormation template file>
LOCAL_DIR = <path of your local dir>

res = subprocess.run(
    ['aws', 'cloudformation', 'describe-stack-resource', '--stack-name', STACK_NAME, '--logical-resource-id', S3_RESOURCE],
    capture_output=True,
)
out = res.stdout.decode('utf-8')
resource_details = json.loads(out)
resource_id = resource_details['StackResourceDetail']['PhysicalResourceId']

res = subprocess.run(
    ['aws', 's3', 'sync', LOCAL_DIR, f's3://{resource_id}/', '--acl', 'public-read']
)