DevOps
15 min de lecture

Créer un Dépôt APT Privé sur S3 : Guide Complet

Guide technique complet pour créer et maintenir un dépôt APT privé sur AWS S3 avec authentification, signatures GPG et automatisation CI/CD.

Arthur Zinck
Arthur Zinck
Expert DevOps Kubernetes & Cloud

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 :

  1. Architecture simple : Pool + Dists avec signatures GPG
  2. Automatisation CI/CD : Publication transparente depuis vos pipelines
  3. Sécurité : IAM + chiffrement + signatures
  4. 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
apt s3 debian ubuntu devops ci-cd gpg aws infrastructure

Partager cet article

Twitter LinkedIn