[{"data":1,"prerenderedAt":1063},["ShallowReactive",2],{"doc-es-\u002Fes\u002Fdocs\u002Fseguridad\u002Fsecretos":3,"docs-es-all":993},{"id":4,"title":5,"body":6,"category":975,"description":976,"draft":977,"extension":978,"icon":979,"lastReviewed":980,"meta":981,"navigation":75,"order":41,"path":982,"prerequisites":983,"readingTime":984,"seo":985,"stem":986,"tags":987,"__hash__":992},"docs_es\u002Fes\u002Fdocs\u002Fseguridad\u002Fsecretos.md","Gestión de secretos",{"type":7,"value":8,"toc":962},"minimark",[9,13,16,19,24,27,138,141,145,205,211,225,229,232,235,242,257,260,264,267,325,328,331,385,388,392,395,467,470,488,491,511,514,518,521,595,604,608,611,636,649,679,682,686,689,807,810,817,821,824,865,872,875,879,882,936,940,958],[10,11,12],"p",{},"Contraseña de base de datos, clave de API, token OAuth, credencial de proveedor. Todo eso es secreto y nada de eso puede estar en el spec del job.",[10,14,15],{},"Por dos motivos. Primero, los specs suelen estar versionados en algún repositorio. Cualquier persona con acceso de lectura al repositorio pasa a tener acceso al secreto. Segundo, los specs transitan por logs, por terminales compartidas, por screenshots de revisión. Cada uno de esos puntos es una fuga esperando ocurrir.",[10,17,18],{},"HeroCtl trae un cofre de secretos integrado. No montas nada por fuera.",[20,21,23],"h2",{"id":22},"creando-un-secreto","Creando un secreto",[10,25,26],{},"Por la CLI, tres formas:",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-bash shiki shiki-themes github-dark-default","# valor literal direto na linha de comando\nheroctl secret create db_password --from-literal=\"s3nh4-l0nga-e-aleatoria\"\n\n# de um arquivo\nheroctl secret create tls_key --from-file=.\u002Fprivkey.pem\n\n# stdin (não fica no histórico do shell)\necho -n \"valor-secreto\" | heroctl secret create api_token --from-stdin\n","bash","",[35,36,37,46,70,77,83,98,103,109],"code",{"__ignoreMap":33},[38,39,42],"span",{"class":40,"line":41},"line",1,[38,43,45],{"class":44},"sH3jZ","# valor literal direto na linha de comando\n",[38,47,49,53,57,60,63,67],{"class":40,"line":48},2,[38,50,52],{"class":51},"sQhOw","heroctl",[38,54,56],{"class":55},"s9uIt"," secret",[38,58,59],{"class":55}," create",[38,61,62],{"class":55}," db_password",[38,64,66],{"class":65},"sFSAA"," --from-literal=",[38,68,69],{"class":55},"\"s3nh4-l0nga-e-aleatoria\"\n",[38,71,73],{"class":40,"line":72},3,[38,74,76],{"emptyLinePlaceholder":75},true,"\n",[38,78,80],{"class":40,"line":79},4,[38,81,82],{"class":44},"# de um arquivo\n",[38,84,86,88,90,92,95],{"class":40,"line":85},5,[38,87,52],{"class":51},[38,89,56],{"class":55},[38,91,59],{"class":55},[38,93,94],{"class":55}," tls_key",[38,96,97],{"class":65}," --from-file=.\u002Fprivkey.pem\n",[38,99,101],{"class":40,"line":100},6,[38,102,76],{"emptyLinePlaceholder":75},[38,104,106],{"class":40,"line":105},7,[38,107,108],{"class":44},"# stdin (não fica no histórico do shell)\n",[38,110,112,115,118,121,125,128,130,132,135],{"class":40,"line":111},8,[38,113,114],{"class":65},"echo",[38,116,117],{"class":65}," -n",[38,119,120],{"class":55}," \"valor-secreto\"",[38,122,124],{"class":123},"suJrU"," |",[38,126,127],{"class":51}," heroctl",[38,129,56],{"class":55},[38,131,59],{"class":55},[38,133,134],{"class":55}," api_token",[38,136,137],{"class":65}," --from-stdin\n",[10,139,140],{},"Por el panel web, hay un formulario equivalente.",[20,142,144],{"id":143},"listando-e-inspeccionando","Listando e inspeccionando",[28,146,148],{"className":30,"code":147,"language":32,"meta":33,"style":33},"# lista todos os segredos visíveis pelo seu token\nheroctl secret list\n\n# mostra metadados (versão, autor, data de criação) — nunca o valor\nheroctl secret describe db_password\n\n# mostra o valor (exige permissão explícita)\nheroctl secret get db_password\n",[35,149,150,155,164,168,173,185,189,194],{"__ignoreMap":33},[38,151,152],{"class":40,"line":41},[38,153,154],{"class":44},"# lista todos os segredos visíveis pelo seu token\n",[38,156,157,159,161],{"class":40,"line":48},[38,158,52],{"class":51},[38,160,56],{"class":55},[38,162,163],{"class":55}," list\n",[38,165,166],{"class":40,"line":72},[38,167,76],{"emptyLinePlaceholder":75},[38,169,170],{"class":40,"line":79},[38,171,172],{"class":44},"# mostra metadados (versão, autor, data de criação) — nunca o valor\n",[38,174,175,177,179,182],{"class":40,"line":85},[38,176,52],{"class":51},[38,178,56],{"class":55},[38,180,181],{"class":55}," describe",[38,183,184],{"class":55}," db_password\n",[38,186,187],{"class":40,"line":100},[38,188,76],{"emptyLinePlaceholder":75},[38,190,191],{"class":40,"line":105},[38,192,193],{"class":44},"# mostra o valor (exige permissão explícita)\n",[38,195,196,198,200,203],{"class":40,"line":111},[38,197,52],{"class":51},[38,199,56],{"class":55},[38,201,202],{"class":55}," get",[38,204,184],{"class":55},[10,206,207,210],{},[35,208,209],{},"heroctl secret get"," es la operación más sensible del sistema. Aparece en el log de auditoría con el nombre de quien leyó, cuándo, y desde qué IP.",[212,213,214],"blockquote",{},[10,215,216,220,221,224],{},[217,218,219],"strong",{},"Atención:"," En producción, restringe ",[35,222,223],{},"secret:read"," al mínimo de roles. Para la mayoría de los equipos, nadie necesita leer valores manualmente — el cluster los inyecta directamente en el job.",[20,226,228],{"id":227},"cifrado-en-reposo","Cifrado en reposo",[10,230,231],{},"Cada secreto se cifra con AES-256 antes de ser persistido. La clave de cifrado del cluster queda protegida y nunca se almacena junto con los datos cifrados.",[10,233,234],{},"Operacionalmente eso significa que un backup del estado del cluster, sin la clave, es inútil para un atacante. Puedes subir un snapshot a un disco duro externo sin preocuparte.",[10,236,237,238,241],{},"La clave en sí se genera en la inicialización del cluster y queda en archivo protegido por permisos de filesystem (",[35,239,240],{},"0600",", owner root) en cada nodo servidor. Para rotarla:",[28,243,245],{"className":30,"code":244,"language":32,"meta":33,"style":33},"heroctl cluster rekey\n",[35,246,247],{"__ignoreMap":33},[38,248,249,251,254],{"class":40,"line":41},[38,250,52],{"class":51},[38,252,253],{"class":55}," cluster",[38,255,256],{"class":55}," rekey\n",[10,258,259],{},"Ese comando re-cifra todos los secretos con una clave nueva e invalida la anterior. Hazlo en ventana de mantenimiento — la operación puede demorar minutos en clusters con miles de secretos.",[20,261,263],{"id":262},"inyectando-en-el-job","Inyectando en el job",[10,265,266],{},"La inyección se hace en el momento en que la asignación inicia. El valor descifrado existe solo en la memoria del proceso, nunca en disco.",[28,268,272],{"className":269,"code":270,"language":271,"meta":33,"style":33},"language-yaml shiki shiki-themes github-dark-default","job: api-pagamentos\nenv:\n  DATABASE_URL: ${secret.database_url}\n  STRIPE_KEY: ${secret.stripe_secret}\n  REDIS_PASSWORD: ${secret.redis_password}\n","yaml",[35,273,274,287,295,305,315],{"__ignoreMap":33},[38,275,276,280,284],{"class":40,"line":41},[38,277,279],{"class":278},"sPWt5","job",[38,281,283],{"class":282},"sZEs4",": ",[38,285,286],{"class":55},"api-pagamentos\n",[38,288,289,292],{"class":40,"line":48},[38,290,291],{"class":278},"env",[38,293,294],{"class":282},":\n",[38,296,297,300,302],{"class":40,"line":72},[38,298,299],{"class":278},"  DATABASE_URL",[38,301,283],{"class":282},[38,303,304],{"class":55},"${secret.database_url}\n",[38,306,307,310,312],{"class":40,"line":79},[38,308,309],{"class":278},"  STRIPE_KEY",[38,311,283],{"class":282},[38,313,314],{"class":55},"${secret.stripe_secret}\n",[38,316,317,320,322],{"class":40,"line":85},[38,318,319],{"class":278},"  REDIS_PASSWORD",[38,321,283],{"class":282},[38,323,324],{"class":55},"${secret.redis_password}\n",[10,326,327],{},"El proceso dentro del contenedor ve las variables como cualquier otra. Ningún cambio en el código de la aplicación.",[10,329,330],{},"Para inyectar como archivo (útil para claves TLS, certificados, JSON de service account):",[28,332,334],{"className":269,"code":333,"language":271,"meta":33,"style":33},"job: webhook-handler\nfiles:\n  - path: \u002Fetc\u002Fapp\u002Fcredentials.json\n    content: ${secret.gcp_service_account}\n    mode: \"0400\"\n",[35,335,336,345,352,365,375],{"__ignoreMap":33},[38,337,338,340,342],{"class":40,"line":41},[38,339,279],{"class":278},[38,341,283],{"class":282},[38,343,344],{"class":55},"webhook-handler\n",[38,346,347,350],{"class":40,"line":48},[38,348,349],{"class":278},"files",[38,351,294],{"class":282},[38,353,354,357,360,362],{"class":40,"line":72},[38,355,356],{"class":282},"  - ",[38,358,359],{"class":278},"path",[38,361,283],{"class":282},[38,363,364],{"class":55},"\u002Fetc\u002Fapp\u002Fcredentials.json\n",[38,366,367,370,372],{"class":40,"line":79},[38,368,369],{"class":278},"    content",[38,371,283],{"class":282},[38,373,374],{"class":55},"${secret.gcp_service_account}\n",[38,376,377,380,382],{"class":40,"line":85},[38,378,379],{"class":278},"    mode",[38,381,283],{"class":282},[38,383,384],{"class":55},"\"0400\"\n",[10,386,387],{},"El archivo se crea en tmpfs (no toca disco), con el permiso indicado, antes de que el proceso principal arranque.",[20,389,391],{"id":390},"versionado-y-rotacion","Versionado y rotación",[10,393,394],{},"Toda actualización de un secreto crea una versión nueva. La versión antigua queda disponible por una ventana de tiempo configurable (default 7 días) para casos de rollback.",[28,396,398],{"className":30,"code":397,"language":32,"meta":33,"style":33},"# atualiza, mantendo histórico\nheroctl secret update db_password --from-literal=\"senha-nova\"\n\n# lista versões\nheroctl secret history db_password\n\n# faz rollback para versão anterior\nheroctl secret rollback db_password --to-version 3\n",[35,399,400,405,421,425,430,441,445,450],{"__ignoreMap":33},[38,401,402],{"class":40,"line":41},[38,403,404],{"class":44},"# atualiza, mantendo histórico\n",[38,406,407,409,411,414,416,418],{"class":40,"line":48},[38,408,52],{"class":51},[38,410,56],{"class":55},[38,412,413],{"class":55}," update",[38,415,62],{"class":55},[38,417,66],{"class":65},[38,419,420],{"class":55},"\"senha-nova\"\n",[38,422,423],{"class":40,"line":72},[38,424,76],{"emptyLinePlaceholder":75},[38,426,427],{"class":40,"line":79},[38,428,429],{"class":44},"# lista versões\n",[38,431,432,434,436,439],{"class":40,"line":85},[38,433,52],{"class":51},[38,435,56],{"class":55},[38,437,438],{"class":55}," history",[38,440,184],{"class":55},[38,442,443],{"class":40,"line":100},[38,444,76],{"emptyLinePlaceholder":75},[38,446,447],{"class":40,"line":105},[38,448,449],{"class":44},"# faz rollback para versão anterior\n",[38,451,452,454,456,459,461,464],{"class":40,"line":111},[38,453,52],{"class":51},[38,455,56],{"class":55},[38,457,458],{"class":55}," rollback",[38,460,62],{"class":55},[38,462,463],{"class":65}," --to-version",[38,465,466],{"class":65}," 3\n",[10,468,469],{},"Por defecto, los jobs en ejecución siguen usando la versión que estaba activa cuando arrancaron. Para forzar relectura, redespliega el job:",[28,471,473],{"className":30,"code":472,"language":32,"meta":33,"style":33},"heroctl job redeploy api-pagamentos\n",[35,474,475],{"__ignoreMap":33},[38,476,477,479,482,485],{"class":40,"line":41},[38,478,52],{"class":51},[38,480,481],{"class":55}," job",[38,483,484],{"class":55}," redeploy",[38,486,487],{"class":55}," api-pagamentos\n",[10,489,490],{},"Para un job que necesita siempre la versión más reciente sin redeploy, declara:",[28,492,494],{"className":269,"code":493,"language":271,"meta":33,"style":33},"env:\n  DATABASE_URL: ${secret.database_url:latest}\n",[35,495,496,502],{"__ignoreMap":33},[38,497,498,500],{"class":40,"line":41},[38,499,291],{"class":278},[38,501,294],{"class":282},[38,503,504,506,508],{"class":40,"line":48},[38,505,299],{"class":278},[38,507,283],{"class":282},[38,509,510],{"class":55},"${secret.database_url:latest}\n",[10,512,513],{},"En ese modo, el cluster reinicia la asignación automáticamente cuando el secreto cambia.",[20,515,517],{"id":516},"permisos-por-rol-business","Permisos por rol (Business+)",[10,519,520],{},"En el plan Business, ganas control granular sobre quién puede hacer qué con qué secreto. El modelo trabaja con scopes jerárquicos:",[28,522,524],{"className":269,"code":523,"language":271,"meta":33,"style":33},"policy \"deploy-prod-secrets\":\n  secret:\n    path: \"prod\u002F*\"\n    capabilities: [\"read\", \"list\"]\n  secret:\n    path: \"prod\u002Fadmin\u002F*\"\n    capabilities: []  # nem listar\n",[35,525,526,533,540,550,570,576,585],{"__ignoreMap":33},[38,527,528,531],{"class":40,"line":41},[38,529,530],{"class":278},"policy \"deploy-prod-secrets\"",[38,532,294],{"class":282},[38,534,535,538],{"class":40,"line":48},[38,536,537],{"class":278},"  secret",[38,539,294],{"class":282},[38,541,542,545,547],{"class":40,"line":72},[38,543,544],{"class":278},"    path",[38,546,283],{"class":282},[38,548,549],{"class":55},"\"prod\u002F*\"\n",[38,551,552,555,558,561,564,567],{"class":40,"line":79},[38,553,554],{"class":278},"    capabilities",[38,556,557],{"class":282},": [",[38,559,560],{"class":55},"\"read\"",[38,562,563],{"class":282},", ",[38,565,566],{"class":55},"\"list\"",[38,568,569],{"class":282},"]\n",[38,571,572,574],{"class":40,"line":85},[38,573,537],{"class":278},[38,575,294],{"class":282},[38,577,578,580,582],{"class":40,"line":100},[38,579,544],{"class":278},[38,581,283],{"class":282},[38,583,584],{"class":55},"\"prod\u002Fadmin\u002F*\"\n",[38,586,587,589,592],{"class":40,"line":105},[38,588,554],{"class":278},[38,590,591],{"class":282},": []  ",[38,593,594],{"class":44},"# nem listar\n",[10,596,597,598,603],{},"Asigna la política a un token o a un rol y listo. Ver el documento de ",[599,600,602],"a",{"href":601},"\u002Fes\u002Fdocs\u002Fseguridad\u002Frbac","RBAC"," para el modelo completo.",[20,605,607],{"id":606},"auditoria-business","Auditoría (Business+)",[10,609,610],{},"Todo acceso queda registrado:",[28,612,614],{"className":30,"code":613,"language":32,"meta":33,"style":33},"heroctl audit secret --name db_password --since 30d\n",[35,615,616],{"__ignoreMap":33},[38,617,618,620,623,625,628,630,633],{"class":40,"line":41},[38,619,52],{"class":51},[38,621,622],{"class":55}," audit",[38,624,56],{"class":55},[38,626,627],{"class":65}," --name",[38,629,62],{"class":55},[38,631,632],{"class":65}," --since",[38,634,635],{"class":55}," 30d\n",[10,637,638,639,563,642,563,645,648],{},"Salida tabular con timestamp, usuario, acción (",[35,640,641],{},"read",[35,643,644],{},"update",[35,646,647],{},"delete","), origen (IP) y resultado. Exporta para análisis externo:",[28,650,652],{"className":30,"code":651,"language":32,"meta":33,"style":33},"heroctl audit secret --since 30d --format json > audit.jsonl\n",[35,653,654],{"__ignoreMap":33},[38,655,656,658,660,662,664,667,670,673,676],{"class":40,"line":41},[38,657,52],{"class":51},[38,659,622],{"class":55},[38,661,56],{"class":55},[38,663,632],{"class":65},[38,665,666],{"class":55}," 30d",[38,668,669],{"class":65}," --format",[38,671,672],{"class":55}," json",[38,674,675],{"class":123}," >",[38,677,678],{"class":55}," audit.jsonl\n",[10,680,681],{},"Configura alertas para patrones anómalos: lectura fuera de horario laboral, mismo secreto leído por usuarios diferentes en ventana corta, fallos de permiso repetidos.",[20,683,685],{"id":684},"backup-cifrado","Backup cifrado",[10,687,688],{},"Los backups de los secretos salen cifrados, listos para enviar a storage S3-compatible:",[28,690,692],{"className":269,"code":691,"language":271,"meta":33,"style":33},"# config do cluster\nbackup:\n  secrets:\n    enabled: true\n    schedule: \"0 3 * * *\"  # 3h da manhã todo dia\n    destination:\n      type: s3\n      bucket: heroctl-backups\n      region: us-east-1\n      prefix: secrets\u002F\n      credentials: ${secret.backup_s3_creds}\n    retention_days: 90\n",[35,693,694,699,706,713,723,736,743,753,763,774,785,796],{"__ignoreMap":33},[38,695,696],{"class":40,"line":41},[38,697,698],{"class":44},"# config do cluster\n",[38,700,701,704],{"class":40,"line":48},[38,702,703],{"class":278},"backup",[38,705,294],{"class":282},[38,707,708,711],{"class":40,"line":72},[38,709,710],{"class":278},"  secrets",[38,712,294],{"class":282},[38,714,715,718,720],{"class":40,"line":79},[38,716,717],{"class":278},"    enabled",[38,719,283],{"class":282},[38,721,722],{"class":65},"true\n",[38,724,725,728,730,733],{"class":40,"line":85},[38,726,727],{"class":278},"    schedule",[38,729,283],{"class":282},[38,731,732],{"class":55},"\"0 3 * * *\"",[38,734,735],{"class":44},"  # 3h da manhã todo dia\n",[38,737,738,741],{"class":40,"line":100},[38,739,740],{"class":278},"    destination",[38,742,294],{"class":282},[38,744,745,748,750],{"class":40,"line":105},[38,746,747],{"class":278},"      type",[38,749,283],{"class":282},[38,751,752],{"class":55},"s3\n",[38,754,755,758,760],{"class":40,"line":111},[38,756,757],{"class":278},"      bucket",[38,759,283],{"class":282},[38,761,762],{"class":55},"heroctl-backups\n",[38,764,766,769,771],{"class":40,"line":765},9,[38,767,768],{"class":278},"      region",[38,770,283],{"class":282},[38,772,773],{"class":55},"us-east-1\n",[38,775,777,780,782],{"class":40,"line":776},10,[38,778,779],{"class":278},"      prefix",[38,781,283],{"class":282},[38,783,784],{"class":55},"secrets\u002F\n",[38,786,788,791,793],{"class":40,"line":787},11,[38,789,790],{"class":278},"      credentials",[38,792,283],{"class":282},[38,794,795],{"class":55},"${secret.backup_s3_creds}\n",[38,797,799,802,804],{"class":40,"line":798},12,[38,800,801],{"class":278},"    retention_days",[38,803,283],{"class":282},[38,805,806],{"class":65},"90\n",[10,808,809],{},"El snapshot se cifra con la clave del cluster antes de ser enviado. El bucket puede estar accesible para otros propósitos sin riesgo — quien tenga acceso de lectura no consigue descifrar nada.",[10,811,812,813,816],{},"Para restaurar en un cluster nuevo, necesitas el snapshot ",[217,814,815],{},"y"," la clave del cluster original. Guarda la clave separada del storage de backup.",[20,818,820],{"id":819},"cofres-externos","Cofres externos",[10,822,823],{},"Para equipos con requisitos de cumplimiento que exigen uso de cofre corporativo ya existente, hay integración opcional:",[28,825,827],{"className":269,"code":826,"language":271,"meta":33,"style":33},"secret_backend:\n  type: aws_kms\n  region: us-east-1\n  key_id: alias\u002Fheroctl-prod\n",[35,828,829,836,846,855],{"__ignoreMap":33},[38,830,831,834],{"class":40,"line":41},[38,832,833],{"class":278},"secret_backend",[38,835,294],{"class":282},[38,837,838,841,843],{"class":40,"line":48},[38,839,840],{"class":278},"  type",[38,842,283],{"class":282},[38,844,845],{"class":55},"aws_kms\n",[38,847,848,851,853],{"class":40,"line":72},[38,849,850],{"class":278},"  region",[38,852,283],{"class":282},[38,854,773],{"class":55},[38,856,857,860,862],{"class":40,"line":79},[38,858,859],{"class":278},"  key_id",[38,861,283],{"class":282},[38,863,864],{"class":55},"alias\u002Fheroctl-prod\n",[10,866,867,868,871],{},"Soportado de fábrica: AWS KMS, GCP KMS, HashiCorp Vault. En ese modo, HeroCtl delega operaciones de cifrado al cofre externo. Los secretos siguen accesibles por la misma sintaxis ",[35,869,870],{},"${secret.nome}",".",[10,873,874],{},"Usa esto si ya tienes el cofre operando y auditado. Para la mayoría de los equipos, el backend nativo es suficiente y más simple.",[20,876,878],{"id":877},"buenas-practicas","Buenas prácticas",[10,880,881],{},"En orden de importancia:",[883,884,885,892,905,911,920,926],"ol",{},[886,887,888,891],"li",{},[217,889,890],{},"Sin hardcode en spec."," Ni en commit, ni temporalmente, ni \"solo para test\". El hábito filtra.",[886,893,894,897,898,563,901,904],{},[217,895,896],{},"Separación dev \u002F staging \u002F prod."," Usa prefijos en el nombre (",[35,899,900],{},"dev\u002Fdb_password",[35,902,903],{},"prod\u002Fdb_password",") o clusters separados. Nunca compartas credencial de producción con ambiente de desarrollo.",[886,906,907,910],{},[217,908,909],{},"Rotación periódica."," Mínimo cada 90 días para credenciales de base de datos y proveedores. Más frecuente para tokens de API que se filtran fácil.",[886,912,913,916,917,919],{},[217,914,915],{},"Least privilege en la lectura."," Casi nadie necesita ",[35,918,223],{},". La inyección automática en el job no exige que la persona que hizo deploy tenga acceso al valor.",[886,921,922,925],{},[217,923,924],{},"Revisión de auditoría mensual."," Mira quién leyó qué. Las anomalías aparecen si se buscan.",[886,927,928,931,932,935],{},[217,929,930],{},"No loguees secretos."," Configura la aplicación para enmascarar variables sensibles en logs. El cluster cifra en reposo, pero si tu aplicación imprime ",[35,933,934],{},"print(os.environ)"," en el startup, se acabó.",[20,937,939],{"id":938},"proximos-pasos","Próximos pasos",[941,942,943,950],"ul",{},[886,944,945,946,949],{},"Configurar ",[599,947,948],{"href":601},"RBAC y tokens"," para limitar quién accede a qué.",[886,951,952,953,957],{},"Revisar ",[599,954,956],{"href":955},"\u002Fes\u002Fdocs\u002Fobservabilidad\u002Fmetricas-logs","métricas y logs"," para detectar uso anómalo.",[959,960,961],"style",{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}",{"title":33,"searchDepth":48,"depth":48,"links":963},[964,965,966,967,968,969,970,971,972,973,974],{"id":22,"depth":48,"text":23},{"id":143,"depth":48,"text":144},{"id":227,"depth":48,"text":228},{"id":262,"depth":48,"text":263},{"id":390,"depth":48,"text":391},{"id":516,"depth":48,"text":517},{"id":606,"depth":48,"text":607},{"id":684,"depth":48,"text":685},{"id":819,"depth":48,"text":820},{"id":877,"depth":48,"text":878},{"id":938,"depth":48,"text":939},"seguranca","Cómo guardar contraseñas, tokens y claves fuera del spec del job, con cifrado en reposo y rotación versionada.",false,"md","i-lucide-key","2026-04-26",{},"\u002Fes\u002Fdocs\u002Fseguridad\u002Fsecretos",[],"8 min de lectura",{"title":5,"description":976},"es\u002Fdocs\u002Fseguridad\u002Fsecretos",[988,989,990,991],"secretos","seguridad","cifrado","rotacion","ueg6WL2_3_hWkIcf10F67wq5OX4VfvGtuBmf4v-NUxI",[994,1000,1006,1011,1017,1021,1027,1032,1037,1042,1048,1052,1056,1057],{"path":995,"title":996,"description":997,"category":998,"order":41,"icon":999},"\u002Fes\u002Fdocs\u002Fapi\u002Freferencia-api","Referencia de la API REST","Endpoints, autenticación JWT, ejemplos con curl y patrones de error de la API de HeroCtl.","api","i-lucide-code",{"path":1001,"title":1002,"description":1003,"category":1004,"order":41,"icon":1005},"\u002Fes\u002Fdocs\u002Fdeploy\u002Fprimer-deploy","Deploy de la primera app","Levanta una aplicación Node.js con base Postgres en 50 líneas de YAML. Incluye health check, rolling update y rollback.","deploy","i-lucide-rocket",{"path":1007,"title":1008,"description":1009,"category":1004,"order":48,"icon":1010},"\u002Fes\u002Fdocs\u002Fdeploy\u002Frolling-canary-blue-green","Rolling, canary, blue-green y rainbow","Cuatro estrategias de deploy. Cuándo usar cada una, con ejemplos completos y trade-offs honestos.","i-lucide-git-branch",{"path":1012,"title":1013,"description":1014,"category":1015,"order":48,"icon":1016},"\u002Fes\u002Fdocs\u002Fobservabilidad\u002Fbackup-restauracion","Backup y restauración del estado del cluster","Cómo guardar, programar y restaurar snapshots del plano de control de HeroCtl. Estrategia de disaster recovery.","observabilidade","i-lucide-archive",{"path":955,"title":1018,"description":1019,"category":1015,"order":41,"icon":1020},"Métricas y logs","Recolección de métricas, logs y traces sin montar una pila de observabilidad externa. Cuándo vale, y cuándo integrar con herramienta de fuera.","i-lucide-activity",{"path":1022,"title":1023,"description":1024,"category":1025,"order":41,"icon":1026},"\u002Fes\u002Fdocs\u002Foperaciones\u002Finstalacion","Instalación","Instala HeroCtl en cualquier servidor Linux con Docker en un solo comando. Cubre prerrequisitos, bootstrap y verificación.","operacoes","i-lucide-download",{"path":1028,"title":1029,"description":1030,"category":1025,"order":79,"icon":1031},"\u002Fes\u002Fdocs\u002Foperaciones\u002Fmulti-region","Multi-region (en planificación Q4 2026)","Qué esperar de multi-region en HeroCtl, cómo correr en varias regiones hoy y la hoja de ruta hasta 2027.","i-lucide-globe",{"path":1033,"title":1034,"description":1035,"category":1025,"order":48,"icon":1036},"\u002Fes\u002Fdocs\u002Foperaciones\u002Fprimer-cluster","Levantar cluster de 3 nodos","Forma un cluster con 3 servidores en menos de 10 minutos. Tolera falla de 1 nodo sin indisponibilidad.","i-lucide-network",{"path":1038,"title":1039,"description":1040,"category":1025,"order":72,"icon":1041},"\u002Fes\u002Fdocs\u002Foperaciones\u002Freferencia-cli","Referencia completa del CLI","Todos los comandos heroctl con sinopsis, flags y ejemplo. Úsalo como chuleta de mesa.","i-lucide-terminal",{"path":1043,"title":1044,"description":1045,"category":1046,"order":48,"icon":1047},"\u002Fes\u002Fdocs\u002Fred\u002Ffirewall","Configuración de firewall","Qué puertos usa HeroCtl, cuáles necesitan estar abiertos y cuáles nunca deberían exponerse a internet.","rede","i-lucide-shield",{"path":1049,"title":1050,"description":1051,"category":1046,"order":41,"icon":1031},"\u002Fes\u002Fdocs\u002Fred\u002Fingress-tls","Ingress y TLS automático","Cómo exponer aplicaciones por el puerto 443 con certificados emitidos y renovados automáticamente, sin operar un router externo.",{"path":601,"title":1053,"description":1054,"category":975,"order":48,"icon":1055},"RBAC y control de acceso (Business+)","Modelo de roles, políticas y tokens para limitar quién puede enviar, leer y operar el cluster.","i-lucide-users",{"path":982,"title":5,"description":976,"category":975,"order":41,"icon":979},{"path":1058,"title":1059,"description":1060,"category":1061,"order":41,"icon":1062},"\u002Fes\u002Fdocs\u002Ftroubleshooting\u002Fproblemas-comunes","Troubleshooting de problemas comunes","Los 12 problemas más frecuentes en clusters HeroCtl, con síntoma, diagnóstico y corrección paso a paso.","troubleshooting","i-lucide-alert-triangle",1777362183086]