Go to file
stef 7a05e3afe4 update index 2025-12-07 10:47:25 +01:00
.github feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
cmd feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
internal feat: add private_key field to JSON responses for all certificate/CA endpoints 2025-12-07 10:06:17 +01:00
tests test: add comprehensive test scripts for exports and private key storage 2025-12-07 09:50:43 +01:00
webui update index 2025-12-07 10:47:25 +01:00
.env.example docs: Ajouter guide de déploiement et fichier .env.example 2025-12-06 23:12:22 +01:00
.gitignore feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
DEPLOYMENT.md last from journey 2025-12-07 01:05:49 +01:00
Dockerfile feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
Makefile feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
README.md docs: update README with private key features and export documentation 2025-12-07 10:09:56 +01:00
compose.yaml feat: PKI API Go avec persistance MongoDB et abstraction storage 2025-12-06 23:11:50 +01:00
go.mod last from journey 2025-12-07 01:05:49 +01:00
test_export.sh feat: add certificate export functionality (PEM, DER, with private key, chain) 2025-12-07 09:28:48 +01:00

README.md

PKI API

API Go complète pour gérer une Infrastructure à Clé Publique (PKI) avec hiérarchie de certificats et persistance MongoDB.

Caractéristiques

  • Authentification JWT : Tous les endpoints protégés par JWT
  • Hiérarchie CA : Support des Root CA, Intermediate CA (Sub-CA) et certificats finaux
  • Signature de certificats : Certificats auto-signés ou signés par une CA
  • Gestion des révocations : Révocation et CRL (Certificate Revocation List)
  • Stockage pluggable : MemoryStore (développement) ou MongoDB (production)
  • Export de certificats : PEM, DER, avec clé privée, chaîne complète
  • Clés privées : Stockage et récupération sécurisés pour tous les certificats (JSON + export fichier)
  • Cryptographie : X.509, RSA 2048-bit, signatures HS256 pour JWT

Architecture

pkiapi/
├── cmd/main.go                    # Point d'entrée avec config
├── internal/
│   ├── api/
│   │   ├── router.go              # Routage Gin
│   │   ├── auth.go                # Login endpoint
│   │   ├── ca.go                  # Handlers CAs
│   │   └── certificates.go        # Handlers certificats
│   ├── auth/
│   │   ├── jwt.go                 # JWT manager
│   │   └── middleware.go          # Middleware d'authentification
│   ├── config/
│   │   └── config.go              # Configuration centralisée
│   ├── pki/
│   │   ├── certificate.go         # Logique certificats X.509
│   │   └── errors.go              # Erreurs PKI
│   └── storage/
│       ├── interface.go           # Interface CertificateStore
│       ├── store.go               # MemoryStore (en mémoire)
│       ├── mongo.go               # MongoStore (persistance)
│       ├── util.go                # Helpers sérialisation
│       └── errors.go              # Erreurs storage
├── tests/                         # Scripts de test
├── go.mod
└── docker-compose.yaml            # Orchestration services

Démarrage rapide

1. Installer et compiler

go mod download
go build -o pkiapi ./cmd/main.go

2. Démarrer le serveur

Mode développement (MemoryStore):

export STORAGE_TYPE=memory
export PORT=8080
./pkiapi
# Serveur lancé sur http://localhost:8080

Mode production (MongoDB via Docker Compose):

docker compose up -d --build
# L'API est disponible sur http://localhost:8080
# MongoDB est disponible sur mongodb://localhost:27017

3. Obtenir un token JWT

curl -X POST http://localhost:8080/api/v1/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}'

# Réponse:
# {
#   "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
#   "expires_in": 86400
# }

API Endpoints

🔐 Authentification (Public)

POST /api/v1/login

Obtient un token JWT pour accéder aux autres endpoints.

Requête :

curl -X POST http://localhost:8080/api/v1/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "admin",
    "password": "admin"
  }'

Réponse :

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 86400
}

🔑 Autorités de Certification (Authentifiés)

POST /api/v1/ca

Crée une nouvelle autorité de certification auto-signée.

Requête :

TOKEN="<your_token>"
curl -X POST http://localhost:8080/api/v1/ca \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "CN=Root CA,O=Example Inc,C=FR",
    "validity_days": 3650
  }'

Réponse :

{
  "ca": {
    "id": "ff3ac5c5-08d1-401b-9e83-f18eda4c538b",
    "subject": "CN=Root CA,O=Example Inc,C=FR",
    "not_before": "2025-12-06T21:45:01Z",
    "not_after": "2035-12-04T21:45:01Z",
    "serial_number": "546965196",
    "certificate": "MIIC5zCCAc+gAwIBAgIDCkUz...",
    "private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
    "is_ca": true
  },
  "created_by": "admin"
}

GET /api/v1/ca/:id

Récupère une autorité de certification par ID (avec clé privée).

Requête :

TOKEN="<your_token>"
CA_ID="ff3ac5c5-08d1-401b-9e83-f18eda4c538b"
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/ca/$CA_ID

Réponse :

{
  "ca": {
    "id": "ff3ac5c5-08d1-401b-9e83-f18eda4c538b",
    "subject": "CN=Root CA,O=Example Inc,C=FR",
    "not_before": "2025-12-06T21:45:01Z",
    "not_after": "2035-12-04T21:45:01Z",
    "serial_number": "546965196",
    "certificate": "MIIC5zCCAc+gAwIBAgIDCkUz...",
    "private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
    "is_ca": true
  }
}

POST /api/v1/ca/sign

Crée une CA intermédiaire (Sub-CA) signée par une CA parent.

Requête :

TOKEN="<your_token>"
PARENT_CA_ID="ff3ac5c5-08d1-401b-9e83-f18eda4c538b"
curl -X POST http://localhost:8080/api/v1/ca/sign \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"parent_ca_id\": \"$PARENT_CA_ID\",
    \"subject\": \"CN=Intermediate CA,O=Example Inc,C=FR\",
    \"validity_days\": 1825
  }"

📜 Certificats (Authentifiés)

POST /api/v1/certificates

Crée un certificat auto-signé avec clé privée.

Requête :

TOKEN="<your_token>"
curl -X POST http://localhost:8080/api/v1/certificates \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "CN=example.com,O=Example Inc,C=FR",
    "validity_days": 365
  }'

Réponse :

{
  "certificate": {
    "id": "8e77050f-d19f-4607-8c49-b974c5f9cb08",
    "subject": "CN=example.com,O=Example Inc,C=FR",
    "issuer": "CN=example.com,O=Example Inc,C=FR",
    "not_before": "2025-12-06T21:41:38Z",
    "not_after": "2026-12-06T21:41:38Z",
    "serial_number": "673075",
    "certificate": "MIIC5zCCAc+gAwIBAgIDCkUzMA0GCSq...",
    "private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
    "revoked": false
  },
  "created_by": "admin"
}

GET /api/v1/certificates/:id

Récupère un certificat par ID (avec clé privée encodée en base64).

Requête :

TOKEN="<your_token>"
CERT_ID="e12e08a9-adeb-404c-a7b7-a613b77dfe66"
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/certificates/$CERT_ID

Réponse :

{
  "certificate": {
    "id": "e12e08a9-adeb-404c-a7b7-a613b77dfe66",
    "subject": "CN=server.example.com,O=Example Inc,C=FR",
    "issuer": "CN=Intermediate CA,O=Example Inc,C=FR",
    "not_before": "2025-12-06T21:45:09Z",
    "not_after": "2026-12-06T21:45:09Z",
    "serial_number": "46798982",
    "certificate": "MIIDFDCCAfygAwIBAgIEAsoYhjANBg...",
    "private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
    "revoked": false
  }
}

POST /api/v1/certificates/sign

Signe un certificat avec une CA (avec clé privée).

Requête :

TOKEN="<your_token>"
CA_ID="b2350d39-53c2-469a-802c-acc39707e352"
curl -X POST http://localhost:8080/api/v1/certificates/sign \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"ca_id\": \"$CA_ID\",
    \"subject\": \"CN=server.example.com,O=Example Inc,C=FR\",
    \"validity_days\": 365
  }"

POST /api/v1/revoke

Révoque un certificat.

Requête :

TOKEN="<your_token>"
CERT_ID="e12e08a9-adeb-404c-a7b7-a613b77dfe66"
curl -X POST http://localhost:8080/api/v1/revoke \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"certificate_id\": \"$CERT_ID\",
    \"reason\": \"Compromised key\"
  }"

GET /api/v1/crl

Récupère la Certificate Revocation List (liste des certificats révoqués).

Requête :

TOKEN="<your_token>"
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/crl

📥 Export de Certificats (Authentifiés)

GET /api/v1/certificates/:id/export/pem

Exporte un certificat au format PEM.

TOKEN="<your_token>"
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/certificates/:id/export/pem \
  -o certificate.pem

GET /api/v1/certificates/:id/export/der

Exporte un certificat au format DER (binaire).

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/certificates/:id/export/der \
  -o certificate.der

GET /api/v1/certificates/:id/export/pem-with-key

Exporte certificat + clé privée au format PEM.

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/certificates/:id/export/pem-with-key \
  -o certificate_with_key.pem

GET /api/v1/certificates/:id/export/chain

Exporte la chaîne complète (certificat + CA parent).

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/v1/certificates/:id/export/chain \
  -o certificate_chain.pem

Clés Privées

Stockage et Récupération

Les clés privées sont automatiquement stockées pour:

  • Tous les certificats auto-signés
  • Tous les certificats signés par une CA
  • Toutes les CAs (Root et Intermediate)

Accès via JSON

Les clés privées sont incluses dans les réponses JSON:

  • Format: Base64 PKCS#8 encodé
  • Champs: private_key (optionnel, présent si disponible)
  • Endpoints retournant des clés privées:
    • POST /api/v1/ca - Création CA
    • GET /api/v1/ca/:id - Récupération CA
    • POST /api/v1/ca/sign - Création Sub-CA
    • POST /api/v1/certificates - Création certificat
    • GET /api/v1/certificates/:id - Récupération certificat
    • POST /api/v1/certificates/sign - Signature certificat

Accès via Export Fichier

Les clés privées peuvent aussi être exportées en fichier:

  • /export/pem-with-key - Certificat + clé privée en PEM
  • /export/chain - Chaîne complète (pour CAs parent)

Base de Données

Les clés privées sont:

  • Sauvegardées en MongoDB (champ private_key en base64)
  • Chiffrées au repos (via votre configuration MongoDB)
  • Accessibles uniquement avec authentification JWT

Tests

Scripts de Test Disponibles

# Test complet (création CA, certificats, exports, revocation)
./tests/test_complete.sh

# Test spécifique des exports
./tests/test_exports.sh

# Test du stockage des clés privées
./tests/test_private_keys.sh

Résultats des Tests

Voir tests/test_results.txt pour les résultats détaillés des tests.


Variables d'Environnement

# Stockage
export STORAGE_TYPE=memory              # memory ou mongodb (défaut: memory)
export MONGO_URI=mongodb://localhost:27017
export MONGO_DB=pkiapi

# Serveur
export PORT=8080
export JWT_SECRET_KEY=your-secret-key
export GIN_MODE=release

Conventions de Code

  • Gestion des erreurs : Propagation simple sans wrapper
  • Concurrence : sync.RWMutex pour le store
  • Cryptographie : Stdlib Go (crypto/x509, crypto/rsa, crypto/rand)
  • JWT : github.com/golang-jwt/jwt/v5
  • MongoDB : go.mongodb.org/mongo-driver

Améliorations Futures

  • Export des certificats (PEM, DER)
  • Clés privées dans JSON responses
  • Support OCSP (Online Certificate Status Protocol)
  • Interface web pour gérer les CAs
  • Auditing et logging complet
  • Rate limiting et throttling
  • Support HSM (Hardware Security Module)

Licence

MIT