Construccion de sistemas de verificacion biometrica para Indonesia: arquitectura y patrones Rust
Engineering Team
Construyendo el backend de verificacion biometrica SIM para Indonesia
Este articulo es la tercera parte de la serie sobre el mandato biometrico SIM de Indonesia, y se centra en las decisiones arquitectonicas practicas y la implementacion de codigo necesarias para construir un sistema de verificacion biometrica de nivel produccion. Profundizaremos en el diseno del sistema, flujos de datos, practicas de cifrado y servicios backend escalables construidos con Rust y Axum.
Vista general de la arquitectura del sistema
Un sistema de verificacion biometrica de nivel produccion consta de multiples componentes interconectados, cada uno con responsabilidades especificas:
Componentes principales
- Servicio de captura (SDK movil/web) — Componente frontend que maneja la captura de imagen facial y la deteccion de vida en el dispositivo
- API Gateway — Gestion centralizada de autenticacion, limitacion de velocidad, enrutamiento de solicitudes y terminacion TLS
- Motor de procesamiento biometrico — Servicio que extrae plantillas de caracteristicas biometricas de imagenes faciales
- Servicio de deteccion de vida — Ejecuta modelos de deteccion de vida pasiva y activa
- Servicio de integracion IKD — Maneja la comunicacion de verificacion 1:1 con la plataforma IKD de Indonesia
- Servicio de cifrado — Gestion de claves AES-256, cifrado/descifrado de plantillas
- Servicio de registro de auditoria — Registra todas las transacciones de verificacion para cumplimiento regulatorio
- Monitoreo y alertas — Salud del sistema, metricas de rendimiento y deteccion de anomalias
Arquitectura de flujo de datos
SDK cliente → API Gateway → Motor biometrico → Plataforma IKD
↓ ↓ ↓
Limitacion de velocidad Servicio crypto Registro de auditoria
↓ ↓ ↓
Cache de auth Gestion de claves Almacenamiento de cumplimiento
Implementacion del backend Rust
Estructura del proyecto
biometric-service/
├── Cargo.toml
├── src/
│ ├── main.rs # Punto de entrada y configuracion del servidor
│ ├── config.rs # Gestion de configuracion
│ ├── routes/
│ │ ├── mod.rs
│ │ ├── verify.rs # Endpoints de verificacion
│ │ ├── health.rs # Verificacion de salud
│ │ └── admin.rs # Endpoints de administracion
│ ├── services/
│ │ ├── mod.rs
│ │ ├── biometric.rs # Procesamiento biometrico
│ │ ├── liveness.rs # Deteccion de vida
│ │ ├── ikd.rs # Cliente plataforma IKD
│ │ ├── crypto.rs # Operaciones de cifrado
│ │ └── audit.rs # Registro de auditoria
│ ├── models/
│ ├── middleware/
│ └── errors.rs
├── migrations/
└── tests/
Endpoint de verificacion principal
use axum::{extract::State, Json};
use chrono::Utc;
use uuid::Uuid;
pub async fn verify_biometric(
State(state): State<AppState>,
Json(req): Json<VerificationRequest>,
) -> Result<Json<VerificationResponse>, AppError> {
let transaction_id = Uuid::new_v4();
let started_at = Utc::now();
req.validate()?;
let liveness = state.liveness_service
.detect(&req.capture_data)
.await
.map_err(|e| {
state.audit.log_failure(transaction_id, "liveness_failed", &e);
e
})?;
if !liveness.is_live {
return Err(AppError::LivenessCheckFailed);
}
let template = state.biometric_engine
.extract(&req.facial_image).await?;
let encrypted = state.crypto_service
.encrypt_template(&template).await?;
let ikd_result = state.ikd_client
.verify(&req.nik, &encrypted).await?;
let elapsed = Utc::now() - started_at;
state.audit.log_verification(AuditRecord {
transaction_id,
nik_hash: hash_nik(&req.nik),
liveness_score: liveness.confidence,
match_score: ikd_result.score,
verified: ikd_result.matched,
duration_ms: elapsed.num_milliseconds(),
timestamp: started_at,
}).await?;
Ok(Json(VerificationResponse {
transaction_id,
verified: ikd_result.matched,
confidence: ikd_result.score,
}))
}
Servicio de cifrado AES-256
use aes_gcm::{Aes256Gcm, KeyInit, Nonce};
use aes_gcm::aead::Aead;
use rand::RngCore;
pub struct CryptoService {
cipher: Aes256Gcm,
}
impl CryptoService {
pub fn new(key: &[u8; 32]) -> Self {
let cipher = Aes256Gcm::new_from_slice(key)
.expect("AES-256 key must be 32 bytes");
Self { cipher }
}
pub async fn encrypt_template(
&self,
template: &BiometricTemplate,
) -> Result<EncryptedTemplate, CryptoError> {
let mut nonce_bytes = [0u8; 12];
rand::thread_rng().fill_bytes(&mut nonce_bytes);
let nonce = Nonce::from_slice(&nonce_bytes);
let plaintext = bincode::serialize(template)?;
let ciphertext = self.cipher
.encrypt(nonce, plaintext.as_ref())
.map_err(|_| CryptoError::EncryptionFailed)?;
Ok(EncryptedTemplate {
ciphertext,
nonce: nonce_bytes.to_vec(),
algorithm: "AES-256-GCM".into(),
})
}
}
Escalabilidad y rendimiento
Con mas de 270 millones de habitantes y 345 millones de tarjetas SIM activas, los requisitos de escala son enormes:
- Estimacion de carga pico: Asumiendo 50 millones de nuevos registros en los primeros 6 meses, aproximadamente 278.000 verificaciones por dia
- Horas pico: El pico puede ser 3-5x del promedio, es decir, 830.000-1.390.000 por dia
- Solicitudes por segundo: Pico de aproximadamente 16 TPS, con margen para trafico en rafagas
Implementacion de cumplimiento UU PDP
pub async fn cleanup_expired_records(
pool: &PgPool,
) -> Result<u64, sqlx::Error> {
let cutoff = Utc::now() - chrono::Duration::days(5 * 365);
let result = sqlx::query("DELETE FROM audit_logs WHERE created_at < $1")
.bind(cutoff).execute(pool).await?;
Ok(result.rows_affected())
}
pub async fn handle_deletion_request(
pool: &PgPool,
nik_hash: &str,
) -> Result<DeletionReport, AppError> {
let mut tx = pool.begin().await?;
let templates_deleted = sqlx::query(
"DELETE FROM biometric_templates WHERE nik_hash = $1"
).bind(nik_hash).execute(&mut *tx).await?.rows_affected();
let logs_anonymized = sqlx::query(
"UPDATE audit_logs SET nik_hash = 'anonymized' WHERE nik_hash = $1"
).bind(nik_hash).execute(&mut *tx).await?.rows_affected();
tx.commit().await?;
Ok(DeletionReport {
templates_deleted,
logs_anonymized,
completed_at: Utc::now(),
})
}
Recomendaciones de despliegue
Centros de datos en Indonesia
Segun el reglamento KOMDIGI y los requisitos de UU PDP, el procesamiento biometrico debe realizarse en centros de datos en Indonesia:
- Principal: Jakarta (cerca de la mayoria de usuarios y la plataforma IKD)
- DR: Surabaya o Bali (redundancia geografica)
- CDN: Nodos de borde nacionales (para distribucion de SDK y recursos estaticos)
Conclusion
La construccion de un sistema de verificacion biometrica que cumpla con el reglamento KOMDIGI de Indonesia es un desafio de ingenieria complejo pero manejable. Puntos clave:
- Seguridad primero: cifrado AES-256, transmision TLS 1.3, arquitectura de confianza cero
- Impulsado por cumplimiento: proteccion de datos UU PDP, retencion de registros de auditoria de 5 anos, derecho de eliminacion del usuario
- Diseno escalable: escalamiento horizontal, caching multinivel, procesamiento asincrono
- Despliegue localizado: centros de datos indonesios, optimizacion de bajo ancho de banda, soporte de diversidad de dispositivos
- Monitoreo integral: metricas en tiempo real, deteccion de anomalias, informes de cumplimiento
Construir este sistema con Rust y Axum proporciona excelentes garantias de rendimiento y seguridad mientras cumple con los estrictos requisitos regulatorios de Indonesia.