2019-10-20 18:51:09 +02:00
|
|
|
.. Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
|
|
|
|
|
|
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0
|
|
|
|
International License (the "License"). You may not use this file except in compliance with the
|
|
|
|
License. A copy of the License is located at http://creativecommons.org/licenses/by-nc-sa/4.0/.
|
|
|
|
|
|
|
|
This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
|
|
either express or implied. See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
|
|
|
|
##############
|
|
|
|
Presigned URLs
|
|
|
|
##############
|
|
|
|
|
|
|
|
A user who does not have AWS credentials or permission to access an S3 object
|
|
|
|
can be granted temporary access by using a presigned URL.
|
|
|
|
|
|
|
|
A presigned URL is generated by an AWS user who has access to the object. The
|
|
|
|
generated URL is then given to the unauthorized user. The presigned URL can be
|
|
|
|
entered in a browser or used by a program or HTML webpage. The credentials
|
|
|
|
used by the presigned URL are those of the AWS user who generated the URL.
|
|
|
|
|
|
|
|
A presigned URL remains valid for a limited period of time which is specified
|
|
|
|
when the URL is generated.
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import boto3
|
|
|
|
from botocore.exceptions import ClientError
|
|
|
|
|
|
|
|
|
|
|
|
def create_presigned_url(bucket_name, object_name, expiration=3600):
|
|
|
|
"""Generate a presigned URL to share an S3 object
|
|
|
|
|
|
|
|
:param bucket_name: string
|
|
|
|
:param object_name: string
|
|
|
|
:param expiration: Time in seconds for the presigned URL to remain valid
|
|
|
|
:return: Presigned URL as string. If error, returns None.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Generate a presigned URL for the S3 object
|
|
|
|
s3_client = boto3.client('s3')
|
|
|
|
try:
|
|
|
|
response = s3_client.generate_presigned_url('get_object',
|
|
|
|
Params={'Bucket': bucket_name,
|
|
|
|
'Key': object_name},
|
|
|
|
ExpiresIn=expiration)
|
|
|
|
except ClientError as e:
|
|
|
|
logging.error(e)
|
|
|
|
return None
|
|
|
|
|
|
|
|
# The response contains the presigned URL
|
|
|
|
return response
|
|
|
|
|
|
|
|
The user can download the S3 object by entering the presigned URL in a browser.
|
|
|
|
A program or HTML page can download the S3 object by using the presigned URL
|
|
|
|
as part of an HTTP GET request.
|
|
|
|
|
|
|
|
The following code demonstrates using the Python ``requests`` package to
|
|
|
|
perform a GET request.
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import requests # To install: pip install requests
|
|
|
|
|
|
|
|
url = create_presigned_url('BUCKET_NAME', 'OBJECT_NAME')
|
|
|
|
if url is not None:
|
|
|
|
response = requests.get(url)
|
|
|
|
|
|
|
|
|
2021-09-22 18:34:33 +02:00
|
|
|
Using presigned URLs to perform other S3 operations
|
2019-10-20 18:51:09 +02:00
|
|
|
===================================================
|
|
|
|
|
|
|
|
The main purpose of presigned URLs is to grant a user temporary access to an
|
|
|
|
S3 object. However, presigned URLs can be used to grant permission to perform
|
|
|
|
additional operations on S3 buckets and objects.
|
|
|
|
|
|
|
|
The ``create_presigned_url_expanded`` method shown below generates a presigned
|
|
|
|
URL to perform a specified S3 operation. The method accepts the name of the S3
|
|
|
|
``Client`` method to perform, such as 'list_buckets' or 'get_bucket_location.'
|
|
|
|
The parameters to pass to the method are specified in the
|
|
|
|
``method_parameters`` dictionary argument. The HTTP method to use (GET, PUT,
|
|
|
|
etc.) can be specified, but the AWS SDK for Python will automatically select
|
|
|
|
the appropriate method so this argument is not normally required.
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import boto3
|
|
|
|
from botocore.exceptions import ClientError
|
|
|
|
|
|
|
|
|
|
|
|
def create_presigned_url_expanded(client_method_name, method_parameters=None,
|
|
|
|
expiration=3600, http_method=None):
|
|
|
|
"""Generate a presigned URL to invoke an S3.Client method
|
|
|
|
|
|
|
|
Not all the client methods provided in the AWS Python SDK are supported.
|
|
|
|
|
|
|
|
:param client_method_name: Name of the S3.Client method, e.g., 'list_buckets'
|
|
|
|
:param method_parameters: Dictionary of parameters to send to the method
|
|
|
|
:param expiration: Time in seconds for the presigned URL to remain valid
|
|
|
|
:param http_method: HTTP method to use (GET, etc.)
|
|
|
|
:return: Presigned URL as string. If error, returns None.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Generate a presigned URL for the S3 client method
|
|
|
|
s3_client = boto3.client('s3')
|
|
|
|
try:
|
|
|
|
response = s3_client.generate_presigned_url(ClientMethod=client_method_name,
|
|
|
|
Params=method_parameters,
|
|
|
|
ExpiresIn=expiration,
|
|
|
|
HttpMethod=http_method)
|
|
|
|
except ClientError as e:
|
|
|
|
logging.error(e)
|
|
|
|
return None
|
|
|
|
|
|
|
|
# The response contains the presigned URL
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2021-09-22 18:34:33 +02:00
|
|
|
Generating a presigned URL to upload a file
|
2019-10-20 18:51:09 +02:00
|
|
|
===========================================
|
|
|
|
|
|
|
|
A user who does not have AWS credentials to upload a file can use a
|
|
|
|
presigned URL to perform the upload. The upload operation makes an HTTP POST
|
|
|
|
request and requires additional parameters to be sent as part of the request.
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import boto3
|
|
|
|
from botocore.exceptions import ClientError
|
|
|
|
|
|
|
|
|
|
|
|
def create_presigned_post(bucket_name, object_name,
|
|
|
|
fields=None, conditions=None, expiration=3600):
|
|
|
|
"""Generate a presigned URL S3 POST request to upload a file
|
|
|
|
|
|
|
|
:param bucket_name: string
|
|
|
|
:param object_name: string
|
|
|
|
:param fields: Dictionary of prefilled form fields
|
|
|
|
:param conditions: List of conditions to include in the policy
|
|
|
|
:param expiration: Time in seconds for the presigned URL to remain valid
|
|
|
|
:return: Dictionary with the following keys:
|
|
|
|
url: URL to post to
|
|
|
|
fields: Dictionary of form fields and values to submit with the POST
|
|
|
|
:return: None if error.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Generate a presigned S3 POST URL
|
|
|
|
s3_client = boto3.client('s3')
|
|
|
|
try:
|
|
|
|
response = s3_client.generate_presigned_post(bucket_name,
|
|
|
|
object_name,
|
|
|
|
Fields=fields,
|
|
|
|
Conditions=conditions,
|
|
|
|
ExpiresIn=expiration)
|
|
|
|
except ClientError as e:
|
|
|
|
logging.error(e)
|
|
|
|
return None
|
|
|
|
|
|
|
|
# The response contains the presigned URL and required fields
|
|
|
|
return response
|
|
|
|
|
|
|
|
The generated presigned URL includes both a URL and additional fields that
|
|
|
|
must be passed as part of the subsequent HTTP POST request.
|
|
|
|
|
|
|
|
The following code demonstrates how to use the ``requests`` package with a
|
|
|
|
presigned POST URL to perform a POST request to upload a file to S3.
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import requests # To install: pip install requests
|
|
|
|
|
|
|
|
# Generate a presigned S3 POST URL
|
|
|
|
object_name = 'OBJECT_NAME'
|
|
|
|
response = create_presigned_post('BUCKET_NAME', object_name)
|
|
|
|
if response is None:
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
# Demonstrate how another Python program can use the presigned URL to upload a file
|
|
|
|
with open(object_name, 'rb') as f:
|
|
|
|
files = {'file': (object_name, f)}
|
|
|
|
http_response = requests.post(response['url'], data=response['fields'], files=files)
|
|
|
|
# If successful, returns HTTP status code 204
|
|
|
|
logging.info(f'File upload HTTP status code: {http_response.status_code}')
|
|
|
|
|
|
|
|
The presigned POST URL and fields values can also be used in an HTML page.
|
|
|
|
|
|
|
|
.. code-block:: html
|
|
|
|
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<!-- Copy the 'url' value returned by S3Client.generate_presigned_post() -->
|
|
|
|
<form action="URL_VALUE" method="post" enctype="multipart/form-data">
|
|
|
|
<!-- Copy the 'fields' key:values returned by S3Client.generate_presigned_post() -->
|
|
|
|
<input type="hidden" name="key" value="VALUE" />
|
|
|
|
<input type="hidden" name="AWSAccessKeyId" value="VALUE" />
|
|
|
|
<input type="hidden" name="policy" value="VALUE" />
|
|
|
|
<input type="hidden" name="signature" value="VALUE" />
|
|
|
|
File:
|
|
|
|
<input type="file" name="file" /> <br />
|
|
|
|
<input type="submit" name="submit" value="Upload to Amazon S3" />
|
|
|
|
</form>
|
|
|
|
</body>
|
|
|
|
</html>
|