Upload pliku i generowanie presigned URL dla S3

Budujesz system w którym potrzebujesz upload plików i jednocześnie chcesz, aby można było ten plik pobrać? Na ratunek przychodzi AWS S3 oraz generowanie presigned URL. W poniższym artykule na prostym przykładzie, pokaże jak przy pomocy python zrobić upload i od razu wygenerować link do pobrania pliku.W pierwszej kolejności musimy mieć skonfigurowane AWS CLI lokalnie, w tym celu odsyłam do dokumetacji AWS https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html

1. Tworzenie bucketu S3

Pierwszą rzeczą, którą musimy zrobić jest utworzenie bucketu S3, który będzie prywatny, ponieważ nie chcemy, aby ktoś z zewnątrz, poza aplikacją, mógł wygrywać sobie i pobierać co chce. Bucket tworzymy poniższym poleceniem

aws s3 mb s3://learning-bucket-for-devops

W odpowiedzi powinniśmy otrzymać

make_bucket: learning-bucket-for-devops

Oczywiście nazwa bucketu jest dowolna, nie musi być taka jak moja 🙂 Przy pomocy polecenia aws s3 ls możemy sobie sprawdzić, czy nasz bucket jest widoczny na liście.

2. Tworzenie skryptu python

Mamy bucket, czas na utworzenie skryptu, nazwijmy go np. app.py i wklejmy do niego poniższy kod

import boto3
import os
from botocore.exceptions import ClientError

bucket_name = "learning-bucket-for-devops"
file_name = "sample.pdf"
object_name = os.path.basename(file_name)

try:
    s3_client = boto3.client('s3',
                             config=boto3.session.Config(s3={'addressing_style': 'path'}, signature_version='s3v4'))
    s3_client.upload_file(file_name, bucket_name, object_name)
    presigned_url = s3_client.generate_presigned_url('get_object',
                                                     Params={
                                                         'Bucket': bucket_name,
                                                         'Key': object_name
                                                     })
    print(presigned_url)
except ClientError as e:
    print(e)

bucket_name – wstawiamy tutaj nazwę naszego bucketu, którą podaliśmy podczas jego tworzenia
file_name – wstawiamy nazwę pliku, który mamy lokalnie obok naszego skryptu, w moim wypadku jest to prosty plik pdf, pobrany z internetu

Powyższy skrypt jest bardzo prosty, ma zrobić upload na S3 wybranego pliku oraz wygenerować dla niego presigned URL, abyśmy mogli go zobaczyć/pobrać tylko za pomocą wygenerowanego linku. Oczywiście, można zbudować sobie REST API z wykorzystaniem API Gateway + Lambdą, która przyjmie plik z formularza, zapisze go na S3 i wygeneruje link, ale może opiszę to w innym artykule, w tym chciałem pokazać jak w prosty sposób, można wgrać plik na S3 i bez robienia go publicznym, pobrać plik.

Wykorzystanie S3 presigned URL to nie jedyne rozwiązanie, aby udostępnić pliki z prywatnego bucketu na zewnątrz, można również wykorzystać CloudFront + OAI lub OAC, ale w tym celu odsyłam do dokumentacji AWS https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

W każdym razie polecam zapoznać się z CloudFront i możliwościami tej usługi 🙂

Wracając do naszego skryptu, odpalmy go przy pomocy polecenia

python3 app.py

W odpowiedzi powinniśmy dostać presigned URL do naszego pliku, jeżeli coś poszło nie tak, to dostaniemy informacje odnośnie błędu. W moim wypadku wyglądał on tak

https://s3.eu-central-1.amazonaws.com/learning-bucket-for-devops/sample.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASSTMFYGKJJDCTGKN%2F20230323%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20230323T085341Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=e48721d09dc0bd0c25f0cdca371bcc3a9734c34be9fc03ce82022bf22c5fbb08

W momencie publikacji tego artykułu, link już nie będzie działał 🙂

3. Presigned URL

Presigned URL możemy wykorzystać do udostępniania plików, bez nadawania uprawnień do bucketu, możemy również wykorzystać go do generowania specjalnych linków do uploadu plików, dzięki czemu, nie wystawiamy bucketu na świat, co za tym idzie mamy wyższy poziom bezpieczeństwa, niż w przypadku kiedy wystawiamy bucket na świat.

W przypadku mojego skryptu nie podaliśmy czasu, po jakim ma wygasnąć link, domyślnie jest to 3600 sekund, ale jeżeli chcemy zmienić ten czas, wystarczy dodać parametr ExpiresIn, jak na poniższym przykładzie

    presigned_url = s3_client.generate_presigned_url('get_object',
                                                     Params={
                                                         'Bucket': bucket_name,
                                                         'Key': object_name
                                                     },
                                                     ExpiresIn=5000)

I to na tyle w tym artykule, mam nadzieję, że zachęciłem chociaż kilka osób, do wykorzystania S3 oraz presigned URL w swoich projektach 🙂

Related Posts