标签归档:S3

S3文件的时区和时间

好多人问S3上文件的时区和时间这类问题,今天总结下:

简单说就是不同工具不同客户端看到的时间是不同的:
例如s3cmd 显示的就是UTC时间,而awscli 显示的就是根据客户端时区换算之后的时间,CloudBerry客户端也显示的是换算之后的时间。

(1)bucket的时间是bucket的创建时间,object时间是它被上传的时间(cloudberry显示成‘修改时间’);s3cmd上传后,再用s3cmd查看,显示的是上传时间对应的UTC时间,但用awscli查看,就能以本地时间显示。所以上传是的时间就是上传那个时刻的时间,不过不同客户端会以不同时区显示而已。
(2)object被下载之后,就出现问题了。s3cmd get下来的文件的时间会显示用s3cmd ls看到的时间,也就是UTC时间;而aws s3 cp下来的时间,也是使用aws s3 ls看到的时间,即本地时间。这样使用两种客户端下载通一个文件,查看下载后的文件的时间将会有两种不同结果(awscli的更准确些,s3cmd下载保存文件是时间没换算)。
(3)使用s3cmd上传大文件时,会被切割成15MB每个分片上传再组装,使用s3cmd获取到的md5sum并不是文件的真实MD5值,这点需要注意,下载大文件的时候会显示md5sum does not match,使用awscli时无此问题。

关于什么时候用哪种工具的问题:
(1)s3cmd上传和下载速度都比较适中,并未充分占满实例的带宽,因此比较适合做小文件或者较高频率的文件上传下载和sync。但是它上传几个GB的单个文件时,可靠性就差一下,有时会失败报错。
(2)awscli工具上传大文件的时候能充分利用网络性能,基本能跑满实例的带宽,上传下载速度特别快,适合在非线上服或者非高峰时间上传单个大文件,优点是速度非常快,缺点是会耗尽实例带宽,还没找到限速方法。
(3)在用到sync功能时,由于s3cmd的MD5问题,同步包含大文件时有时会有报错,建议包含大文件使用aws s3 sync;只有小文件时s3cmd sync或者aws s3 sync都行。

使用HTTP POST在浏览器上传文件至S3

我们可以在http页面中构造一个预先授权的http post表单,实现在浏览器端使用POST方式上传文件到S3。表单内容如下:

<html> 
  <head>
    <title>S3 POST Form</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>

  <body> 
    <form action="https://cypay-test.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
      <input type="hidden" name="key" value="upload/${filename}">
      <input type="hidden" name="AWSAccessKeyId" value="xxxxxxxx"> 
      <input type="hidden" name="acl" value="private"> 
      <input type="hidden" name="success_action_redirect" value="http://your-success-page">
      <input type="hidden" name="policy" value="xxxx">
      <input type="hidden" name="signature" value="xxxx">
      <input type="hidden" name="Content-Type" value="image/jpeg">
      <!-- Include any additional input fields here -->

      File to upload to S3: 
      <input name="file" type="file"> 
      <br> 
      <input type="submit" value="Upload File to S3"> 
    </form> 
  </body>
</html>

其中,value="upload/${filename}"为目的地址,目录会自动创建
name="success_action_redirect" value="http://your-success-page",上传成功之后的跳转页面
name="policy" value="xxxx"base64加密的policy字符串
name="signature" value="xxxx",用SECRET_KEY使用base64加密的签名
加密算法如下python版:

import base64
import hmac, hashlib

AWS_SECRET_ACCESS_KEY = r"xxxxxx"
policy_document ='''
{
  "expiration": "2020-01-01T00:00:00Z",
  "conditions": [ 
    {"bucket": "your-bucket"}, 
    ["starts-with", "$key", ""],
    {"acl": "private"},
    {"success_action_redirect": "http://your-success-page"},
    ["starts-with", "$Content-Type", ""],
    ["content-length-range", 0, 1048576000]
  ]
}
'''
policy = base64.b64encode(policy_document)
signature = base64.b64encode(hmac.new(AWS_SECRET_ACCESS_KEY, policy, hashlib.sha1).digest())
print policy
print signature

设置IAM用户权限允许访问特定S3的bucket或者目录

通过设置IAM用户权限,可以限制IAM用户访问特定的S3 bucket或者目录的权限。

(1) case1:只允许IAM用户通过API或者s3cmd命令行工具访问特定S3 bucket
{
  "Statement": [
    {
       "Effect": "Allow",
       "Action": ["s3:ListBucket" ],
       "Resource": [ "arn:aws:s3:::mod-backup"]
    },
    {
        "Effect": "Allow",
        "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
        "Resource": [ "arn:aws:s3:::mod-backup/*"]
    }
  ]
}

这样虽然直接 s3cmd ls会报Access Deny,但是s3cmd ls s3://mod-backup还是可以看到的

(2) case2: 使用CloudBerry这类图形化工具,只允许用户访问特定的S3bucket或者特定目录
IAM user的授权跟API方式的一样
{
  "Statement": [
    {
       "Effect": "Allow",
       "Action": ["s3:ListBucket" ],
       "Resource": [ "arn:aws:s3:::mod-backup"]
    },
    {
        "Effect": "Allow",
        "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
        "Resource": [ "arn:aws:s3:::mod-backup/*"]
    }
  ]
}
在配置CloudBerry的时候,通过配置External Bucket来只显示该Bucket或者某个目录
<1>配置整个bucket是External Bucket填写bucket name,例如mod-backup
<2>若只有改Bucket下某个目录的权限,就填写mod-backup/wangfei
(3) case3: 允许IAM用户通过AWS console(web管理页面)访问且仅能访问特定S3 bucket
{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetBucketLocation", "s3:ListAllMyBuckets"],
      "Resource": "arn:aws:s3:::*"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket" ],
      "Resource": [ "arn:aws:s3:::mod-backup"]
    },
    {
      "Effect": "Allow",
      "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
      "Resource": [ "arn:aws:s3:::mod-backup/*"]
    }
  ]
}

这样IAM用户只能读写mod-backup这个bucket,但是又个问题,虽然其他的bucket无权限访问到,但是在bucket列表中依然能看到,但看不到里面的内容。修改成

     "Action": ["s3:GetBucketLocation", "s3:ListAllMyBuckets"],
      "Resource": "arn:aws:s3:::mod-backup"

这样也不行,这样什么bucket都列举不出来,因为s3:GetBucketLocation这个api操作的对象只能是AllBucket。

 

简明 s3cmd 安装与使用手册

简明 s3cmd 安装与使用手册(part one)
——————
Preface
S3是亚马逊AWS提供的简单存储服务(可以理解为有公网域名的大容量高可用存储)
S3配合CloudFront服务可作为CDN使用,它提供多节点全球发布
在使用过程中,一般是通过web页面上传内容到S3 Bucket(Bucket桶,S3里存内容的容器)
这个过程缓慢繁琐容易中断
推荐S3cmd这个软件用命令行实现
如下就是这个命令行工具的简明手册

1) 注册 Amazon AWS / S3
首先得注册S3服务,这个一般账号创建完毕之后应该都有,然后创建用户,这时会生成
你的Access Key and Secret Key,下载保存好备用
这个key对是你通过命名行工具控制AWS资源的信任验证
当你具有AWS某项权限之后,就可以通过你的keys命令行控制了

2) 安装s3cmd并设置好
下载下来之后,直接解压就可以使用其中的二进制可执行文件了
你可以安装到系统中去,这样在任何目录下都可以直接使用s3cmd
安装:

python setup.py install

(注意此处的python必须是2.6版本以上)
或者使用pip来安装,如果没有pip命令,就

yum -y install python-pip
然后pip install s3cmd

然后设置

s3cmd --configure

执行s3cmd –configure之后会提示你输入你的Access Key和 Secret Key
然后会提示时候进行上传测试,测试OK之后环境设置就OK
然后保存设置

3) s3cmd mb创建新Bucket(即S3容器)

s3cmd mb s3://my-new-bucket-name
s3cmd ls s3://my-new-bucket-name/*

s3cmd ls 该命令可以list出你当前的S3 bucket

4) 上传文件到bucket:

上传单个文件

~$ s3cmd put some-file.xml s3://public.s3tools.org/somefile.xml
some-file.xml -&gt; s3://public.s3tools.org/somefile.xml [1 of 1]
123456 of 123456 100% in 2s 51.75 kB/s done

上传多个目录到bucket:

~$ s3cmd put --recursive dir1 dir2 s3://public.s3tools.org/somewhere/
File 'dir1/file1-1.txt' stored as 's3://public.s3tools.org/somewhere/dir1/file1-1.txt' [1 of 5]
...

目标目录不用提前创建,上传时会自动创建

5) 从S3 bucket上下载文件
下载单个文件

~$ s3cmd get s3://public.s3tools.org/somefile.xml some-file-2.xml
s3://public.s3tools.org/somefile.xml -&gt; some-file-2.xml [1 of 1]
123456 of 123456 100% in 3s 35.75 kB/s done

下载整个目录

~$ s3cmd get --recursive s3://public.s3tools.org/somewhere
File s3://public.s3tools.org/somewhere/dir1/file1-1.txt saved as './somewhere/dir1/file1-1.txt'
...

注意下面两条命名的区别
get s3://public.s3tools.org/somewhere
get s3://public.s3tools.org/somewhere/

第一条命令下载下来的东西会是/somewhere/dir1/** 即连同somewhere及其子目录一并下载,并在本地创建相同的目录结构
第二条下载下来的没有somewhere目录,即指下载该目录的内容,在本地并不创建somewhere目录,一般会使用recursive参数

~$ s3cmd get --recursive s3://public.s3tools.org/somewhere/*

来下载该目录下所有内容,包括子目录

如果你指定下载存放目录,结果会是这样的

~$ s3cmd get --recursive s3://public.s3tools.org/somewhere /tmp
File s3://public.s3tools.org/somewhere/dir1/file1-1.txt saved as '/tmp/dir1/file1-1.txt'
...

6) 删除操作:

删除 s3://public.s3tools.org/somewhere/下的所有内容

~$ s3cmd del --recursive s3://public.s3tools.org/somewhere/
File s3://public.s3tools.org/somewhere/dir1/file1-1.txt deleted
...

删除整个S3 bucket

~$ s3cmd rb s3://public.s3tools.org
ERROR: S3 error: 409 (BucketNotEmpty): The bucket you tried to delete is not empty

注意删除整个S3 bucket之前你必须确保它是空的
确保是空的bucket之后用上面的命令删除bucket
或者强行删除 – -force

7) 同步操作

1、同步当前目录下所有文件

~$ s3cmd sync ./ s3://my-bucket-name/

2、加 ” – -delete-removed”参数后,会删除本地不存在的文件。

~$ s3cmd sync --delete-removed ./ s3://my-bucket-name/

3、加 ” – -skip-existing”参数后,不进行MD5校验,直接跳过本地已存在的文件。

~$ s3cmd sync --skip-existing ./ s3://my-bucket-name/

8) 高级同步操作

1、排除、包含规则(- -exclude 、- -include)

~$ s3cmd sync --exclude '*.doc' --include 'dir2/*' ./ s3://my-bucket-name/

2、从文件中载入排除或包含规则。(- -exclude-from、- -include-from)

~$ s3cmd sync --exclude-from exclude.txt ./ s3://my-bucket-name/

exclude.txt 文件内容:

# comments here
*.jpg
*.gif

3、排除或包含规则支持正则表达式

--rexclude 、--rinclude、--rexclude-from、--rinclude-from

S3cmd官网 http://s3tools.org
亚马逊AWS S3服务官网 http://aws.amazon.com/s3

使放进S3 Bucket目录里的内容public

如果想要使放进S3里某个目录下的内容自动变成public,可以添加如下Bucket Policy

{
        “Version”: “2008-10-17”,
        “Statement”: [
                {
                       “Sid”: “AddPerm”,
                       “Effect”: “Allow”,
                       “Principal”: {
                               “AWS”: “*”
                               },
                       “Action”: “s3:GetObject”,
                       “Resource”: “arn:aws:s3:::<your-bucket-name>/<public-dir>/*”
                }
        ]
}