TP : Fonction serverless minimale avec AWS SAM, cfn-lint et Checkov
Objectif
Déployer une fonction Lambda minimale avec AWS SAM, puis analyser le modèle d’infrastructure et les permissions IAM associées.
- Créer une application SAM minimale
- Écrire une fonction Lambda Python
- Créer un modèle SAM volontairement imparfait
- Valider le modèle avec SAM CLI
- Analyser le modèle avec cfn-lint
- Analyser le modèle avec Checkov
- Corriger les permissions IAM et la configuration Lambda
- Déployer la fonction
- Tester l’invocation
- Consulter les journaux
- Supprimer les ressources
Sources
Durée estimée
| Séquence | Durée |
|---|---|
| Préparation locale | 20 min |
| Création du projet SAM | 25 min |
| Validation SAM | 20 min |
| Analyse avec cfn-lint | 20 min |
| Analyse avec Checkov | 30 min |
| Correction du modèle | 35 min |
| Déploiement | 30 min |
| Test et journaux | 20 min |
| Nettoyage | 15 min |
| Total | 3 h 15 |
Compétences travaillées
| Compétence | Niveau attendu |
|---|---|
| Lire un modèle SAM | Débutant à intermédiaire |
| Déployer une fonction Lambda simple | Intermédiaire |
| Comprendre les rôles IAM Lambda | Intermédiaire |
| Analyser un modèle CloudFormation avec cfn-lint | Intermédiaire |
| Analyser un modèle SAM avec Checkov | Intermédiaire |
| Corriger des permissions IAM trop larges | Intermédiaire |
| Lire les journaux CloudWatch Logs d’une Lambda | Intermédiaire |
Scénario
Une équipe souhaite créer une fonction Lambda minimale pour exposer un traitement simple.
Avant de généraliser ce modèle, l’équipe veut vérifier :
la validité du modèle SAMla qualité structurelle du modèle CloudFormationles permissions IAM accordées à la fonctionla configuration des journauxla capacité à tester et supprimer proprement les ressourcesLe modèle initial fonctionne, mais il contient volontairement une politique IAM trop large.
Étape 1 : Préparation de l’environnement
1.1. Créer le répertoire de travail
mkdir -p tp-serverless-securisecd tp-serverless-securisemkdir -p src events rapports/cfn-lint rapports/checkov1.2. Créer un .gitignore
cat > .gitignore <<'EOF'.venv/.aws-sam/response.jsonrapports/__pycache__/*.pycEOF1.3. Créer un environnement Python
python3 -m venv .venvsource .venv/bin/activate # Linux/macOS# ou.\.venv\Scripts\Activate # Windows PowerShell
python -m pip install --upgrade pip1.4. Installer AWS SAM CLI
macOS :
brew install aws-sam-cliLinux (installeur officiel AWS) :
curl -sSL https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip \ -o aws-sam-cli-linux-x86_64.zipunzip aws-sam-cli-linux-x86_64.zip -d sam-installationsudo ./sam-installation/installrm -rf aws-sam-cli-linux-x86_64.zip sam-installationVérifier l’installation :
sam --version1.5. Installer cfn-lint et Checkov
pip install cfn-lint checkovcfn-lint --versioncheckov --version1.6. Vérifier AWS CLI
aws --versionaws sts get-caller-identity --profile defaultÉtape 2 : Création de la fonction Lambda
2.1. Créer le fichier Python
cat > src/app.py <<'EOF'import jsonimport osfrom datetime import datetime, timezone
def lambda_handler(event, context): app_name = os.getenv("APP_NAME", "serverless-security-lab")
response = { "application": app_name, "message": "Fonction Lambda exécutée avec succès", "timestamp": datetime.now(timezone.utc).isoformat(), "input": event }
return { "statusCode": 200, "body": json.dumps(response) }EOF2.2. Créer un événement de test
cat > events/event.json <<'EOF'{ "source": "tp", "action": "test-local"}EOFÉtape 3 : Création d’un modèle SAM volontairement imparfait
cat > template.yaml <<'EOF'AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Description: Fonction Lambda minimale pour TP sécurité serverless
Globals: Function: Runtime: python3.12 Timeout: 30 MemorySize: 128
Resources: LabFunction: Type: AWS::Serverless::Function Properties: FunctionName: serverless-security-lab-function CodeUri: src/ Handler: app.lambda_handler Environment: Variables: APP_NAME: serverless-security-lab Policies: - Statement: - Effect: Allow Action: - "*" Resource: "*"
Outputs: LabFunctionName: Description: Nom de la fonction Lambda Value: !Ref LabFunction
LabFunctionArn: Description: ARN de la fonction Lambda Value: !GetAtt LabFunction.ArnEOFCe modèle fonctionne, mais il contient une permission IAM trop large :
Action: "*"Resource: "*"Étape 4 : Validation avec AWS SAM CLI
4.1. Valider le modèle SAM
sam validate4.2. Construire l’application
sam build4.3. Tester localement (optionnel — nécessite Docker)
Prérequis :
sam local invokerequiert que Docker soit installé et en cours d’exécution. Si Docker n’est pas disponible, cette étape peut être ignorée — les analyses statiques des sections suivantes restent pleinement fonctionnelles.
sam local invoke LabFunction \ --event events/event.jsonUn modèle valide pour SAM peut tout de même contenir une politique IAM dangereuse. La validation syntaxique ne remplace pas l’analyse sécurité.
Étape 5 : Analyse avec cfn-lint
5.1. Lancer cfn-lint
Note : cfn-lint retourne un code de sortie non nul (2 ou supérieur) lorsqu’il détecte des erreurs ou avertissements. Le
|| trueci-dessous permet de capturer le rapport dans le fichier même si cfn-lint signale des problèmes, sans interrompre le shell.
cfn-lint template.yaml \ > rapports/cfn-lint/cfn-lint-template.txt || true5.2. Afficher le rapport
cat rapports/cfn-lint/cfn-lint-template.txtcfn-lint vérifie la structure et la validité du modèle CloudFormation ou SAM. Il détecte des erreurs de propriétés, de types, de références ou de structure. Il ne remplace pas une analyse sécurité approfondie des permissions IAM — c’est le rôle de Checkov.
Étape 6 : Analyse avec Checkov
Note sur
--output-file-path console,...: cette syntaxe peut échouer selon la version de Checkov installée. Si la commande combinée ci-dessous échoue, utiliser les deux commandes séparées indiquées en commentaire.
6.1. Scanner le modèle SAM
checkov \ -f template.yaml \ --framework cloudformation \ --output cli \ --output json \ --output-file-path console,rapports/checkov/checkov-template.json
# Si la commande ci-dessus échoue, exécuter séparément :# checkov -f template.yaml --framework cloudformation --output cli# checkov -f template.yaml --framework cloudformation --output json \# --output-file-path rapports/checkov/checkov-template.json6.2. Afficher le rapport JSON
cat rapports/checkov/checkov-template.jsonAnalyse attendue :
| Constat | Ressource | Risque |
|---|---|---|
| Politique IAM trop large | LabFunction | Surprivilège |
Action * | Politique IAM | Droits non maîtrisés |
Ressource * | Politique IAM | Périmètre global |
| Rétention des journaux non définie | Fonction Lambda | Conservation non maîtrisée |
Le modèle SAM est valide, mais la politique IAM attachée à la fonction est trop permissive. Le rôle d’exécution Lambda doit respecter le moindre privilège.
Étape 7 : Correction du modèle SAM
cat > template.yaml <<'EOF'AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Description: Fonction Lambda minimale pour TP sécurité serverless
Globals: Function: Runtime: python3.12 Timeout: 10 MemorySize: 128 Tracing: Active Environment: Variables: APP_NAME: serverless-security-lab
Resources: LabFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: /aws/lambda/serverless-security-lab-function RetentionInDays: 7
LabFunction: Type: AWS::Serverless::Function Properties: FunctionName: serverless-security-lab-function CodeUri: src/ Handler: app.lambda_handler Description: Fonction Lambda minimale pour TP sécurité serverless Policies: - AWSLambdaBasicExecutionRole Tags: Project: serverless-security-lab Environment: lab DependsOn: - LabFunctionLogGroup
Outputs: LabFunctionName: Description: Nom de la fonction Lambda Value: !Ref LabFunction
LabFunctionArn: Description: ARN de la fonction Lambda Value: !GetAtt LabFunction.ArnEOFCorrections apportées :
| Élément | Avant | Après |
|---|---|---|
| Timeout | 30 secondes | 10 secondes |
| Politique IAM | Action: "*" et Resource: "*" | AWSLambdaBasicExecutionRole |
| Journaux | Créés implicitement | Groupe de journaux explicite |
| Rétention des journaux | Non définie | 7 jours |
| Balises | Absentes | Présentes |
| Traçage | Non configuré | Activé |
Étape 8 : Vérification après correction
8.1. Valider le modèle SAM corrigé
sam validatesam build8.2. Relancer cfn-lint
cfn-lint template.yaml \ > rapports/cfn-lint/cfn-lint-template-after-fix.txt || true
cat rapports/cfn-lint/cfn-lint-template-after-fix.txt8.3. Relancer Checkov
checkov \ -f template.yaml \ --framework cloudformation \ --output cli \ --output json \ --output-file-path console,rapports/checkov/checkov-template-after-fix.json
cat rapports/checkov/checkov-template-after-fix.json| Élément | Avant correction | Après correction |
|---|---|---|
| Politique IAM | Trop large | Réduite |
Action * | Présente | Supprimée |
Ressource * | Présente dans la politique personnalisée | Supprimée |
| Rétention des journaux | Non définie | Définie |
| Balises | Absentes | Présentes |
| Modèle SAM | Valide | Valide |
Étape 9 : Déploiement de la fonction
Note sur le bucket SAM :
--resolve-s3crée automatiquement un bucket S3 pour stocker les artefacts de déploiement (code Lambda packagé). Ce bucket n’est pas supprimé parsam delete. Il devra être supprimé manuellement lors du nettoyage (section 11).
9.1. Déployer avec SAM
sam deploy \ --stack-name serverless-security-lab \ --resolve-s3 \ --capabilities CAPABILITY_IAM \ --region eu-west-1 \ --profile default9.2. Récupérer les sorties de la pile
aws cloudformation describe-stacks \ --stack-name serverless-security-lab \ --region eu-west-1 \ --profile default \ --query "Stacks[0].Outputs"9.3. Invoquer la fonction
aws lambda invoke \ --function-name serverless-security-lab-function \ --payload file://events/event.json \ --cli-binary-format raw-in-base64-out \ --region eu-west-1 \ --profile default \ response.jsonNote Windows : l’option
--payload '{...}'avec une chaîne JSON inline pose des problèmes d’échappement sur PowerShell. Utiliserfile://events/event.jsoncomme ci-dessus pour éviter ce problème sur tous les systèmes.
Afficher la réponse :
cat response.jsonÉtape 10 : Consultation des journaux
10.1. Lister les groupes de journaux Lambda
aws logs describe-log-groups \ --log-group-name-prefix "/aws/lambda/serverless-security-lab-function" \ --region eu-west-1 \ --profile default10.2. Lister les flux de journaux
aws logs describe-log-streams \ --log-group-name "/aws/lambda/serverless-security-lab-function" \ --order-by LastEventTime \ --descending \ --max-items 5 \ --region eu-west-1 \ --profile default10.3. Lire les événements récents
aws logs filter-log-events \ --log-group-name "/aws/lambda/serverless-security-lab-function" \ --limit 20 \ --region eu-west-1 \ --profile defaultLa fonction Lambda écrit des journaux dans CloudWatch Logs. Le rôle d’exécution Lambda dispose uniquement des permissions nécessaires à l’écriture des journaux. La rétention est définie à 7 jours.
Nettoyage
11.1. Identifier le bucket SAM créé par --resolve-s3
sam deploy --resolve-s3 crée un bucket S3 nommé automatiquement. L’identifier avant suppression :
aws s3api list-buckets \ --profile default \ --query "Buckets[?starts_with(Name, 'aws-sam-cli-managed')].Name" \ --output text11.2. Supprimer la pile CloudFormation
sam delete \ --stack-name serverless-security-lab \ --region eu-west-1 \ --profile default11.3. Vérifier que la pile est supprimée
aws cloudformation describe-stacks \ --stack-name serverless-security-lab \ --region eu-west-1 \ --profile defaultNote : lorsque la pile n’existe plus, cette commande retourne une erreur
ValidationError: Stack with id serverless-security-lab does not exist. C’est le résultat attendu — cela confirme la suppression.
11.4. Supprimer le bucket SAM manuellement
Remplacer <NOM_BUCKET_SAM> par la valeur récupérée à l’étape 11.1 :
# Vider le bucket (requis avant suppression)aws s3 rm s3://<NOM_BUCKET_SAM> --recursive --profile default
# Supprimer le bucketaws s3api delete-bucket \ --bucket <NOM_BUCKET_SAM> \ --region eu-west-1 \ --profile default11.5. Supprimer les fichiers temporaires locaux
rm -f response.jsonrm -rf .aws-samrm -rf rapportsdeactivaterm -rf .venvPoints clés
sam validatevérifie la syntaxe du modèle, pas la sécurité des permissions IAM- cfn-lint et Checkov sont complémentaires : cfn-lint valide la structure, Checkov analyse la sécurité
- Une fonction Lambda doit avoir un rôle IAM minimal —
AWSLambdaBasicExecutionRolesuffit pour les logs - La rétention des journaux CloudWatch doit toujours être définie explicitement
sam deploy --resolve-s3crée un bucket S3 qui ne sera pas supprimé parsam deletesam local invokenécessite Docker — les analyses statiques fonctionnent sans- Tout déploiement serverless crée aussi des ressources IAM à auditer
Repères formateur
Résultat attendu avec SAM CLI
sam validate doit confirmer que le modèle est valide. Le point important est qu’un modèle valide n’est pas forcément sécurisé.
sam local invoke nécessite Docker. Si Docker n’est pas disponible en salle, cette étape est optionnelle — les analyses statiques restent l’objectif principal du TP.
Résultat attendu avec cfn-lint
cfn-lint doit vérifier la cohérence du modèle CloudFormation ou SAM. Il peut détecter des erreurs de structure, mais ne suffit pas à qualifier les permissions IAM.
Le code de sortie non nul de cfn-lint en présence d’erreurs est attendu et documenté — il ne représente pas un dysfonctionnement de l’outil.
Résultat attendu avec Checkov
Checkov doit identifier la politique IAM trop large dans le modèle initial :
Action: "*"Resource: "*"Remédiation attendue
remplacer la politique IAM générique par AWSLambdaBasicExecutionRoledéfinir une durée de rétention des journauxréduire le timeoutajouter des balisesactiver le traçagePoint de vigilance nettoyage
Le bucket S3 créé par --resolve-s3 n’est pas supprimé par sam delete. Si non supprimé, il génère un coût de stockage faible mais continu. Vérifier sa suppression en fin de TP.
Synthèse attendue
un modèle SAM valide n'est pas forcément sécuriséune fonction Lambda doit avoir un rôle IAM minimalles journaux doivent avoir une rétention définiecfn-lint et Checkov sont complémentairesle déploiement serverless crée aussi des ressources IAMsam delete ne supprime pas le bucket d'artefacts SAM