aws go amazon-s3 pre-signed-url

go - aws s3 get



¿Cómo hacer una carga POST pre-firmada a AWS S3 en Go? (3)

A primera vista, parece que POST funciona con una política y firma adjuntas, diseñada para cargas basadas en navegador. Consulte los documentos de AWS para obtener más detalles .

Específicamente, debe generar una política y firmarla , luego incluirla en el formulario HTML y, por lo tanto, la solicitud POST, junto con el resto de la información requerida. O deja que el navegador lo haga por ti.

En el caso de cargas POST de formularios HTML, solo está firmando la cadena de políticas. La URL final a publicar puede variar en función del contenido del formulario: https://bucket.s3.amazonaws.com/<depends-on-form-content> . Por lo tanto, no puede preseleccionar esa URL porque no sabe de qué se trata.

Esto es diferente a una URL firmada a la que PONE un archivo. Puede firmarlo porque conoce la URL completa: https://bucket.s3.amazonaws.com/known-key

Puede crear una solicitud POST con la política y los parámetros adecuados y cargarla a través de POST de esa manera. Sin embargo, deberá conocer el contenido del formulario para conocer la URL de antemano. En ese caso, también puede utilizar una URL PUT preestablecida.

Al menos así es como aparece de un vistazo ...

Me gustaría hacer un POST pre-firmado para subir archivos a un cubo AWS S3 . ¿Cómo se haría esto en Go?

Tenga en cuenta que esto no es lo mismo que la carga previamente firmada con PUT.


Entonces, para ayudar a otros, responderé la pregunta yo mismo y proporcionaré algún código para ayudar a otros que puedan tener el mismo problema.

Ejemplo de aplicación web para Google App Engine que representa un formulario POST pre-firmado aquí .

Y una pequeña biblioteca que creé haciendo el POST pre-firmado en Go .

En resumen, al hacer un POST prescrito a un cubo Amazon S3 de lectura pública, necesita:

1. Configure el cubo S3 para que solo permita la descarga pública.

Ejemplo de política de depósito que solo permite lectura pública.

{ "Version": "2012-10-17", "Id": "akjsdhakshfjlashdf", "Statement": [ { "Sid": "kjahsdkajhsdkjasda", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::BUCKETNAMEHERE/*" } ] }

2. Cree una política para HTTP POST que permita la carga.

AWS S3 documentos

Ejemplo de plantilla de política POST con vencimiento para cargar una clave específica, en un depósito específico y permitir el acceso de lectura pública.

{ "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. Genere y firme la política usando las credenciales del propietario del cubo S3.

AWS documentos

  • Complete los valores correctos de caducidad, depósito, clave, credenciales y fecha.
  • base64 codifica la política.
  • HMAC-SHA256 la política para obtener una firma.
  • hex codificar la firma.

4. Construya y PUBLIQUE los datos de formulario multiparte

AWS S3 documentos

Ahora bien, generaría un formulario HTML y obtendría automáticamente la solicitud de datos de formulario multiparte correcta como se describe en el enlace anterior.

Quería hacer esto a mano en Ir, así que aquí está cómo hacerlo.

De cualquier forma, debe proporcionar todas las partes que se especifican en la política POST que creó en los pasos 2 y 3. Tampoco puede tener campos adicionales en la solicitud, excepto los obligatorios (no en la política).

El orden de los campos también se especifica y todos ellos son campos multiparte en la solicitud 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 }


Aquí hay un enfoque alternativo de https://github.com/minio/minio-go que le puede interesar para obtener una forma programática completa de generar una política de publicación preestablecida.

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") }

Paso 1:

policy := minio.NewPostPolicy() policy.SetKey("myobject") policy.SetBucket("mybucket") policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days

Cree una nueva estructura de política, esta estructura de política implementa los siguientes métodos.

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

Paso 2:

m, err := s3Client.PresignedPostPolicy(policy) if err != nil { fmt.Println(err) return }

Ahora PresignedPostPolicy () toma la estructura PostPolicy y devuelve un mapa de "clave / valores" que se puede utilizar en su formulario HTML o curl para subir datos a s3.