2

I've followed the go-cloud tutorial and I've managed to write a file to my S3 bucket.

But how do I set ACL: s3.ObjectCannedACLPublicRead aka public-read aka work readable permissions on that object?!

My workaround is sadly to set a public bucket policy for my gocloud.dev/blob/s3blob based project.

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
hendry
  • 9,725
  • 18
  • 81
  • 139

3 Answers3

3

It looks like the library expects anything inconsistent between providers to be provided as BeforeWrite callbacks:

opts := &blob.WriterOptions{}
opts.BeforeWrite(func(i interface{}) bool {
    p, ok := i.(*s3manager.UploadInput)
    if !ok {
        return false
    }
    p.ACL = aws.String("public-read")
    return true
})

w, err := b.NewWriter(ctx, "feeds/index.html", opts)

Warning: I totally didn't test this code, but it fmt'd, so it should work?

I will warn you, it seems this library is in alpha, for these types of reasons. Relying on this kind of work around is going to cause you issues trying to reuse it for all cloud providers. Ultimately, I suggest just implementing the functionality you'd like using the provided SDKs, and leveraging the Factory/Adapter pattern to retrieve the right adapter for a given call.

syntaqx
  • 2,636
  • 23
  • 29
  • I know it's possible with the aws-sdk-go. I'm trying to achieve this with "Portable Cloud Programming with Go Cloud". – hendry Jan 10 '19 at 09:02
  • My mistake. I've updated my answer to leverage the library you're asking. If this works for what you're trying to do, please "✔ Accept" this answer - Otherwise, let me know what I can do to help. – syntaqx Jan 10 '19 at 09:28
2

Setting the ACL at the bucket/container level is probably the right thing to do. Setting per-blob ACLs may be difficult to manage effectively. It is possible on some blob storage providers (AWS S3, GCS) but not others (Azure), so Go Cloud hasn't added support for it. Additionally, all 3 providers (and Go Cloud) support "signed URL" functionality, where you as an owner of the resource can create a URL that provides public read access to it for a limited period of time.

1

anything inconsistent between providers to be provided as BeforeWrite as @syntaqx said.

b, err := s3blob.OpenBucket(ctx, bucket, s, nil)
    if err != nil {
        return
    }
    before := func(asFunc func(interface{}) bool) error {
        req := &s3manager.UploadInput{}
        ok := asFunc(&req)
        if !ok {
            return errors.New("invalid s3 type")
        }
        req.ACL = aws.String(acl)
        return nil
    }
    w, err := b.NewWriter(ctx, appendTime(fileName), &blob.WriterOptions{
        ContentType: forceContentTypeByExtension(fileName),
        BeforeWrite: before,
    })