Utilisation d'Amazon S3 Object Lambda pour filigraner dynamiquement des images à mesure de leur extraction
DIDACTICIEL
Présentation
Amazon S3 Object Lambda vous permet d'intégrer votre propre code aux requêtes S3 GET, HEAD et LIST, afin de modifier les données à mesure de leur renvoi vers une application. Vous pouvez utiliser un code personnalisé pour modifier les données renvoyées par les requêtes S3 GET afin de convertir les formats de données (de XML à JSON, par exemple), de redimensionner de façon dynamique des images, de supprimer les données confidentielles et plus encore. Vous pouvez également utiliser S3 Object Lambda pour modifier le résultat des requêtes S3 LIST afin de créer une vue personnalisée des objets d'un compartiment, et les requêtes S3 HEAD pour modifier les métadonnées d'objets telles que leur nom et leur taille.
L'objectif de ce didacticiel est de vous montrer comment démarrer avec Amazon S3 Object Lambda. De nombreuses organisations stockent dans Amazon S3 des images auxquelles différentes applications accèdent, chacune ayant des exigences uniques de format de données. Dans certains cas, vous devrez peut-être modifier les images pour y inclure un filigrane en fonction du statut de l'utilisateur (par exemple, un abonné payant peut voir des images sans filigrane, tandis qu'un utilisateur non payant voit des images filigranées).
Dans ce didacticiel, nous utiliserons S3 Object Lambda pour ajouter un filigrane à une image lors de son extraction d'Amazon S3. S3 Object Lambda peut être utilisé pour modifier les données à mesure de leur extraction d'Amazon S3, et ce, sans en conserver plusieurs copies dérivées ni modifier l'objet existant. La présentation de multiples vues des mêmes données et l'élimination du besoin de stocker des copies dérivées permettent d'économiser sur les coûts de stockage.
Votre projet
Dans ce tutoriel, vous allez :
- créer un compartiment Amazon S3
- créer un point d'accès S3
- créer une fonction AWS Lambda pour modifier les images
- créer un point d'accès S3 Object Lambda
Conditions préalables
Pour suivre ce didacticiel, vous devez disposer d'un compte AWS. Accédez à cette page de support pour plus d'informations sur la création et l'activation d'un nouveau compte AWS.
Vous pouvez créer un utilisateur IAM dans le cadre du didacticiel ou ajouter des autorisations à un utilisateur IAM existant. Pour suivre ce didacticiel, votre utilisateur IAM doit avoir les autorisations suivantes pour accéder aux ressources AWS pertinentes et effectuer des actions spécifiques :
- s3:CreateBucket
- s3:PutObject
- s3:GetObject
- s3:ListBucket
- s3:CreateAccessPoint
- s3:CreateAccessPointForObjectLambda
- s3-object-lambda:WriteGetObjectResponse
- lambda:CreateFunction
- lambda:InvokeFunction
- iam:AttachRolePolicy
- iam:CreateRole
- iam:PutRolePolicy
Pour nettoyer les ressources que vous créez dans le cadre de ce didacticiel, vous aurez besoin des autorisations IAM suivantes :
- s3:DeleteBucket
- s3:DeleteAccessPoint
- s3:DeleteAccessPointForObjectLambda
- lambda:DeleteFunction
- iam:DeleteRole
Expérience en matière d'utilisation des services AWS
Durée
20 minutes
Coût
Moins de 1 USD (page de tarification Amazon S3)
Éléments requis
Compte AWS*
* Les comptes créés au cours des dernières 24 heures peuvent ne pas encore avoir accès aux ressources requises dans le cadre de ce didacticiel.
Services utilisés
Date de la dernière mise à jour
1er février 2023
Conditions préalables
Pour suivre ce didacticiel, vous devez disposer d'un compte AWS. Accédez à cette page de support pour plus d'informations sur la création et l'activation d'un nouveau compte AWS.
Vous pouvez créer un utilisateur IAM dans le cadre du didacticiel ou ajouter des autorisations à un utilisateur IAM existant. Pour suivre ce didacticiel, votre utilisateur IAM doit avoir les autorisations suivantes pour accéder aux ressources AWS pertinentes et effectuer des actions spécifiques :
-
Autorisations requises
- s3:CreateBucket
- s3:PutObject
- s3:GetObject
- s3:ListBucket
- s3:CreateAccessPoint
- s3:CreateAccessPointForObjectLambda
- s3-object-lambda:WriteGetObjectResponse
- lambda:CreateFunction
- lambda:InvokeFunction
- iam:AttachRolePolicy
- iam:CreateRole
- iam:PutRolePolicy
-
Autorisations requises
Pour nettoyer les ressources que vous créez dans le cadre de ce didacticiel, vous aurez besoin des autorisations IAM suivantes :
- s3:DeleteBucket
- s3:DeleteAccessPoint
- s3:DeleteAccessPointForObjectLambda
- lambda:DeleteFunction
- iam:DeleteRole
Implémentation
Étape 1 : Créer un compartiment Amazon S3
1.1 – Se connecter à la console Amazon S3
- Connectez-vous à la console de gestion AWS et ouvrez la console Amazon S3.
1.2 – Créer un compartiment S3
- Sélectionnez Buckets (Compartiments) dans le volet de navigation de gauche du menu Amazon S3, puis choisissez le bouton Create bucket (Créer un compartiment).
1.3 –
- Dans le champ Bucket name (Nom du compartiment), saisissez un nom descriptif et unique au niveau mondial pour votre compartiment. Sélectionnez la région AWS dans laquelle vous souhaitez que votre compartiment soit créé. Plus tard dans ce didacticiel, nous allons créer une autre ressource qui doit résider dans la même région AWS.
- Vous pouvez laisser les options restantes avec leurs sélections par défaut. Accédez au bas de la page et choisissez Create bucket (Créer un compartiment).
Étape 2 : Charger un objet
2.1 – Charger un objet
- Dans la liste des compartiments disponibles, sélectionnez le nom du compartiment que vous venez de créer.
2.2 –
- Ensuite, assurez-vous que l'onglet Objects (Objets) est sélectionné. Puis, dans la section Objects (Objets), choisissez le bouton Upload (Charger).
2.3 – Ajouter des fichiers
- Choisissez le bouton Add files (Ajouter des fichiers), puis sélectionnez l'image que vous souhaitez charger depuis votre navigateur de fichiers.
- Si vous le souhaitez, vous pouvez charger cet exemple d'image.
2.4 – Charger
- Accédez au bas de la page et choisissez le bouton Upload (Charger).
2.5 –
- Une fois le chargement terminé avec succès, choisissez le bouton Close (Fermer).
Étape 3 : Créer un point d'accès S3
Créez un point d'accès Amazon S3 qui sera utilisé pour prendre en charge le point d'accès S3 Object Lambda, que nous allons créer plus tard dans le didacticiel.
3.1– Créer un point d'accès S3
- Accédez à la console S3 et sélectionnez l'option de menu Access Points (Points d'accès) dans le volet de navigation de gauche. Choisissez ensuite le bouton Create access point (Créer un point d'accès).
3.2 –
- Dans la section Properties (Propriétés), saisissez le nom du point d'accès souhaité, puis choisissez le nom du compartiment que vous avez saisi à l'étape 1 en sélectionnant le bouton Browse S3 (Parcourir S3). Ensuite, définissez Network origin (Origine du réseau) sur Internet.
3.3 –
- Conservez toutes les autres valeurs par défaut telles quelles. Accédez au bas de la page et choisissez le bouton Create access point (Créer un point d'accès).
3.4 –
- Le point d'accès S3 apparaît désormais dans la liste lorsque vous accédez à Access Points (Points d'accès) dans le volet de navigation de gauche.
Étape 4 : Créer la fonction Lambda
- Créez ensuite une fonction Lambda qui sera invoquée lors de l'envoi de requêtes S3 GET via un point d'accès S3 Object Lambda.
- Nous utiliserons AWS CloudShell depuis la console de gestion AWS pour créer et tester S3 Object Lambda. Vous pouvez utiliser votre propre ordinateur ou une instance AWS Cloud9 pour créer la solution, à condition de satisfaire aux exigences suivantes :
– Dernière version de l'interface de la ligne de commande (CLI) AWS
– Informations d'identification pour créer des fonctions/couches AWS Lambda et un rôle IAM
– Python 3.9
– Utilitaire zip
– Utilitaire jq
4.1 – Démarrer un terminal CloudShell
Sélectionnez l'icône CloudShell dans le menu situé dans le coin supérieur droit de la console de gestion AWS.
Si une fenêtre d'introduction à CloudShell apparaît, lisez-en le contenu et choisissez Close (Fermer).
Un nouvel onglet de navigateur s'ouvre avec le terminal CloudShell (similaire à la capture d'écran suivante) :
4.2 – Préparer CloudShell pour déployer la fonction Lambda
- Exécutez le code suivant dans CloudShell afin de préparer l'environnement et de déployer la couche Lambda avec le module Pillow. Copiez et collez le code suivant dans CloudShell pour installer les dépendances requises et déployer la fonction Lambda.
# Install the required libraries to build new python
sudo yum install gcc openssl-devel bzip2-devel libffi-devel -y
# Install Pyenv
curl https://pyenv.run | bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
# Install Python version 3.9
pyenv install 3.9.13
pyenv global 3.9.13
# Build the pillow Lambda layer
mkdir python
cd python
pip install pillow -t .
cd ..
zip -r9 pillow.zip python/
aws lambda publish-layer-version \
--layer-name Pillow \
--description "Python Image Library" \
--license-info "HPND" \
--zip-file fileb://pillow.zip \
--compatible-runtimes python3.9
Remarque : Lorsque vous copiez et collez du code, CloudShell ouvre une fenêtre d'avertissement pour vous permettre de confirmer le collage du code multiligne. Sélectionnez Paste (Coller).
Cette étape peut prendre 10 à 15 minutes.
4.3 – Créer la fonction Lambda
- Téléchargez une police TrueType à utiliser par la fonction Lambda pour ajouter un filigrane à une image. Copiez et collez les commandes suivantes dans CloudShell.
wget https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/branding/Amazon_Typefaces_Complete_Font_Set_Mar2020.zip
- Extrayez la police TrueType à utiliser pour écrire le texte en filigrane dans l'image.
unzip -oj Amazon_Typefaces_Complete_Font_Set_Mar2020.zip "Amazon_Typefaces_Complete_Font_Set_Mar2020/Ember/AmazonEmber_Rg.ttf"
- Créez le code Lambda à utiliser pour traiter les requêtes S3 Object Lambda.
cat << EOF > lambda.py
import boto3
import json
import os
import logging
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from urllib import request
from urllib.parse import urlparse, parse_qs, unquote
from urllib.error import HTTPError
from typing import Optional
logger = logging.getLogger('S3-img-processing')
logger.addHandler(logging.StreamHandler())
logger.setLevel(getattr(logging, os.getenv('LOG_LEVEL', 'INFO')))
FILE_EXT = {
'JPEG': ['.jpg', '.jpeg'],
'PNG': ['.png'],
'TIFF': ['.tif']
}
OPACITY = 64 # 0 = transparent and 255 = full solid
def get_img_encoding(file_ext: str) -> Optional[str]:
result = None
for key, value in FILE_EXT.items():
if file_ext in value:
result = key
break
return result
def add_watermark(img: Image, text: str) -> Image:
font = ImageFont.truetype("AmazonEmber_Rg.ttf", 82)
txt = Image.new('RGBA', img.size, (255, 255, 255, 0))
if img.mode != 'RGBA':
image = img.convert('RGBA')
else:
image = img
d = ImageDraw.Draw(txt)
# Positioning Text
width, height = image.size
text_width, text_height = d.textsize(text, font)
x = width / 2 - text_width / 2
y = height / 2 - text_height / 2
# Applying Text
d.text((x, y), text, fill=(255, 255, 255, OPACITY), font=font)
# Combining Original Image with Text and Saving
watermarked = Image.alpha_composite(image, txt)
return watermarked
def handler(event, context) -> dict:
logger.debug(json.dumps(event))
object_context = event["getObjectContext"]
# Get the presigned URL to fetch the requested original object
# from S3
s3_url = object_context["inputS3Url"]
# Extract the route and request token from the input context
request_route = object_context["outputRoute"]
request_token = object_context["outputToken"]
parsed_url = urlparse(event['userRequest']['url'])
object_key = parsed_url.path
logger.info(f'Object to retrieve: {object_key}')
parsed_qs = parse_qs(parsed_url.query)
for k, v in parsed_qs.items():
parsed_qs[k][0] = unquote(v[0])
filename = os.path.splitext(os.path.basename(object_key))
# Get the original S3 object using the presigned URL
req = request.Request(s3_url)
try:
response = request.urlopen(req)
except HTTPError as e:
logger.info(f'Error downloading the object. Error code: {e.code}')
logger.exception(e.read())
return {'status_code': e.code}
if encoding := get_img_encoding(filename[1].lower()):
logger.info(f'Compatible Image format found! Processing image: {"".join(filename)}')
img = Image.open(response)
logger.debug(f'Image format: {img.format}')
logger.debug(f'Image mode: {img.mode}')
logger.debug(f'Image Width: {img.width}')
logger.debug(f'Image Height: {img.height}')
img_result = add_watermark(img, parsed_qs.get('X-Amz-watermark', ['Watermark'])[0])
img_bytes = BytesIO()
if img.mode != 'RGBA':
# Watermark added an Alpha channel that is not compatible with JPEG. We need to convert to RGB to save
img_result = img_result.convert('RGB')
img_result.save(img_bytes, format='JPEG')
else:
# Will use the original image format (PNG, GIF, TIFF, etc.)
img_result.save(img_bytes, encoding)
img_bytes.seek(0)
transformed_object = img_bytes.read()
else:
logger.info(f'File format not compatible. Bypass file: {"".join(filename)}')
transformed_object = response.read()
# Write object back to S3 Object Lambda
s3 = boto3.client('s3')
# The WriteGetObjectResponse API sends the transformed data
if os.getenv('AWS_EXECUTION_ENV'):
s3.write_get_object_response(
Body=transformed_object,
RequestRoute=request_route,
RequestToken=request_token)
else:
# Running in a local environment. Saving the file locally
with open(f'myImage{filename[1]}', 'wb') as f:
logger.debug(f'Writing file: myImage{filename[1]} to the local filesystem')
f.write(transformed_object)
# Exit the Lambda function: return the status code
return {'status_code': 200}
EOF
- Créez le fichier zip Lambda qui contient le code Python et le fichier de police TrueType.
zip -r9 lambda.zip lambda.py AmazonEmber_Rg.ttf
- Créez le rôle IAM qui s'attache à la fonction Lambda.
aws iam create-role --role-name ol-lambda-images --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
- Associez une politique IAM prédéfinie au rôle IAM créé précédemment. Cette politique contient les autorisations minimales requises pour exécuter la fonction Lambda.
aws iam attach-role-policy --role-name ol-lambda-images --policy-arn arn:aws:iam::aws:policy/service-role/AmazonS3ObjectLambdaExecutionRolePolicy
export OL_LAMBDA_ROLE=$(aws iam get-role --role-name ol-lambda-images | jq -r .Role.Arn)
export LAMBDA_LAYER=$(aws lambda list-layers --query 'Layers[?contains(LayerName, `Pillow`) == `true`].LatestMatchingVersion.LayerVersionArn' | jq -r .[])
- Créez et chargez la fonction Lambda.
aws lambda create-function --function-name ol_image_processing \
--zip-file fileb://lambda.zip --handler lambda.handler --runtime python3.9 \
--role $OL_LAMBDA_ROLE \
--layers $LAMBDA_LAYER \
--memory-size 1024
Étape 5 : Créer un point d'accès S3 Object Lambda
5.1 – Créer le point d'accès S3 Object Lambda
- Accédez à la console S3 et choisissez Object Lambda Access Points (Points d'accès Object Lambda) dans le volet de navigation de gauche. Choisissez le bouton Create Object Lambda Access Point (Créer un point d'accès Object Lambda).
Dans la section General (Généralités), pour Object Lambda Access Point name (Nom du point d'accès Object Lambda), saisissez ol-amazon-s3-images-guide.
Assurez-vous que la région AWS du point d'accès S3 Object Lambda correspond à celle que vous avez spécifiée lors de la création du compartiment S3 à l'étape 1.3.
Pour Supporting Access Point (Point d'accès de support), spécifiez l'Amazon Resource Name (ARN) du point d'accès S3 que vous avez créé à l'étape 3.2 à l'aide du bouton Browse S3 (Parcourir S3).
Accédez au bas de la page pour afficher Transformation configuration (Configuration de la transformation). Dans la liste des API S3, sélectionnez l'option GetObject.
Sous Lambda function (Fonction Lambda), spécifiez ol_image_processing.
Accédez ensuite au bas de la page et choisissez Create Object Lambda Access Point (Créer un point d'accès Object Lambda).
Étape 6 : Télécharger des images depuis le point d'accès S3 Object Lambda
6.1 – Ouvrir le point d'accès S3 Object Lambda
- Revenez à la liste des points d'accès S3 Object Lambda en choisissant Object Lambda Access Points (Points d'accès Object Lambda) dans le volet de navigation gauche de la console S3, puis sélectionnez le point d'accès S3 Object Lambda que vous avez créé à l'étape 5.1. Dans cet exemple, nous avons choisi ol-amazon-s3-images-guide comme point d'accès S3 Object Lambda.
Sélectionnez l'image que vous avez chargée à l'étape 2.4, puis choisissez le bouton Open (Ouvrir).
6.2 – Télécharger l'image transformée depuis l'AWS CLI
- Vous pouvez également télécharger l'image à l'aide d'AWS CLI. Pour ce faire, vous avez besoin de l'Amazon Resource Name (ARN) du point d'accès S3 Object Lambda. Dans la console S3, accédez à la page Object Lambda Access Points (Points d'accès Object Lambda), sélectionnez le nom du point d'accès S3 Object Lambda, puis sélectionnez l'onglet Properties (Propriétés) et choisissez l'icône de copie sous Amazon Resource Name (ARN).
6.3 – Exécuter la commande AWS CLI depuis le CloudShell
Dans l'onglet de navigateur de CloudShell, saisissez les informations suivantes :
aws s3api get-object --bucket <paste the ARN copied above here> --key <image filename here> <filename to write here>
6.4 – Télécharger l'image sur votre ordinateur local
Dans CloudShell, choisissez Actions dans le coin supérieur droit, puis sélectionnez Download file (Télécharger un fichier).
Saisissez le nom de fichier que vous avez défini à l'étape 6.3 lors du téléchargement de l'image depuis le point d'accès S3 Object Lambda, puis choisissez Download (Télécharger).
Vous pouvez maintenant ouvrir l'image depuis votre ordinateur local.
Remarque : Les visionneuses d'images peuvent varier en fonction de l'ordinateur et du système d'exploitation utilisés. Contactez votre administrateur si vous ne savez pas quelle application utiliser pour ouvrir l'image.
Étape 7 : Nettoyer les ressources
7.1 – Supprimer le point d'accès S3 Object Lambda
- Accédez à la console S3 et choisissez Object Lambda Access Points (Points d'accès Object Lambda) dans le volet de navigation de gauche.
- Sur la page Object Lambda Access Points (Points d'accès Object Lambda), choisissez le bouton radio situé à gauche du point d'accès S3 Object Lambda que vous avez créé à l'étape 5.1.
Choisissez Delete (Supprimer).
Confirmez la suppression de votre point d'accès S3 Object Lambda en saisissant son nom dans le champ de texte qui apparaît, puis choisissez Delete (Supprimer).
7.2 – Supprimer le point d'accès S3
- Dans le volet de navigation gauche de la console S3, choisissez Access Points (Points d'accès).
- Accédez au point d'accès S3 que vous avez créé à l'étape 3.1, puis choisissez le bouton radio situé en regard du nom du point d'accès S3.
- Choisissez Delete (Supprimer).
Confirmez la suppression de votre point d'accès en saisissant son nom dans le champ de texte qui apparaît, puis choisissez Delete (Supprimer).
7.3 – Supprimer l'objet de test
- Accédez à la console S3 et sélectionnez l'option de menu Buckets (Compartiments) dans le volet de navigation de gauche. Tout d'abord, vous devez supprimer l'objet de test dans votre compartiment de test. Sélectionnez le nom du compartiment que vous avez utilisé dans le cadre de ce didacticiel.
- Sélectionnez la case située à gauche du nom de votre objet de test, puis choisissez le bouton Delete (Supprimer).
- Sur la page Delete objects (Supprimer des objets), vérifiez que vous avez sélectionné le bon objet à supprimer, puis saisissez Delete (Supprimer) dans la case de confirmation Permanently delete objects (Supprimer définitivement des objets). Puis, choisissez le bouton Delete objects (Supprimer des objets) pour continuer.
7.4 – Supprimer le compartiment S3
- Choisissez ensuite Buckets (Compartiments) dans le volet de navigation gauche du menu de la console S3. Sélectionnez le bouton radio à gauche du compartiment source que vous avez créé dans le cadre de ce didacticiel, puis choisissez le bouton Delete (Supprimer).
Consultez le message d'avertissement. Si vous souhaitez poursuivre la suppression de ce compartiment, saisissez-en le nom dans la case de confirmation Delete bucket (Supprimer un compartiment), puis sélectionnez Delete bucket (Supprimer un compartiment).
7.5 – Supprimer la fonction Lambda
- Dans le volet de navigation gauche de la console AWS Lambda, choisissez Functions (Fonctions).
- Cochez la case située à gauche du nom de la fonction que vous avez créée à l'étape 4.3.
- Choisissez ensuite Actions, puis Delete (Supprimer). Dans la boîte de dialogue Delete function (Supprimer la fonction), choisissez Delete (Supprimer).
Conclusion
Félicitations ! Vous avez appris à utiliser Amazon S3 Object Lambda pour ajouter dynamiquement un filigrane à une image à mesure de son extraction, renvoyant l'image traitée au client requérant. Vous pouvez personnaliser la fonction Lambda en fonction de votre cas d'utilisation afin de modifier les données renvoyées par les requêtes S3 GET, HEAD et LIST. Les cas d'utilisation courants sont : la personnalisation de filigranes à l'aide de détails spécifiques à l'appelant, le masquage de données sensibles, le filtrage de certaines lignes de données, l'enrichissement de données avec des informations provenant d'autres bases de données, la conversion de formats de données et plus encore.