# 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) - ✅ **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 └── go.mod ``` ## Démarrage rapide ### 1. Installer et compiler ```bash go mod download go build -o pkiapi ./cmd/main.go ``` ### 2. Démarrer le serveur **Mode développement (MemoryStore):** ```bash export STORAGE_TYPE=memory export PORT=8080 ./pkiapi # Serveur lancé sur http://localhost:8080 ``` **Mode production (MongoDB):** ```bash export STORAGE_TYPE=mongodb export MONGO_URI=mongodb://mongodb-server:27017 export MONGO_DB=pkiapi-prod export JWT_SECRET_KEY=super-secret-key ./pkiapi ``` ### 3. Obtenir un token JWT ```bash 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 :** ```bash curl -X POST http://localhost:8080/api/v1/login \ -H "Content-Type: application/json" \ -d '{ "username": "admin", "password": "admin" }' ``` **Réponse :** ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 86400 } ``` --- ### 🔑 Autorités de Certification (Authentifiés) #### GET /api/v1/ca Liste toutes les autorités de certification. **Requête :** ```bash TOKEN="" curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8080/api/v1/ca ``` **Réponse :** ```json { "cas": [ { "id": "16de28da-f25e-49cd-81de-a929d34dfe08", "subject": "CN=Root CA,O=Example,C=FR", "issuer": "CN=Root CA,O=Example,C=FR", "not_before": "2025-12-06T22:52:48Z", "not_after": "2035-12-04T22:52:48Z", "serial_number": "574847517" } ] } ``` --- #### POST /api/v1/ca Crée une nouvelle autorité de certification auto-signée. **Requête :** ```bash 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 :** ```json { "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...", "is_ca": true }, "created_by": "admin" } ``` --- #### GET /api/v1/ca/:id Récupère une autorité de certification par ID. **Requête :** ```bash TOKEN="" CA_ID="ff3ac5c5-08d1-401b-9e83-f18eda4c538b" curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8080/api/v1/ca/$CA_ID ``` **Réponse :** ```json { "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...", "is_ca": true } } ``` --- #### POST /api/v1/ca/sign Crée une CA intermédiaire (Sub-CA) signée par une CA parent. **Requête :** ```bash 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 }" ``` **Réponse :** ```json { "ca": { "id": "b2350d39-53c2-469a-802c-acc39707e352", "subject": "CN=Intermediate CA,O=Example Inc,C=FR", "not_before": "2025-12-06T21:45:09Z", "not_after": "2030-12-05T21:45:09Z", "serial_number": "576310632", "certificate": "MIIDOTCCAiGgAwIBAgIEIlnNaD...", "is_ca": true }, "created_by": "admin", "signed_by": "ff3ac5c5-08d1-401b-9e83-f18eda4c538b" } ``` --- ### 📜 Certificats (Authentifiés) #### GET /api/v1/certificates Liste tous les certificats. **Requête :** ```bash TOKEN="" curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8080/api/v1/certificates ``` **Réponse :** ```json { "certificates": [ { "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", "revoked": false } ] } ``` --- #### POST /api/v1/certificates Crée un certificat auto-signé. **Requête :** ```bash 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 :** ```json { "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...", "revoked": false }, "created_by": "admin" } ``` --- #### POST /api/v1/certificates/sign Signe un certificat avec une CA. **Requête :** ```bash 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 }" ``` **Réponse :** ```json { "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...", "revoked": false }, "created_by": "admin", "signed_by": "b2350d39-53c2-469a-802c-acc39707e352" } ``` --- #### GET /api/v1/certificates/:id Récupère un certificat par ID. **Requête :** ```bash TOKEN="" CERT_ID="e12e08a9-adeb-404c-a7b7-a613b77dfe66" curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8080/api/v1/certificates/$CERT_ID ``` **Réponse :** ```json { "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...", "revoked": false } } ``` --- #### POST /api/v1/revoke Révoque un certificat. **Requête :** ```bash 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\" }" ``` **Réponse :** ```json { "message": "certificat révoqué", "id": "e12e08a9-adeb-404c-a7b7-a613b77dfe66", "reason": "Compromised key" } ``` --- #### GET /api/v1/crl Récupère la Certificate Revocation List (liste des certificats révoqués). **Requête :** ```bash TOKEN="" curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8080/api/v1/crl ``` **Réponse :** ```json { "crl": [ { "serial_number": "46798982", "subject": "CN=server.example.com,O=Example Inc,C=FR" } ], "version": 1 } ``` --- ## Variables d'Environnement - `JWT_SECRET_KEY` : Secret pour signer les tokens JWT (défaut: `your-secret-key-change-in-prod`) ```bash export JWT_SECRET_KEY="your-secure-secret-key" ./pkiapi ``` --- ## Exemple de flux complet ```bash # 1. Obtenir un token TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin"}' | jq -r '.token') echo "Token: $TOKEN" # 2. Créer une Root CA ROOT_CA=$(curl -s -X POST http://localhost:8080/api/v1/ca \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"subject":"CN=Root CA,O=Example,C=FR","validity_days":3650}') ROOT_CA_ID=$(echo $ROOT_CA | jq -r '.ca.id') echo "Root CA ID: $ROOT_CA_ID" # 3. Créer une Sub-CA SUB_CA=$(curl -s -X POST http://localhost:8080/api/v1/ca/sign \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"parent_ca_id\":\"$ROOT_CA_ID\",\"subject\":\"CN=Intermediate CA,O=Example,C=FR\",\"validity_days\":1825}") SUB_CA_ID=$(echo $SUB_CA | jq -r '.ca.id') echo "Sub-CA ID: $SUB_CA_ID" # 4. Signer un certificat avec la Sub-CA CERT=$(curl -s -X POST http://localhost:8080/api/v1/certificates/sign \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"ca_id\":\"$SUB_CA_ID\",\"subject\":\"CN=app.example.com,O=Example,C=FR\",\"validity_days\":365}") CERT_ID=$(echo $CERT | jq -r '.certificate.id') echo "Certificate ID: $CERT_ID" # 5. Lister toutes les CAs curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/v1/ca | jq . # 6. Lister tous les certificats curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/v1/certificates | jq . # 7. Révoquer le certificat curl -s -X POST http://localhost:8080/api/v1/revoke \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"certificate_id\":\"$CERT_ID\",\"reason\":\"Test\"}" | jq . # 8. Voir la CRL curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/v1/crl | jq . ``` --- ## Structure du projet ``` pkiapi/ ├── cmd/main.go # Point d'entrée ├── internal/ │ ├── api/ │ │ ├── router.go # Routes Gin │ │ ├── auth.go # Login │ │ ├── ca.go # Handlers CA │ │ └── certificates.go # Handlers certificats │ ├── auth/ │ │ ├── jwt.go # JWT manager │ │ └── middleware.go # Middleware JWT │ ├── pki/ │ │ ├── certificate.go # Logique X.509 │ │ └── errors.go # Erreurs PKI │ └── storage/ │ ├── store.go # Store thread-safe │ └── errors.go # Erreurs storage ├── go.mod ├── go.sum ├── Makefile ├── README.md └── .gitignore ``` --- ## 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 --- ## Future améliorations - [ ] Persistance en base de données (PostgreSQL) - [ ] Support OCSP (Online Certificate Status Protocol) - [ ] Interface web pour gérer les CAs - [ ] Export des certificats (PEM, DER) - [ ] Support des chaînes intermédiaires - [ ] Auditing et logging - [ ] Rate limiting et throttling --- ## Licence MIT