title: golang: GET request for presigned url of S3 object with SSE fails with 403 error
body: <p>I'm getting 403 Forbidden HTTP response when I make a <code>GET</code> request to a presigned url generated by the AWS <code>Presign</code> method in Go. </p>
  
  <p>The error message is: </p>
  
  <blockquote>
    <p>The request signature we calculated does not match the signature you provided. Check your key and signing method</p>
  </blockquote>
  
  <p><code>X-Amz-SignedHeaders</code> is: <code>host;x-amz-server-side-encryption-customer-algorithm;x-amz-server-side-encryption-customer-key;x-amz-server-side-encryption-customer-key-md5</code></p>
  
  <p>I'm writing the object to S3 like this:</p>
  
  <pre class="lang-golang prettyprint-override"><code>type DocumentStore struct {
      bucketName               string
      bucketEncryptionKeyAlias string
      aws                      *session.Session
  }
  
  func (s *DocumentStore) PutDocument(ctx context.Context, envelope []byte, metadata map[string]string) (PutDocumentResult, error) {
      uploader := s3manager.NewUploader(s.aws)
  
      var objectKey = uuid.New().String()
  
      if _, err := uploader.UploadWithContext(ctx, &amp;s3manager.UploadInput{
          Bucket:               aws.String(s.bucketName),
          Key:                  aws.String(objectKey),
          ContentType:          aws.String("application/octet-stream"),
          Body:                 bytes.NewReader(envelope),
          ServerSideEncryption: aws.String(s3.ServerSideEncryptionAwsKms),
          SSEKMSKeyId:          aws.String(s.bucketEncryptionKeyAlias),
          Metadata:             aws.StringMap(metadata),
      }); err != nil {
          return PutDocumentResult{}, fmt.Errorf("put document failed on upload: %v", err.Error())
      }
  
      return PutDocumentResult{
          BucketName: s.bucketName,
          ObjectKey:  objectKey,
      }, nil
  }
  </code></pre>
  
  <p>I'm signing the url like this:</p>
  
  <pre class="lang-golang prettyprint-override"><code>func (s *DocumentStore) NewSignedGetURL(ctx context.Context, objectKey string, ttl time.Duration) (string, error) {
      svc := s3.New(s.aws)
  
      req, _ := svc.GetObjectRequest(&amp;s3.GetObjectInput{
          Bucket: aws.String(s.bucketName),
          Key: aws.String(objectKey),
          SSECustomerKey: aws.String(s.bucketEncryptionKeyAlias),
          SSECustomerAlgorithm: aws.String(s3.ServerSideEncryptionAwsKms),
      })
  
      url, err := req.Presign(ttl)
      if err != nil {
          return "", fmt.Errorf("failed to presign GetObjectRequest for key %q: %v", objectKey, err)
      }
  
      return url, nil
  }
  </code></pre>
  
  <p>And I'm calling the methods like this:</p>
  
  <pre class="lang-golang prettyprint-override"><code>result, err := target.PutDocument(context.TODO(), envelope, metadata)
  if err != nil {
      t.Errorf("PutDocument failed: %v", err)
      return
  }
  
  getURL, err := target.NewSignedGetURL(context.TODO(), result.ObjectKey, time.Minute*5)
  if err != nil {
      t.Errorf("failed to sign url: %v", err)
      return
  }
  
  req, _ := http.NewRequest("GET", getURL, nil)
  req.Header.Add("x-amz-server-side-encryption-customer-algorithm", s3.ServerSideEncryptionAwsKms)
  req.Header.Add("x-amz-server-side-encryption-customer-key", test.cfg.AWS.BucketKMSAlias)
  req.Header.Add("x-amz-server-side-encryption-customer-key-md5", "")
  
  resp, err := http.DefaultClient.Do(req.WithContext(context.TODO()))
  if err != nil {
      t.Errorf("failed to request object from signed url: %v", err)
      return
  }
  defer resp.Body.Close()
  
  data, err := ioutil.ReadAll(resp.Body)
  if err != nil {
      t.Errorf("failed to read object stream from S3: %v", err)
      return
  }
  
  if resp.StatusCode != http.StatusOK {
      t.Errorf("failed to get object. Http status: %s(%d)\n%s", resp.Status, resp.StatusCode, data)
      return
  }
  </code></pre>
  
  <p>I can read the download the file from the <code>aws cli</code> like this:</p>
  
  <pre><code>aws --profile dispatcher_stage --region us-east-1 s3 cp s3://[bucket-name]/0c/09179312-e283-431c-ab71-6a0c437177fe . --sse aws:kms --sse-kms-key-id alias/[key-alias-name]
  </code></pre>
  
  <p>What am I missing?</p>