[{"data":1,"prerenderedAt":1063},["ShallowReactive",2],{"doc-en-\u002Fen\u002Fdocs\u002Fsecurity\u002Fsecrets":3,"docs-en-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_en\u002Fen\u002Fdocs\u002Fsecurity\u002Fsecrets.md","Secret management",{"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",{},"Database password, API key, OAuth token, provider credential. All of these are secrets and none of them belong in the job spec.",[10,14,15],{},"For two reasons. First, specs are usually versioned in some repository. Anyone with read access to the repo gets access to the secret. Second, specs travel through logs, shared terminals, review screenshots. Each of those points is a leak waiting to happen.",[10,17,18],{},"HeroCtl ships with an integrated secret vault. You don't wire anything in from the outside.",[20,21,23],"h2",{"id":22},"creating-a-secret","Creating a secret",[10,25,26],{},"From the CLI, three forms:",[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],{},"Through the web panel there is an equivalent form.",[20,142,144],{"id":143},"listing-and-inspecting","Listing and inspecting",[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"," is the most sensitive operation in the system. It shows up in the audit log with the name of who read it, when, and from which IP.",[212,213,214],"blockquote",{},[10,215,216,220,221,224],{},[217,218,219],"strong",{},"Warning:"," In production, restrict ",[35,222,223],{},"secret:read"," to the minimum number of roles. For most teams, no one needs to read values manually — the cluster injects them straight into the job.",[20,226,228],{"id":227},"encryption-at-rest","Encryption at rest",[10,230,231],{},"Each secret is encrypted with AES-256 before being persisted. The cluster's encryption key is protected and is never stored alongside the encrypted data.",[10,233,234],{},"Operationally this means a backup of cluster state, without the key, is useless to an attacker. You can carry a snapshot on an external hard drive without worry.",[10,236,237,238,241],{},"The key itself is generated at cluster initialization and lives in a file protected by filesystem permissions (",[35,239,240],{},"0600",", owner root) on each server node. To rotate it:",[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],{},"This command re-encrypts every secret with a new key and invalidates the old one. Do it during a maintenance window — the operation can take minutes on clusters with thousands of secrets.",[20,261,263],{"id":262},"injecting-into-the-job","Injecting into the job",[10,265,266],{},"Injection happens the moment the allocation starts. The decrypted value exists only in the process memory, never on disk.",[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],{},"The process inside the container sees the variables like any other. No application code change required.",[10,329,330],{},"To inject as a file (useful for TLS keys, certificates, service account JSON):",[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],{},"The file is created on tmpfs (it never touches disk), with the indicated permission, before the main process starts.",[20,389,391],{"id":390},"versioning-and-rotation","Versioning and rotation",[10,393,394],{},"Every update to a secret creates a new version. The old version stays available for a configurable time window (default 7 days) for rollback cases.",[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],{},"By default, running jobs keep using the version that was active when they started. To force a re-read, redeploy the 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],{},"For a job that always needs the latest version without redeploy, declare:",[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],{},"In this mode, the cluster automatically restarts the allocation when the secret changes.",[20,515,517],{"id":516},"per-role-permissions-business","Per-role permissions (Business+)",[10,519,520],{},"In the Business plan, you get fine-grained control over who can do what with which secret. The model works with hierarchical scopes:",[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],{},"Attach the policy to a token or a role and you're done. See the ",[599,600,602],"a",{"href":601},"\u002Fen\u002Fdocs\u002Fsecurity\u002Frbac","RBAC"," document for the complete model.",[20,605,607],{"id":606},"audit-business","Audit (Business+)",[10,609,610],{},"Every access is recorded:",[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],{},"Tabular output with timestamp, user, action (",[35,640,641],{},"read",[35,643,644],{},"update",[35,646,647],{},"delete","), source (IP), and result. Export for external analysis:",[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],{},"Configure alerts for anomalous patterns: reads outside business hours, the same secret read by different users in a short window, repeated permission failures.",[20,683,685],{"id":684},"encrypted-backup","Encrypted backup",[10,687,688],{},"Secret backups come out encrypted, ready to ship to S3-compatible storage:",[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],{},"The snapshot is encrypted with the cluster key before being shipped. The bucket can be reachable for other purposes without risk — anyone with read access cannot decrypt anything.",[10,811,812,813,816],{},"To restore on a new cluster, you need the snapshot ",[217,814,815],{},"and"," the original cluster's key. Keep the key separate from the backup storage.",[20,818,820],{"id":819},"external-vaults","External vaults",[10,822,823],{},"For teams with compliance requirements that mandate use of an existing corporate vault, there is an optional integration:",[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],{},"Supported out of the box: AWS KMS, GCP KMS, HashiCorp Vault. In this mode, HeroCtl delegates encryption operations to the external vault. Secrets remain accessible through the same ",[35,869,870],{},"${secret.name}"," syntax.",[10,873,874],{},"Use this if you already have the vault running and audited. For most teams, the native backend is enough and simpler.",[20,876,878],{"id":877},"best-practices","Best practices",[10,880,881],{},"In order of importance:",[883,884,885,892,905,911,920,926],"ol",{},[886,887,888,891],"li",{},[217,889,890],{},"No hardcoding in the spec."," Not in a commit, not temporarily, not \"just for testing\". The habit leaks.",[886,893,894,897,898,563,901,904],{},[217,895,896],{},"Separate dev \u002F staging \u002F prod."," Use prefixes in the name (",[35,899,900],{},"dev\u002Fdb_password",[35,902,903],{},"prod\u002Fdb_password",") or separate clusters. Never share production credentials with a development environment.",[886,906,907,910],{},[217,908,909],{},"Periodic rotation."," Minimum every 90 days for database and provider credentials. More frequently for API tokens that leak easily.",[886,912,913,916,917,919],{},[217,914,915],{},"Least privilege on reads."," Almost no one needs ",[35,918,223],{},". Automatic injection into the job does not require the person who deployed it to have access to the value.",[886,921,922,925],{},[217,923,924],{},"Monthly audit review."," Look at who read what. Anomalies show up if you look.",[886,927,928,931,932,935],{},[217,929,930],{},"Don't log secrets."," Configure the application to mask sensitive variables in logs. The cluster encrypts at rest, but if your app prints ",[35,933,934],{},"print(os.environ)"," on startup, it's over.",[20,937,939],{"id":938},"next-steps","Next steps",[941,942,943,950],"ul",{},[886,944,945,946,949],{},"Configure ",[599,947,948],{"href":601},"RBAC and tokens"," to limit who accesses what.",[886,951,952,953,957],{},"Review ",[599,954,956],{"href":955},"\u002Fen\u002Fdocs\u002Fobservability\u002Fmetrics-logs","metrics and logs"," to detect anomalous use.",[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","How to keep passwords, tokens, and keys outside the job spec, with encryption at rest and versioned rotation.",false,"md","i-lucide-key","2026-04-26",{},"\u002Fen\u002Fdocs\u002Fsecurity\u002Fsecrets",[],"8 min read",{"title":5,"description":976},"en\u002Fdocs\u002Fsecurity\u002Fsecrets",[988,989,990,991],"secrets","security","encryption","rotation","MTvkkJZh8OgEUv4kt0Bev0t9nKdO2hfiYq85qIpYWvQ",[994,1000,1006,1011,1017,1022,1028,1032,1038,1043,1048,1052,1056,1057],{"path":995,"title":996,"description":997,"category":998,"order":41,"icon":999},"\u002Fen\u002Fdocs\u002Fapi\u002Fapi-reference","REST API reference","Endpoints, JWT authentication, curl examples, and error patterns of the HeroCtl API.","api","i-lucide-code",{"path":1001,"title":1002,"description":1003,"category":1004,"order":41,"icon":1005},"\u002Fen\u002Fdocs\u002Fdeploy\u002Ffirst-deploy","Deploy your first app","Bring up a Node.js application with a Postgres database in 50 lines of YAML. Includes health check, rolling deploy, and rollback.","deploy","i-lucide-rocket",{"path":1007,"title":1008,"description":1009,"category":1004,"order":48,"icon":1010},"\u002Fen\u002Fdocs\u002Fdeploy\u002Frolling-canary-blue-green","Rolling, canary, blue-green, and rainbow","Four deploy strategies. When to use each, with complete examples and honest trade-offs.","i-lucide-git-branch",{"path":1012,"title":1013,"description":1014,"category":1015,"order":48,"icon":1016},"\u002Fen\u002Fdocs\u002Fnetworking\u002Ffirewall","Firewall configuration","Which ports HeroCtl uses, which need to stay open, and which should never be exposed to the internet.","rede","i-lucide-shield",{"path":1018,"title":1019,"description":1020,"category":1015,"order":41,"icon":1021},"\u002Fen\u002Fdocs\u002Fnetworking\u002Fingress-tls","Ingress and automatic TLS","How to expose applications on port 443 with certificates issued and renewed automatically, without operating an external router.","i-lucide-globe",{"path":1023,"title":1024,"description":1025,"category":1026,"order":48,"icon":1027},"\u002Fen\u002Fdocs\u002Fobservability\u002Fbackup-restore","Backup and restore of cluster state","How to save, schedule, and restore HeroCtl control plane snapshots. Disaster recovery strategy.","observabilidade","i-lucide-archive",{"path":955,"title":1029,"description":1030,"category":1026,"order":41,"icon":1031},"Metrics and logs","Collect metrics, logs, and traces without standing up an external observability stack. When it's worth it, and when to integrate with an outside tool.","i-lucide-activity",{"path":1033,"title":1034,"description":1035,"category":1036,"order":72,"icon":1037},"\u002Fen\u002Fdocs\u002Foperations\u002Fcli-reference","Complete CLI reference","All heroctl commands with synopsis, flags, and example. Use as a desk reference.","operacoes","i-lucide-terminal",{"path":1039,"title":1040,"description":1041,"category":1036,"order":48,"icon":1042},"\u002Fen\u002Fdocs\u002Foperations\u002Ffirst-cluster","Bring up a 3-node cluster","Form a cluster with 3 servers in under 10 minutes. Tolerates 1-node failure with no downtime.","i-lucide-network",{"path":1044,"title":1045,"description":1046,"category":1036,"order":41,"icon":1047},"\u002Fen\u002Fdocs\u002Foperations\u002Finstallation","Installation","Install HeroCtl on any Linux server with Docker in a single command. Covers prerequisites, bootstrap, and verification.","i-lucide-download",{"path":1049,"title":1050,"description":1051,"category":1036,"order":79,"icon":1021},"\u002Fen\u002Fdocs\u002Foperations\u002Fmulti-region","Multi-region (planned for Q4 2026)","What to expect from multi-region in HeroCtl, how to run across regions today, and the roadmap through 2027.",{"path":601,"title":1053,"description":1054,"category":975,"order":48,"icon":1055},"RBAC and access control (Business+)","Role, policy, and token model to limit who can submit, read, and operate the 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},"\u002Fen\u002Fdocs\u002Ftroubleshooting\u002Fcommon-problems","Troubleshooting common problems","The 12 most frequent problems in HeroCtl clusters, with symptom, diagnosis, and step-by-step fix.","troubleshooting","i-lucide-alert-triangle",1777362181722]