1import{j as e}from"./index-prc0XQdj.js";let r=` 2 3La integración de Lamassu con AWS IoT Core cubre el puente entre la PKI gestionada por Lamassu y la plataforma de conectividad de AWS. Cuando un dispositivo obtiene su certificado a través del proceso de enrolamiento EST, el conector se encarga de que ese certificado y la identidad asociada sean reconocidos en AWS IoT Core sin intervención manual. El resultado es que el dispositivo puede autenticarse directamente en AWS con el mismo certificado X.509 que Lamassu emitió. 4 5Desde el punto de vista del protocolo, el dispositivo se autentica ante AWS IoT Core mediante TLS mutuo (mTLS): presenta su certificado X.509 emitido por Lamassu como certificado de cliente, y AWS IoT Core verifica la cadena de certificados hasta llegar a la CA registrada en la cuenta. Lamassu actúa como autoridad de certificación (CA); el conector se encarga de que esa CA esté registrada en AWS y de que el certificado del dispositivo sea conocido por la plataforma antes de que el dispositivo intente conectarse (en modo \`auto\`) o en su primera conexión (en modo JITP). 6 7Este documento está dirigido tanto al administrador PKI, que necesita configurar el conector y registrar las CAs, como al desarrollador de firmware de dispositivos, que necesita entender cómo se nombran los Things, cómo funciona el Device Shadow y qué ocurre cuando un certificado se revoca. Para el desarrollador de firmware, el dato más importante es que el **nombre del Thing en AWS (ThingName) corresponde siempre al Common Name (CN) del certificado emitido por Lamassu**, independientemente del modo de aprovisionamiento. 8 9Arquitectura del conector [#arquitectura-del-conector] 10 11El conector de AWS IoT Core es un proceso Go independiente, un binario o contenedor separado del núcleo de Lamassu. En un despliegue monolÃtico se compila por defecto (etiqueta de compilación \`!noaws\`) y se activa mediante \`aws_iot_manager.enabled: true\` en el fichero de configuración. En despliegues distribuidos, se ejecuta como un contenedor propio con acceso a los servicios de CA, DMS Manager y Device Manager de Lamassu a través de HTTP. 12 13El conector no sondea los servicios de Lamassu periódicamente. En su lugar, **se suscribe al bus de eventos interno** de Lamassu (AMQP o AWS SQS/SNS, configurable) y reacciona a los eventos que le interesan: creación o actualización de CAs, creación o actualización de DMS, vinculación de identidad de dispositivo, cambio de estado de certificado, actualización de metadatos de certificado y actualización de metadatos de dispositivo. Este modelo orientado a eventos garantiza que la sincronización con AWS sea casi inmediata y no genere carga de sondeo. 14 15Para evitar bucles infinitos, el conector ignora cualquier evento cuyo campo \`source\` de CloudEvent coincida con su propia URI de origen. Esto previene que las escrituras de metadatos que el propio conector realiza vuelvan a disparar el mismo flujo. 16 17Cuando se ejecutan varios conectores en paralelo, por ejemplo, para distintas cuentas de AWS, cada instancia tiene su propio \`connector_id\`. Todos los metadatos que el conector escribe en Lamassu se almacenan bajo la clave \`lamassu.io/iot/{connector_id}\`, lo que permite coexistencia sin colisiones. 18 19Prerrequisitos [#prerrequisitos] 20 21Antes de activar el conector es necesario disponer de una cuenta AWS con los permisos IAM adecuados y tener el conector correctamente configurado. El proceso de despliegue (Docker Compose, Kubernetes o binario) se describe en la [documentación de despliegue](/docs/deployment/overview). 22 23Permisos IAM necesarios [#permisos-iam-necesarios] 24 25La identidad IAM con la que opera el conector debe tener al mÃnimo los siguientes permisos sobre los recursos de la cuenta destino: 26 27| Acción IAM | Propósito | 28| ------------------------------------------------------ | --------------------------------------------------------------------------- | 29| \`iot:GetRegistrationCode\` | Obtener el código de verificación para el registro de CA en Primary Account | 30| \`iot:RegisterCACertificate\` | Registrar la CA en AWS IoT | 31| \`iot:DescribeCACertificate\` | Consultar el estado del registro de la CA | 32| \`iot:CreateThing\` / \`iot:UpdateThing\` | Crear o actualizar Things en IoT Core | 33| \`iot:RegisterThing\` | Aprovisionar Things mediante plantilla | 34| \`iot:RegisterCertificate\` | Registrar certificados de dispositivo | 35| \`iot:UpdateCertificate\` | Cambiar el estado de un certificado (ACTIVE / INACTIVE / REVOKED) | 36| \`iot:CreatePolicy\` / \`iot:AttachPolicy\` | Crear y adjuntar polÃticas IoT | 37| \`iot:CreateThingGroup\` / \`iot:AddThingToThingGroup\` | Gestionar grupos de Things | 38| \`iot:CreateProvisioningTemplate\` | Crear plantillas JITP | 39| \`iotdata:GetThingShadow\` / \`iotdata:UpdateThingShadow\` | Leer y escribir el Device Shadow | 40 41Para el mecanismo de desconexión forzada tras revocación también se requiere acceso a la API del plano de datos de AWS IoT (\`iot:Connect\` con SigV4 sobre WebSocket), que se negocia de forma implÃcita con las credenciales del conector. 42 43Parámetros de configuración [#parámetros-de-configuración] 44 45| Parámetro | Tipo | Requerido | Descripción | 46| ------------------------------ | ------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | 47| \`connector_id\` | string | Sà | Identificador único de esta instancia del conector. Se usa como espacio de nombres para los metadatos: \`lamassu.io/iot/{connector_id}\`. | 48| \`aws_config.region\` | string | Sà | Región AWS donde opera el conector. | 49| \`aws_config.auth_method\` | string | Sà | Método de autenticación: \`static\`, \`role\` o vacÃo (cadena de credenciales por defecto del SDK). | 50| \`aws_config.access_key_id\` | string | Solo con \`auth_method=static\` | Clave de acceso AWS. | 51| \`aws_config.secret_access_key\` | string | Solo con \`auth_method=static\` | Clave secreta AWS. | 52| \`aws_config.session_token\` | string | No | Token de sesión (con \`auth_method=static\`). | 53| \`aws_config.role_arn\` | string | Solo con \`auth_method=role\` | ARN del rol a asumir. | 54| \`aws_config.endpoint_url\` | string | No | URL alternativa para todos los servicios AWS (útil con LocalStack en pruebas). | 55| \`subscriber_event_bus\` | objeto | Sà | Configuración del bus de eventos al que se suscribe el conector (AMQP o AWS SQS/SNS). | 56| \`dms_manager_client\` | string | Sà | URL HTTP del servicio DMS Manager de Lamassu. | 57| \`device_manager_client\` | string | Sà | URL HTTP del Device Manager de Lamassu. | 58| \`ca_client\` | string | Sà | URL HTTP del servicio de CA de Lamassu. | 59 60Registro de la CA en AWS IoT Core [#registro-de-la-ca-en-aws-iot-core] 61 62Para que los dispositivos puedan autenticarse en AWS IoT Core con certificados emitidos por una CA de Lamassu, esa CA debe registrarse previamente en la cuenta AWS. El conector gestiona este registro de forma automática en respuesta a los eventos \`EventCreateCAKey\`, \`EventImportCAKey\` y \`EventUpdate
62CAMetadataKey\`, pero la operación **solo se dispara cuando el administrador la solicita explÃcitamente** mediante el campo de metadatos de la CA. 63 64Cómo solicitar el registro [#cómo-solicitar-el-registro] 65 66El registro se desencadena estableciendo el valor \`registration.status = "REQUESTED"\` en la clave \`lamassu.io/iot/{connector_id}\` de los metadatos de la CA. Esto puede hacerse desde la consola de Lamassu en la sección de gestión de la CA o mediante la API. 67 68Una vez recibido el evento, el conector intenta registrar la CA en AWS y actualiza el campo \`registration.status\` en los metadatos de la CA con el resultado: \`"SUCCEEDED"\` si el registro fue correcto, o \`"FAILED"\` acompañado de un mensaje de error en caso contrario. El proceso es asÃncrono, por lo que es necesario consultar periódicamente el estado de los metadatos hasta que la operación concluya. 69 70Primary Account [#primary-account] 71 72Cuando el parámetro \`primary_account\` es \`true\`, el conector ejecuta el flujo completo de registro con verificación de posesión de clave privada: 73 741. Llama a \`iot:GetRegistrationCode\` para obtener el código de verificación de AWS. 752. El conector genera internamente un par de claves RSA-2048 efÃmero y construye un CSR cuyo Common Name es exactamente ese código de registro. A continuación llama al servicio de firma de Lamassu para que la CA registrada emita un certificado de verificación X.509 real firmando ese CSR. La clave privada efÃmera se usa únicamente para este propósito y no se almacena ni se envÃa a AWS. 763. EnvÃa a AWS la CA (en PEM) y el certificado de verificación mediante \`iot:RegisterCACertificate\`, activando el registro con \`AllowAutoRegistration: true\`. 77 78Solo una cuenta puede ser propietaria de una CA en una región AWS dada. Si la CA ya está registrada con el mismo número de serie, el conector omite el paso silenciosamente. 79 80Los tags que AWS IoT Core aplica al certificado de CA registrado son \`LMS.CA.ID\`, \`LMS.CA.SN\` y \`LMS.CA.CN\`. 81 82Secondary Account (SNI-only) [#secondary-account-sni-only] 83 84Cuando \`primary_account\` es \`false\`, el conector registra la CA usando el modo \`CertificateMode: SNI_ONLY\`. Este modo no requiere código de verificación ni acceso a la clave privada de la CA, por lo que es la opción adecuada cuando la CA se gestiona desde otra cuenta de AWS o cuando el administrador no dispone de la clave privada. Es el método habitual para registrar la misma CA en varias cuentas de AWS simultáneamente. 85 86Configuración del DMS [#configuración-del-dms] 87 88Cada DMS que participe en la integración con AWS IoT Core debe tener configurada la clave de metadatos \`lamassu.io/iot/{connector_id}\`. El campo más importante de esa configuración es \`registration_mode\`, que determina cómo se aprovisionan los dispositivos en AWS. 89 90Existen tres modos de registro, y la elección entre ellos depende de la estrategia de aprovisionamiento de la flota. 91 92Modo none [#modo-none] 93 94En este modo el conector **no crea Things, grupos ni polÃticas** en AWS IoT Core. Se limita a sincronizar el estado de los certificados (activo, revocado, suspendido) a medida que cambian en Lamassu. Es el modo adecuado cuando el aprovisionamiento de Things en AWS se gestiona por un sistema externo y solo se necesita que Lamassu mantenga el estado de los certificados actualizado. 95 96Modo auto [#modo-auto] 97 98El modo \`auto\` delega en Lamassu el aprovisionamiento completo del dispositivo en AWS en el momento del enrolamiento. Cuando el dispositivo completa con éxito su enrolamiento EST y Lamassu emite el evento \`EventBindDeviceIdentityKey\`, el conector ejecuta automáticamente la siguiente secuencia: 99 1001. Crea o actualiza las polÃticas IoT configuradas en el DMS. 1012. Crea el grupo raÃz \`LAMASSU\` en la cuenta AWS (si no existe) y los grupos hijos configurados en el DMS como subgrupos de \`LAMASSU\`. Si los grupos ya existen, el error \`ResourceAlreadyExistsException\` se ignora, por lo que la operación es idempotente. 1023. Si el Thing ya existÃa en AWS IoT Core, el conector itera todos los certificados (principals) actualmente adjuntos a ese Thing y los marca como \`REVOKED\` en AWS, para garantizar que los certificados anteriores no puedan seguir siendo usados para autenticarse.
1034. Llama a \`iot:RegisterThing\` con una plantilla de aprovisionamiento de estilo CloudFormation que crea el Thing, registra el certificado del dispositivo (PEM del certificado del dispositivo y del certificado de la CA emisora) y adjunta las polÃticas configuradas. 104 Una vez completado el aprovisionamiento, el conector almacena el ARN del certificado resultante en los metadatos del certificado de Lamassu bajo la clave \`lamassu.io/iot/{connector_id}\` y marca el dispositivo como \`Registered: true\` en Device Manager. 105 106**El nombre del Thing en AWS es el Common Name (CN) del certificado del dispositivo.** Esta convención es fundamental para el desarrollador de firmware: el valor \`/CN=\` que el dispositivo incluye en su CSR al enrolarse se convierte en el ThingName con el que deberá identificarse en todas las operaciones MQTT contra AWS IoT Core. 107 108Modo jitp [#modo-jitp] 109 110El modo Just-In-Time Provisioning (JITP) delega el aprovisionamiento en AWS en lugar de hacerlo el conector directamente. Cuando el conector detecta que el DMS está en modo \`jitp\`, crea una plantilla de aprovisionamiento JITP en AWS IoT Core y la adjunta al certificado de CA registrado. Esta plantilla se crea o actualiza en el momento en que el DMS se crea o actualiza en Lamassu - no en el momento del enrolamiento del dispositivo. A partir de ese momento, cuando un dispositivo con un certificado emitido por esa CA se conecta por primera vez a AWS IoT Core, AWS ejecuta la plantilla automáticamente: crea el Thing, registra el certificado y lo activa. 111 112El nombre del Thing en la plantilla JITP se deriva de \`AWS::IoT::Certificate::CommonName\`, que corresponde al CN del certificado del dispositivo - la misma convención que el modo \`auto\`. 113 114Este modo requiere que se configure el campo \`jitp_config.provisioning_role_arn\` con el ARN de un rol IAM que AWS IoT Core pueda asumir para ejecutar la plantilla. Si no se configura, el conector utiliza el valor por defecto \`arn:aws:iam::{account}:role/JITPRole\` y registra un aviso en el log. El administrador debe asegurarse de que ese rol existe en la cuenta y tiene los permisos necesarios antes de activar el modo JITP. 115 116Aprovisionamiento de dispositivos (modo automático) [#aprovisionamiento-de-dispositivos-modo-automático] 117 118Para el desarrollador de firmware, el modo \`auto\` es transparente: el dispositivo realiza su enrolamiento EST de la forma habitual y, como efecto secundario, queda aprovisionado en AWS IoT Core sin ningún paso adicional. 119 120El flujo completo desde el punto de vista del dispositivo es el siguiente: 121 122\`\`\`bash 123# 1. El dispositivo genera su clave privada y su CSR con el CN que será su ThingName 124openssl ecparam -name prime256v1 -genkey -noout -out device.key 125openssl req -new -key device.key -sha256 -out device.csr \\ 126 -subj "/CN=mi-dispositivo-001/O=Acme/OU=IoT" 127 128# 2. El dispositivo se enrola en Lamassu vÃa EST 129openssl req -in device.csr -outform DER | base64 -w 0 > device.csr.b64 130curl -s --cacert lamassu-trust.pem \\ 131 --cert bootstrap.crt --key bootstrap.key \\ 132 -H "Content-Type: application/pkcs10" \\ 133 --data-binary "@device.csr.b64" \\ 134 "https://<EST_HOST>/.well-known/est/<DMS_ID>/simpleenroll" \\ 135 -o enroll.b64 136 137# 3. El dispositivo extrae su certificado 138base64 -d -i enroll.b64 | openssl pkcs7 -inform DER -print_certs -out device.crt 139 140# A partir de este punto, el conector crea automáticamente el Thing "mi-dispositivo-001" 141# en AWS IoT Core. El dispositivo puede conectarse a AWS con el mismo certificado. 142\`\`\` 143 144Una vez que el conector completa el aprovisionamiento, el dispositivo puede conectarse al endpoint AWS IoT Core de MQTT usando su clave privada y el certificado emitido por Lamassu. El ThingName con el que debe identificarse en AWS es exactamente el CN del certificado. 145 146Aprovisionamiento de dispositivos (modo JITP) [#aprovisionamiento-de-dispositivos-modo-jitp] 147 148En el modo JITP el dispositivo también realiza su enrolamiento EST de forma convencional y obtiene su certificado de Lamassu. La diferencia es que AWS IoT Core no conoce al dispositivo hasta que este intenta conectarse por primera vez. 149 150Cuando el dispositivo establece su primera conexión MQTT a AWS IoT Core presentando el certificado emitido por Lamassu, AWS detecta que el certificado pertenece a una CA registrada con una plantilla JITP, ejecuta esa plantilla y crea el Thing automáticamente. La conexión inicial puede fallar o demorarse mientras se ejecuta la plantilla; el firmware debe estar preparado para reintentar la conexión. 151 152Para que el flujo JITP funcione correctamente: 153 154* La CA debe estar registrada en AWS en modo Primary Account (el modo SNI-only no admite JITP). 155* El rol IAM configurado en \`jitp_config.provisioning_role_arn\` debe existir y tener permisos para crear Things, registrar certificados y adju
155ntar polÃticas en la cuenta AWS. 156* El dispositivo debe presentar tanto su certificado como el certificado de la CA emisora en el handshake TLS con AWS IoT Core. 157 158Los certificados aprovisionados mediante JITP **no tienen asociada la clave de metadatos del conector** (\`lamassu.io/iot/{connector_id}\`) en Lamassu. Como consecuencia, los cambios de estado de esos certificados en Lamassu no se sincronizan automáticamente con AWS a través del mecanismo de sincronización de estado descrito en la siguiente sección. 159 160Sincronización del estado del certificado [#sincronización-del-estado-del-certificado] 161 162El conector escucha el evento \`EventUpdateCertificateStatusKey\` y, cuando un certificado que tiene la clave de metadatos del conector cambia de estado en Lamassu, replica ese cambio en AWS IoT Core. La tabla siguiente muestra la correspondencia de estados: 163 164| Estado en Lamassu | Razón de revocación | Estado en AWS IoT Core | 165| ----------------- | -------------------- | ---------------------- | 166| \`Active\` | Ninguna | \`ACTIVE\` | 167| \`Revoked\` | \`certificateHold\` | \`INACTIVE\` | 168| \`Revoked\` | Cualquier otra razón | \`REVOKED\` | 169 170Solo los estados \`Active\` y \`Revoked\` producen una llamada a \`iot:UpdateCertificate\`. Los demás estados del ciclo de vida de Lamassu (\`RenewalWindow\`, \`AboutToExpire\`, \`Expired\`) no se sincronizan con AWS IoT Core; el estado del certificado en AWS permanece sin cambios hasta que el estado en Lamassu sea \`Active\` o \`Revoked\`. 171 172Desconexión forzada al revocar [#desconexión-forzada-al-revocar] 173 174Cuando el conector marca un certificado como \`REVOKED\` o \`INACTIVE\` en AWS, ejecuta adicionalmente una desconexión forzada del dispositivo. Para ello abre una conexión MQTT sobre WebSocket (con autenticación SigV4 con las credenciales del conector) al endpoint de datos de AWS IoT Core, usando el CN del certificado como identificador de cliente MQTT, y la cierra inmediatamente. Esto termina cualquier sesión MQTT activa que el dispositivo pueda tener en ese momento. 175 176Esta desconexión forzada se produce en el momento en que Lamassu registra el cambio de estado. Si el dispositivo vuelve a intentar conectarse tras la desconexión, AWS IoT Core rechazará la conexión porque el certificado ya figura como \`REVOKED\` o \`INACTIVE\`. 177 178Los certificados aprovisionados en modo JITP no disponen de esta sincronización automática, ya que no tienen la clave de metadatos del conector. 179 180Device Shadow y automatización [#device-shadow-y-automatización] 181 182El conector puede escribir en el Device Shadow de AWS IoT Core para enviar señales de acción al firmware del dispositivo. Esta funcionalidad se activa por DMS mediante \`shadow_config.enable: true\`. 183 184Si \`shadow_config.shadow_name\` contiene un valor, el conector usa un Named Shadow con ese nombre; en caso contrario, usa el Classic Shadow (shadow predeterminado del Thing). 185 186Qué escribe el conector en el shadow [#qué-escribe-el-conector-en-el-shadow] 187 188El conector escribe en el campo \`desired.identity_actions\` del documento shadow. Cada entrada contiene un timestamp Unix en milisegundos. El firmware del dispositivo debe leer este campo y actuar en consecuencia. 189 190Existen dos tipos de acciones: 191 192**\`UPDATE_CERTIFICATE\`**: se escribe cuando la ventana de renovación preventiva de un certificado se activa - es decir, cuando el campo \`triggered\` de la delta de renovación preventiva pasa de \`false\` a \`true\`. Esta acción indica al dispositivo que debe iniciar el proceso de re-enrolamiento para renovar su certificado antes de que expire. 193 194**\`UPDATE_TRUST_ANCHOR_LIST\`**: se escribe en todos los dispositivos de un DMS cuando la lista \`ManagedCAs\` del DMS cambia. Esta acción indica al dispositivo que debe actualizar su almacén de CAs de confianza. 195 196El proceso de escritura en el shadow consiste en leer el shadow actual (\`iotdata:GetThingShadow\`), combinar las nuevas acciones con las existentes y escribir el resultado (\`iotdata:UpdateThingShadow\`). Si el shadow no existe, el conector lo crea. Tras una escritura correcta, la lista de acciones pendientes en los metadatos del dispositivo en Lamassu se limpia. 197 198\`\`\`json 199{ 200 "state": { 201 "desired": { 202 "identity_actions": { 203 "UPDATE_CERTIFICATE": 1716300000000, 204 "UPDATE_TRUST_ANCHOR_LIST": 1716299000000 205 } 206 } 207 } 208} 209\`\`\` 210 211PolÃticas de AWS IoT [#polÃticas-de-aws-iot] 212
213El conector crea y adjunta las polÃticas que se configuran en el DMS. Una polÃtica tÃpica para un dispositivo que usa MQTT y Device Shadow tiene la siguiente estructura: 214 215\`\`\`json 216{ 217 "Version": "2012-10-17", 218 "Statement": [ 219 { 220 "Effect": "Allow", 221 "Action": [ 222 "iot:Connect" 223 ], 224 "Resource": [ 225 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:client/\${iot:Connection.Thing.ThingName}" 226 ] 227 }, 228 { 229 "Effect": "Allow", 230 "Action": [ 231 "iot:Publish" 232 ], 233 "Resource": [ 234 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/\${iot:Connection.Thing.ThingName}", 235 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/\${iot:Connection.Thing.ThingName}/shadow/[name/\${ShadowName}/]*" 236 ] 237 }, 238 { 239 "Effect": "Allow", 240 "Action": [ 241 "iot:Subscribe" 242 ], 243 "Resource": [ 244 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topicfilter/$aws/things/\${iot:Connection.Thing.ThingName}", 245 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topicfilter/$aws/things/\${iot:Connection.Thing.ThingName}/shadow/[name/\${ShadowName}/]*" 246 ] 247 }, 248 { 249 "Effect": "Allow", 250 "Action": [ 251 "iot:Receive" 252 ], 253 "Resource": [ 254 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/\${iot:Connection.Thing.ThingName}", 255 "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/\${iot:Connection.Thing.ThingName}/shadow/[name/\${ShadowName}/]*" 256 ] 257 } 258 ] 259} 260\`\`\` 261 262En la polÃtica anterior, los marcadores \`<AWS_REGION>\` y \`<AWS_ACCOUNT_ID>\` deben reemplazarse por la región AWS y el identificador de cuenta de doce dÃgitos de la cuenta destino antes de aplicar la polÃtica. La variable \`\${iot:Connection.Thing.ThingName}\` limita automáticamente cada permiso al Thing al que el dispositivo está conectado, siguiendo el principio de mÃnimo privilegio. La variable \`\${ShadowName}\` en los ARN de shadow es un marcador que debe reemplazarse con el valor de \`shadow_config.shadow_name\` configurado en el DMS; si se usa el Classic Shadow, se puede simplificar eliminando el segmento \`name/\${ShadowName}/\`. Las polÃticas de AWS IoT no admiten expresiones regulares con alternancia; la notación \`[name/\${ShadowName}/]*\` representa la opcionalidad del segmento dentro de las restricciones de la sintaxis de ARN. 263 264El primer statement permite que el dispositivo se conecte usando su ThingName como identificador MQTT. El segundo autoriza la publicación en el topic MQTT genérico del Thing y en los topics del shadow, necesario para que el dispositivo pueda actualizar el estado reportado. Los dos últimos statements otorgan permisos de suscripción y recepción sobre los mismos topics, lo que permite al dispositivo recibir actualizaciones del shadow (por ejemplo, las acciones \`UPDATE_CERTIFICATE\` y \`UPDATE_TRUST_ANCHOR_LIST\` escritas por el conector). 265 266Solución de problemas [#solución-de-problemas] 267 268**SÃntoma:** El registro de la CA permanece indefinidamente en estado \`REQUESTED\`. 269 270**Causa:** El conector no está en ejecución o no está suscrito al bus de eventos. También puede indicar credenciales IAM incorrectas, permisos insuficientes o que la clave de metadatos se escribió con un \`connector_id\` incorrecto. 271 272**Resolución:** Verificar que el proceso del conector está activo y que los logs no muestran errores de comunicación con AWS. Comprobar que el campo de metadatos se escribió bajo la clave exacta \`lamassu.io/iot/{connector_id}\`. Si el error persiste, el conector actualizará el estado a \`FAILED\` con un mensaje descriptivo en los metadatos de la CA. 273 274*** 275 276**SÃntoma:** El estado de un certificado no se sincroniza con AWS tras una revocación. 277 278**Causa:** Lo más habitual es que el certificado fue aprovisionado en modo JITP. Los certificados JITP no tienen la clave de metadatos del conector y quedan fuera del mecanismo de sincronización de estado. Si el DMS está en modo \`auto\`, puede indicar que el aprovisionamiento inicial no completó correctamente y el ARN de AWS no se almacenó en los metadatos del certificado. 279 280**Resolución:** Para certificados JITP, migrar el DMS a modo \`auto\` y re-aprovisionar los dispositivos afectados. Para certificados en modo \`auto\`, verificar que el certificado tiene el ARN de AWS almacenado en sus metadatos; si no lo tiene, repetir el aprovisionamiento. 281 282*** 283 284**SÃntoma:** La desconexión forzada no termina la sesión MQTT del dispositivo tras la revocación. 285 286**Causa:** El dispositivo usa un client ID MQTT diferente al CN del certificado. La desconexión forzada abre una conexión usando el CN como client ID; si el firmware usa otro identificador, la desconexión no afecta a esa sesión. 287 288**Resolución:** Asegurarse de que el firmware usa exactamente el CN del certificado como identificador de cliente MQTT. Ese CN coincide con el ThingName en AWS IoT Core. 289 290*** 291 292**SÃntoma:** El dispositivo recibe \`CLIENT_ID_REJECTED\` al conectarse a AWS IoT Core. 293 294**Causa:** El client ID MQTT no coincide con el ThingName, que es siempre el CN del certificado emitido por Lamassu. 295 296**Resolución:** Verificar que el firmware usa exactamente el valor del campo CN incluido en el CSR de enrolamiento como identificador de cliente MQTT. 297 298*** 299 300**SÃntoma:** La primera conexión MQTT del dispositivo en modo JITP falla o excede el tiempo de espera. 301 302**Causa:** Es el comportamiento esperado mientras AWS ejecuta la plantilla JITP en la primera conexión del dispositivo. 303 304**Resolución:** El firmware debe implementar reintentos con backoff exponencial para la primera conexión. Si el fallo persiste más allá de unos minutos, verificar que el rol IAM configurado en \`jitp_config.provisioning_role_arn\` existe en la cuenta y tiene permisos para crear Things, registrar certificados y adju
304ntar polÃticas. 305 306*** 307 308**SÃntoma:** El Device Shadow no se actualiza cuando deberÃa. 309 310**Causa:** La función de shadow está desactivada en la configuración del DMS, las credenciales del conector carecen de permisos sobre la API de datos de IoT, o el firmware lee un shadow diferente al configurado. 311 312**Resolución:** Comprobar que \`shadow_config.enable\` está a \`true\` en los metadatos del conector para el DMS correspondiente. Si se usa Named Shadow, verificar que \`shadow_config.shadow_name\` contiene el nombre correcto y que el firmware lee ese Named Shadow y no el Classic Shadow. Confirmar que las credenciales del conector tienen permisos \`iotdata:GetThingShadow\` y \`iotdata:UpdateThingShadow\`. 313 314<Cards> 315 <Card title="Configurar un DMS" href="/docs/platform/pki/device-enrollment" /> 316 317 <Card title="Enrolamiento de dispositivos (EST)" href="/docs/platform/pki/est-enrollment" /> 318 319 <Card title="Gestión de certificados" href="/docs/platform/pki/certificates" /> 320</Cards> 321`,c={title:"AWS IoT Core",description:"El conector de Lamassu para AWS IoT Core sincroniza las identidades de los dispositivos con la plataforma AWS, gestionando el registro de CAs, el aprovisionamiento de Things y el ciclo de vida de los certificados de forma automática y orientada a eventos."},d={contents:[{heading:void 0,content:"La integración de Lamassu con AWS IoT Core cubre el puente entre la PKI gestionada por Lamassu y la plataforma de conectividad de AWS. Cuando un dispositivo obtiene su certificado a través del proceso de enrolamiento EST, el conector se encarga de que ese certificado y la identidad asociada sean reconocidos en AWS IoT Core sin intervención manual. El resultado es que el dispositivo puede autenticarse directamente en AWS con el mismo certificado X.509 que Lamassu emitió."},{heading:void 0,content:"Desde el punto de vista del protocolo, el dispositivo se autentica ante AWS IoT Core mediante TLS mutuo (mTLS): presenta su certificado X.509 emitido por Lamassu como certificado de cliente, y AWS IoT Core verifica la cadena de certificados hasta llegar a la CA registrada en la cuenta. Lamassu actúa como autoridad de certificación (CA); el conector se encarga de que esa CA esté registrada en AWS y de que el certificado del dispositivo sea conocido por la plataforma antes de que el dispositivo intente conectarse (en modo `auto`) o en su primera conexión (en modo JITP)."},{heading:void 0,content:"Este documento está dirigido tanto al administrador PKI, que necesita configurar el conector y registrar las CAs, como al desarrollador de firmware de dispositivos, que necesita entender cómo se nombran los Things, cómo funciona el Device Shadow y qué ocurre cuando un certificado se revoca. Para el desarrollador de firmware, el dato más importante es que el **nombre del Thing en AWS (ThingName) corresponde siempre al Common Name (CN) del certificado emitido por Lamassu**, independientemente del modo de aprovisionamiento."},{heading:"arquitectura-del-conector",content:"El conector de AWS IoT Core es un proceso Go independiente, un binario o contenedor separado del núcleo de Lamassu. En un despliegue monolÃtico se compila por defecto (etiqueta de compilación `!noaws`) y se activa mediante `aws_iot_manager.enabled: true` en el fichero de configuración. En despliegues distribuidos, se ejecuta como un contenedor propio con acceso a los servicios de CA, DMS Manager y Device Manager de Lamassu a través de HTTP."},{heading:"arquitectura-del-conector",content:"El conector no sondea los servicios de Lamassu periódicamente. En su lugar, **se suscribe al bus de eventos interno** de Lamassu (AMQP o AWS SQS/SNS, configurable) y reacciona a los eventos que le interesan: creación o actualización de CAs, creación o actualización de DMS, vinculación de identidad de dispositivo, cambio de estado de certificado, actualización de metadatos de certificado y actualización de metadatos de dispositivo. Este modelo orientado a eventos garantiza que la sincronización con AWS sea casi inmediata y no genere carga de sondeo."},{heading:"arquitectura-del-conector",content:"Para evitar bucles infinitos, el conector ignora cualquier evento cuyo campo `source` de CloudEvent coincida con su propia URI de origen. Esto previene que las escrituras de metadatos que el propio conector realiza vuelvan a disparar el mismo flujo."},{heading:"arquitectura-del-conector",content:"Cuando se ejecutan varios conectores en paralelo, por ejemplo, para distintas cuentas de AWS, cada instancia tiene su propio `connector_id`. Todos los metadatos que el conector escribe en Lamassu se almacenan bajo la clave `lamassu.io/iot/{connector_id}`, lo que permite coexistencia sin colisiones."},{heading:"prerrequisitos",content:"Antes de activar el conector es necesario disponer de una cuenta AWS con los permisos IAM adecuados y tener el conector correctamente configurado. El proceso de despliegue (Docker Compose, Kubernetes o binario) se describe en la documentación de despliegue."},{heading:"permisos-iam-necesarios",content:"La identidad IAM con la que opera el conector debe tener al mÃnimo los siguientes permisos sobre los re
321cursos de la cuenta destino:"},{heading:"permisos-iam-necesarios",content:"Acción IAM"},{heading:"permisos-iam-necesarios",content:"Propósito"},{heading:"permisos-iam-necesarios",content:"`iot:GetRegistrationCode`"},{heading:"permisos-iam-necesarios",content:"Obtener el código de verificación para el registro de CA en Primary Account"},{heading:"permisos-iam-necesarios",content:"`iot:RegisterCACertificate`"},{heading:"permisos-iam-necesarios",content:"Registrar la CA en AWS IoT"},{heading:"permisos-iam-necesarios",content:"`iot:DescribeCACertificate`"},{heading:"permisos-iam-necesarios",content:"Consultar el estado del registro de la CA"},{heading:"permisos-iam-necesarios",content:"`iot:CreateThing` / `iot:UpdateThing`"},{heading:"permisos-iam-necesarios",content:"Crear o actualizar Things en IoT Core"},{heading:"permisos-iam-necesarios",content:"`iot:RegisterThing`"},{heading:"permisos-iam-necesarios",content:"Aprovisionar Things mediante plantilla"},{heading:"permisos-iam-necesarios",content:"`iot:RegisterCertificate`"},{heading:"permisos-iam-necesarios",content:"Registrar certificados de dispositivo"},{heading:"permisos-iam-necesarios",content:"`iot:UpdateCertificate`"},{heading:"permisos-iam-necesarios",content:"Cambiar el estado de un certificado (ACTIVE / INACTIVE / REVOKED)"},{heading:"permisos-iam-necesarios",content:"`iot:CreatePolicy` / `iot:AttachPolicy`"},{heading:"permisos-iam-necesarios",content:"Crear y adjuntar polÃticas IoT"},{heading:"permisos-iam-necesarios",content:"`iot:CreateThingGroup` / `iot:AddThingToThingGroup`"},{heading:"permisos-iam-necesarios",content:"Gestionar grupos de Things"},{heading:"permisos-iam-necesarios",content:"`iot:CreateProvisioningTemplate`"},{heading:"permisos-iam-necesarios",content:"Crear plantillas JITP"},{heading:"permisos-iam-necesarios",content:"`iotdata:GetThingShadow` / `iotdata:UpdateThingShadow`"},{heading:"permisos-iam-necesarios",content:"Leer y escribir el Device Shadow"},{heading:"permisos-iam-necesarios",content:"Para el mecanismo de desconexión forzada tras revocación también se requiere acceso a la API del plano de datos de AWS IoT (`iot:Connect` con SigV4 sobre WebSocket), que se negocia de forma implÃcita con las credenciales del conector."},{heading:"parámetros-de-configuración",content:"Parámetro"},{heading:"parámetros-de-configuración",content:"Tipo"},{heading:"parámetros-de-configuración",content:"Requerido"},{heading:"parámetros-de-configuración",content:"Descripción"},{heading:"parámetros-de-configuración",content:"`connector_id`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"Identificador único de esta instancia del conector. Se usa como espacio de nombres para los metadatos: `lamassu.io/iot/{connector_id}`."},{heading:"parámetros-de-configuración",content:"`aws_config.region`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"Región AWS donde opera el conector."},{heading:"parámetros-de-configuración",content:"`aws_config.auth_method`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"Método de autenticación: `static`, `role` o vacÃo (cadena de credenciales por defecto del SDK)."},{heading:"parámetros-de-configuración",content:"`aws_config.access_key_id`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"Solo con `auth_method=static`"},{heading:"parámetros-de-configuración",content:"Clave de acceso AWS."},{heading:"parámetros-de-configuración",content:"`aws_config.secret_access_key`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"Solo con `auth_method=static`"},{heading:"parámetros-de-configuración",content:"Clave secreta AWS."},{heading:"parámetros-de-configuración",content:"`aws_config.session_token`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"No"},{heading:"parámetros-de-configuración",content:"Token de sesión (con `auth_method=static`)."},{heading:"parámetros-de-configuración",content:"`aws_config.role_arn`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"Solo con `auth_method=role`"},{heading:"parámetros-de-configuración",content:"ARN del rol a asumir."},{heading:"parámetros-de-configuración",content:"`aws_config.endpoint_url`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"No"},{heading:"parámetros-de-configuración",content:"URL alternativa para todos los servicios AWS (útil con LocalStack en pruebas)."},{heading:"parámetros-de-configuración",content:"`subscriber_event_bus`"},{heading:"parámetros-de-configuración",content:"objeto"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"Configuración del bus de eventos al que se suscribe el conector (AMQP o AWS SQS/SNS)."},{heading:"parámetros-de-configuración",content:"`dms_manager_client`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"URL HTTP del servicio DMS Manager de Lamassu."},{heading:"parámetros-de-configuración",content:"`device_manager_client`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"URL HTTP del Device Manager de Lamassu."},{heading:"parámetros-de-configuración",content:"`ca_client`"},{heading:"parámetros-de-configuración",content:"string"},{heading:"parámetros-de-configuración",content:"SÃ"},{heading:"parámetros-de-configuración",content:"URL HTTP del servicio de CA de Lamassu."},{heading:"registro-de-la-ca-en-aws-iot-core",content:"Para que los dispositivos puedan autenticarse en AWS IoT Core con certificados emitidos por una CA de Lamassu, esa CA debe registrarse previamente en la cuenta AWS. El conector gestiona este registro de forma automática en respuesta a los eventos `EventCreateCAKey`, `EventImportCAKey` y `EventUpdate
321CAMetadataKey`, pero la operación **solo se dispara cuando el administrador la solicita explÃcitamente** mediante el campo de metadatos de la CA."},{heading:"cómo-solicitar-el-registro",content:'El registro se desencadena estableciendo el valor `registration.status = "REQUESTED"` en la clave `lamassu.io/iot/{connector_id}` de los metadatos de la CA. Esto puede hacerse desde la consola de Lamassu en la sección de gestión de la CA o mediante la API.'},{heading:"cómo-solicitar-el-registro",content:'Una vez recibido el evento, el conector intenta registrar la CA en AWS y actualiza el campo `registration.status` en los metadatos de la CA con el resultado: `"SUCCEEDED"` si el registro fue correcto, o `"FAILED"` acompañado de un mensaje de error en caso contrario. El proceso es asÃncrono, por lo que es necesario consultar periódicamente el estado de los metadatos hasta que la operación concluya.'},{heading:"primary-account",content:"Cuando el parámetro `primary_account` es `true`, el conector ejecuta el flujo completo de registro con verificación de posesión de clave privada:"},{heading:"primary-account",content:"Llama a `iot:GetRegistrationCode` para obtener el código de verificación de AWS."},{heading:"primary-account",content:"El conector genera internamente un par de claves RSA-2048 efÃmero y construye un CSR cuyo Common Name es exactamente ese código de registro. A continuación llama al servicio de firma de Lamassu para que la CA registrada emita un certificado de verificación X.509 real firmando ese CSR. La clave privada efÃmera se usa únicamente para este propósito y no se almacena ni se envÃa a AWS."},{heading:"primary-account",content:"EnvÃa a AWS la CA (en PEM) y el certificado de verificación mediante `iot:RegisterCACertificate`, activando el registro con `AllowAutoRegistration: true`."},{heading:"primary-account",content:"Solo una cuenta puede ser propietaria de una CA en una región AWS dada. Si la CA ya está registrada con el mismo número de serie, el conector omite el paso silenciosamente."},{heading:"primary-account",content:"Los tags que AWS IoT Core aplica al certificado de CA registrado son `LMS.CA.ID`, `LMS.CA.SN` y `LMS.CA.CN`."},{heading:"secondary-account-sni-only",content:"Cuando `primary_account` es `false`, el conector registra la CA usando el modo `CertificateMode: SNI_ONLY`. Este modo no requiere código de verificación ni acceso a la clave privada de la CA, por lo que es la opción adecuada cuando la CA se gestiona desde otra cuenta de AWS o cuando el administrador no dispone de la clave privada. Es el método habitual para registrar la misma CA en varias cuentas de AWS simultáneamente."},{heading:"configuración-del-dms",content:"Cada DMS que participe en la integración con AWS IoT Core debe tener configurada la clave de metadatos `lamassu.io/iot/{connector_id}`. El campo más importante de esa configuración es `registration_mode`, que determina cómo se aprovisionan los dispositivos en AWS."},{heading:"configuración-del-dms",content:"Existen tres modos de registro, y la elección entre ellos depende de la estrategia de aprovisionamiento de la flota."},{heading:"modo-none",content:"En este modo el conector **no crea Things, grupos ni polÃticas** en AWS IoT Core. Se limita a sincronizar el estado de los certificados (activo, revocado, suspendido) a medida que cambian en Lamassu. Es el modo adecuado cuando el aprovisionamiento de Things en AWS se gestiona por un sistema externo y solo se necesita que Lamassu mantenga el estado de los certificados actualizado."},{heading:"modo-auto",content:"El modo `auto` delega en Lamassu el aprovisionamiento completo del dispositivo en AWS en el momento del enrolamiento. Cuando el dispositivo completa con éxito su enrolamiento EST y Lamassu emite el evento `EventBindDeviceIdentityKey`, el conector ejecuta automáticamente la siguiente secuencia:"},{heading:"modo-auto",content:"Crea o actualiza las polÃticas IoT configuradas en el DMS."},{heading:"modo-auto",content:"Crea el grupo raÃz `LAMASSU` en la cuenta AWS (si no existe) y los grupos hijos configurados en el DMS como subgrupos de `LAMASSU`. Si los grupos ya existen, el error `ResourceAlreadyExistsException` se ignora, por lo que la operación es idempotente."},{heading:"modo-auto",content:"Si el Thing ya existÃa en AWS IoT Core, el conector itera todos los certificados (principals) actualmente adjuntos a ese Thing y los marca como `REVOKED` en AWS, para garantizar que los certificados anteriores no puedan seguir siendo usados para autenticarse."},{heading:"modo-auto",content:"Llama a `iot:RegisterThing` con una plantilla de aprovisionamiento de estilo CloudFormation que crea el Thing, registra el certificado del dispositivo (PEM del certificado del dispositivo y del certificado de la CA emisora) y adjunta las polÃticas configuradas.\nUna vez completado el aprovisionamiento, el conector almacena el ARN del certificado resultante en los metadatos del certificado de Lamassu bajo la clave `lamassu.io/iot/{connector_id}` y marca el dispositivo como `Registered: true` en Device Manager."},{heading:"modo-auto",content:"**El nombre del Thing en AWS es el Common Name (CN) del certificado del dispositivo.** Esta convención es fundamental para el desarrollador de firmware: el valor `/CN=` que el dispositivo incluye en su CSR al enrolarse se convierte en el ThingName con el que deberá identificarse en todas las operaciones MQTT contra AWS IoT Core."},{heading:"modo-jitp",content:"El modo Just-In-Time Provisioning (JITP) delega el aprovisionamiento en AWS en lugar de hacerlo el conector directamente. Cuando el conector detecta que el DMS está en modo `jitp`, crea una plantilla de aprovisionamiento JITP en AWS IoT Core y la adjunta al certificado de CA registrado. Esta plantilla se crea o actualiza en el momento en que el DMS se crea o actualiza en Lamassu - no en el momento del enrolamiento del dispositivo. A partir de ese momento, cuando un dispositivo con un certificado emitido por esa CA se conecta por primera vez a AWS IoT Core, AWS ejecuta la plantilla automáticamente: crea el Thing, registra el certificado y lo activa."},{heading:"modo-jitp",content:"El nombre del Thing en la plantilla JITP se deriva de `AWS::IoT::Certificate::CommonName`, que corresponde al CN del certificado del dispositivo - la misma convención que el modo `auto`."},{heading:"modo-jitp",content:"Este modo requiere que se configure el campo `jitp_config.provisioning_role_arn` con el ARN de un rol IAM que AWS IoT Core pueda asumir para ejecutar la plantilla. Si no se configura, el conector utiliza el valor por defecto `arn:aws:iam::{account}:role/JITPRole` y registra un aviso en el log. El administrador debe asegurarse de que ese rol existe en la cuenta y tiene los permisos necesarios antes de activar el modo JITP."},{heading:"aprovisionamiento-de-dispositivos-modo-automático",content:"Para el desarrollador de firmware, el modo `auto` es transparente: el dispositivo realiza su enrolamiento EST de la forma habitual y, como efecto secundario, queda aprovisionado en AWS IoT Core sin ningún paso adicional."},{heading:"aprovisionamiento-de-dispositivos-modo-automático",content:"El flujo completo desde el punto de vista del dispositivo es el siguiente:"},{heading:"aprovisionamiento-de-dispositivos-modo-automático",content:"Una vez que el conector completa el aprovisionamiento, el dispositivo puede conectarse al endpoint AWS IoT Core de MQTT usando su clave privada y el certificado emitido por Lamassu. El ThingName con el que debe identificarse en AWS es exactamente el CN del certificado."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"En el modo JITP el dispositivo también realiza su enrolamiento EST de forma convencional y obtiene su certificado de Lamassu. La diferencia es que AWS IoT Core no conoce al dispositivo hasta que este intenta conectarse por primera vez."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"Cuando el dispositivo establece su primera conexión MQTT a AWS IoT Core presentando el certificado emitido por Lamassu, AWS detecta que el certificado pertenece a una CA registrada con una plantilla JITP, ejecuta esa plantilla y crea el Thing automáticamente. La conexión inicial puede fallar o demorarse mientras se ejecuta la plantilla; el firmware debe estar preparado para reintentar la conexión."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"Para que el flujo JITP funcione correctamente:"},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"La CA debe estar registrada en AWS en modo Primary Account (el modo SNI-only no admite JITP)."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"El rol IAM configurado en `jitp_config.provisioning_role_arn` debe existir y tener permisos para crear Things, registrar certificados y adju
321ntar polÃticas en la cuenta AWS."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"El dispositivo debe presentar tanto su certificado como el certificado de la CA emisora en el handshake TLS con AWS IoT Core."},{heading:"aprovisionamiento-de-dispositivos-modo-jitp",content:"Los certificados aprovisionados mediante JITP **no tienen asociada la clave de metadatos del conector** (`lamassu.io/iot/{connector_id}`) en Lamassu. Como consecuencia, los cambios de estado de esos certificados en Lamassu no se sincronizan automáticamente con AWS a través del mecanismo de sincronización de estado descrito en la siguiente sección."},{heading:"sincronización-del-estado-del-certificado",content:"El conector escucha el evento `EventUpdateCertificateStatusKey` y, cuando un certificado que tiene la clave de metadatos del conector cambia de estado en Lamassu, replica ese cambio en AWS IoT Core. La tabla siguiente muestra la correspondencia de estados:"},{heading:"sincronización-del-estado-del-certificado",content:"Estado en Lamassu"},{heading:"sincronización-del-estado-del-certificado",content:"Razón de revocación"},{heading:"sincronización-del-estado-del-certificado",content:"Estado en AWS IoT Core"},{heading:"sincronización-del-estado-del-certificado",content:"`Active`"},{heading:"sincronización-del-estado-del-certificado",content:"Ninguna"},{heading:"sincronización-del-estado-del-certificado",content:"`ACTIVE`"},{heading:"sincronización-del-estado-del-certificado",content:"`Revoked`"},{heading:"sincronización-del-estado-del-certificado",content:"`certificateHold`"},{heading:"sincronización-del-estado-del-certificado",content:"`INACTIVE`"},{heading:"sincronización-del-estado-del-certificado",content:"`Revoked`"},{heading:"sincronización-del-estado-del-certificado",content:"Cualquier otra razón"},{heading:"sincronización-del-estado-del-certificado",content:"`REVOKED`"},{heading:"sincronización-del-estado-del-certificado",content:"Solo los estados `Active` y `Revoked` producen una llamada a `iot:UpdateCertificate`. Los demás estados del ciclo de vida de Lamassu (`RenewalWindow`, `AboutToExpire`, `Expired`) no se sincronizan con AWS IoT Core; el estado del certificado en AWS permanece sin cambios hasta que el estado en Lamassu sea `Active` o `Revoked`."},{heading:"desconexión-forzada-al-revocar",content:"Cuando el conector marca un certificado como `REVOKED` o `INACTIVE` en AWS, ejecuta adicionalmente una desconexión forzada del dispositivo. Para ello abre una conexión MQTT sobre WebSocket (con autenticación SigV4 con las credenciales del conector) al endpoint de datos de AWS IoT Core, usando el CN del certificado como identificador de cliente MQTT, y la cierra inmediatamente. Esto termina cualquier sesión MQTT activa que el dispositivo pueda tener en ese momento."},{heading:"desconexión-forzada-al-revocar",content:"Esta desconexión forzada se produce en el momento en que Lamassu registra el cambio de estado. Si el dispositivo vuelve a intentar conectarse tras la desconexión, AWS IoT Core rechazará la conexión porque el certificado ya figura como `REVOKED` o `INACTIVE`."},{heading:"desconexión-forzada-al-revocar",content:"Los certificados aprovisionados en modo JITP no disponen de esta sincronización automática, ya que no tienen la clave de metadatos del conector."},{heading:"device-shadow-y-automatización",content:"El conector puede escribir en el Device Shadow de AWS IoT Core para enviar señales de acción al firmware del dispositivo. Esta funcionalidad se activa por DMS mediante `shadow_config.enable: true`."},{heading:"device-shadow-y-automatización",content:"Si `shadow_config.shadow_name` contiene un valor, el conector usa un Named Shadow con ese nombre; en caso contrario, usa el Classic Shadow (shadow predeterminado del Thing)."},{heading:"qué-escribe-el-conector-en-el-shadow",content:"El conector escribe en el campo `desired.identity_actions` del documento shadow. Cada entrada contiene un timestamp Unix en milisegundos. El firmware del dispositivo debe leer este campo y actuar en consecuencia."},{heading:"qué-escribe-el-conector-en-el-shadow",content:"Existen dos tipos de acciones:"},{heading:"qué-escribe-el-conector-en-el-shadow",content:"**`UPDATE_CERTIFICATE`**: se escribe cuando la ventana de renovación preventiva de un certificado se activa - es decir, cuando el campo `triggered` de la delta de renovación preventiva pasa de `false` a `true`. Esta acción indica al dispositivo que debe iniciar el proceso de re-enrolamiento para renovar su certificado antes de que expire."},{heading:"qué-escribe-el-conector-en-el-shadow",content:"**`UPDATE_TRUST_ANCHOR_LIST`**: se escribe en todos los dispositivos de un DMS cuando la lista `ManagedCAs` del DMS cambia. Esta acción indica al dispositivo que debe actualizar su almacén de CAs de confianza."},{heading:"qué-escribe-el-conector-en-el-shadow",content:"El proceso de escritura en el shadow consiste en leer el shadow actual (`iotdata:GetThingShadow`), combinar las nuevas acciones con las existentes y escribir el resultado (`iotdata:UpdateThingShadow`). Si el shadow no existe, el conector lo crea. Tras una escritura correcta, la lista de acciones pendientes en los metadatos del dispositivo en Lamassu se limpia."},{heading:"polÃticas-de-aws-iot",content:"El conector crea y adju
321nta las polÃticas que se configuran en el DMS. Una polÃtica tÃpica para un dispositivo que usa MQTT y Device Shadow tiene la siguiente estructura:"},{heading:"polÃticas-de-aws-iot",content:"En la polÃtica anterior, los marcadores `<AWS_REGION>` y `<AWS_ACCOUNT_ID>` deben reemplazarse por la región AWS y el identificador de cuenta de doce dÃgitos de la cuenta destino antes de aplicar la polÃtica. La variable `${iot:Connection.Thing.ThingName}` limita automáticamente cada permiso al Thing al que el dispositivo está conectado, siguiendo el principio de mÃnimo privilegio. La variable `${ShadowName}` en los ARN de shadow es un marcador que debe reemplazarse con el valor de `shadow_config.shadow_name` configurado en el DMS; si se usa el Classic Shadow, se puede simplificar eliminando el segmento `name/${ShadowName}/`. Las polÃticas de AWS IoT no admiten expresiones regulares con alternancia; la notación `[name/${ShadowName}/]*` representa la opcionalidad del segmento dentro de las restricciones de la sintaxis de ARN."},{heading:"polÃticas-de-aws-iot",content:"El primer statement permite que el dispositivo se conecte usando su ThingName como identificador MQTT. El segundo autoriza la publicación en el topic MQTT genérico del Thing y en los topics del shadow, necesario para que el dispositivo pueda actualizar el estado reportado. Los dos últimos statements otorgan permisos de suscripción y recepción sobre los mismos topics, lo que permite al dispositivo recibir actualizaciones del shadow (por ejemplo, las acciones `UPDATE_CERTIFICATE` y `UPDATE_TRUST_ANCHOR_LIST` escritas por el conector)."},{heading:"solución-de-problemas",content:"**SÃntoma:** El registro de la CA permanece indefinidamente en estado `REQUESTED`."},{heading:"solución-de-problemas",content:"**Causa:** El conector no está en ejecución o no está suscrito al bus de eventos. También puede indicar credenciales IAM incorrectas, permisos insuficientes o que la clave de metadatos se escribió con un `connector_id` incorrecto."},{heading:"solución-de-problemas",content:"**Resolución:** Verificar que el proceso del conector está activo y que los logs no muestran errores de comunicación con AWS. Comprobar que el campo de metadatos se escribió bajo la clave exacta `lamassu.io/iot/{connector_id}`. Si el error persiste, el conector actualizará el estado a `FAILED` con un mensaje descriptivo en los metadatos de la CA."},{heading:"solución-de-problemas",content:"**SÃntoma:** El estado de un certificado no se sincroniza con AWS tras una revocación."},{heading:"solución-de-problemas",content:"**Causa:** Lo más habitual es que el certificado fue aprovisionado en modo JITP. Los certificados JITP no tienen la clave de metadatos del conector y quedan fuera del mecanismo de sincronización de estado. Si el DMS está en modo `auto`, puede indicar que el aprovisionamiento inicial no completó correctamente y el ARN de AWS no se almacenó en los metadatos del certificado."},{heading:"solución-de-problemas",content:"**Resolución:** Para certificados JITP, migrar el DMS a modo `auto` y re-aprovisionar los dispositivos afectados. Para certificados en modo `auto`, verificar que el certificado tiene el ARN de AWS almacenado en sus metadatos; si no lo tiene, repetir el aprovisionamiento."},{heading:"solución-de-problemas",content:"**SÃntoma:** La desconexión forzada no termina la sesión MQTT del dispositivo tras la revocación."},{heading:"solución-de-problemas",content:"**Causa:** El dispositivo usa un client ID MQTT diferente al CN del certificado. La desconexión forzada abre una conexión usando el CN como client ID; si el firmware usa otro identificador, la desconexión no afecta a esa sesión."},{heading:"solución-de-problemas",content:"**Resolución:** Asegurarse de que el firmware usa exactamente el CN del certificado como identificador de cliente MQTT. Ese CN coincide con el ThingName en AWS IoT Core."},{heading:"solución-de-problemas",content:"**SÃntoma:** El dispositivo recibe `CLIENT_ID_REJECTED` al conectarse a AWS IoT Core."},{heading:"solución-de-problemas",content:"**Causa:** El client ID MQTT no coincide con el ThingName, que es siempre el CN del certificado emitido por Lamassu."},{heading:"solución-de-problemas",content:"**Resolución:** Verificar que el firmware usa exactamente el valor del campo CN incluido en el CSR de enrolamiento como identificador de cliente MQTT."},{heading:"solución-de-problemas",content:"**SÃntoma:** La primera conexión MQTT del dispositivo en modo JITP falla o excede el tiempo de espera."},{heading:"solución-de-problemas",content:"**Causa:** Es el comportamiento esperado mientras AWS ejecuta la plantilla JITP en la primera conexión del dispositivo."},{heading:"solución-de-problemas",content:"**Resolución:** El firmware debe implementar reintentos con backoff exponencial para la primera conexión. Si el fallo persiste más allá de unos minutos, verificar que el rol IAM configurado en `jitp_config.provisioning_role_arn` existe en la cuenta y tiene permisos para crear Things, registrar certificados y adju
321ntar polÃticas."},{heading:"solución-de-problemas",content:"**SÃntoma:** El Device Shadow no se actualiza cuando deberÃa."},{heading:"solución-de-problemas",content:"**Causa:** La función de shadow está desactivada en la configuración del DMS, las credenciales del conector carecen de permisos sobre la API de datos de IoT, o el firmware lee un shadow diferente al configurado."},{heading:"solución-de-problemas",content:"**Resolución:** Comprobar que `shadow_config.enable` está a `true` en los metadatos del conector para el DMS correspondiente. Si se usa Named Shadow, verificar que `shadow_config.shadow_name` contiene el nombre correcto y que el firmware lee ese Named Shadow y no el Classic Shadow. Confirmar que las credenciales del conector tienen permisos `iotdata:GetThingShadow` y `iotdata:UpdateThingShadow`."},{heading:"solución-de-problemas",content:'<Card title="Configurar un DMS" href="/docs/platform/pki/device-enrollment" />'},{heading:"solución-de-problemas",content:'<Card title="Enrolamiento de dispositivos (EST)" href="/docs/platform/pki/est-enrollment" />'},{heading:"solución-de-problemas",content:'<Card title="Gestión de certificados" href="/docs/platform/pki/certificates" />'}],headings:[{id:"arquitectura-del-conector",content:"Arquitectura del conector"},{id:"prerrequisitos",content:"Prerrequisitos"},{id:"permisos-iam-necesarios",content:"Permisos IAM necesarios"},{id:"parámetros-de-configuración",content:"Parámetros de configuración"},{id:"registro-de-la-ca-en-aws-iot-core",content:"Registro de la CA en AWS IoT Core"},{id:"cómo-solicitar-el-registro",content:"Cómo solicitar el registro"},{id:"primary-account",content:"Primary Account"},{id:"secondary-account-sni-only",content:"Secondary Account (SNI-only)"},{id:"configuración-del-dms",content:"Configuración del DMS"},{id:"modo-none",content:"Modo `none`"},{id:"modo-auto",content:"Modo `auto`"},{id:"modo-jitp",content:"Modo `jitp`"},{id:"aprovisionamiento-de-dispositivos-modo-automático",content:"Aprovisionamiento de dispositivos (modo automático)"},{id:"aprovisionamiento-de-dispositivos-modo-jitp",content:"Aprovisionamiento de dispositivos (modo JITP)"},{id:"sincronización-del-estado-del-certificado",content:"Sincronización del estado del certificado"},{id:"desconexión-forzada-al-revocar",content:"Desconexión forzada al revocar"},{id:"device-shadow-y-automatización",content:"Device Shadow y automatización"},{id:"qué-escribe-el-conector-en-el-shadow",content:"Qué escribe el conector en el shadow"},{id:"polÃticas-de-aws-iot",content:"PolÃticas de AWS IoT"},{id:"solución-de-problemas",content:"Solución de problemas"}]};const l=[{depth:2,url:"#arquitectura-del-conector",title:e.jsx(e.Fragment,{children:"Arquitectura del conector"})},{depth:2,url:"#prerrequisitos",title:e.jsx(e.Fragment,{children:"Prerrequisitos"})},{depth:3,url:"#permisos-iam-necesarios",title:e.jsx(e.Fragment,{children:"Permisos IAM necesarios"})},{depth:3,url:"#parámetros-de-configuración",title:e.jsx(e.Fragment,{children:"Parámetros de configuración"})},{depth:2,url:"#registro-de-la-ca-en-aws-iot-core",title:e.jsx(e.Fragment,{children:"Registro de la CA en AWS IoT Core"})},{depth:3,url:"#cómo-solicitar-el-registro",title:e.jsx(e.Fragment,{children:"Cómo solicitar el registro"})},{depth:3,url:"#primary-account",title:e.jsx(e.Fragment,{children:"Primary Account"})},{depth:3,url:"#secondary-account-sni-only",title:e.jsx(e.Fragment,{children:"Secondary Account (SNI-only)"})},{depth:2,url:"#configuración-del-dms",title:e.jsx(e.Fragment,{children:"Configuración del DMS"})},{depth:3,url:"#modo-none",title:e.jsxs(e.Fragment,{children:["Modo ",e.jsx("code",{children:"none"})]})},{depth:3,url:"#modo-auto",title:e.jsxs(e.Fragment,{children:["Modo ",e.jsx("code",{children:"auto"})]})},{depth:3,url:"#modo-jitp",title:e.jsxs(e.Fragment,{children:["Modo ",e.jsx("code",{children:"jitp"})]})},{depth:2,url:"#aprovisionamiento-de-dispositivos-modo-automático",title:e.jsx(e.Fragment,{children:"Aprovisionamiento de dispositivos (modo automático)"})},{depth:2,url:"#aprovisionamiento-de-dispositivos-modo-jitp",title:e.jsx(e.Fragment,{children:"Aprovisionamiento de dispositivos (modo JITP)"})},{depth:2,url:"#sincronización-del-estado-del-certificado",title:e.jsx(e.Fragment,{children:"Sincronización del estado del certificado"})},{depth:3,url:"#desconexión-forzada-al-revocar",title:e.jsx(e.Fragment,{children:"Desconexión forzada al revocar"})},{depth:2,url:"#device-shadow-y-automatización",title:e.jsx(e.Fragment,{children:"Device Shadow y automatización"})},{depth:3,url:"#qué-escribe-el-conector-en-el-shadow",title:e.jsx(e.Fragment,{children:"Qué escribe el conector en el shadow"})},{depth:2,url:"#polÃticas-de-aws-iot",title:e.jsx(e.Fragment,{children:"PolÃticas de AWS IoT"})},{depth:2,url:"#solución-de-problemas",title:e.jsx(e.Fragment,{children:"Solución de problemas"})}];function s(a){const i={a:"a",code:"code",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...a.components},{Card:n,Cards:o}=i;return n||t("Card"),o||t("Cards"),e.jsxs(e.Fragment,{children:[e.jsx(i.p,{children:"La integración de Lamassu con AWS IoT Core cubre el puente entre la PKI gestionada por Lamassu y la plataforma de conectividad de AWS. Cuando un dispositivo obtiene su certificado a través del proceso de enrolamiento EST, el conector se encarga de que ese certificado y la identidad asociada sean reconocidos en AWS IoT Core sin intervención manual. El resultado es que el dispositivo puede autenticarse directamente en AWS con el mismo certificado X.509 que Lamassu emitió."}),` 322`,e.jsxs(i.p,{children:["Desde el punto de vista del protocolo, el dispositivo se autentica ante AWS IoT Core mediante TLS mutuo (mTLS): presenta su certificado X.509 emitido por Lamassu como certificado de cliente, y AWS IoT Core verifica la cadena de certificados hasta llegar a la CA registrada en la cuenta. Lamassu actúa como autoridad de certificación (CA); el conector se encarga de que esa CA esté registrada en AWS y de que el certificado del dispositivo sea conocido por la plataforma antes de que el dispositivo intente conectarse (en modo ",e.jsx(i.code,{children:"auto"}),") o en su primera conexión (en modo JITP)."]}),` 323`,e.jsxs(i.p,{children:["Este documento está dirigido tanto al administrador PKI, que necesita configurar el conector y registrar las CAs, como al desarrollador de firmware de dispositivos, que necesita entender cómo se nombran los Things, cómo funciona el Device Shadow y qué ocurre cuando un certificado se revoca. Para el desarrollador de firmware, el dato más importante es que el ",e.jsx(i.strong,{children:"nombre del Thing en AWS (ThingName) corresponde siempre al Common Name (CN) del certificado emitido por Lamassu"}),", independientemente del modo de aprovisionamiento."]}),` 324`,e.jsx(i.h2,{id:"arquitectura-del-conector",children:"Arquitectura del conector"}),` 325`,e.jsxs(i.p,{children:["El conector de AWS IoT Core es un proceso Go independiente, un binario o contenedor separado del núcleo de Lamassu. En un despliegue monolÃtico se compila por defecto (etiqueta de compilación ",e.jsx(i.code,{children:"!noaws"}),") y se activa mediante ",e.jsx(i.code,{children:"aws_iot_manager.enabled: true"})," en el fichero de configuración. En despliegues distribuidos, se ejecuta como un contenedor propio con acceso a los servicios de CA, DMS Manager y Device Manager de Lamassu a través de HTTP."]}),` 326`,e.jsxs(i.p,{children:["El conector no sondea los servicios de Lamassu periódicamente. En su lugar, ",e.jsx(i.strong,{children:"se suscribe al bus de eventos interno"})," de Lamassu (AMQP o AWS SQS/SNS, configurable) y reacciona a los eventos que le interesan: creación o actualización de CAs, creación o actualización de DMS, vinculación de identidad de dispositivo, cambio de estado de certificado, actualización de metadatos de certificado y actualización de metadatos de dispositivo. Este modelo orientado a eventos garantiza que la sincronización con AWS sea casi inmediata y no genere carga de sondeo."]}),` 327`,e.jsxs(i.p,{children:["Para evitar bucles infinitos, el conector ignora cualquier evento cuyo campo ",e.jsx(i.code,{children:"source"})," de CloudEvent coincida con su propia URI de origen. Esto previene que las escrituras de metadatos que el propio conector realiza vuelvan a disparar el mismo flujo."]}),` 328`,e.jsxs(i.p,{children:["Cuando se ejecutan varios conectores en paralelo, por ejemplo, para distintas cuentas de AWS, cada instancia tiene su propio ",e.jsx(i.code,{children:"connector_id"}),". Todos los metadatos que el conector escribe en Lamassu se almacenan bajo la clave ",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"}),", lo que permite coexistencia sin colisiones."]}),` 329`,e.jsx(i.h2,{id:"prerrequisitos",children:"Prerrequisitos"}),` 330`,e.jsxs(i.p,{children:["Antes de activar el conector es necesario disponer de una cuenta AWS con los permisos IAM adecuados y tener el conector correctamente configurado. El proceso de despliegue (Docker Compose, Kubernetes o binario) se describe en la ",e.jsx(i.a,{href:"/docs/deployment/overview",children:"documentación de despliegue"}),"."]}),` 331`,e.jsx(i.h3,{id:"permisos-iam-necesarios",children:"Permisos IAM necesarios"}),` 332`,e.jsx(i.p,{children:"La identidad IAM con la que opera el conector debe tener al mÃnimo los siguientes permisos sobre los re
332cursos de la cuenta destino:"}),` 333`,e.jsxs(i.table,{children:[e.jsx(i.thead,{children:e.jsxs(i.tr,{children:[e.jsx(i.th,{children:"Acción IAM"}),e.jsx(i.th,{children:"Propósito"})]})}),e.jsxs(i.tbody,{children:[e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:GetRegistrationCode"})}),e.jsx(i.td,{children:"Obtener el código de verificación para el registro de CA en Primary Account"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:RegisterCACertificate"})}),e.jsx(i.td,{children:"Registrar la CA en AWS IoT"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:DescribeCACertificate"})}),e.jsx(i.td,{children:"Consultar el estado del registro de la CA"})]}),e.jsxs(i.tr,{children:[e.jsxs(i.td,{children:[e.jsx(i.code,{children:"iot:CreateThing"})," / ",e.jsx(i.code,{children:"iot:UpdateThing"})]}),e.jsx(i.td,{children:"Crear o actualizar Things en IoT Core"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:RegisterThing"})}),e.jsx(i.td,{children:"Aprovisionar Things mediante plantilla"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:RegisterCertificate"})}),e.jsx(i.td,{children:"Registrar certificados de dispositivo"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:UpdateCertificate"})}),e.jsx(i.td,{children:"Cambiar el estado de un certificado (ACTIVE / INACTIVE / REVOKED)"})]}),e.jsxs(i.tr,{children:[e.jsxs(i.td,{children:[e.jsx(i.code,{children:"iot:CreatePolicy"})," / ",e.jsx(i.code,{children:"iot:AttachPolicy"})]}),e.jsx(i.td,{children:"Crear y adjuntar polÃticas IoT"})]}),e.jsxs(i.tr,{children:[e.jsxs(i.td,{children:[e.jsx(i.code,{children:"iot:CreateThingGroup"})," / ",e.jsx(i.code,{children:"iot:AddThingToThingGroup"})]}),e.jsx(i.td,{children:"Gestionar grupos de Things"})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"iot:CreateProvisioningTemplate"})}),e.jsx(i.td,{children:"Crear plantillas JITP"})]}),e.jsxs(i.tr,{children:[e.jsxs(i.td,{children:[e.jsx(i.code,{children:"iotdata:GetThingShadow"})," / ",e.jsx(i.code,{children:"iotdata:UpdateThingShadow"})]}),e.jsx(i.td,{children:"Leer y escribir el Device Shadow"})]})]})]}),` 334`,e.jsxs(i.p,{children:["Para el mecanismo de desconexión forzada tras revocación también se requiere acceso a la API del plano de datos de AWS IoT (",e.jsx(i.code,{children:"iot:Connect"})," con SigV4 sobre WebSocket), que se negocia de forma implÃcita con las credenciales del conector."]}),` 335`,e.jsx(i.h3,{id:"parámetros-de-configuración",children:"Parámetros de configuración"}),` 336`,e.jsxs(i.table,{children:[e.jsx(i.thead,{children:e.jsxs(i.tr,{children:[e.jsx(i.th,{children:"Parámetro"}),e.jsx(i.th,{children:"Tipo"}),e.jsx(i.th,{children:"Requerido"}),e.jsx(i.th,{children:"Descripción"})]})}),e.jsxs(i.tbody,{children:[e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"connector_id"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsxs(i.td,{children:["Identificador único de esta instancia del conector. Se usa como espacio de nombres para los metadatos: ",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"}),"."]})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.region"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsx(i.td,{children:"Región AWS donde opera el conector."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.auth_method"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsxs(i.td,{children:["Método de autenticación: ",e.jsx(i.code,{children:"static"}),", ",e.jsx(i.code,{children:"role"})," o vacÃo (cadena de credenciales por defecto del SDK)."]})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.access_key_id"})}),e.jsx(i.td,{children:"string"}),e.jsxs(i.td,{children:["Solo con ",e.jsx(i.code,{children:"auth_method=static"})]}),e.jsx(i.td,{children:"Clave de acceso AWS."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.secret_access_key"})}),e.jsx(i.td,{children:"string"}),e.jsxs(i.td,{children:["Solo con ",e.jsx(i.code,{children:"auth_method=static"})]}),e.jsx(i.td,{children:"Clave secreta AWS."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.session_token"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"No"}),e.jsxs(i.td,{children:["Token de sesión (con ",e.jsx(i.code,{children:"auth_method=static"}),")."]})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.role_arn"})}),e.jsx(i.td,{children:"string"}),e.jsxs(i.td,{children:["Solo con ",e.jsx(i.code,{children:"auth_method=role"})]}),e.jsx(i.td,{children:"ARN del rol a asumir."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"aws_config.endpoint_url"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"No"}),e.jsx(i.td,{children:"URL alternativa para todos los servicios AWS (útil con LocalStack en pruebas)."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"subscriber_event_bus"})}),e.jsx(i.td,{children:"objeto"}),e.jsx(i.td,{children:"SÃ"}),e.jsx(i.td,{children:"Configuración del bus de eventos al que se suscribe el conector (AMQP o AWS SQS/SNS)."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"dms_manager_client"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsx(i.td,{children:"URL HTTP del servicio DMS Manager de Lamassu."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"device_manager_client"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsx(i.td,{children:"URL HTTP del Device Manager de Lamassu."})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"ca_client"})}),e.jsx(i.td,{children:"string"}),e.jsx(i.td,{children:"SÃ"}),e.jsx(i.td,{children:"URL HTTP del servicio de CA de Lamassu."})]})]})]}),` 337`,e.jsx(i.h2,{id:"registro-de-la-ca-en-aws-iot-core",children:"Registro de la CA en AWS IoT Core"}),` 338`,e.jsxs(i.p,{children:["Para que los dispositivos puedan autenticarse en AWS IoT Core con certificados emitidos por una CA de Lamassu, esa CA debe registrarse previamente en la cuenta AWS. El conector gestiona este registro de forma automática en respuesta a los eventos ",e.jsx(i.code,{children:"EventCreateCAKey"}),", ",e.jsx(i.code,{children:"EventImportCAKey"}
338)," y ",e.jsx(i.code,{children:"EventUpdateCAMetadataKey"}),", pero la operación ",e.jsx(i.strong,{children:"solo se dispara cuando el administrador la solicita explÃcitamente"})," mediante el campo de metadatos de la CA."]}),` 339`,e.jsx(i.h3,{id:"cómo-solicitar-el-registro",children:"Cómo solicitar el registro"}),` 340`,e.jsxs(i.p,{children:["El registro se desencadena estableciendo el valor ",e.jsx(i.code,{children:'registration.status = "REQUESTED"'})," en la clave ",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"})," de los metadatos de la CA. Esto puede hacerse desde la consola de Lamassu en la sección de gestión de la CA o mediante la API."]}),` 341`,e.jsxs(i.p,{children:["Una vez recibido el evento, el conector intenta registrar la CA en AWS y actualiza el campo ",e.jsx(i.code,{children:"registration.status"})," en los metadatos de la CA con el resultado: ",e.jsx(i.code,{children:'"SUCCEEDED"'})," si el registro fue correcto, o ",e.jsx(i.code,{children:'"FAILED"'})," acompañado de un mensaje de error en caso contrario. El proceso es asÃncrono, por lo que es necesario consultar periódicamente el estado de los metadatos hasta que la operación concluya."]}),` 342`,e.jsx(i.h3,{id:"primary-account",children:"Primary Account"}),` 343`,e.jsxs(i.p,{children:["Cuando el parámetro ",e.jsx(i.code,{children:"primary_account"})," es ",e.jsx(i.code,{children:"true"}),", el conector ejecuta el flujo completo de registro con verificación de posesión de clave privada:"]}),` 344`,e.jsxs(i.ol,{children:[` 345`,e.jsxs(i.li,{children:["Llama a ",e.jsx(i.code,{children:"iot:GetRegistrationCode"})," para obtener el código de verificación de AWS."]}),` 346`,e.jsx(i.li,{children:"El conector genera internamente un par de claves RSA-2048 efÃmero y construye un CSR cuyo Common Name es exactamente ese código de registro. A continuación llama al servicio de firma de Lamassu para que la CA registrada emita un certificado de verificación X.509 real firmando ese CSR. La clave privada efÃmera se usa únicamente para este propósito y no se almacena ni se envÃa a AWS."}),` 347`,e.jsxs(i.li,{children:["EnvÃa a AWS la CA (en PEM) y el certificado de verificación mediante ",e.jsx(i.code,{children:"iot:RegisterCACertificate"}),", activando el registro con ",e.jsx(i.code,{children:"AllowAutoRegistration: true"}),"."]}),` 348`]}),` 349`,e.jsx(i.p,{children:"Solo una cuenta puede ser propietaria de una CA en una región AWS dada. Si la CA ya está registrada con el mismo número de serie, el conector omite el paso silenciosamente."}),` 350`,e.jsxs(i.p,{children:["Los tags que AWS IoT Core aplica al certificado de CA registrado son ",e.jsx(i.code,{children:"LMS.CA.ID"}),", ",e.jsx(i.code,{children:"LMS.CA.SN"})," y ",e.jsx(i.code,{children:"LMS.CA.CN"}),"."]}),` 351`,e.jsx(i.h3,{id:"secondary-account-sni-only",children:"Secondary Account (SNI-only)"}),` 352`,e.jsxs(i.p,{children:["Cuando ",e.jsx(i.code,{children:"primary_account"})," es ",e.jsx(i.code,{children:"false"}),", el conector registra la CA usando el modo ",e.jsx(i.code,{children:"CertificateMode: SNI_ONLY"}),". Este modo no requiere código de verificación ni acceso a la clave privada de la CA, por lo que es la opción adecuada cuando la CA se gestiona desde otra cuenta de AWS o cuando el administrador no dispone de la clave privada. Es el método habitual para registrar la misma CA en varias cuentas de AWS simultáneamente."]}),` 353`,e.jsx(i.h2,{id:"configuración-del-dms",children:"Configuración del DMS"}),` 354`,e.jsxs(i.p,{children:["Cada DMS que participe en la integración con AWS IoT Core debe tener configurada la clave de metadatos ",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"}),". El campo más importante de esa configuración es ",e.jsx(i.code,{children:"registration_mode"}),", que determina cómo se aprovisionan los dispositivos en AWS."]}),` 355`,e.jsx(i.p,{children:"Existen tres modos de registro, y la elección entre ellos depende de la estrategia de aprovisionamiento de la flota."}),` 356`,e.jsxs(i.h3,{id:"modo-none",children:["Modo ",e.jsx(i.code,{children:"none"})]}),` 357`,e.jsxs(i.p,{children:["En este modo el conector ",e.jsx(i.strong,{children:"no crea Things, grupos ni polÃticas"})," en AWS IoT Core. Se limita a sincronizar el estado de los certificados (activo, revocado, suspendido) a medida que cambian en Lamassu. Es el modo adecuado cuando el aprovisionamiento de Things en AWS se gestiona por un sistema externo y solo se necesita que Lamassu mantenga el estado de los certificados actualizado."]}),` 358`,e.jsxs(i.h3,{id:"modo-auto",children:["Modo ",e.jsx(i.code,{children:"auto"})]}),` 359`,e.jsxs(i.p,{children:["El modo ",e.jsx(i.code,{children:"auto"})," delega en Lamassu el aprovisionamiento completo del dispositivo en AWS en el momento del enrolamiento. Cuando el dispositivo completa con éxito su enrolamiento EST y Lamassu emite el evento ",e.jsx(i.code,{children:"EventBindDeviceIdentityKey"}),", el conector ejecuta automáticamente la siguiente secuencia:"]}),` 360`,e.jsxs(i.ol,{children:[` 361`,e.jsx(i.li,{children:"Crea o actualiza las polÃticas IoT configuradas en el DMS."}),` 362`,e.jsxs(i.li,{children:["Crea el grupo raÃz ",e.jsx(i.code,{children:"LAMASSU"})," en la cuenta AWS (si no existe) y los grupos hijos configurados en el DMS como subgrupos de ",e.jsx(i.code,{children:"LAMASSU"}),". Si los grupos ya existen, el error ",e.jsx(i.code,{children:"ResourceAlreadyExistsException"})," se ignora, por lo que la operación es idempotente."]}),` 363`,e.jsxs(i.li,{children:["Si el Thing ya existÃa en AWS IoT Core, el conector itera todos los certificados (principals) actualmente adjuntos a ese Thing y los marca como ",e.jsx(i.code,{children:"REVOKED"})," en AWS, para garantizar que los certificados anteriores no puedan seguir siendo usados para autenticarse."]}),` 364`,e.jsxs(i.li,{children:["Llama a ",e.jsx(i.code,{children:"iot:RegisterThing"}),` con una plantilla de aprovisionamiento de estilo CloudFormation que crea el Thing, registra el certificado del dispositivo (PEM del certificado del dispositivo y del certificado de la CA emisora) y adjunta las polÃticas configuradas. 365Una vez completado el aprovisionamiento, el conector almacena el ARN del certificado resultante en los metadatos del certificado de Lamassu bajo la clave `,e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"})," y marca el dispositivo como ",e.jsx(i.code,{children:"Registered: true"})," en Device Manager."]}),` 366`]}),` 367`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"El nombre del Thing en AWS es el Common Name (CN) del certificado del dispositivo."})," Esta convención es fundamental para el desarrollador de firmware: el valor ",e.jsx(i.code,{children:"/CN="})," que el dispositivo incluye en su CSR al enrolarse se convierte en el ThingName con el que deberá identificarse en todas las operaciones MQTT contra AWS IoT Core."]}),` 368`,e.jsxs(i.h3,{id:"modo-jitp",children:["Modo ",e.jsx(i.code,{children:"jitp"})]}),` 369`,e.jsxs(i.p,{children:["El modo Just-In-Time Provisioning (JITP) delega el aprovisionamiento en AWS en lugar de hacerlo el conector directamente. Cuando el conector detecta que el DMS está en modo ",e.jsx(i.code,{children:"jitp"}),", crea una plantilla de aprovisionamiento JITP en AWS IoT Core y la adjunta al certificado de CA registrado. Esta plantilla se crea o actualiza en el momento en que el DMS se crea o actualiza en Lamassu - no en el momento del enrolamiento del dispositivo. A partir de ese momento, cuando un dispositivo con un certificado emitido por esa CA se conecta por primera vez a AWS IoT Core, AWS ejecuta la plantilla automáticamente: crea el Thing, registra el certificado y lo activa."]}),` 370`,e.jsxs(i.p,{children:["El nombre del Thing en la plantilla JITP se deriva de ",e.jsx(i.code,{children:"AWS::IoT::Certificate::CommonName"}),", que corresponde al CN del certificado del dispositivo - la misma convención que el modo ",e.jsx(i.code,{children:"auto"}),"."]}),` 371`,e.jsxs(i.p,{children:["Este modo requiere que se configure el campo ",e.jsx(i.code,{children:"jitp_config.provisioning_role_arn"})," con el ARN de un rol IAM que AWS IoT Core pueda asumir para ejecutar la plantilla. Si no se configura, el conector utiliza el valor por defecto ",e.jsx(i.code,{children:"arn:aws:iam::{account}:role/JITPRole"})," y registra un aviso en el log. El administrador debe asegurarse de que ese rol existe en la cuenta y tiene los permisos necesarios antes de activar el modo JITP."]}),` 372`,e.jsx(i.h2,{id:"aprovisionamiento-de-dispositivos-modo-automático",children:"Aprovisionamiento de dispositivos (modo automático)"}),` 373`,e.jsxs(i.p,{children:["Para el desarrollador de firmware, el modo ",e.jsx(i.code,{children:"auto"})," es transparente: el dispositivo realiza su enrolamiento EST de la forma habitual y, como efecto secundario, queda aprovisionado en AWS IoT Core sin ningún paso adicional."]}),` 374`,e.jsx(i.p,{children:"El flujo completo desde el punto de vista del dispositivo es el siguiente:"}),` 375`,e.jsx(e.Fragment,{children:e.jsx(i.pre,{className:"shiki shiki-themes min-light min-dark",style:{"--shiki-light":"#24292eff","--shiki-dark":"#b392f0","--shiki-light-bg":"#ffffff","--shiki-dark-bg":"#1f1f1f"},tabIndex:"0",icon:'<svg viewBox="0 0 24 24">
375<path d="m 4,4 a 1,1 0 0 0 -0.7070312,0.2929687 1,1 0 0 0 0,1.4140625 L 8.5859375,11 3.2929688,16.292969 a 1,1 0 0 0 0,1.414062 1,1 0 0 0 1.4140624,0 l 5.9999998,-6 a 1.0001,1.0001 0 0 0 0,-1.414062 L 4.7070312,4.2929687 A 1,1 0 0 0 4,4 Z m 8,14 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 h 8 a 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" fill="currentColor" /></svg>',children:e.jsxs(i.code,{children:[e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#C2C3C5","--shiki-dark":"#6B737C"},children:"# 1. El dispositivo genera su clave privada y su CSR con el CN que será su ThingName"})}),` 376`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"openssl"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" ecparam"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -name"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" prime256v1"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -genkey"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -noout"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -out"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.key"})]}),` 377`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"openssl"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" req"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -new"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -key"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.key"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -sha256"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -out"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.csr"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 378`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -subj"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "/CN=mi-dispositivo-001/O=Acme/OU=IoT"'})]}),` 379`,e.jsx(i.span,{className:"line"}),` 380`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#C2C3C5","--shiki-dark":"#6B737C"},children:"# 2. El dispositivo se enrola en Lamassu vÃa EST"})}),` 381`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"openssl"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" req"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -in"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.csr"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -outform"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" DER"}),e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F97583"},children:" |"}),e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" base64"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -w"}),e.jsx(i.span,{style:{"--shiki-light":"#1976D2","--shiki-dark":"#F8F8F8"},children:" 0"}),e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F97583"},children:" >"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.csr.b64"})]}),` 382`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"curl"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -s"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" --cacert"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" lamassu-trust.pem"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 383`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" --cert"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" bootstrap.crt"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" --key"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" bootstrap.key"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 384`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -H"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB
38470"},children:' "Content-Type: application/pkcs10"'}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 385`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" --data-binary"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "@device.csr.b64"'}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 386`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "https://<EST_HOST>/.well-known/est/<DMS_ID>/simpleenroll"'}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" \\"})]}),` 387`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -o"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" enroll.b64"})]}),` 388`,e.jsx(i.span,{className:"line"}),` 389`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#C2C3C5","--shiki-dark":"#6B737C"},children:"# 3. El dispositivo extrae su certificado"})}),` 390`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"base64"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -d"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -i"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" enroll.b64"}),e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F97583"},children:" |"}),e.jsx(i.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" openssl"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" pkcs7"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -inform"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" DER"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -print_certs"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" -out"}),e.jsx(i.span,{style:{"--shiki-light":"#2B5581","--shiki-dark":"#9DB1C5"},children:" device.crt"})]}),` 391`,e.jsx(i.span,{className:"line"}),` 392`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#C2C3C5","--shiki-dark":"#6B737C"},children:'# A partir de este punto, el conector crea automáticamente el Thing "mi-dispositivo-001"'})}),` 393`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#C2C3C5","--shiki-dark":"#6B737C"},children:"# en AWS IoT Core. El dispositivo puede conectarse a AWS con el mismo certificado."})})]})})}),` 394`,e.jsx(i.p,{children:"Una vez que el conector completa el aprovisionamiento, el dispositivo puede conectarse al endpoint AWS IoT Core de MQTT usando su clave privada y el certificado emitido por Lamassu. El ThingName con el que debe identificarse en AWS es exactamente el CN del certificado."}),` 395`,e.jsx(i.h2,{id:"aprovisionamiento-de-dispositivos-modo-jitp",children:"Aprovisionamiento de dispositivos (modo JITP)"}),` 396`,e.jsx(i.p,{children:"En el modo JITP el dispositivo también realiza su enrolamiento EST de forma convencional y obtiene su certificado de Lamassu. La diferencia es que AWS IoT Core no conoce al dispositivo hasta que este intenta conectarse por primera vez."}),` 397`,e.jsx(i.p,{children:"Cuando el dispositivo establece su primera conexión MQTT a AWS IoT Core presentando el certificado emitido por Lamassu, AWS detecta que el certificado pertenece a una CA registrada con una plantilla JITP, ejecuta esa plantilla y crea el Thing automáticamente. La conexión inicial puede fallar o demorarse mientras se ejecuta la plantilla; el firmware debe estar preparado para reintentar la conexión."}),` 398`,e.jsx(i.p,{children:"Para que el flujo JITP funcione correctamente:"}),` 399`,e.jsxs(i.ul,{children:[` 400`,e.jsx(i.li,{children:"La CA debe estar registrada en AWS en modo Primary Account (el modo SNI-only no admite JITP)."}),` 401`,e.jsxs(i.li,{children:["El rol IAM configurado en ",e.jsx(i.code,{children:"jitp_config.provisioning_role_arn"})," debe existir y tener permisos para crear Things, registrar certificados y adju
401ntar polÃticas en la cuenta AWS."]}),` 402`,e.jsx(i.li,{children:"El dispositivo debe presentar tanto su certificado como el certificado de la CA emisora en el handshake TLS con AWS IoT Core."}),` 403`]}),` 404`,e.jsxs(i.p,{children:["Los certificados aprovisionados mediante JITP ",e.jsx(i.strong,{children:"no tienen asociada la clave de metadatos del conector"})," (",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"}),") en Lamassu. Como consecuencia, los cambios de estado de esos certificados en Lamassu no se sincronizan automáticamente con AWS a través del mecanismo de sincronización de estado descrito en la siguiente sección."]}),` 405`,e.jsx(i.h2,{id:"sincronización-del-estado-del-certificado",children:"Sincronización del estado del certificado"}),` 406`,e.jsxs(i.p,{children:["El conector escucha el evento ",e.jsx(i.code,{children:"EventUpdateCertificateStatusKey"})," y, cuando un certificado que tiene la clave de metadatos del conector cambia de estado en Lamassu, replica ese cambio en AWS IoT Core. La tabla siguiente muestra la correspondencia de estados:"]}),` 407`,e.jsxs(i.table,{children:[e.jsx(i.thead,{children:e.jsxs(i.tr,{children:[e.jsx(i.th,{children:"Estado en Lamassu"}),e.jsx(i.th,{children:"Razón de revocación"}),e.jsx(i.th,{children:"Estado en AWS IoT Core"})]})}),e.jsxs(i.tbody,{children:[e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"Active"})}),e.jsx(i.td,{children:"Ninguna"}),e.jsx(i.td,{children:e.jsx(i.code,{children:"ACTIVE"})})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"Revoked"})}),e.jsx(i.td,{children:e.jsx(i.code,{children:"certificateHold"})}),e.jsx(i.td,{children:e.jsx(i.code,{children:"INACTIVE"})})]}),e.jsxs(i.tr,{children:[e.jsx(i.td,{children:e.jsx(i.code,{children:"Revoked"})}),e.jsx(i.td,{children:"Cualquier otra razón"}),e.jsx(i.td,{children:e.jsx(i.code,{children:"REVOKED"})})]})]})]}),` 408`,e.jsxs(i.p,{children:["Solo los estados ",e.jsx(i.code,{children:"Active"})," y ",e.jsx(i.code,{children:"Revoked"})," producen una llamada a ",e.jsx(i.code,{children:"iot:UpdateCertificate"}),". Los demás estados del ciclo de vida de Lamassu (",e.jsx(i.code,{children:"RenewalWindow"}),", ",e.jsx(i.code,{children:"AboutToExpire"}),", ",e.jsx(i.code,{children:"Expired"}),") no se sincronizan con AWS IoT Core; el estado del certificado en AWS permanece sin cambios hasta que el estado en Lamassu sea ",e.jsx(i.code,{children:"Active"})," o ",e.jsx(i.code,{children:"Revoked"}),"."]}),` 409`,e.jsx(i.h3,{id:"desconexión-forzada-al-revocar",children:"Desconexión forzada al revocar"}),` 410`,e.jsxs(i.p,{children:["Cuando el conector marca un certificado como ",e.jsx(i.code,{children:"REVOKED"})," o ",e.jsx(i.code,{children:"INACTIVE"})," en AWS, ejecuta adicionalmente una desconexión forzada del dispositivo. Para ello abre una conexión MQTT sobre WebSocket (con autenticación SigV4 con las credenciales del conector) al endpoint de datos de AWS IoT Core, usando el CN del certificado como identificador de cliente MQTT, y la cierra inmediatamente. Esto termina cualquier sesión MQTT activa que el dispositivo pueda tener en ese momento."]}),` 411`,e.jsxs(i.p,{children:["Esta desconexión forzada se produce en el momento en que Lamassu registra el cambio de estado. Si el dispositivo vuelve a intentar conectarse tras la desconexión, AWS IoT Core rechazará la conexión porque el certificado ya figura como ",e.jsx(i.code,{children:"REVOKED"})," o ",e.jsx(i.code,{children:"INACTIVE"}),"."]}),` 412`,e.jsx(i.p,{children:"Los certificados aprovisionados en modo JITP no disponen de esta sincronización automática, ya que no tienen la clave de metadatos del conector."}),` 413`,e.jsx(i.h2,{id:"device-shadow-y-automatización",children:"Device Shadow y automatización"}),` 414`,e.jsxs(i.p,{children:["El conector puede escribir en el Device Shadow de AWS IoT Core para enviar señales de acción al firmware del dispositivo. Esta funcionalidad se activa por DMS mediante ",e.jsx(i.code,{children:"shadow_config.enable: true"}),"."]}),` 415`,e.jsxs(i.p,{children:["Si ",e.jsx(i.code,{children:"shadow_config.shadow_name"})," contiene un valor, el conector usa un Named Shadow con ese nombre; en caso contrario, usa el Classic Shadow (shadow predeterminado del Thing)."]}),` 416`,e.jsx(i.h3,{id:"qué-escribe-el-conector-en-el-shadow",children:"Qué escribe el conector en el shadow"}),` 417`,e.jsxs(i.p,{children:["El conector escribe en el campo ",e.jsx(i.code,{children:"desired.identity_actions"})," del documento shadow. Cada entrada contiene un timestamp Unix en milisegundos. El firmware del dispositivo debe leer este campo y actuar en consecuencia."]}),` 418`,e.jsx(i.p,{children:"Existen dos tipos de acciones:"}),` 419`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:e.jsx(i.code,{children:"UPDATE_CERTIFICATE"})}),": se escribe cuando la ventana de renovación preventiva de un certificado se activa - es decir, cuando el campo ",e.jsx(i.code,{children:"triggered"})," de la delta de renovación preventiva pasa de ",e.jsx(i.code,{children:"false"})," a ",e.jsx(i.code,{children:"true"}),". Esta acción indica al dispositivo que debe iniciar el proceso de re-enrolamiento para renovar su certificado antes de que expire."]}),` 420`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:e.jsx(i.code,{children:"UPDATE_TRUST_ANCHOR_LIST"})}),": se escribe en todos los dispositivos de un DMS cuando la lista ",e.jsx(i.code,{children:"ManagedCAs"})," del DMS cambia. Esta acción indica al dispositivo que debe actualizar su almacén de CAs de confianza."]}),` 421`,e.jsxs(i.p,{children:["El proceso de escritura en el shadow consiste en leer el shadow actual (",e.jsx(i.code,{children:"iotdata:GetThingShadow"}),"), combinar las nuevas acciones con las existentes y escribir el resultado (",e.jsx(i.code,{children:"iotdata:UpdateThingShadow"}),"). Si el shadow no existe, el conector lo crea. Tras una escritura correcta, la lista de acciones pendientes en los metadatos del dispositivo en Lamassu se limpia."]}),` 422`,e.jsx(e.Fragment,{children:e.jsx(i.pre,{className:"shiki shiki-themes min-light min-dark",style:{"--shiki-light":"#24292eff","--shiki-dark":"#b392f0","--shiki-light-bg":"#ffffff","--shiki-dark-bg":"#1f1f1f"},tabIndex:"0",icon:'<svg viewBox="0 0 24 24">
422<path d="M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z" fill="currentColor" /></svg>',children:e.jsxs(i.code,{children:[e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:"{"})}),` 423`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "state"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})]}),` 424`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "desired"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})]}),` 425`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "identity_actions"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})]}),` 426`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "UPDATE_CERTIFICATE"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#1976D2","--shiki-dark":"#F8F8F8"},children:" 1716300000000"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 427`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "UPDATE_TRUST_ANCHOR_LIST"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#1976D2","--shiki-dark":"#F8F8F8"},children:" 1716299000000"})]}),` 428`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"})}),` 429`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"})}),` 430`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"})}),` 431`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:"}"})})]})})}),` 432`,e.jsx(i.h2,{id:"polÃticas-de-aws-iot",children:"PolÃticas de AWS IoT"}),` 433`,e.jsx(i.p,{children:"El conector crea y adjunta las polÃticas que se configuran en el DMS. Una polÃtica tÃpica para un dispositivo que usa MQTT y Device Shadow tiene la siguiente estructura:"}),` 434`,e.jsx(e.Fragment,{children:e.jsx(i.pre,{className:"shiki shiki-themes min-light min-dark",style:{"--shiki-light":"#24292eff","--shiki-dark":"#b392f0","--shiki-light-bg":"#ffffff","--shiki-dark-bg":"#1f1f1f"},tabIndex:"0",icon:'<svg viewBox="0 0 24 24"><path d="M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z" fill="currentColor" /></svg>',children:e.jsxs(i.code,{children:[e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:"{"})}),` 435`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Version"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB
43570"},children:' "2012-10-17"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 436`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Statement"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 437`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})}),` 438`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Effect"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "Allow"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 439`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Action"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 440`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "iot:Connect"'})}),` 441`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 442`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Resource"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 443`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:client/${iot:Connection.Thing.ThingName}"'})}),` 444`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"})}),` 445`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 446`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})}),` 447`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Effect"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "Allow"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 448`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Action"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 449`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "iot:Publish"'})}),` 450`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 451`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Resource"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 452`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB
45270"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/${iot:Connection.Thing.ThingName}"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 453`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/${iot:Connection.Thing.ThingName}/shadow/[name/${ShadowName}/]*"'})}),` 454`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"})}),` 455`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 456`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})}),` 457`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Effect"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "Allow"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 458`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Action"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 459`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "iot:Subscribe"'})}),` 460`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 461`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Resource"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 462`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 463`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/shadow/[name/${ShadowName}/]*"'})}),` 464`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"})}),` 465`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 466`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" {"})}),` 467`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Effect"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "Allow"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 468`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Action"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 469`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB
46970"},children:' "iot:Receive"'})}),` 470`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 471`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#D32F2F","--shiki-dark":"#F8F8F8"},children:' "Resource"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:":"}),e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ["})]}),` 472`,e.jsxs(i.span,{className:"line",children:[e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/${iot:Connection.Thing.ThingName}"'}),e.jsx(i.span,{style:{"--shiki-light":"#212121","--shiki-dark":"#BBBBBB"},children:","})]}),` 473`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#FFAB70"},children:' "arn:aws:iot:<AWS_REGION>:<AWS_ACCOUNT_ID>:topic/$aws/things/${iot:Connection.Thing.ThingName}/shadow/[name/${ShadowName}/]*"'})}),` 474`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"})}),` 475`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" }"})}),` 476`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:" ]"})}),` 477`,e.jsx(i.span,{className:"line",children:e.jsx(i.span,{style:{"--shiki-light":"#24292EFF","--shiki-dark":"#B392F0"},children:"}"})})]})})}),` 478`,e.jsxs(i.p,{children:["En la polÃtica anterior, los marcadores ",e.jsx(i.code,{children:"<AWS_REGION>"})," y ",e.jsx(i.code,{children:"<AWS_ACCOUNT_ID>"})," deben reemplazarse por la región AWS y el identificador de cuenta de doce dÃgitos de la cuenta destino antes de aplicar la polÃtica. La variable ",e.jsx(i.code,{children:"${iot:Connection.Thing.ThingName}"})," limita automáticamente cada permiso al Thing al que el dispositivo está conectado, siguiendo el principio de mÃnimo privilegio. La variable ",e.jsx(i.code,{children:"${ShadowName}"})," en los ARN de shadow es un marcador que debe reemplazarse con el valor de ",e.jsx(i.code,{children:"shadow_config.shadow_name"})," configurado en el DMS; si se usa el Classic Shadow, se puede simplificar eliminando el segmento ",e.jsx(i.code,{children:"name/${ShadowName}/"}),". Las polÃticas de AWS IoT no admiten expresiones regulares con alternancia; la notación ",e.jsx(i.code,{children:"[name/${ShadowName}/]*"})," representa la opcionalidad del segmento dentro de las restricciones de la sintaxis de ARN."]}),` 479`,e.jsxs(i.p,{children:["El primer statement permite que el dispositivo se conecte usando su ThingName como identificador MQTT. El segundo autoriza la publicación en el topic MQTT genérico del Thing y en los topics del shadow, necesario para que el dispositivo pueda actualizar el estado reportado. Los dos últimos statements otorgan permisos de suscripción y recepción sobre los mismos topics, lo que permite al dispositivo recibir actualizaciones del shadow (por ejemplo, las acciones ",e.jsx(i.code,{children:"UPDATE_CERTIFICATE"})," y ",e.jsx(i.code,{children:"UPDATE_TRUST_ANCHOR_LIST"})," escritas por el conector)."]}),` 480`,e.jsx(i.h2,{id:"solución-de-problemas",children:"Solución de problemas"}),` 481`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," El registro de la CA permanece indefinidamente en estado ",e.jsx(i.code,{children:"REQUESTED"}),"."]}),` 482`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," El conector no está en ejecución o no está suscrito al bus de eventos. También puede indicar credenciales IAM incorrectas, permisos insuficientes o que la clave de metadatos se escribió con un ",e.jsx(i.code,{children:"connector_id"})," incorrecto."]}),` 483`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," Verificar que el proceso del conector está activo y que los logs no muestran errores de comunicación con AWS. Comprobar que el campo de metadatos se escribió bajo la clave exacta ",e.jsx(i.code,{children:"lamassu.io/iot/{connector_id}"}),". Si el error persiste, el conector actualizará el estado a ",e.jsx(i.code,{children:"FAILED"})," con un mensaje descriptivo en los metadatos de la CA."]}
483),` 484`,e.jsx(i.hr,{}),` 485`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," El estado de un certificado no se sincroniza con AWS tras una revocación."]}),` 486`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," Lo más habitual es que el certificado fue aprovisionado en modo JITP. Los certificados JITP no tienen la clave de metadatos del conector y quedan fuera del mecanismo de sincronización de estado. Si el DMS está en modo ",e.jsx(i.code,{children:"auto"}),", puede indicar que el aprovisionamiento inicial no completó correctamente y el ARN de AWS no se almacenó en los metadatos del certificado."]}),` 487`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," Para certificados JITP, migrar el DMS a modo ",e.jsx(i.code,{children:"auto"})," y re-aprovisionar los dispositivos afectados. Para certificados en modo ",e.jsx(i.code,{children:"auto"}),", verificar que el certificado tiene el ARN de AWS almacenado en sus metadatos; si no lo tiene, repetir el aprovisionamiento."]}),` 488`,e.jsx(i.hr,{}),` 489`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," La desconexión forzada no termina la sesión MQTT del dispositivo tras la revocación."]}),` 490`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," El dispositivo usa un client ID MQTT diferente al CN del certificado. La desconexión forzada abre una conexión usando el CN como client ID; si el firmware usa otro identificador, la desconexión no afecta a esa sesión."]}),` 491`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," Asegurarse de que el firmware usa exactamente el CN del certificado como identificador de cliente MQTT. Ese CN coincide con el ThingName en AWS IoT Core."]}),` 492`,e.jsx(i.hr,{}),` 493`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," El dispositivo recibe ",e.jsx(i.code,{children:"CLIENT_ID_REJECTED"})," al conectarse a AWS IoT Core."]}),` 494`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," El client ID MQTT no coincide con el ThingName, que es siempre el CN del certificado emitido por Lamassu."]}),` 495`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," Verificar que el firmware usa exactamente el valor del campo CN incluido en el CSR de enrolamiento como identificador de cliente MQTT."]}),` 496`,e.jsx(i.hr,{}),` 497`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," La primera conexión MQTT del dispositivo en modo JITP falla o excede el tiempo de espera."]}),` 498`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," Es el comportamiento esperado mientras AWS ejecuta la plantilla JITP en la primera conexión del dispositivo."]}),` 499`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," El firmware debe implementar reintentos con backoff exponencial para la primera conexión. Si el fallo persiste más allá de unos minutos, verificar que el rol IAM configurado en ",e.jsx(i.code,{children:"jitp_config.provisioning_role_arn"})," existe en la cuenta y tiene permisos para crear Things, registrar certificados y adju
499ntar polÃticas."]}),` 500`,e.jsx(i.hr,{}),` 501`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"SÃntoma:"})," El Device Shadow no se actualiza cuando deberÃa."]}),` 502`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Causa:"})," La función de shadow está desactivada en la configuración del DMS, las credenciales del conector carecen de permisos sobre la API de datos de IoT, o el firmware lee un shadow diferente al configurado."]}),` 503`,e.jsxs(i.p,{children:[e.jsx(i.strong,{children:"Resolución:"})," Comprobar que ",e.jsx(i.code,{children:"shadow_config.enable"})," está a ",e.jsx(i.code,{children:"true"})," en los metadatos del conector para el DMS correspondiente. Si se usa Named Shadow, verificar que ",e.jsx(i.code,{children:"shadow_config.shadow_name"})," contiene el nombre correcto y que el firmware lee ese Named Shadow y no el Classic Shadow. Confirmar que las credenciales del conector tienen permisos ",e.jsx(i.code,{children:"iotdata:GetThingShadow"})," y ",e.jsx(i.code,{children:"iotdata:UpdateThingShadow"}),"."]}),` 504`,e.jsxs(o,{children:[e.jsx(n,{title:"Configurar un DMS",href:"/docs/platform/pki/device-enrollment"}),e.jsx(n,{title:"Enrolamiento de dispositivos (EST)",href:"/docs/platform/pki/est-enrollment"}),e.jsx(n,{title:"Gestión de certificados",href:"/docs/platform/pki/certificates"})]})]})}function h(a={}){const{wrapper:i}=a.components||{};return i?e.jsx(i,{...a,children:e.jsx(s,{...a})}):s(a)}function t(a,i){throw new Error("Expected component `"+a+"` to be defined: you likely forgot to import, pass, or provide it.")}const u=Object.freeze(Object.defineProperty({__proto__:null,_markdown:r,default:h,frontmatter:c,structuredData:d,toc:l},Symbol.toStringTag,{value:"Module"}));export{u as _};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.