Sign S3 upload policy using Instance Profile crede

2019-06-25 14:36发布

问题:

I'm putting together a drag & drop interface for file uploads to go directly to S3. My workflow is something like this:

  1. Upon drop I make an AJAX request to the server,
  2. The server generates and signs an S3 upload policy,
  3. The client side completes the upload.

Signing the policy is done with the secret key, as described in this article. However, I'm facing the following problems:

  1. I can obviously do Aws::getConfig() and fish out the secret key from there, but that doesn't seem to be a very clean approach.

  2. When deployed on EC2, I won't have access to the secret key at all, because I'm using instance roles so that I don't have to store my credentials on the server itself.

In both cases I could circumvent the SDK and do it manually, so the question really is: can this be done with the SDK, and if so, how?

回答1:

It turns out that this just needed some digging around in the API. The credentials can be pulled from any of the clients that you instantiate via Aws\Common\Aws::get().

// create builder; not passing credentials here
$aws = Aws\Common\Aws::factory(array(
    'region' => 'us-east-1',
));
$s3 = $aws->get('s3');
// get credentials interface
$credentials = $s3->getCredentials();

To sign the policy string you need an instance of S3Signature. According to the documentation for AbstractClient::getSignature() it would seem that you can't obtain this from S3Client, but judging from this part of the code it seems that you can.

The last step is to call the ::signString() method to generate the signature:

$policy = base64_encode(json_encode($policy_data));
$signer = $s3->getSignature();
$signature = $signer->signString($policy, $credentials);

Internally $credentials->getSecretKey() is called, which loads the necessary credentials from the meta data service when necessary; otherwise it uses the credentials that are passed to Aws::factory().

Update

It's also possible to do this without any clients:

$credentials = Aws\Common\Credentials\Credentials::factory();
$signer = new S3Signature();

$signature = $signer->signString($policy, $credentials);