Objectif :
Limiter les ressources (CPU et mémoire) d'un conteneur pour éviter qu'il ne consomme toutes les ressources du système hôte en cas d'attaque ou de problème.
Tâches :
Vous gérez une application web qui connaît parfois des pics de charge importants. Vous souhaitez déployer cette application dans un conteneur Docker, mais vous voulez vous assurer qu'elle ne consommera pas plus de 512Mo de RAM et qu'elle n'utilisera pas plus de 1 CPU, afin de protéger les autres applications tournant sur le même serveur.
Créez un conteneur exécutant NGINX avec les limites suivantes :
Vérifiez la configuration des limites de ressources depuis l'intérieur du conteneur.
# 1. Création du conteneur avec les limites spécifiées
docker container run -d --name web_secured \
-m 512m \
--memory-reservation 256m \
--cpus=1 \
nginx
# 2. Vérification des limites depuis l'intérieur du conteneur
docker exec -it web_secured bash
# Vérifier la limite de mémoire (en octets, 512Mo = 536870912 octets)
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# Vérifier la réservation de mémoire
cat /sys/fs/cgroup/memory/memory.soft_limit_in_bytes
# Pour les CPU, on peut vérifier avec
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
# Le ratio quota/period nous donne le nombre de CPU alloués
Objectif :
Comprendre et mettre en œuvre Docker Content Trust pour signer et vérifier des images Docker, afin de garantir l'intégrité et l'authenticité des images utilisées en production.
Tâches :
Vous êtes responsable de la sécurité dans votre entreprise et vous voulez vous assurer que seules des images de confiance (signées) sont utilisées dans l'environnement de production.
# 1. Activer Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# 2. Créer un Dockerfile simple
mkdir ~/secure-app && cd ~/secure-app
cat > Dockerfile << EOF
FROM alpine:latest
CMD echo "Hello, Secure World!"
EOF
# 3. Builder l'image
docker build -t votre-username/secure-app:v1 .
# 4. Générer une clé de signature (si pas déjà fait)
docker trust key generate votre-username
# 5. Ajouter le signataire au dépôt
docker trust signer add --key votre-username.pub votre-username votre-username/secure-app
# 6. Se connecter à Docker Hub
docker login
# 7. Signer et push l'image
docker trust sign votre-username/secure-app:v1
# Ou directement push avec DOCKER_CONTENT_TRUST=1 activé
docker push votre-username/secure-app:v1
# 8. Vérifier la signature de l'image
docker trust inspect votre-username/secure-app:v1
# 9. Tester le pull d'une image non signée avec DCT activé
# Cela devrait échouer
docker pull mongo:latest
# 10. Tester le pull d'une image signée avec DCT activé
# Cela devrait réussir
docker pull votre-username/secure-app:v1
Objectif : Comprendre et appliquer les principes du principe de moindre privilège en configurant un conteneur avec des restrictions de sécurité appropriées.
Tâches : Vous devez déployer une application Python simple qui servira un message "Hello, World!" sur le port 8080. Vous voulez vous assurer que le conteneur est configuré selon les bonnes pratiques de sécurité.
Voici le code app.py
:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, Secure World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Créez un conteneur Docker basé sur l'image python:3.13-alpine avec les contraintes suivantes :
Lancez un simple serveur HTTP Python dans ce conteneur qui répond "Hello, Secure World!" sur le port 8080.
Vérifiez que :
# 1. Création d'un répertoire de travail pour notre application
mkdir -p ~/secure-app && cd ~/secure-app
# 2. Création d'un script Flask simple
cat > app.py << EOF
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, Secure World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
EOF
# 3. Création du Dockerfile
cat > Dockerfile << EOF
FROM python:3.13-alpine
# Installation de Flask
RUN pip install --no-cache-dir flask
# Création d'un utilisateur non-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Création du répertoire de travail
WORKDIR /app
# Copie du script Python
COPY app.py .
# Exposition du port
EXPOSE 8080
# Changement vers l'utilisateur non-root
USER appuser
# Démarrage de l'application
CMD ["python", "app.py"]
EOF
# 4. Construction de l'image
docker build -t secure-python-app .
# 5. Exécution du conteneur avec des contraintes de sécurité
docker run -d --name secure-python \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
--tmpfs /tmp:rw,size=32M \
--memory 256m \
--cpus 0.5 \
--security-opt no-new-privileges \
-p 8080:8080 \
secure-python-app
# 6. Vérification que le serveur fonctionne
sleep 2 # Attendre que le serveur démarre
curl http://localhost:8080
# Résultat attendu: Hello, Secure World!
# 7. Vérification des contraintes de sécurité
# Vérifier que le conteneur s'exécute avec un utilisateur non-root
docker exec -it secure-python sh -c "id"
# Résultat attendu: uid n'est pas 0 (root)
# Vérifier les capabilities disponibles (devraient être très limitées)
docker exec -it secure-python sh -c "grep Cap /proc/self/status"
# Résultat attendu: Seule la capability NET_BIND_SERVICE devrait être présente
# Vérifier que le système de fichiers est bien en lecture seule
docker exec -it secure-python sh -c "touch /test.txt"
# Résultat attendu: touch: /test.txt: Read-only file system
# Vérifier que le dossier temporaire est accessible en écriture
docker exec -it secure-python sh -c "touch /tmp/test.txt && echo 'It works' > /tmp/test.txt && cat /tmp/test.txt"
# Résultat attendu: It works
# Vérifier les limites de ressources
docker exec -it secure-python sh -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
# Résultat attendu: 268435456 (256 Mo)
</details>