Modelo de seguridad del Cosigner

Ninguna parte puede mover fondos por sí sola: ni Fystack, ni tu host, ni nada que esté en medio.

Quién controla qué

Tú Fystack
Host del cosigner, almacenamiento, red Apex: emparejamiento, identidades, revocación
Clave de almacenamiento: contraseña o política de KMS Orquestador: sesiones
Servidor de callback, política y claves Gateway: autenticación y retransmisión de streams
Backups, exportaciones, actualizaciones Nodos de MPCium y políticas del workspace

Controles de firma

Cada firma debe superar todos estos controles:

  1. Políticas del workspace y grupos de aprobación en Apex.
  2. Firma del iniciador: el orquestador solo acepta solicitudes firmadas por Apex.
  3. Fijación del comité: los participantes y el umbral deben coincidir con los del keygen.
  4. Firma del orquestador: el cosigner la verifica contra la clave fijada durante el emparejamiento.
  5. Firma del aprobador: obligatoria para las billeteras con un aprobador.
  6. Tu callback: debe devolver un approve firmado.
  7. Umbral: se requiere el fragmento de tu cosigner.

Si Fystack se viera completamente comprometido, los controles 1 a 5 podrían fallar. El paso 6 sigue vigente: se ejecuta en tu infraestructura, con claves que Fystack nunca ve, sobre los bytes exactos que se van a firmar.

Autenticación

Identidad del cosigner: clave Ed25519. Se almacena en state/cosigner.key (0600). Se registra una sola vez en Apex mediante un token de emparejamiento. Firma el JWT del Gateway, cada evento de sesión y mensaje entre peers, y las entradas de auditoría.

Cosigner → Fystack: un JWT EdDSA por stream.

Gateway JWT claims

{
  "iss": "<cosigner_id>",
  "sub": "<cosigner_id>",
  "aud": "cosigner-gateway",
  "ctx": "cosigner-gateway-auth-v1",
  "jti": "<random>",
  "iat": 1791794400,
  "exp": 1791794460
}

El Gateway acepta solo EdDSA, comprueba la audiencia y la expiración (con un margen de 30s) y rechaza un jti reutilizado durante 2 minutos. La revocación desconecta de inmediato los streams activos.

Fystack → cosigner: la clave y la huella digital del orquestador se fijan durante el emparejamiento. Cada mensaje de control debe estar firmado por ella con un número de secuencia creciente. Las firmas de resultados usan un prefijo distinto para que no puedan reutilizarse como mensajes de control.

Participante ↔ participante: las claves de los peers llegan en el session_start firmado. Intercambio X25519 firmado, claves HKDF por dirección, ChaCha20-Poly1305. El Gateway y el orquestador solo ven texto cifrado.

Cifrado en reposo

La contraseña o AWS KMS desenvuelve la KEK de almacenamiento, HKDF deriva cuatro claves de ámbito y cada fila se cifra con AES-256-GCM
Click to open the full-size diagram
  • Clave de almacenamiento: 32 bytes, se desenvuelve al iniciar a partir de una contraseña (Argon2id t=3, 64 MiB) o de AWS KMS. Solo en memoria y se pone a cero después de usarla.
  • Claves de ámbito: HKDF-SHA256 deriva claves separadas para shares, preparams, checkpoints y metadata.
  • Filas: AES-256-GCM, nonce aleatorio de 12 bytes, vinculado al ámbito y a la clave de la fila. Las filas movidas no se pueden descifrar.
  • Ningún fragmento sale en texto plano: se eliminan de los eventos. Las exportaciones se sellan con RSA-OAEP + AES-GCM o con una frase de contraseña.

Desbloqueo con contraseña: cosigner-cli nunca coloca la contraseña en variables de entorno ni en argumentos. Abre un socket local de un solo uso; el contenedor demuestra un token de 32 bytes mediante HMAC y recibe la contraseña cifrada con AES-GCM.

Hardening del runtime

  • Imagen distroless, sin root, fijada por digest.
  • Sistema de archivos raíz de solo lectura; tmpfs para /tmp y /run/cosigner.
  • Se eliminan todas las capabilities, no-new-privileges.
  • La configuración y los secretos se montan en solo lectura.
  • Límites: mensajes de control de 128 KiB, 20 inicios y 10 abortos por minuto, 5 sesiones simultáneas.

Registro de auditoría

JSONL de solo anexado. Cada entrada está firmada e incluye el hash de la entrada anterior, por lo que las ediciones y eliminaciones se pueden detectar. Envíalo fuera del host.

Verificación de la cadena de suministro

Los binarios, instaladores e imágenes se compilan con workflows de release de GitHub Actions y se firman con Sigstore. El certificado indica el workflow y el tag exactos. El pipeline del runtime también ejecuta go mod verify, pruebas de condiciones de carrera, una comprobación de reproducibilidad, govulncheck y gosec, y adjunta un SBOM y la procedencia.

cosigner-cli verifica en cada up, update y doctor. Para comprobarlo manualmente:

Verificar los artefactos de release

cosign verify ghcr.io/fystack/cosigner@sha256:<digest> \
  --certificate-identity https://github.com/fystack/cosigner/.github/workflows/release.yml@refs/tags/<version> \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Digests y checksums: cosigner.fystack.io. Informa cualquier discrepancia a security@fystack.io.

Riesgos residuales

  • Modo regular = custodia en el host. El acceso root o a Docker en el host permite leer la memoria. El soporte para Nitro Enclave (próximamente) eliminará ese riesgo.
  • Calidad del callback. Un callback que aprueba sin decodificar la transacción no aporta nada. Deniega por defecto.
  • Disponibilidad. Un host hostil puede bloquear el tráfico o eliminar y revertir filas. El cifrado detecta ediciones, no eliminaciones. Mantén backups.
  • Duplicados. Nunca ejecutes el mismo cosigner en dos hosts.
  • Material de recuperación. Las contraseñas de backup y las frases de contraseña de exportación desbloquean tu fragmento. Guárdalas por separado.

Antes de usar fondos reales: prueba la restauración, el reinicio, los fallos y la revocación de IAM, y obtén una revisión independiente.