ファイルを AWS S3 バケットにアップロードするために署名付き POST を実行したいのですが、これは Go でどのように行われますか?
これは、PUT を使用した署名済みアップロードとは異なることに注意してください。
ファイルを AWS S3 バケットにアップロードするために署名付き POST を実行したいのですが、これは Go でどのように行われますか?
これは、PUT を使用した署名済みアップロードとは異なることに注意してください。
したがって、他の人を助けるために、私は自分で質問に答え、同じ問題を抱えている可能性のある他の人を助けるためのコードを提供します.
署名済みの POST フォームをレンダリングする Google App Engine のサンプル Web アプリは、こちらにあります。
Goで署名済みの POST を実行するために作成した小さなライブラリ。
つまり、署名付き POST をパブリック読み取り Amazon S3 バケットに実行するには、次のことを行う必要があります。
1. パブリック ダウンロードのみを許可するように S3 バケットを構成します。
パブリック読み取りのみを許可するバケット ポリシーの例。
{
"Version": "2012-10-17",
"Id": "akjsdhakshfjlashdf",
"Statement": [
{
"Sid": "kjahsdkajhsdkjasda",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKETNAMEHERE/*"
}
]
}
2. アップロードを許可する HTTP POST のポリシーを作成します。
特定のキーを特定のバケットにアップロードし、パブリック読み取りアクセスを許可する有効期限付きの POST ポリシー テンプレートの例。
{ "expiration": "%s",
"conditions": [
{"bucket": "%s"},
["starts-with", "$key", "%s"],
{"acl": "public-read"},
{"x-amz-credential": "%s"},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-date": "%s" }
]
}
3. S3 バケット所有者の認証情報を使用してポリシーを生成し、署名します。
4. マルチパート フォーム データの構築と POST
上記のリンクで説明されているように、HTML フォームを生成し、正しいマルチパート フォーム データ リクエストを自動的に取得します。
Goでこれを手動でやりたかったので、その方法を次に示します。
どちらの方法でも、ステップ 2 と 3 で作成した POST ポリシーで指定されているすべての部分を提供する必要があります。必須フィールド (ポリシーにないもの) を除いて、リクエストに追加フィールドを含めることもできません。
フィールドの順序も指定されており、それらはすべて HTTP POST 要求のマルチパート フィールドです。
func Upload(url string, fields Fields) error {
var b bytes.Buffer
w := multipart.NewWriter(&b)
for _, f := range fields {
fw, err := w.CreateFormField(f.Key)
if err != nil {
return err
}
if _, err := fw.Write([]byte(f.Value)); err != nil {
return err
}
}
w.Close()
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return err
}
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return err
}
if res.StatusCode != http.StatusOK {
err = fmt.Errorf("bad status: %s", res.Status)
}
return nil
}
これは、 https://github.com/minio/minio-goからの別のアプローチであり、 署名付きの投稿ポリシーを生成する完全なプログラムによる方法が必要な場合があります。
package main
import (
"fmt"
"log"
"time"
"github.com/minio/minio-go"
)
func main() {
policy := minio.NewPostPolicy()
policy.SetKey("myobject")
policy.SetBucket("mybucket")
policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
config := minio.Config{
AccessKeyID: "YOUR-ACCESS-KEY-HERE",
SecretAccessKey: "YOUR-PASSWORD-HERE",
Endpoint: "https://s3.amazonaws.com",
}
s3Client, err := minio.New(config)
if err != nil {
log.Fatalln(err)
}
m, err := s3Client.PresignedPostPolicy(policy)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("curl ")
for k, v := range m {
fmt.Printf("-F %s=%s ", k, v)
}
fmt.Printf("-F file=@/etc/bashrc ")
fmt.Printf(config.Endpoint + "/mybucket\n")
}
ステップ1:
policy := minio.NewPostPolicy()
policy.SetKey("myobject")
policy.SetBucket("mybucket")
policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
新しいポリシー構造をインスタンス化します。このポリシー構造は次のメソッドを実装します。
func NewPostPolicy() *PostPolicy
func (p *PostPolicy) SetBucket(bucket string) error
func (p *PostPolicy) SetContentLength(min, max int) error
func (p *PostPolicy) SetContentType(contentType string) error
func (p *PostPolicy) SetExpires(t time.Time) error
func (p *PostPolicy) SetKey(key string) error
func (p *PostPolicy) SetKeyStartsWith(keyStartsWith string) error
func (p PostPolicy) String() string
ステップ2:
m, err := s3Client.PresignedPostPolicy(policy)
if err != nil {
fmt.Println(err)
return
}
PresignedPostPolicy() はPostPolicy
構造を取得し、HTML フォームまたは curl コマンドで使用してデータを s3 にアップロードできる「キー/値」のマップを返します。
一見すると、ブラウザベースのアップロード用に設計されたポリシーと署名が添付された状態で POST が動作するように見えます。詳細については、AWS ドキュメントを参照してください。
具体的には、ポリシーを生成して署名する必要があります。次に、それらを HTML フォームに含め、それによって POST 要求に、残りの必要な情報を含めます。または、ブラウザに任せてください。
HTML フォームの POST アップロードの場合、ポリシー文字列に署名するだけです。投稿される最終的な URL は、フォームの内容によって異なります: https://bucket.s3.amazonaws.com/<depends-on-form-content>
. そのため、その URL が何であるかわからないため、その URL に署名することはできません。
これは、ファイルを PUT する署名付き URL とは異なります。完全な URL を知っているため、署名できます。https://bucket.s3.amazonaws.com/known-key
適切なポリシーとパラメータを使用して POST リクエストを作成し、その方法で POST 経由でアップロードできます。ただし、事前に URL を知るには、フォームの内容を知っておく必要があります。その場合、署名付きの PUT URL を使用することもできます。
少なくとも、一見するとそう見えます...