Créer un Dépôt APT Privé sur S3 : Guide Complet
Pourquoi Créer un Dépôt APT Privé ?
Quand tu développes des applications internes ou que tu veux distribuer tes packages Debian/Ubuntu de manière contrôlée, créer ton propre dépôt APT devient essentiel.
Les avantages concrets : - Contrôle total : Gestion des versions, rollbacks, accès sélectif - Sécurité : Packages signés, authentification, pas d’exposition publique - Performance : Hébergement proche de tes serveurs - Coûts : S3 coûte une fraction d’un serveur dédié
Cas d’usage réels : - Applications internes d’entreprise - Packages propriétaires ou sous licence - Versions bêta avant publication publique - Environnements isolés (staging, production)
Architecture d’un Dépôt APT sur S3
Structure Standard APT
bucket-apt-repo/
├── dists/
│ └── focal/ # Distribution (Ubuntu 20.04)
│ ├── Release # Métadonnées signées
│ ├── Release.gpg # Signature GPG
│ └── main/
│ └── binary-amd64/
│ └── Packages.gz
└── pool/
└── main/
└── mon-app_1.0.0_amd64.deb
Composants Essentiels
Pool : Stockage physique des packages .deb
Dists : Métadonnées et index pour chaque distribution
Release : Fichier principal avec checksums et signatures
Configuration Initiale
1. Création du Bucket S3
# Créer le bucket avec versioning
aws s3 mb s3://mon-apt-repo --region eu-west-3
aws s3api put-bucket-versioning \
--bucket mon-apt-repo \
--versioning-configuration Status=Enabled
# Configuration CORS pour accès web
aws s3api put-bucket-cors \
--bucket mon-apt-repo \
--cors-configuration file://cors.json
cors.json :
{
"CORSRules": [
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedOrigins": ["*"],
"MaxAgeSeconds": 3600
}
]
}
2. Politique IAM pour Accès Contrôlé
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::ACCOUNT:user/apt-publisher"},
"Action": ["s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::mon-apt-repo/*"
},
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::ACCOUNT:role/ec2-apt-access"},
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::mon-apt-repo/*"
}
]
}
3. Génération de Clés GPG
# Générer une clé dédiée au dépôt
gpg --batch --generate-key <<EOF
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Mon Depot APT
Name-Email: apt@monentreprise.com
Expire-Date: 2y
%no-protection
%commit
EOF
# Exporter la clé publique
gpg --armor --export apt@monentreprise.com > apt-repo.gpg.key
Script de Publication Automatisé
Publication avec deb-s3
#!/bin/bash
set -euo pipefail
DISTRIBUTION="focal"
COMPONENT="main"
S3_BUCKET="mon-apt-repo"
GPG_KEY="apt@monentreprise.com"
AWS_REGION="eu-west-3"
# Installation de deb-s3 si nécessaire
if ! command -v deb-s3 &> /dev/null; then
gem install deb-s3
fi
# Publication du package
deb-s3 upload \
--bucket="$S3_BUCKET" \
--codename="$DISTRIBUTION" \
--component="$COMPONENT" \
--sign="$GPG_KEY" \
--preserve-versions \
--cache-control="max-age=300" \
--region="$AWS_REGION" \
*.deb
echo "✅ Package publié sur s3://$S3_BUCKET/"
Script Avancé avec deb-s3
#!/bin/bash
set -euo pipefail
PACKAGE_FILE="$1"
DISTRIBUTION="${2:-focal}"
COMPONENT="${3:-main}"
S3_BUCKET="mon-apt-repo"
GPG_KEY="apt@monentreprise.com"
AWS_REGION="eu-west-3"
if [[ ! -f "$PACKAGE_FILE" ]]; then
echo "❌ Package file not found: $PACKAGE_FILE"
exit 1
fi
# Extraire les métadonnées du package
PACKAGE_NAME=$(dpkg-deb -W --showformat='${Package}' "$PACKAGE_FILE")
VERSION=$(dpkg-deb -W --showformat='${Version}' "$PACKAGE_FILE")
ARCHITECTURE=$(dpkg-deb -W --showformat='${Architecture}' "$PACKAGE_FILE")
echo "📦 Publishing $PACKAGE_NAME v$VERSION for $ARCHITECTURE"
# Configuration deb-s3
export DEB_S3_CODENAME="$DISTRIBUTION"
export DEB_S3_COMPONENT="$COMPONENT"
export DEB_S3_ORIGIN="Mon Entreprise"
export DEB_S3_LABEL="Mon Depot APT"
# Publication avec deb-s3
deb-s3 upload \
--bucket="$S3_BUCKET" \
--codename="$DISTRIBUTION" \
--component="$COMPONENT" \
--sign="$GPG_KEY" \
--preserve-versions \
--cache-control="max-age=300" \
--region="$AWS_REGION" \
--architecture="$ARCHITECTURE" \
--origin="Mon Entreprise" \
--label="Mon Depot APT" \
"$PACKAGE_FILE"
# Vérification de la publication
echo "🔍 Vérification de la publication..."
deb-s3 verify \
--bucket="$S3_BUCKET" \
--codename="$DISTRIBUTION" \
--component="$COMPONENT" \
--region="$AWS_REGION"
echo "✅ Package $PACKAGE_NAME v$VERSION published successfully"
echo "📍 Available at: deb https://$S3_BUCKET.s3.$AWS_REGION.amazonaws.com/ $DISTRIBUTION $COMPONENT"
Intégration CI/CD
GitLab CI Pipeline
stages:
- build
- package
- publish
variables:
PACKAGE_NAME: "mon-app"
DEBIAN_FRONTEND: noninteractive
build_deb:
stage: package
image: ubuntu:20.04
before_script:
- apt-get update && apt-get install -y build-essential devscripts debhelper
script:
- debuild -us -uc
- mv ../*.deb ./
artifacts:
paths:
- "*.deb"
expire_in: 1 hour
publish_apt:
stage: publish
image: ruby:3.0
dependencies:
- build_deb
before_script:
- apt-get update && apt-get install -y awscli gnupg
- gem install deb-s3
- echo "$GPG_PRIVATE_KEY" | gpg --import
script:
- |
deb-s3 upload \
--bucket="$S3_BUCKET" \
--codename="focal" \
--component="main" \
--sign="$GPG_KEY_ID" \
--preserve-versions \
--region="eu-west-3" \
*.deb
only:
- main
- tags
GitHub Actions
name: Build and Publish APT Package
on:
push:
tags: ['v*']
workflow_dispatch:
jobs:
publish-apt:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
- name: Install deb-s3
run: gem install deb-s3
- name: Setup GPG
run: |
echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --import
- name: Build DEB package
run: |
sudo apt-get update
sudo apt-get install -y build-essential devscripts debhelper
debuild -us -uc
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-3
- name: Publish to APT repo
run: |
deb-s3 upload \
--bucket="${{ secrets.S3_BUCKET }}" \
--codename="focal" \
--component="main" \
--sign="${{ secrets.GPG_KEY_ID }}" \
--preserve-versions \
--region="eu-west-3" \
../*.deb
Configuration Côté Client
Installation du Dépôt
# Ajouter la clé GPG
curl -fsSL https://mon-apt-repo.s3.eu-west-3.amazonaws.com/apt-repo.gpg.key | sudo apt-key add -
# Ajouter le dépôt
echo "deb https://mon-apt-repo.s3.eu-west-3.amazonaws.com/ focal main" | \
sudo tee /etc/apt/sources.list.d/mon-repo.list
# Mettre à jour et installer
sudo apt update
sudo apt install mon-app
Configuration avec Authentification
Pour un accès restreint via IAM :
# Installation du plugin S3
sudo apt install apt-transport-s3
# Configuration avec credentials
echo "deb s3://mon-apt-repo/ focal main" | \
sudo tee /etc/apt/sources.list.d/mon-repo-private.list
# Créer le fichier de configuration S3
sudo tee /etc/apt/s3auth.conf <<EOF
AccessKeyId = AKIA...
SecretAccessKey = ...
Region = eu-west-3
EOF
sudo chmod 600 /etc/apt/s3auth.conf
Monitoring et Maintenance
Métriques CloudWatch
# Script de monitoring des téléchargements
aws logs create-log-group --log-group-name apt-repo-access
# Activer les logs d'accès S3
aws s3api put-bucket-logging \
--bucket mon-apt-repo \
--bucket-logging-status file://logging.json
Nettoyage Automatique
#!/bin/bash
# Supprimer les anciennes versions (garde les 5 dernières)
PACKAGE_PREFIX="pool/main/m/mon-app"
aws s3api list-objects-v2 \
--bucket mon-apt-repo \
--prefix "$PACKAGE_PREFIX" \
--query 'Contents[?LastModified<=`2024-01-01`].Key' \
--output text | \
while read -r key; do
echo "Deleting old package: $key"
aws s3 rm "s3://mon-apt-repo/$key"
done
Sécurisation Avancée
Chiffrement et Accès Contrôlé
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::mon-apt-repo",
"arn:aws:s3:::mon-apt-repo/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
Rotation des Clés GPG
#!/bin/bash
# Script de rotation annuelle
OLD_KEY="apt@monentreprise.com"
NEW_KEY="apt-2025@monentreprise.com"
# Générer nouvelle clé
gpg --batch --generate-key <<EOF
Key-Type: RSA
Key-Length: 4096
Name-Real: Mon Depot APT 2025
Name-Email: $NEW_KEY
Expire-Date: 2y
%no-protection
%commit
EOF
# Re-signer le dépôt avec la nouvelle clé
deb-s3 sign \
--bucket="$S3_BUCKET" \
--codename="focal" \
--component="main" \
--sign="$NEW_KEY" \
--region="eu-west-3"
# Upload de la nouvelle clé publique
gpg --armor --export "$NEW_KEY" > apt-repo-2025.gpg.key
aws s3 cp apt-repo-2025.gpg.key s3://mon-apt-repo/
Patterns Avancés
Multi-Architecture
# Structure pour supporter amd64 et arm64
dists/focal/main/
├── binary-amd64/
│ └── Packages.gz
└── binary-arm64/
└── Packages.gz
# Script de build cross-platform
build_for_architecture() {
local arch="$1"
docker run --rm -v "$(pwd):/src" -w /src \
--platform "linux/$arch" \
ubuntu:20.04 \
bash -c "apt update && apt install -y build-essential && debuild -us -uc"
}
build_for_architecture "amd64"
build_for_architecture "arm64"
Environnements Multiples
# Structure pour staging/production
dists/
├── focal-staging/
└── focal/
Conclusion
Un dépôt APT privé sur S3 offre flexibilité, sécurité et contrôle des coûts. Les points clés :
- Architecture simple : Pool + Dists avec signatures GPG
- Automatisation CI/CD : Publication transparente depuis vos pipelines
- Sécurité : IAM + chiffrement + signatures
- Maintenance : Monitoring et nettoyage automatique
Pour aller plus loin : L’intégration avec des outils comme Artifactory ou Nexus peut simplifier la gestion multi-format (APT + Docker + npm) dans un seul système unifié.
Cette approche convient parfaitement aux équipes DevOps qui veulent maîtriser leur chaîne de distribution tout en optimisant les coûts d’infrastructure.
Points clés à retenir
- ✓ S3 comme hébergement APT : coût réduit et haute disponibilité
- ✓ Signatures GPG automatisées pour la sécurité des packages
- ✓ Architecture multi-distributions avec structure Release/Packages
- ✓ Intégration CI/CD pour publication automatique des packages
- ✓ Gestion des permissions IAM pour accès contrôlé au dépôt