[{"data":1,"prerenderedAt":1233},["ShallowReactive",2],{"doc-en-\u002Fen\u002Fdocs\u002Fsecurity\u002Frbac":3,"docs-en-all":1163},{"id":4,"title":5,"body":6,"category":1144,"description":1145,"draft":1146,"extension":1147,"icon":1148,"lastReviewed":1149,"meta":1150,"navigation":248,"order":186,"path":1151,"prerequisites":1152,"readingTime":1153,"seo":1154,"stem":1155,"tags":1156,"__hash__":1162},"docs_en\u002Fen\u002Fdocs\u002Fsecurity\u002Frbac.md","RBAC and access control (Business+)",{"type":7,"value":8,"toc":1131},"minimark",[9,13,16,21,82,85,93,97,100,153,156,199,203,206,423,426,481,484,528,540,544,555,663,666,671,720,723,727,730,768,771,774,798,802,805,896,899,923,927,930,1029,1032,1035,1055,1059,1104,1108,1127],[10,11,12],"p",{},"In the Community plan, anyone with the admin token does everything. That's acceptable for small teams, but scales poorly. Starting with the Business plan, the cluster gains a role model with fine granularity.",[10,14,15],{},"This document explains the model, shows how to assign roles, and closes with practices that work in production.",[17,18,20],"h2",{"id":19},"the-model-in-four-concepts","The model in four concepts",[22,23,24,37],"table",{},[25,26,27],"thead",{},[28,29,30,34],"tr",{},[31,32,33],"th",{},"Concept",[31,35,36],{},"What it is",[38,39,40,52,62,72],"tbody",{},[28,41,42,49],{},[43,44,45],"td",{},[46,47,48],"strong",{},"User",[43,50,51],{},"Human or service identity",[28,53,54,59],{},[43,55,56],{},[46,57,58],{},"Token",[43,60,61],{},"Bearer credential associated with a user",[28,63,64,69],{},[43,65,66],{},[46,67,68],{},"Role",[43,70,71],{},"Name aggregating one or more policies",[28,73,74,79],{},[43,75,76],{},[46,77,78],{},"Policy",[43,80,81],{},"Concrete rules: what is allowed on which resource",[10,83,84],{},"A user has one or more tokens. Each token carries one or more roles. Each role is a set of policies. Each policy authorizes capabilities on resources.",[10,86,87,88,92],{},"When a call reaches the cluster, the token resolves to the effective set of capabilities. If the requested operation is in the set, it proceeds. Otherwise it gets ",[89,90,91],"code",{},"403 Forbidden",".",[17,94,96],{"id":95},"built-in-roles","Built-in roles",[10,98,99],{},"For most teams, the four ready-made roles cover what's needed:",[22,101,102,111],{},[25,103,104],{},[28,105,106,108],{},[31,107,68],{},[31,109,110],{},"What it does",[38,112,113,123,133,143],{},[28,114,115,120],{},[43,116,117],{},[89,118,119],{},"admin",[43,121,122],{},"Everything. Includes creating users, changing policies, rekey, snapshot.",[28,124,125,130],{},[43,126,127],{},[89,128,129],{},"operator",[43,131,132],{},"Submits and manages jobs in any namespace. Does not create users.",[28,134,135,140],{},[43,136,137],{},[89,138,139],{},"deployer",[43,141,142],{},"Submits jobs in specific namespaces. Does not inspect secrets.",[28,144,145,150],{},[43,146,147],{},[89,148,149],{},"viewer",[43,151,152],{},"Read-only. Sees jobs, allocations, metrics. Does not see secrets.",[10,154,155],{},"List what exists:",[157,158,163],"pre",{"className":159,"code":160,"language":161,"meta":162,"style":162},"language-bash shiki shiki-themes github-dark-default","heroctl acl role list\nheroctl acl role describe operator\n","bash","",[89,164,165,184],{"__ignoreMap":162},[166,167,170,174,178,181],"span",{"class":168,"line":169},"line",1,[166,171,173],{"class":172},"sQhOw","heroctl",[166,175,177],{"class":176},"s9uIt"," acl",[166,179,180],{"class":176}," role",[166,182,183],{"class":176}," list\n",[166,185,187,189,191,193,196],{"class":168,"line":186},2,[166,188,173],{"class":172},[166,190,177],{"class":176},[166,192,180],{"class":176},[166,194,195],{"class":176}," describe",[166,197,198],{"class":176}," operator\n",[17,200,202],{"id":201},"custom-policies","Custom policies",[10,204,205],{},"When the built-in roles aren't enough, write a policy in YAML:",[157,207,211],{"className":208,"code":209,"language":210,"meta":162,"style":162},"language-yaml shiki shiki-themes github-dark-default","# arquivo: deployer-prod.yaml\nname: deployer-prod\ndescription: \"Submete jobs no namespace prod, sem ler segredos\"\n\nrules:\n  - resource: job\n    namespace: \"prod\"\n    capabilities: [\"read\", \"list\", \"submit\", \"stop\"]\n\n  - resource: namespace\n    name: \"prod\"\n    capabilities: [\"read\"]\n\n  - resource: alloc\n    namespace: \"prod\"\n    capabilities: [\"read\", \"logs\"]\n\n  - resource: secret\n    capabilities: []  # negado explicitamente\n","yaml",[89,212,213,219,232,243,250,259,273,284,315,320,332,342,353,358,370,379,395,400,412],{"__ignoreMap":162},[166,214,215],{"class":168,"line":169},[166,216,218],{"class":217},"sH3jZ","# arquivo: deployer-prod.yaml\n",[166,220,221,225,229],{"class":168,"line":186},[166,222,224],{"class":223},"sPWt5","name",[166,226,228],{"class":227},"sZEs4",": ",[166,230,231],{"class":176},"deployer-prod\n",[166,233,235,238,240],{"class":168,"line":234},3,[166,236,237],{"class":223},"description",[166,239,228],{"class":227},[166,241,242],{"class":176},"\"Submete jobs no namespace prod, sem ler segredos\"\n",[166,244,246],{"class":168,"line":245},4,[166,247,249],{"emptyLinePlaceholder":248},true,"\n",[166,251,253,256],{"class":168,"line":252},5,[166,254,255],{"class":223},"rules",[166,257,258],{"class":227},":\n",[166,260,262,265,268,270],{"class":168,"line":261},6,[166,263,264],{"class":227},"  - ",[166,266,267],{"class":223},"resource",[166,269,228],{"class":227},[166,271,272],{"class":176},"job\n",[166,274,276,279,281],{"class":168,"line":275},7,[166,277,278],{"class":223},"    namespace",[166,280,228],{"class":227},[166,282,283],{"class":176},"\"prod\"\n",[166,285,287,290,293,296,299,302,304,307,309,312],{"class":168,"line":286},8,[166,288,289],{"class":223},"    capabilities",[166,291,292],{"class":227},": [",[166,294,295],{"class":176},"\"read\"",[166,297,298],{"class":227},", ",[166,300,301],{"class":176},"\"list\"",[166,303,298],{"class":227},[166,305,306],{"class":176},"\"submit\"",[166,308,298],{"class":227},[166,310,311],{"class":176},"\"stop\"",[166,313,314],{"class":227},"]\n",[166,316,318],{"class":168,"line":317},9,[166,319,249],{"emptyLinePlaceholder":248},[166,321,323,325,327,329],{"class":168,"line":322},10,[166,324,264],{"class":227},[166,326,267],{"class":223},[166,328,228],{"class":227},[166,330,331],{"class":176},"namespace\n",[166,333,335,338,340],{"class":168,"line":334},11,[166,336,337],{"class":223},"    name",[166,339,228],{"class":227},[166,341,283],{"class":176},[166,343,345,347,349,351],{"class":168,"line":344},12,[166,346,289],{"class":223},[166,348,292],{"class":227},[166,350,295],{"class":176},[166,352,314],{"class":227},[166,354,356],{"class":168,"line":355},13,[166,357,249],{"emptyLinePlaceholder":248},[166,359,361,363,365,367],{"class":168,"line":360},14,[166,362,264],{"class":227},[166,364,267],{"class":223},[166,366,228],{"class":227},[166,368,369],{"class":176},"alloc\n",[166,371,373,375,377],{"class":168,"line":372},15,[166,374,278],{"class":223},[166,376,228],{"class":227},[166,378,283],{"class":176},[166,380,382,384,386,388,390,393],{"class":168,"line":381},16,[166,383,289],{"class":223},[166,385,292],{"class":227},[166,387,295],{"class":176},[166,389,298],{"class":227},[166,391,392],{"class":176},"\"logs\"",[166,394,314],{"class":227},[166,396,398],{"class":168,"line":397},17,[166,399,249],{"emptyLinePlaceholder":248},[166,401,403,405,407,409],{"class":168,"line":402},18,[166,404,264],{"class":227},[166,406,267],{"class":223},[166,408,228],{"class":227},[166,410,411],{"class":176},"secret\n",[166,413,415,417,420],{"class":168,"line":414},19,[166,416,289],{"class":223},[166,418,419],{"class":227},": []  ",[166,421,422],{"class":217},"# negado explicitamente\n",[10,424,425],{},"Apply:",[157,427,429],{"className":159,"code":428,"language":161,"meta":162,"style":162},"heroctl acl policy create -f deployer-prod.yaml\n\n# anexa a política a um papel novo\nheroctl acl role create --name deploy-prod --policies deployer-prod\n",[89,430,431,450,454,459],{"__ignoreMap":162},[166,432,433,435,437,440,443,447],{"class":168,"line":169},[166,434,173],{"class":172},[166,436,177],{"class":176},[166,438,439],{"class":176}," policy",[166,441,442],{"class":176}," create",[166,444,446],{"class":445},"sFSAA"," -f",[166,448,449],{"class":176}," deployer-prod.yaml\n",[166,451,452],{"class":168,"line":186},[166,453,249],{"emptyLinePlaceholder":248},[166,455,456],{"class":168,"line":234},[166,457,458],{"class":217},"# anexa a política a um papel novo\n",[166,460,461,463,465,467,469,472,475,478],{"class":168,"line":245},[166,462,173],{"class":172},[166,464,177],{"class":176},[166,466,180],{"class":176},[166,468,442],{"class":176},[166,470,471],{"class":445}," --name",[166,473,474],{"class":176}," deploy-prod",[166,476,477],{"class":445}," --policies",[166,479,480],{"class":176}," deployer-prod\n",[10,482,483],{},"Common capabilities:",[485,486,487,498,507,516,522],"ul",{},[488,489,490,493,494,497],"li",{},[89,491,492],{},"read"," \u002F ",[89,495,496],{},"list"," — reading",[488,499,500,493,503,506],{},[89,501,502],{},"submit",[89,504,505],{},"update"," — creation and modification",[488,508,509,493,512,515],{},[89,510,511],{},"stop",[89,513,514],{},"delete"," — termination",[488,517,518,521],{},[89,519,520],{},"logs"," — access to allocation stdout\u002Fstderr",[488,523,524,527],{},[89,525,526],{},"exec"," — open a shell in a running allocation",[529,530,531],"blockquote",{},[10,532,533,536,537,539],{},[46,534,535],{},"Warning:"," ",[89,538,526],{}," in production is one of the most dangerous capabilities. Treat it as root access in the container. Restrict to at most two or three operators.",[17,541,543],{"id":542},"creating-tokens","Creating tokens",[10,545,546,547,550,551,554],{},"A token is what goes in the ",[89,548,549],{},"HEROCTL_TOKEN"," variable or the ",[89,552,553],{},"X-Heroctl-Token"," header:",[157,556,558],{"className":159,"code":557,"language":161,"meta":162,"style":162},"# token de longa duração para operador humano\nheroctl acl token create \\\n  --name \"joao-deploy-prod\" \\\n  --policies deploy-prod \\\n  --ttl 90d\n\n# token curto para CI\u002FCD\nheroctl acl token create \\\n  --name \"ci-pipeline\" \\\n  --policies deployer \\\n  --ttl 1h \\\n  --bound-cidr 10.20.0.0\u002F16\n",[89,559,560,565,580,590,599,607,611,616,628,637,646,655],{"__ignoreMap":162},[166,561,562],{"class":168,"line":169},[166,563,564],{"class":217},"# token de longa duração para operador humano\n",[166,566,567,569,571,574,576],{"class":168,"line":186},[166,568,173],{"class":172},[166,570,177],{"class":176},[166,572,573],{"class":176}," token",[166,575,442],{"class":176},[166,577,579],{"class":578},"suJrU"," \\\n",[166,581,582,585,588],{"class":168,"line":234},[166,583,584],{"class":445},"  --name",[166,586,587],{"class":176}," \"joao-deploy-prod\"",[166,589,579],{"class":578},[166,591,592,595,597],{"class":168,"line":245},[166,593,594],{"class":445},"  --policies",[166,596,474],{"class":176},[166,598,579],{"class":578},[166,600,601,604],{"class":168,"line":252},[166,602,603],{"class":445},"  --ttl",[166,605,606],{"class":176}," 90d\n",[166,608,609],{"class":168,"line":261},[166,610,249],{"emptyLinePlaceholder":248},[166,612,613],{"class":168,"line":275},[166,614,615],{"class":217},"# token curto para CI\u002FCD\n",[166,617,618,620,622,624,626],{"class":168,"line":286},[166,619,173],{"class":172},[166,621,177],{"class":176},[166,623,573],{"class":176},[166,625,442],{"class":176},[166,627,579],{"class":578},[166,629,630,632,635],{"class":168,"line":317},[166,631,584],{"class":445},[166,633,634],{"class":176}," \"ci-pipeline\"",[166,636,579],{"class":578},[166,638,639,641,644],{"class":168,"line":322},[166,640,594],{"class":445},[166,642,643],{"class":176}," deployer",[166,645,579],{"class":578},[166,647,648,650,653],{"class":168,"line":334},[166,649,603],{"class":445},[166,651,652],{"class":176}," 1h",[166,654,579],{"class":578},[166,656,657,660],{"class":168,"line":344},[166,658,659],{"class":445},"  --bound-cidr",[166,661,662],{"class":176}," 10.20.0.0\u002F16\n",[10,664,665],{},"The output includes the token secret only once. If you lose it, generate another — there is no recovery.",[667,668,670],"h3",{"id":669},"long-lived-vs-short-lived","Long-lived vs short-lived",[22,672,673,683],{},[25,674,675],{},[28,676,677,680],{},[31,678,679],{},"Use case",[31,681,682],{},"Recommended TTL",[38,684,685,693,701,712],{},[28,686,687,690],{},[43,688,689],{},"Human operator",[43,691,692],{},"30 to 90 days",[28,694,695,698],{},[43,696,697],{},"CI\u002FCD pipeline",[43,699,700],{},"1 to 24 hours (renewed each run)",[28,702,703,706],{},[43,704,705],{},"Monitoring integration",[43,707,708,709,711],{},"1 year, with ",[89,710,149],{}," scope only",[28,713,714,717],{},[43,715,716],{},"Break-glass emergency token",[43,718,719],{},"No expiration, kept in physical safe",[10,721,722],{},"Short tokens with automatic renewal are preferable. The operational cost has dropped significantly since CI\u002FCDs gained native OIDC.",[17,724,726],{"id":725},"revocation","Revocation",[10,728,729],{},"At any time:",[157,731,733],{"className":159,"code":732,"language":161,"meta":162,"style":162},"heroctl acl token list\nheroctl acl token revoke \u003Cid-do-token>\n",[89,734,735,745],{"__ignoreMap":162},[166,736,737,739,741,743],{"class":168,"line":169},[166,738,173],{"class":172},[166,740,177],{"class":176},[166,742,573],{"class":176},[166,744,183],{"class":176},[166,746,747,749,751,753,756,759,762,765],{"class":168,"line":186},[166,748,173],{"class":172},[166,750,177],{"class":176},[166,752,573],{"class":176},[166,754,755],{"class":176}," revoke",[166,757,758],{"class":578}," \u003C",[166,760,761],{"class":176},"id-do-toke",[166,763,764],{"class":227},"n",[166,766,767],{"class":578},">\n",[10,769,770],{},"Revocation is immediate and propagates to all nodes within seconds. Use it when someone leaves the team, when you suspect compromise, or when rotating.",[10,772,773],{},"To revoke all tokens of a user at once:",[157,775,777],{"className":159,"code":776,"language":161,"meta":162,"style":162},"heroctl acl token revoke --user joao --all\n",[89,778,779],{"__ignoreMap":162},[166,780,781,783,785,787,789,792,795],{"class":168,"line":169},[166,782,173],{"class":172},[166,784,177],{"class":176},[166,786,573],{"class":176},[166,788,755],{"class":176},[166,790,791],{"class":445}," --user",[166,793,794],{"class":176}," joao",[166,796,797],{"class":445}," --all\n",[17,799,801],{"id":800},"audit-log","Audit log",[10,803,804],{},"Every authenticated call is recorded. This includes calls that failed for permission reasons.",[157,806,808],{"className":159,"code":807,"language":161,"meta":162,"style":162},"# últimos 7 dias para um usuário específico\nheroctl audit log --user joao --since 7d\n\n# todas as falhas de autorização\nheroctl audit log --result deny --since 24h\n\n# tudo o que tocou um job específico\nheroctl audit log --resource job --name api-pagamentos --since 30d\n",[89,809,810,815,835,839,844,863,867,872],{"__ignoreMap":162},[166,811,812],{"class":168,"line":169},[166,813,814],{"class":217},"# últimos 7 dias para um usuário específico\n",[166,816,817,819,822,825,827,829,832],{"class":168,"line":186},[166,818,173],{"class":172},[166,820,821],{"class":176}," audit",[166,823,824],{"class":176}," log",[166,826,791],{"class":445},[166,828,794],{"class":176},[166,830,831],{"class":445}," --since",[166,833,834],{"class":176}," 7d\n",[166,836,837],{"class":168,"line":234},[166,838,249],{"emptyLinePlaceholder":248},[166,840,841],{"class":168,"line":245},[166,842,843],{"class":217},"# todas as falhas de autorização\n",[166,845,846,848,850,852,855,858,860],{"class":168,"line":252},[166,847,173],{"class":172},[166,849,821],{"class":176},[166,851,824],{"class":176},[166,853,854],{"class":445}," --result",[166,856,857],{"class":176}," deny",[166,859,831],{"class":445},[166,861,862],{"class":176}," 24h\n",[166,864,865],{"class":168,"line":261},[166,866,249],{"emptyLinePlaceholder":248},[166,868,869],{"class":168,"line":275},[166,870,871],{"class":217},"# tudo o que tocou um job específico\n",[166,873,874,876,878,880,883,886,888,891,893],{"class":168,"line":286},[166,875,173],{"class":172},[166,877,821],{"class":176},[166,879,824],{"class":176},[166,881,882],{"class":445}," --resource",[166,884,885],{"class":176}," job",[166,887,471],{"class":445},[166,889,890],{"class":176}," api-pagamentos",[166,892,831],{"class":445},[166,894,895],{"class":176}," 30d\n",[10,897,898],{},"Each record has: timestamp, identity, source IP, target resource, operation, result. Export for external analysis as JSON:",[157,900,902],{"className":159,"code":901,"language":161,"meta":162,"style":162},"heroctl audit log --since 30d --format json\n",[89,903,904],{"__ignoreMap":162},[166,905,906,908,910,912,914,917,920],{"class":168,"line":169},[166,907,173],{"class":172},[166,909,821],{"class":176},[166,911,824],{"class":176},[166,913,831],{"class":445},[166,915,916],{"class":176}," 30d",[166,918,919],{"class":445}," --format",[166,921,922],{"class":176}," json\n",[17,924,926],{"id":925},"sso-integration-business","SSO integration (Business)",[10,928,929],{},"For larger teams, managing tokens by hand doesn't scale. SSO via SAML or OIDC integrates with your existing identity provider:",[157,931,933],{"className":208,"code":932,"language":210,"meta":162,"style":162},"sso:\n  type: oidc\n  issuer: https:\u002F\u002Fidp.empresa.com.br\n  client_id: heroctl-prod\n  client_secret: ${secret.oidc_client_secret}\n  group_to_role:\n    \"engineering-prod\": operator\n    \"engineering-dev\": deployer\n    \"sre\": admin\n    \"*\": viewer\n",[89,934,935,942,952,962,972,982,989,999,1009,1019],{"__ignoreMap":162},[166,936,937,940],{"class":168,"line":169},[166,938,939],{"class":223},"sso",[166,941,258],{"class":227},[166,943,944,947,949],{"class":168,"line":186},[166,945,946],{"class":223},"  type",[166,948,228],{"class":227},[166,950,951],{"class":176},"oidc\n",[166,953,954,957,959],{"class":168,"line":234},[166,955,956],{"class":223},"  issuer",[166,958,228],{"class":227},[166,960,961],{"class":176},"https:\u002F\u002Fidp.empresa.com.br\n",[166,963,964,967,969],{"class":168,"line":245},[166,965,966],{"class":223},"  client_id",[166,968,228],{"class":227},[166,970,971],{"class":176},"heroctl-prod\n",[166,973,974,977,979],{"class":168,"line":252},[166,975,976],{"class":223},"  client_secret",[166,978,228],{"class":227},[166,980,981],{"class":176},"${secret.oidc_client_secret}\n",[166,983,984,987],{"class":168,"line":261},[166,985,986],{"class":223},"  group_to_role",[166,988,258],{"class":227},[166,990,991,994,996],{"class":168,"line":275},[166,992,993],{"class":176},"    \"engineering-prod\"",[166,995,228],{"class":227},[166,997,998],{"class":176},"operator\n",[166,1000,1001,1004,1006],{"class":168,"line":286},[166,1002,1003],{"class":176},"    \"engineering-dev\"",[166,1005,228],{"class":227},[166,1007,1008],{"class":176},"deployer\n",[166,1010,1011,1014,1016],{"class":168,"line":317},[166,1012,1013],{"class":176},"    \"sre\"",[166,1015,228],{"class":227},[166,1017,1018],{"class":176},"admin\n",[166,1020,1021,1024,1026],{"class":168,"line":322},[166,1022,1023],{"class":176},"    \"*\"",[166,1025,228],{"class":227},[166,1027,1028],{"class":176},"viewer\n",[10,1030,1031],{},"Users authenticate through the web panel and automatically receive the set of roles corresponding to their IdP groups. When they leave the company, they are deprovisioned in the IdP, and access to the cluster ends with it.",[10,1033,1034],{},"For CLI, OIDC device flow:",[157,1036,1038],{"className":159,"code":1037,"language":161,"meta":162,"style":162},"heroctl auth login\n# abre navegador, completa autenticação no IdP, volta para o terminal\n",[89,1039,1040,1050],{"__ignoreMap":162},[166,1041,1042,1044,1047],{"class":168,"line":169},[166,1043,173],{"class":172},[166,1045,1046],{"class":176}," auth",[166,1048,1049],{"class":176}," login\n",[166,1051,1052],{"class":168,"line":186},[166,1053,1054],{"class":217},"# abre navegador, completa autenticação no IdP, volta para o terminal\n",[17,1056,1058],{"id":1057},"best-practices","Best practices",[1060,1061,1062,1068,1074,1080,1086,1092,1098],"ol",{},[488,1063,1064,1067],{},[46,1065,1066],{},"Least privilege."," Start by denying everything, open exactly what's needed. It's easier to loosen later than to tighten.",[488,1069,1070,1073],{},[46,1071,1072],{},"No shared tokens."," Each person, each service, each pipeline has their own. Audit only works if identity is unique.",[488,1075,1076,1079],{},[46,1077,1078],{},"Quarterly rotation."," Long-lived tokens cycle on a predictable schedule. Mark it on the calendar.",[488,1081,1082,1085],{},[46,1083,1084],{},"Monthly audit review."," Thirty minutes a month looking at the log. Strange patterns show up if you look.",[488,1087,1088,1091],{},[46,1089,1090],{},"Documented break-glass."," Have an emergency admin token, with long expiration, kept out of band (physical safe, password manager with dedicated 2FA). Use it once a year, at most.",[488,1093,1094,1097],{},[46,1095,1096],{},"Onboarding and offboarding by checklist."," When someone joins: create tokens, assign roles. When they leave: revoke. Don't trust memory.",[488,1099,1100,1103],{},[46,1101,1102],{},"CI tokens with no external credentials."," Use the CI provider's OIDC directly against the cluster, with no static secret. Reduces leak surface.",[17,1105,1107],{"id":1106},"next-steps","Next steps",[485,1109,1110,1119],{},[488,1111,1112,1113,1118],{},"Review the ",[1114,1115,1117],"a",{"href":1116},"\u002Fen\u002Fdocs\u002Fsecurity\u002Fsecrets","secrets"," configuration, which has its own permission model.",[488,1120,1121,1122,1126],{},"See ",[1114,1123,1125],{"href":1124},"\u002Fen\u002Fdocs\u002Fobservability\u002Fmetrics-logs","metrics and logs"," to correlate audit events with cluster behavior.",[1128,1129,1130],"style",{},"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 .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 .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}",{"title":162,"searchDepth":186,"depth":186,"links":1132},[1133,1134,1135,1136,1139,1140,1141,1142,1143],{"id":19,"depth":186,"text":20},{"id":95,"depth":186,"text":96},{"id":201,"depth":186,"text":202},{"id":542,"depth":186,"text":543,"children":1137},[1138],{"id":669,"depth":234,"text":670},{"id":725,"depth":186,"text":726},{"id":800,"depth":186,"text":801},{"id":925,"depth":186,"text":926},{"id":1057,"depth":186,"text":1058},{"id":1106,"depth":186,"text":1107},"seguranca","Role, policy, and token model to limit who can submit, read, and operate the cluster.",false,"md","i-lucide-users","2026-04-26",{},"\u002Fen\u002Fdocs\u002Fsecurity\u002Frbac",[],"7 min read",{"title":5,"description":1145},"en\u002Fdocs\u002Fsecurity\u002Frbac",[1157,1158,1159,939,1160,1161],"rbac","acl","tokens","audit","business","G7q4VBMEVhnzOJ5TC0CjNd5yKTpYXibCj40hv5Btq7s",[1164,1170,1176,1181,1187,1192,1198,1202,1208,1213,1218,1222,1223,1227],{"path":1165,"title":1166,"description":1167,"category":1168,"order":169,"icon":1169},"\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":1171,"title":1172,"description":1173,"category":1174,"order":169,"icon":1175},"\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":1177,"title":1178,"description":1179,"category":1174,"order":186,"icon":1180},"\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":1182,"title":1183,"description":1184,"category":1185,"order":186,"icon":1186},"\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":1188,"title":1189,"description":1190,"category":1185,"order":169,"icon":1191},"\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":1193,"title":1194,"description":1195,"category":1196,"order":186,"icon":1197},"\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":1124,"title":1199,"description":1200,"category":1196,"order":169,"icon":1201},"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":1203,"title":1204,"description":1205,"category":1206,"order":234,"icon":1207},"\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":1209,"title":1210,"description":1211,"category":1206,"order":186,"icon":1212},"\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":1214,"title":1215,"description":1216,"category":1206,"order":169,"icon":1217},"\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":1219,"title":1220,"description":1221,"category":1206,"order":245,"icon":1191},"\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":1151,"title":5,"description":1145,"category":1144,"order":186,"icon":1148},{"path":1116,"title":1224,"description":1225,"category":1144,"order":169,"icon":1226},"Secret management","How to keep passwords, tokens, and keys outside the job spec, with encryption at rest and versioned rotation.","i-lucide-key",{"path":1228,"title":1229,"description":1230,"category":1231,"order":169,"icon":1232},"\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",1777362181771]