{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms","title":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","description":"Un walkthrough técnico profundo de módulos de seguridad hardware, servicios cloud KMS, interfaces PKCS#11, patrones de envelope encryption, y cómo armar una arquitectura de gestión de secretos que sobreviva una auditoría.","language":"es","datePublished":"2026-01-25","dateModified":null,"contentFormat":"text/markdown","content":"Security\n\n# HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos\n\n2026-01-257 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/hardware-security-modules-hsm-cloud-kms>)\n\n## Arquitectura y Principios de un HSM\n\nUn Hardware Security Module es una pieza de hardware dedicada, una caja física o una placa PCIe, cuyo único trabajo es generar, almacenar y usar claves criptográficas sin jamás exponerlas. El material de claves vive dentro de un boundary resistente a manipulación. Si alguien físicamente se mete en el HSM, las claves se destruyen automáticamente (esto se llama zeroización).\n\nLa propiedad crítica es que las claves nunca salen del HSM en plaintext. Puede pedirle al HSM que encripte datos con una clave almacenada, desencripte datos, firme un mensaje, verifique una firma, pero no es posible pedirle que te dé la clave en sí. Esto es fundamentalmente diferente de un administrador de secretos como [HashiCorp Vault](<https://www.vaultproject.io/>), donde los secretos se almacenan encriptados pero pueden recuperarse en plaintext.\n\n## PKCS#11: La Interfaz Universal de HSM\n\nPKCS#11 (también llamado Cryptoki) es la API estándar para interactuar con tokens criptográficos, incluyendo HSMs. Es una API en C de los 90s, y se nota, pero es lo que todo usa.\n\n```c\n// pkcs11_example.c - Operaciones básicas de HSM via PKCS#11\n#include <pkcs11.h>\n#include <stdio.h>\n\nint main() {\n CK_RV rv;\n CK_SESSION_HANDLE session;\n CK_SLOT_ID slot = 0;\n\n rv = C_Initialize(NULL);\n rv = C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION,\n NULL, NULL, &session);\n\n CK_UTF8CHAR pin[] = \"crypto-user-pin\";\n rv = C_Login(session, CKU_USER, pin, sizeof(pin) - 1);\n\n // Generar una key AES-256 dentro del HSM\n CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL, 0 };\n CK_ULONG key_length = 32;\n CK_BBOOL true_val = CK_TRUE;\n CK_BBOOL false_val = CK_FALSE;\n CK_UTF8CHAR label[] = \"mi-data-encryption-key\";\n\n CK_ATTRIBUTE key_template[] = {\n { CKA_TOKEN, &true_val, sizeof(true_val) },\n { CKA_ENCRYPT, &true_val, sizeof(true_val) },\n { CKA_DECRYPT, &true_val, sizeof(true_val) },\n { CKA_EXTRACTABLE, &false_val, sizeof(false_val) }, // NO se puede exportar\n { CKA_SENSITIVE, &true_val, sizeof(true_val) },\n { CKA_LABEL, label, sizeof(label) - 1 },\n { CKA_VALUE_LEN, &key_length, sizeof(key_length) },\n };\n\n CK_OBJECT_HANDLE key;\n rv = C_GenerateKey(session, &mechanism, key_template,\n sizeof(key_template) / sizeof(CK_ATTRIBUTE), &key);\n\n // Encriptar datos usando la key (la key nunca sale del HSM)\n CK_BYTE plaintext[] = \"password de la base: hunter2\";\n CK_BYTE ciphertext[256];\n CK_ULONG ciphertext_len = sizeof(ciphertext);\n\n CK_GCM_PARAMS gcm_params = {\n .pIv = (CK_BYTE_PTR)\"random-iv-12b\",\n .ulIvLen = 12,\n .ulIvBits = 96,\n .pAAD = NULL, .ulAADLen = 0, .ulTagBits = 128,\n };\n CK_MECHANISM enc_mechanism = { CKM_AES_GCM, &gcm_params, sizeof(gcm_params) };\n\n rv = C_EncryptInit(session, &enc_mechanism, key);\n rv = C_Encrypt(session, plaintext, sizeof(plaintext) - 1,\n ciphertext, &ciphertext_len);\n\n printf(\"Encriptado %lu bytes\\n\", ciphertext_len);\n\n C_Logout(session);\n C_CloseSession(session);\n C_Finalize(NULL);\n return 0;\n}\n```\n\nObservar ` CKA_EXTRACTABLE = false ` y ` CKA_SENSITIVE = true `. Estos atributos aseguran que la key jamás puede exportarse del HSM.\n\n## Cloud KMS: HSMs como Servicio\n\n### AWS KMS y Envelope Encryption\n\n```python\n# aws_kms_envelope.py - Envelope encryption con AWS KMS\nimport boto3\nimport os\nfrom cryptography.hazmat.primitives.ciphers.aead import AESGCM\n\nkms = boto3.client('kms', region_name='us-east-1')\nCMK_KEY_ID = 'arn:aws:kms:us-east-1:123456789:key/mrk-abc123'\n\ndef encrypt_data(plaintext: bytes, context: dict) -> dict:\n \"\"\"\n Envelope encryption:\n 1. KMS genera una data key (dentro del HSM)\n 2. KMS devuelve data key plaintext + data key encriptada\n 3. Usamos la data key plaintext para encriptar localmente\n 4. Descartamos la data key plaintext\n 5. Guardamos la data key encriptada junto al ciphertext\n \"\"\"\n response = kms.generate_data_key(\n KeyId=CMK_KEY_ID,\n KeySpec='AES_256',\n EncryptionContext=context # Atada a este contexto\n )\n\n plaintext_key = response['Plaintext']\n encrypted_key = response['CiphertextBlob']\n\n nonce = os.urandom(12)\n aesgcm = AESGCM(plaintext_key)\n ciphertext = aesgcm.encrypt(nonce, plaintext, None)\n\n # CRÍTICO - borrar la key plaintext de memoria\n plaintext_key = b'\\x00' * len(plaintext_key)\n del plaintext_key\n\n return {\n 'ciphertext': ciphertext,\n 'nonce': nonce,\n 'encrypted_data_key': encrypted_key,\n 'encryption_context': context,\n }\n\ndef decrypt_data(envelope: dict) -> bytes:\n response = kms.decrypt(\n CiphertextBlob=envelope['encrypted_data_key'],\n EncryptionContext=envelope['encryption_context']\n )\n plaintext_key = response['Plaintext']\n\n aesgcm = AESGCM(plaintext_key)\n plaintext = aesgcm.decrypt(\n envelope['nonce'], envelope['ciphertext'], None\n )\n\n plaintext_key = b'\\x00' * len(plaintext_key)\n del plaintext_key\n return plaintext\n\ncontext = {'service': 'payment-api', 'environment': 'production'}\nenvelope = encrypt_data(b'database_password=super_secret_123', context)\nrecovered = decrypt_data(envelope)\n```\n\nEl parámetro ` EncryptionContext ` se suele pasar por alto pero es crítico para la seguridad. Ata la data key encriptada a un contexto específico. Si alguien intenta desencriptar la data key con un contexto diferente, KMS rechaza.\n\n### Rotación de Keys que No Rompe Nada\n\n```python\n# key_rotation.py\nimport boto3\nfrom datetime import datetime, timedelta\n\nkms = boto3.client('kms')\n\ndef setup_automatic_rotation(key_id: str):\n kms.enable_key_rotation(KeyId=key_id)\n status = kms.get_key_rotation_status(KeyId=key_id)\n print(f\"Rotación habilitada: {status['KeyRotationEnabled']}\")\n\ndef manual_rotation_with_alias(old_key_id: str, alias_name: str):\n \"\"\"Rotación manual usando aliases, útil para rotar más seguido que anualmente.\"\"\"\n new_key = kms.create_key(\n Description=f'Key rotada - {datetime.now().isoformat()}',\n KeyUsage='ENCRYPT_DECRYPT',\n Origin='AWS_KMS',\n Tags=[\n {'TagKey': 'RotatedFrom', 'TagValue': old_key_id},\n {'TagKey': 'RotationDate', 'TagValue': datetime.now().isoformat()},\n ]\n )\n new_key_id = new_key['KeyMetadata']['KeyId']\n\n # Actualizar alias para apuntar a la nueva key\n kms.update_alias(AliasName=alias_name, TargetKeyId=new_key_id)\n\n # LA KEY VIEJA PERMANECE ACTIVA para desencriptación\n # Este es el insight clave: no re-encriptás datos existentes\n print(f\"Alias {alias_name} ahora apunta a {new_key_id}\")\n print(f\"Key vieja {old_key_id} sigue activa para desencriptación\")\n```\n\n## La Arquitectura Completa de Gestión de Secretos\n\n```\n┌─────────────────────────────────────────────────────┐\n│ Capa de Aplicación │\n│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │\n│ │ Payment │ │ Auth │ │ Notification │ │\n│ │ Service │ │ Service │ │ Service │ │\n│ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │\n│ │ │ │ │\n│ ┌────▼──────────────▼──────────────────▼────────┐ │\n│ │ HashiCorp Vault │ │\n│ │ - Credenciales dinámicas de base de datos │ │\n│ │ - Emisión de certificados PKI │ │\n│ │ - Encriptación transit (delega a KMS) │ │\n│ │ - Secretos con leases y auto-rotación │ │\n│ └────────────────────┬──────────────────────────┘ │\n│ │ │\n│ ┌────────────────────▼──────────────────────────┐ │\n│ │ AWS KMS │ │\n│ │ - Auto-unseal de Vault │ │\n│ │ - Envelope encryption para transit engine │ │\n│ │ - S3 SSE-KMS para audit logs │ │\n│ │ - Master key para TDE de RDS │ │\n│ └────────────────────┬──────────────────────────┘ │\n│ │ │\n│ ┌────────────────────▼──────────────────────────┐ │\n│ │ AWS CloudHSM (FIPS 140-2 L3) │ │\n│ │ - Custom KMS key store │ │\n│ │ - Gestión de keys PCI DSS │ │\n│ │ - Keys de firma de código │ │\n│ └───────────────────────────────────────────────┘ │\n└─────────────────────────────────────────────────────┘\n```\n\n```hcl\n# vault_config.hcl\nstorage \"raft\" {\n path = \"/opt/vault/data\"\n node_id = \"vault-1\"\n\n retry_join {\n leader_api_addr = \"https://vault-2.internal:8200\"\n }\n retry_join {\n leader_api_addr = \"https://vault-3.internal:8200\"\n }\n}\n\nlistener \"tcp\" {\n address = \"0.0.0.0:8200\"\n tls_cert_file = \"/opt/vault/tls/vault.crt\"\n tls_key_file = \"/opt/vault/tls/vault.key\"\n}\n\nseal \"awskms\" {\n region = \"us-east-1\"\n kms_key_id = \"mrk-abc123\"\n}\n```\n\nLa arquitectura de tres niveles es deliberada:\n\n1. **Vault** maneja secretos dinámicos (credenciales de base de datos que rotan cada hora), PKI, y entrega de secretos a las aplicaciones.\n2. **KMS** maneja el auto-unseal de Vault y provee la encriptación de respaldo para el transit engine de Vault.\n3. **CloudHSM** respalda el custom key store de KMS para claves de encriptación reguladas por PCI.\n\n## Qué Hice Mal\n\nDos cosas me afectaron en este proyecto:\n\nPrimero, subestimé el costo de CloudHSM. A aproximadamente $1.50/hora por HSM (y se necesita al menos dos para HA), son más de $2,000/mes solo por los HSMs. Para la mayoría de las cargas de trabajo, KMS estándar a $1/key/mes más $0.03/10,000 llamadas API es más que suficiente.\n\nSegundo, el ecosistema de tooling de PKCS#11 es doloroso. Las librerías son viejas, la documentación asume que se ejecuta Solaris, y depurar errores de sesión requiere leer hex dumps. Si es posible quedarte en la capa de API del cloud KMS, hacelo.\n\nEl archivo ` .env ` ya no existe. Las contraseñas de base de datos rotan cada hora. El audit trail muestra exactamente quién accedió a qué key, cuándo. ¿Y la siguiente auditoría de seguridad? Pasó sin hallazgos. Eso se sintió bien.\n\n## Preguntas frecuentes\n\n### ¿Necesito un HSM dedicado o el cloud KMS es suficiente?\n\nCloud KMS (AWS KMS, Azure Key Vault, GCP Cloud KMS) es suficiente para el 95% de las cargas de trabajo. Necesitás un HSM dedicado (CloudHSM, Azure Dedicated HSM) solo cuando requisitos regulatorios exigen hardware single-tenant, cuando se necesita operaciones criptográficas custom no soportadas por KMS, o cuando se necesita acceso directo PKCS#11/JCE.\n\n### ¿Cuál es la diferencia entre una CMK y una data key?\n\nUna Customer Master Key (CMK) vive dentro del KMS/HSM y nunca sale. Una data key es generada por KMS, usada para encriptar tus datos reales, y después la data key misma es encriptada por la CMK. Este approach de dos niveles es envelope encryption.\n\n### ¿Cada cuánto debería rotar las claves de encriptación?\n\nRotar CMKs anualmente como baseline. AWS KMS soporta rotación automática anual. Las data keys pueden rotarse más seguido si es necesario. Lo importante es que la rotación sea automática y no requiera re-encriptar datos existentes cuando se utiliza envelope encryption.\n\n## Tips\n\n1. **Tip:** Nunca exportes master keys de un HSM. Si tu arquitectura requiere que la master key salga del boundary del HSM, tu arquitectura está mal. Utilizar ` envelope encryption ` en su lugar.\n2. **Tip:** AWS KMS ` GenerateDataKey ` devuelve tanto la versión plaintext como ciphertext de la data key. Utilizar el plaintext para encriptar, descartalo inmediatamente de memoria, guardá solo el ciphertext junto con los datos encriptados.\n3. **Tip:** Key rotation no significa re-encriptar todo. Con envelope encryption, solo rotás la KEK, las data keys existentes siguen válidas porque están encriptadas con la versión vieja de la KEK, que KMS todavía sabe desencriptar.\n4. **Tip:** Siempre colocar un ` DeletionWindowInDays ` de al menos 14 días para eliminación de keys en KMS. Borrar una key KMS accidentalmente es permanente y catastrófico, ese es 14 días salvaron a más de un equipo que conozco.\n\n- hsm\n- kms\n- pkcs11\n- envelope-encryption\n- key-rotation\n- aws-cloudhsm\n- secrets-management\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#title"},{"level":2,"text":"Arquitectura y Principios de un HSM","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#arquitectura-y-principios-de-un-hsm"},{"level":2,"text":"PKCS#11: La Interfaz Universal de HSM","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#pkcs11-la-interfaz-universal-de-hsm"},{"level":2,"text":"Cloud KMS: HSMs como Servicio","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#cloud-kms-hsms-como-servicio"},{"level":3,"text":"AWS KMS y Envelope Encryption","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#aws-kms-y-envelope-encryption"},{"level":3,"text":"Rotación de Keys que No Rompe Nada","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#rotacin-de-keys-que-no-rompe-nada"},{"level":2,"text":"La Arquitectura Completa de Gestión de Secretos","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#la-arquitectura-completa-de-gestin-de-secretos"},{"level":2,"text":"Qué Hice Mal","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#qu-hice-mal"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#questions"},{"level":3,"text":"¿Necesito un HSM dedicado o el cloud KMS es suficiente?","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-1"},{"level":3,"text":"¿Cuál es la diferencia entre una CMK y una data key?","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-2"},{"level":3,"text":"¿Cada cuánto debería rotar las claves de encriptación?","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-3"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#article-tips"}],"sections":[{"heading":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","level":1,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms","content":"Security"},{"heading":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","level":1,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#title","content":"2026-01-257 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/hardware-security-modules-hsm-cloud-kms>)"},{"heading":"Arquitectura y Principios de un HSM","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#arquitectura-y-principios-de-un-hsm","content":"Un Hardware Security Module es una pieza de hardware dedicada, una caja física o una placa PCIe, cuyo único trabajo es generar, almacenar y usar claves criptográficas sin jamás exponerlas. El material de claves vive dentro de un boundary resistente a manipulación. Si alguien físicamente se mete en el HSM, las claves se destruyen automáticamente (esto se llama zeroización).\n\nLa propiedad crítica es que las claves nunca salen del HSM en plaintext. Puede pedirle al HSM que encripte datos con una clave almacenada, desencripte datos, firme un mensaje, verifique una firma, pero no es posible pedirle que te dé la clave en sí. Esto es fundamentalmente diferente de un administrador de secretos como [HashiCorp Vault](<https://www.vaultproject.io/>), donde los secretos se almacenan encriptados pero pueden recuperarse en plaintext."},{"heading":"PKCS#11: La Interfaz Universal de HSM","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#pkcs11-la-interfaz-universal-de-hsm","content":"PKCS#11 (también llamado Cryptoki) es la API estándar para interactuar con tokens criptográficos, incluyendo HSMs. Es una API en C de los 90s, y se nota, pero es lo que todo usa.\n\n```c\n// pkcs11_example.c - Operaciones básicas de HSM via PKCS#11\n#include <pkcs11.h>\n#include <stdio.h>\n\nint main() {\n CK_RV rv;\n CK_SESSION_HANDLE session;\n CK_SLOT_ID slot = 0;\n\n rv = C_Initialize(NULL);\n rv = C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION,\n NULL, NULL, &session);\n\n CK_UTF8CHAR pin[] = \"crypto-user-pin\";\n rv = C_Login(session, CKU_USER, pin, sizeof(pin) - 1);\n\n // Generar una key AES-256 dentro del HSM\n CK_MECHANISM mechanism = { CKM_AES_KEY_GEN, NULL, 0 };\n CK_ULONG key_length = 32;\n CK_BBOOL true_val = CK_TRUE;\n CK_BBOOL false_val = CK_FALSE;\n CK_UTF8CHAR label[] = \"mi-data-encryption-key\";\n\n CK_ATTRIBUTE key_template[] = {\n { CKA_TOKEN, &true_val, sizeof(true_val) },\n { CKA_ENCRYPT, &true_val, sizeof(true_val) },\n { CKA_DECRYPT, &true_val, sizeof(true_val) },\n { CKA_EXTRACTABLE, &false_val, sizeof(false_val) }, // NO se puede exportar\n { CKA_SENSITIVE, &true_val, sizeof(true_val) },\n { CKA_LABEL, label, sizeof(label) - 1 },\n { CKA_VALUE_LEN, &key_length, sizeof(key_length) },\n };\n\n CK_OBJECT_HANDLE key;\n rv = C_GenerateKey(session, &mechanism, key_template,\n sizeof(key_template) / sizeof(CK_ATTRIBUTE), &key);\n\n // Encriptar datos usando la key (la key nunca sale del HSM)\n CK_BYTE plaintext[] = \"password de la base: hunter2\";\n CK_BYTE ciphertext[256];\n CK_ULONG ciphertext_len = sizeof(ciphertext);\n\n CK_GCM_PARAMS gcm_params = {\n .pIv = (CK_BYTE_PTR)\"random-iv-12b\",\n .ulIvLen = 12,\n .ulIvBits = 96,\n .pAAD = NULL, .ulAADLen = 0, .ulTagBits = 128,\n };\n CK_MECHANISM enc_mechanism = { CKM_AES_GCM, &gcm_params, sizeof(gcm_params) };\n\n rv = C_EncryptInit(session, &enc_mechanism, key);\n rv = C_Encrypt(session, plaintext, sizeof(plaintext) - 1,\n ciphertext, &ciphertext_len);\n\n printf(\"Encriptado %lu bytes\\n\", ciphertext_len);\n\n C_Logout(session);\n C_CloseSession(session);\n C_Finalize(NULL);\n return 0;\n}\n```\n\nObservar ` CKA_EXTRACTABLE = false ` y ` CKA_SENSITIVE = true `. Estos atributos aseguran que la key jamás puede exportarse del HSM."},{"heading":"Cloud KMS: HSMs como Servicio","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#cloud-kms-hsms-como-servicio","content":""},{"heading":"AWS KMS y Envelope Encryption","level":3,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#aws-kms-y-envelope-encryption","content":"```python\n# aws_kms_envelope.py - Envelope encryption con AWS KMS\nimport boto3\nimport os\nfrom cryptography.hazmat.primitives.ciphers.aead import AESGCM\n\nkms = boto3.client('kms', region_name='us-east-1')\nCMK_KEY_ID = 'arn:aws:kms:us-east-1:123456789:key/mrk-abc123'\n\ndef encrypt_data(plaintext: bytes, context: dict) -> dict:\n \"\"\"\n Envelope encryption:\n 1. KMS genera una data key (dentro del HSM)\n 2. KMS devuelve data key plaintext + data key encriptada\n 3. Usamos la data key plaintext para encriptar localmente\n 4. Descartamos la data key plaintext\n 5. Guardamos la data key encriptada junto al ciphertext\n \"\"\"\n response = kms.generate_data_key(\n KeyId=CMK_KEY_ID,\n KeySpec='AES_256',\n EncryptionContext=context # Atada a este contexto\n )\n\n plaintext_key = response['Plaintext']\n encrypted_key = response['CiphertextBlob']\n\n nonce = os.urandom(12)\n aesgcm = AESGCM(plaintext_key)\n ciphertext = aesgcm.encrypt(nonce, plaintext, None)\n\n # CRÍTICO - borrar la key plaintext de memoria\n plaintext_key = b'\\x00' * len(plaintext_key)\n del plaintext_key\n\n return {\n 'ciphertext': ciphertext,\n 'nonce': nonce,\n 'encrypted_data_key': encrypted_key,\n 'encryption_context': context,\n }\n\ndef decrypt_data(envelope: dict) -> bytes:\n response = kms.decrypt(\n CiphertextBlob=envelope['encrypted_data_key'],\n EncryptionContext=envelope['encryption_context']\n )\n plaintext_key = response['Plaintext']\n\n aesgcm = AESGCM(plaintext_key)\n plaintext = aesgcm.decrypt(\n envelope['nonce'], envelope['ciphertext'], None\n )\n\n plaintext_key = b'\\x00' * len(plaintext_key)\n del plaintext_key\n return plaintext\n\ncontext = {'service': 'payment-api', 'environment': 'production'}\nenvelope = encrypt_data(b'database_password=super_secret_123', context)\nrecovered = decrypt_data(envelope)\n```\n\nEl parámetro ` EncryptionContext ` se suele pasar por alto pero es crítico para la seguridad. Ata la data key encriptada a un contexto específico. Si alguien intenta desencriptar la data key con un contexto diferente, KMS rechaza."},{"heading":"Rotación de Keys que No Rompe Nada","level":3,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#rotacin-de-keys-que-no-rompe-nada","content":"```python\n# key_rotation.py\nimport boto3\nfrom datetime import datetime, timedelta\n\nkms = boto3.client('kms')\n\ndef setup_automatic_rotation(key_id: str):\n kms.enable_key_rotation(KeyId=key_id)\n status = kms.get_key_rotation_status(KeyId=key_id)\n print(f\"Rotación habilitada: {status['KeyRotationEnabled']}\")\n\ndef manual_rotation_with_alias(old_key_id: str, alias_name: str):\n \"\"\"Rotación manual usando aliases, útil para rotar más seguido que anualmente.\"\"\"\n new_key = kms.create_key(\n Description=f'Key rotada - {datetime.now().isoformat()}',\n KeyUsage='ENCRYPT_DECRYPT',\n Origin='AWS_KMS',\n Tags=[\n {'TagKey': 'RotatedFrom', 'TagValue': old_key_id},\n {'TagKey': 'RotationDate', 'TagValue': datetime.now().isoformat()},\n ]\n )\n new_key_id = new_key['KeyMetadata']['KeyId']\n\n # Actualizar alias para apuntar a la nueva key\n kms.update_alias(AliasName=alias_name, TargetKeyId=new_key_id)\n\n # LA KEY VIEJA PERMANECE ACTIVA para desencriptación\n # Este es el insight clave: no re-encriptás datos existentes\n print(f\"Alias {alias_name} ahora apunta a {new_key_id}\")\n print(f\"Key vieja {old_key_id} sigue activa para desencriptación\")\n```"},{"heading":"La Arquitectura Completa de Gestión de Secretos","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#la-arquitectura-completa-de-gestin-de-secretos","content":"```\n┌─────────────────────────────────────────────────────┐\n│ Capa de Aplicación │\n│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │\n│ │ Payment │ │ Auth │ │ Notification │ │\n│ │ Service │ │ Service │ │ Service │ │\n│ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │\n│ │ │ │ │\n│ ┌────▼──────────────▼──────────────────▼────────┐ │\n│ │ HashiCorp Vault │ │\n│ │ - Credenciales dinámicas de base de datos │ │\n│ │ - Emisión de certificados PKI │ │\n│ │ - Encriptación transit (delega a KMS) │ │\n│ │ - Secretos con leases y auto-rotación │ │\n│ └────────────────────┬──────────────────────────┘ │\n│ │ │\n│ ┌────────────────────▼──────────────────────────┐ │\n│ │ AWS KMS │ │\n│ │ - Auto-unseal de Vault │ │\n│ │ - Envelope encryption para transit engine │ │\n│ │ - S3 SSE-KMS para audit logs │ │\n│ │ - Master key para TDE de RDS │ │\n│ └────────────────────┬──────────────────────────┘ │\n│ │ │\n│ ┌────────────────────▼──────────────────────────┐ │\n│ │ AWS CloudHSM (FIPS 140-2 L3) │ │\n│ │ - Custom KMS key store │ │\n│ │ - Gestión de keys PCI DSS │ │\n│ │ - Keys de firma de código │ │\n│ └───────────────────────────────────────────────┘ │\n└─────────────────────────────────────────────────────┘\n```\n\n```hcl\n# vault_config.hcl\nstorage \"raft\" {\n path = \"/opt/vault/data\"\n node_id = \"vault-1\"\n\n retry_join {\n leader_api_addr = \"https://vault-2.internal:8200\"\n }\n retry_join {\n leader_api_addr = \"https://vault-3.internal:8200\"\n }\n}\n\nlistener \"tcp\" {\n address = \"0.0.0.0:8200\"\n tls_cert_file = \"/opt/vault/tls/vault.crt\"\n tls_key_file = \"/opt/vault/tls/vault.key\"\n}\n\nseal \"awskms\" {\n region = \"us-east-1\"\n kms_key_id = \"mrk-abc123\"\n}\n```\n\nLa arquitectura de tres niveles es deliberada:\n\n1. **Vault** maneja secretos dinámicos (credenciales de base de datos que rotan cada hora), PKI, y entrega de secretos a las aplicaciones.\n2. **KMS** maneja el auto-unseal de Vault y provee la encriptación de respaldo para el transit engine de Vault.\n3. **CloudHSM** respalda el custom key store de KMS para claves de encriptación reguladas por PCI."},{"heading":"Qué Hice Mal","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#qu-hice-mal","content":"Dos cosas me afectaron en este proyecto:\n\nPrimero, subestimé el costo de CloudHSM. A aproximadamente $1.50/hora por HSM (y se necesita al menos dos para HA), son más de $2,000/mes solo por los HSMs. Para la mayoría de las cargas de trabajo, KMS estándar a $1/key/mes más $0.03/10,000 llamadas API es más que suficiente.\n\nSegundo, el ecosistema de tooling de PKCS#11 es doloroso. Las librerías son viejas, la documentación asume que se ejecuta Solaris, y depurar errores de sesión requiere leer hex dumps. Si es posible quedarte en la capa de API del cloud KMS, hacelo.\n\nEl archivo ` .env ` ya no existe. Las contraseñas de base de datos rotan cada hora. El audit trail muestra exactamente quién accedió a qué key, cuándo. ¿Y la siguiente auditoría de seguridad? Pasó sin hallazgos. Eso se sintió bien."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#questions","content":""},{"heading":"¿Necesito un HSM dedicado o el cloud KMS es suficiente?","level":3,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-1","content":"Cloud KMS (AWS KMS, Azure Key Vault, GCP Cloud KMS) es suficiente para el 95% de las cargas de trabajo. Necesitás un HSM dedicado (CloudHSM, Azure Dedicated HSM) solo cuando requisitos regulatorios exigen hardware single-tenant, cuando se necesita operaciones criptográficas custom no soportadas por KMS, o cuando se necesita acceso directo PKCS#11/JCE."},{"heading":"¿Cuál es la diferencia entre una CMK y una data key?","level":3,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-2","content":"Una Customer Master Key (CMK) vive dentro del KMS/HSM y nunca sale. Una data key es generada por KMS, usada para encriptar tus datos reales, y después la data key misma es encriptada por la CMK. Este approach de dos niveles es envelope encryption."},{"heading":"¿Cada cuánto debería rotar las claves de encriptación?","level":3,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#question-3","content":"Rotar CMKs anualmente como baseline. AWS KMS soporta rotación automática anual. Las data keys pueden rotarse más seguido si es necesario. Lo importante es que la rotación sea automática y no requiera re-encriptar datos existentes cuando se utiliza envelope encryption."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#article-tips","content":"1. **Tip:** Nunca exportes master keys de un HSM. Si tu arquitectura requiere que la master key salga del boundary del HSM, tu arquitectura está mal. Utilizar ` envelope encryption ` en su lugar.\n2. **Tip:** AWS KMS ` GenerateDataKey ` devuelve tanto la versión plaintext como ciphertext de la data key. Utilizar el plaintext para encriptar, descartalo inmediatamente de memoria, guardá solo el ciphertext junto con los datos encriptados.\n3. **Tip:** Key rotation no significa re-encriptar todo. Con envelope encryption, solo rotás la KEK, las data keys existentes siguen válidas porque están encriptadas con la versión vieja de la KEK, que KMS todavía sabe desencriptar.\n4. **Tip:** Siempre colocar un ` DeletionWindowInDays ` de al menos 14 días para eliminación de keys en KMS. Borrar una key KMS accidentalmente es permanente y catastrófico, ese es 14 días salvaron a más de un equipo que conozco.\n\n- hsm\n- kms\n- pkcs11\n- envelope-encryption\n- key-rotation\n- aws-cloudhsm\n- secrets-management\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/hardware-security-modules-hsm-cloud-kms"},{"text":"HashiCorp Vault","url":"https://www.vaultproject.io/"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms"},"headline":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","description":"Un walkthrough técnico profundo de módulos de seguridad hardware, servicios cloud KMS, interfaces PKCS#11, patrones de envelope encryption, y cómo armar una arquitectura de gestión de secretos que sobreviva una auditoría.","datePublished":"2026-01-25","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://lucioduran.com/favicons/og-default.png","url":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"Security","keywords":"hsm, kms, pkcs11, envelope-encryption, key-rotation, aws-cloudhsm, secrets-management","wordCount":1194,"timeRequired":"PT7M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/hardware-security-modules-hsm-cloud-kms"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"HSMs y Cloud KMS: PKCS#11, Envelope Encryption y Arquitectura Real de Gestión de Secretos","item":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿Necesito un HSM dedicado o el cloud KMS es suficiente?","acceptedAnswer":{"@type":"Answer","text":"Cloud KMS (AWS KMS, Azure Key Vault, GCP Cloud KMS) es suficiente para el 95% de las cargas de trabajo. Necesitás un HSM dedicado (CloudHSM, Azure Dedicated HSM) solo cuando requisitos regulatorios exigen hardware single-tenant, cuando se necesita operaciones criptográficas custom no soportadas por KMS, o cuando se necesita acceso directo PKCS#11/JCE."}},{"@type":"Question","name":"¿Cuál es la diferencia entre una CMK y una data key?","acceptedAnswer":{"@type":"Answer","text":"Una Customer Master Key (CMK) vive dentro del KMS/HSM y nunca sale. Una data key es generada por KMS, usada para encriptar tus datos reales, y después la data key misma es encriptada por la CMK. Este approach de dos niveles es envelope encryption."}},{"@type":"Question","name":"¿Cada cuánto debería rotar las claves de encriptación?","acceptedAnswer":{"@type":"Answer","text":"Rotar CMKs anualmente como baseline. AWS KMS soporta rotación automática anual. Las data keys pueden rotarse más seguido si es necesario. Lo importante es que la rotación sea automática y no requiera re-encriptar datos existentes cuando se utiliza envelope encryption."}}]}]}],"contentHash":"9412edcbda76ed8e4fa134427ec807dbca8e9e6b998580169996d891cc7f1616","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/hardware-security-modules-hsm-cloud-kms","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":61602,"contentBytes":12922}}
