[{"data":1,"prerenderedAt":1484},["ShallowReactive",2],{"docs-nav":3,"docs:\u002Fdocs\u002Fremote-access":139},[4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136],{"path":5,"title":6},"\u002Fdocs\u002Faccess-gating","Protect a local route",{"path":8,"title":9},"\u002Fdocs\u002Farchitecture\u002Fsecurity-and-trust","Security and trust",{"path":11,"title":12},"\u002Fdocs\u002Fconcepts\u002Fbuilds-and-deployments","Build and deploy",{"path":14,"title":15},"\u002Fdocs\u002Fconcepts\u002Fconfiguration-ownership","Where configuration belongs",{"path":17,"title":18},"\u002Fdocs\u002Fconcepts\u002Fenvironments-and-secrets","Environment values and secrets",{"path":20,"title":21},"\u002Fdocs\u002Fconcepts\u002Fmental-model","How projects fit together",{"path":23,"title":24},"\u002Fdocs\u002Fconcepts\u002Fplans-and-apply","Plans and apply",{"path":26,"title":27},"\u002Fdocs\u002Fconcepts\u002Ftargets-and-runtimes","Choose a target and runtime",{"path":29,"title":30},"\u002Fdocs\u002Fcontribute\u002Freleases","Publish a release",{"path":32,"title":33},"\u002Fdocs\u002Fdevelopment-mounts","Development mounts",{"path":35,"title":36},"\u002Fdocs\u002Fgetting-started","Getting started",{"path":38,"title":39},"\u002Fdocs\u002Fhelp\u002Ffaq","FAQ",{"path":41,"title":42},"\u002Fdocs\u002Fhelp\u002Ftroubleshooting","Troubleshooting",{"path":44,"title":45},"\u002Fdocs\u002Fhow-to\u002Fdeploy-production","Prepare a deployment environment",{"path":47,"title":48},"\u002Fdocs\u002Fhow-to\u002Fswarm-cluster","Run on a multi-node Swarm",{"path":50,"title":51},"\u002Fdocs","mm documentation",{"path":53,"title":54},"\u002Fdocs\u002Fjobs-and-schedules","Jobs and schedules",{"path":56,"title":57},"\u002Fdocs\u002Flocal-dashboard","Local dashboard",{"path":59,"title":60},"\u002Fdocs\u002Flocal-https","Local HTTPS",{"path":62,"title":63},"\u002Fdocs\u002Flocal-services","Local services",{"path":65,"title":66},"\u002Fdocs\u002Fmcp","Let an AI agent work on your project",{"path":68,"title":69},"\u002Fdocs\u002Fmulti-project-hosts","Run multiple projects on one host",{"path":71,"title":72},"\u002Fdocs\u002Fonboarding","Set up a project",{"path":74,"title":75},"\u002Fdocs\u002Fopenbao","Use OpenBao",{"path":77,"title":78},"\u002Fdocs\u002Fproject\u002Fcontributing","Contributing",{"path":80,"title":81},"\u002Fdocs\u002Fproject\u002Flicense","License",{"path":83,"title":84},"\u002Fdocs\u002Fproject\u002Fsecurity","Security",{"path":86,"title":87},"\u002Fdocs\u002Freference\u002Fcapability-matrix","Supported features and platforms",{"path":89,"title":90},"\u002Fdocs\u002Freference\u002Fcli","CLI command reference",{"path":92,"title":93},"\u002Fdocs\u002Freference\u002Fconfiguration","Configuration",{"path":95,"title":96},"\u002Fdocs\u002Freference\u002Fenvironment-variables","Environment variables",{"path":98,"title":99},"\u002Fdocs\u002Freference\u002Ferrors-and-exit-codes","Errors and exit codes",{"path":101,"title":102},"\u002Fdocs\u002Freference\u002Fknown-issues","Known limitations",{"path":104,"title":105},"\u002Fdocs\u002Fremote-access","Manage remote access",{"path":107,"title":108},"\u002Fdocs\u002Fremote-daemon","Set up a remote host",{"path":110,"title":111},"\u002Fdocs\u002Fruntime-observability","Status, logs, and commands",{"path":113,"title":114},"\u002Fdocs\u002Fsecret-delivery","Pass secrets to your app",{"path":116,"title":117},"\u002Fdocs\u002Fsecret-providers","Choose a secret store",{"path":119,"title":120},"\u002Fdocs\u002Fstart\u002Finstall","Install mm",{"path":122,"title":123},"\u002Fdocs\u002Fterminal-ui","Terminal UI",{"path":125,"title":126},"\u002Fdocs\u002Ftutorials\u002Fdotnet-web-api",".NET web API example",{"path":128,"title":129},"\u002Fdocs\u002Ftutorials\u002Ffirst-local-app","First local app",{"path":131,"title":132},"\u002Fdocs\u002Ftutorials\u002Flaravel-rust","Laravel and Rust example",{"path":134,"title":135},"\u002Fdocs\u002Ftutorials\u002Fnode-fullstack","Node full stack example",{"path":137,"title":138},"\u002Fdocs\u002Fvault","Use HashiCorp Vault",{"id":140,"title":105,"body":141,"description":1477,"extension":1478,"meta":1479,"navigation":1480,"path":104,"seo":1481,"stem":1482,"__hash__":1483},"docs\u002Fdocs\u002Fremote-access.md",{"type":142,"value":143,"toc":1466},"minimark",[144,153,162,167,239,266,507,510,558,571,575,578,635,641,712,743,769,772,776,827,833,852,859,874,878,881,889,898,937,940,947,951,956,999,1005,1023,1060,1066,1070,1080,1139,1157,1167,1170,1245,1248,1252,1305,1323,1329,1384,1388,1395,1398,1426,1437,1448,1452,1462],[145,146,147,148,152],"p",{},"Access to remote environments lives in the repo, in the ",[149,150,151],"code",{},"users:"," key. Each user\nlists their public keys and a level per environment. A change to access is an\nordinary commit, reviewed like any other. The host applies it to an environment\nwhen that environment is deployed or synced.",[145,154,155,156,161],{},"Complete ",[157,158,160],"a",{"href":159},".\u002Fremote-daemon","remote host setup"," first.",[163,164,166],"h2",{"id":165},"levels","Levels",[168,169,170,183],"table",{},[171,172,173],"thead",{},[174,175,176,180],"tr",{},[177,178,179],"th",{},"Level",[177,181,182],{},"Allows",[184,185,186,200,212,227],"tbody",{},[174,187,188,194],{},[189,190,191],"td",{},[149,192,193],{},"view",[189,195,196,197],{},"plan, status, inspect, logs, and ",[149,198,199],{},"mm target swarm nodes",[174,201,202,207],{},[189,203,204],{},[149,205,206],{},"operate",[189,208,209,211],{},[149,210,193],{}," plus restart and job run, cancel, and retry",[174,213,214,219],{},[189,215,216],{},[149,217,218],{},"deploy",[189,220,221,223,224],{},[149,222,206],{}," plus deploy and ",[149,225,226],{},"mm team sync",[174,228,229,234],{},[189,230,231],{},[149,232,233],{},"admin",[189,235,236,238],{},[149,237,218],{}," plus exec, forward, secrets, blocks, audit, and Swarm groups, storage, and ingress",[145,240,241,242,245,246,249,250,253,254,257,258,261,262,265],{},"Add-ons grant more without raising the level: ",[149,243,244],{},"exec"," and ",[149,247,248],{},"forward"," take ",[149,251,252],{},"true","\nor a list of services, and ",[149,255,256],{},"secrets: true"," allows secret metadata and changes.\nThe host's ",[149,259,260],{},"ceiling"," in ",[149,263,264],{},"host.yaml"," caps all of these per environment.",[267,268,273],"pre",{"className":269,"code":270,"language":271,"meta":272,"style":272},"language-yaml shiki shiki-themes mm","users:\n  alice:\n    keys:\n      - ssh-ed25519 AAAAC3Nza… mm:alice@laptop\n    access:\n      staging: deploy\n      production: view\n  bob:\n    keys:\n      - key: sk-ssh-ed25519@openssh.com AAAAGnNr… mm:bob@yubikey\n        expires: 2027-01-31\n    access:\n      \"*\": operate # every environment\n      production: { level: deploy, exec: [api] }\n  ci:\n    machine: true\n    keys: [ssh-ed25519 AAAA… ci@github]\n    access: { staging: deploy, production: deploy }\n","yaml","",[149,274,275,288,296,304,314,322,334,345,353,360,373,385,392,407,445,453,465,480],{"__ignoreMap":272},[276,277,280,284],"span",{"class":278,"line":279},"line",1,[276,281,283],{"class":282},"sWZmh","users",[276,285,287],{"class":286},"sIbZ0",":\n",[276,289,291,294],{"class":278,"line":290},2,[276,292,293],{"class":282},"  alice",[276,295,287],{"class":286},[276,297,299,302],{"class":278,"line":298},3,[276,300,301],{"class":282},"    keys",[276,303,287],{"class":286},[276,305,307,310],{"class":278,"line":306},4,[276,308,309],{"class":286},"      -",[276,311,313],{"class":312},"sv8ni"," ssh-ed25519 AAAAC3Nza… mm:alice@laptop\n",[276,315,317,320],{"class":278,"line":316},5,[276,318,319],{"class":282},"    access",[276,321,287],{"class":286},[276,323,325,328,331],{"class":278,"line":324},6,[276,326,327],{"class":282},"      staging",[276,329,330],{"class":286},":",[276,332,333],{"class":312}," deploy\n",[276,335,337,340,342],{"class":278,"line":336},7,[276,338,339],{"class":282},"      production",[276,341,330],{"class":286},[276,343,344],{"class":312}," view\n",[276,346,348,351],{"class":278,"line":347},8,[276,349,350],{"class":282},"  bob",[276,352,287],{"class":286},[276,354,356,358],{"class":278,"line":355},9,[276,357,301],{"class":282},[276,359,287],{"class":286},[276,361,363,365,368,370],{"class":278,"line":362},10,[276,364,309],{"class":286},[276,366,367],{"class":282}," key",[276,369,330],{"class":286},[276,371,372],{"class":312}," sk-ssh-ed25519@openssh.com AAAAGnNr… mm:bob@yubikey\n",[276,374,376,379,381],{"class":278,"line":375},11,[276,377,378],{"class":282},"        expires",[276,380,330],{"class":286},[276,382,384],{"class":383},"sN9xe"," 2027-01-31\n",[276,386,388,390],{"class":278,"line":387},12,[276,389,319],{"class":282},[276,391,287],{"class":286},[276,393,395,398,400,403],{"class":278,"line":394},13,[276,396,397],{"class":312},"      \"*\"",[276,399,330],{"class":286},[276,401,402],{"class":312}," operate",[276,404,406],{"class":405},"sP7nD"," # every environment\n",[276,408,410,412,414,417,420,422,425,428,431,433,436,439,442],{"class":278,"line":409},14,[276,411,339],{"class":282},[276,413,330],{"class":286},[276,415,416],{"class":286}," {",[276,418,419],{"class":282}," level",[276,421,330],{"class":286},[276,423,424],{"class":312}," deploy",[276,426,427],{"class":286},",",[276,429,430],{"class":282}," exec",[276,432,330],{"class":286},[276,434,435],{"class":286}," [",[276,437,438],{"class":312},"api",[276,440,441],{"class":286},"]",[276,443,444],{"class":286}," }\n",[276,446,448,451],{"class":278,"line":447},15,[276,449,450],{"class":282},"  ci",[276,452,287],{"class":286},[276,454,456,459,461],{"class":278,"line":455},16,[276,457,458],{"class":282},"    machine",[276,460,330],{"class":286},[276,462,464],{"class":463},"s1Wbj"," true\n",[276,466,468,470,472,474,477],{"class":278,"line":467},17,[276,469,301],{"class":282},[276,471,330],{"class":286},[276,473,435],{"class":286},[276,475,476],{"class":312},"ssh-ed25519 AAAA… ci@github",[276,478,479],{"class":286},"]\n",[276,481,483,485,487,489,492,494,496,498,501,503,505],{"class":278,"line":482},18,[276,484,319],{"class":282},[276,486,330],{"class":286},[276,488,416],{"class":286},[276,490,491],{"class":282}," staging",[276,493,330],{"class":286},[276,495,424],{"class":312},[276,497,427],{"class":286},[276,499,500],{"class":282}," production",[276,502,330],{"class":286},[276,504,424],{"class":312},[276,506,444],{"class":286},[145,508,509],{},"Rules:",[511,512,513,529,536,542],"ul",{},[514,515,516,517,520,521,524,525,528],"li",{},"User names match ",[149,518,519],{},"[a-z][a-z0-9-]*",". Keys are ",[149,522,523],{},"ssh-ed25519"," or\n",[149,526,527],{},"sk-ssh-ed25519@openssh.com","; RSA and ECDSA are rejected.",[514,530,531,532,535],{},"A key belongs to one user. An environment's own entry overrides ",[149,533,534],{},"*",".",[514,537,538,541],{},[149,539,540],{},"mm config validate"," checks the users file, and the host checks it again.",[514,543,544,547,548,550,551,554,555,535],{},[149,545,546],{},"mm.overrides.yaml"," cannot set ",[149,549,283],{},", ",[149,552,553],{},"agents",", or ",[149,556,557],{},"deploy-from",[145,559,560,561,564,565,261,568,535],{},"To give access its own reviewers, move it to its own file with\n",[149,562,563],{},"mm config split users"," and list ",[149,566,567],{},".config\u002Fmm\u002Fusers.yaml",[149,569,570],{},"CODEOWNERS",[163,572,574],{"id":573},"agent-keys","Agent keys",[145,576,577],{},"An AI agent reaches a remote environment with its own key, never yours. Create\nit and add it to your entry:",[267,579,583],{"className":580,"code":581,"language":582,"meta":272,"style":272},"language-sh shiki shiki-themes mm","mm key create --agent\nmm team join --agent                    # reviewed edit of the users file\nmm team join --agent --plan PLAN_HASH --yes\n","sh",[149,584,585,600,616],{"__ignoreMap":272},[276,586,587,591,593,596],{"class":278,"line":279},[276,588,590],{"class":589},"svrjQ","mm",[276,592,367],{"class":312},[276,594,595],{"class":312}," create",[276,597,599],{"class":598},"sbRf1"," --agent\n",[276,601,602,604,607,610,613],{"class":278,"line":290},[276,603,590],{"class":589},[276,605,606],{"class":312}," team",[276,608,609],{"class":312}," join",[276,611,612],{"class":598}," --agent",[276,614,615],{"class":405},"                    # reviewed edit of the users file\n",[276,617,618,620,622,624,626,629,632],{"class":278,"line":298},[276,619,590],{"class":589},[276,621,606],{"class":312},[276,623,609],{"class":312},[276,625,612],{"class":598},[276,627,628],{"class":598}," --plan",[276,630,631],{"class":312}," PLAN_HASH",[276,633,634],{"class":598}," --yes\n",[145,636,637,638,330],{},"The entry gains a key marked ",[149,639,640],{},"agent: true",[267,642,644],{"className":269,"code":643,"language":271,"meta":272,"style":272},"users:\n  alice:\n    keys:\n      - ssh-ed25519 AAAAC3Nza… mm:alice@laptop\n      - key: ssh-ed25519 AAAAC3Nza… mm-agent:alice@laptop\n        agent: true\n    access:\n      staging: deploy\n      production: view\n",[149,645,646,652,658,664,670,681,690,696,704],{"__ignoreMap":272},[276,647,648,650],{"class":278,"line":279},[276,649,283],{"class":282},[276,651,287],{"class":286},[276,653,654,656],{"class":278,"line":290},[276,655,293],{"class":282},[276,657,287],{"class":286},[276,659,660,662],{"class":278,"line":298},[276,661,301],{"class":282},[276,663,287],{"class":286},[276,665,666,668],{"class":278,"line":306},[276,667,309],{"class":286},[276,669,313],{"class":312},[276,671,672,674,676,678],{"class":278,"line":316},[276,673,309],{"class":286},[276,675,367],{"class":282},[276,677,330],{"class":286},[276,679,680],{"class":312}," ssh-ed25519 AAAAC3Nza… mm-agent:alice@laptop\n",[276,682,683,686,688],{"class":278,"line":324},[276,684,685],{"class":282},"        agent",[276,687,330],{"class":286},[276,689,464],{"class":463},[276,691,692,694],{"class":278,"line":336},[276,693,319],{"class":282},[276,695,287],{"class":286},[276,697,698,700,702],{"class":278,"line":347},[276,699,327],{"class":282},[276,701,330],{"class":286},[276,703,333],{"class":312},[276,705,706,708,710],{"class":278,"line":355},[276,707,339],{"class":282},[276,709,330],{"class":286},[276,711,344],{"class":312},[145,713,714,715,722,723,725,726,550,728,730,731,734,735,737,738,740,741,535],{},"The host gives an agent key your access limited by the\n",[157,716,718,721],{"href":717},".\u002Fmcp#set-what-agents-may-do",[149,719,720],{},"agents:"," block"," of the deployed commit, and\nby the host's ",[149,724,260],{},". An agent key never gets ",[149,727,233],{},[149,729,248],{},", or\n",[149,732,733],{},"secrets",", and it gets ",[149,736,244],{}," only for services that both you and the block\nallow. Without an ",[149,739,720],{}," entry for the environment it gets ",[149,742,193],{},[511,744,745,756,763],{},[514,746,747,748,751,752,755],{},"The agent appears as ",[149,749,750],{},"alice (agent)"," in plans, ",[149,753,754],{},"mm team whoami",", and the\naudit log.",[514,757,758,759,762],{},"A user needs a key of their own to have an agent key, and a ",[149,760,761],{},"machine"," user\ncannot have one. When your own keys expire or are removed, your agent's\naccess ends too.",[514,764,765,768],{},[149,766,767],{},"mmd access block"," works on an agent key's fingerprint and leaves your own\nkey working.",[145,770,771],{},"An agent key is a plain key file, because an agent cannot touch a security\nkey. Keep your own key on a security key, or otherwise out of the agent's\nreach: the host can only tell an agent from you by the key it presents.",[163,773,775],{"id":774},"join-a-team","Join a team",[267,777,779],{"className":580,"code":778,"language":582,"meta":272,"style":272},"mm key create                                  # once per device\nmm team join --request staging=deploy          # reviewed edit of the users file\nmm team join --request staging=deploy --plan PLAN_HASH --yes\n",[149,780,781,792,809],{"__ignoreMap":272},[276,782,783,785,787,789],{"class":278,"line":279},[276,784,590],{"class":589},[276,786,367],{"class":312},[276,788,595],{"class":312},[276,790,791],{"class":405},"                                  # once per device\n",[276,793,794,796,798,800,803,806],{"class":278,"line":290},[276,795,590],{"class":589},[276,797,606],{"class":312},[276,799,609],{"class":312},[276,801,802],{"class":598}," --request",[276,804,805],{"class":312}," staging=deploy",[276,807,808],{"class":405},"          # reviewed edit of the users file\n",[276,810,811,813,815,817,819,821,823,825],{"class":278,"line":298},[276,812,590],{"class":589},[276,814,606],{"class":312},[276,816,609],{"class":312},[276,818,802],{"class":598},[276,820,805],{"class":312},[276,822,628],{"class":598},[276,824,631],{"class":312},[276,826,634],{"class":598},[145,828,829,830,832],{},"Commit the change and open a pull request. Once it is merged, an admin deploys\nor runs ",[149,831,226],{}," for each environment. Then check:",[267,834,836],{"className":580,"code":835,"language":582,"meta":272,"style":272},"mm --environment staging team whoami\n",[149,837,838],{"__ignoreMap":272},[276,839,840,842,845,847,849],{"class":278,"line":279},[276,841,590],{"class":589},[276,843,844],{"class":598}," --environment",[276,846,491],{"class":312},[276,848,606],{"class":312},[276,850,851],{"class":312}," whoami\n",[145,853,854,855,858],{},"Expected result: your name, key fingerprint, level, and the commit whose users\nfile the environment enforces. ",[149,856,857],{},"mm key create --security-key"," uses a FIDO2\nsecurity key instead of a key file.",[145,860,861,862,865,866,869,870,873],{},"To add someone else, or a CI key: ",[149,863,864],{},"mm team add NAME --key 'ssh-ed25519 AAAA…' --access staging=deploy",", with ",[149,867,868],{},"--machine"," for automation. ",[149,871,872],{},"mm team show","\nlists everyone in the users file.",[163,875,877],{"id":876},"apply-access-changes","Apply access changes",[145,879,880],{},"Deploying an environment applies the users file of the deployed commit to that\nenvironment first, then deploys. The plan shows the access change:",[267,882,887],{"className":883,"code":885,"language":886,"meta":272},[884],"language-text","  access changes in staging:\n    carol: none -> deploy, +1 key(s)\n","text",[149,888,885],{"__ignoreMap":272},[145,890,891,892,894,895,897],{},"To change access without deploying, use ",[149,893,226],{}," (needs ",[149,896,218],{},"):",[267,899,901],{"className":580,"code":900,"language":582,"meta":272,"style":272},"mm --environment production team sync                       # plans from HEAD\nmm --environment production team sync --plan PLAN_HASH --yes\n",[149,902,903,919],{"__ignoreMap":272},[276,904,905,907,909,911,913,916],{"class":278,"line":279},[276,906,590],{"class":589},[276,908,844],{"class":598},[276,910,500],{"class":312},[276,912,606],{"class":312},[276,914,915],{"class":312}," sync",[276,917,918],{"class":405},"                       # plans from HEAD\n",[276,920,921,923,925,927,929,931,933,935],{"class":278,"line":290},[276,922,590],{"class":589},[276,924,844],{"class":598},[276,926,500],{"class":312},[276,928,606],{"class":312},[276,930,915],{"class":312},[276,932,628],{"class":598},[276,934,631],{"class":312},[276,936,634],{"class":598},[145,938,939],{},"Each environment is reconciled on its own: syncing staging never changes\nproduction.",[145,941,942,943,535],{},"On a Swarm, the change reaches the other managers too, and the command waits\nfor them to confirm. See\n",[157,944,946],{"href":945},".\u002Fhow-to\u002Fswarm-cluster#access-on-every-manager","access on every manager",[163,948,950],{"id":949},"control-which-commits-deploy","Control which commits deploy",[145,952,953,955],{},[149,954,557],{}," limits an environment to commits on certain branches:",[267,957,959],{"className":269,"code":958,"language":271,"meta":272,"style":272},"environments:\n  production:\n    target: prod-eu\n    deploy-from: [main]\n",[149,960,961,968,975,985],{"__ignoreMap":272},[276,962,963,966],{"class":278,"line":279},[276,964,965],{"class":282},"environments",[276,967,287],{"class":286},[276,969,970,973],{"class":278,"line":290},[276,971,972],{"class":282},"  production",[276,974,287],{"class":286},[276,976,977,980,982],{"class":278,"line":298},[276,978,979],{"class":282},"    target",[276,981,330],{"class":286},[276,983,984],{"class":312}," prod-eu\n",[276,986,987,990,992,994,997],{"class":278,"line":306},[276,988,989],{"class":282},"    deploy-from",[276,991,330],{"class":286},[276,993,435],{"class":286},[276,995,996],{"class":312},"main",[276,998,479],{"class":286},[145,1000,1001,1002,1004],{},"A commit must be on one of the listed branches of the origin, and a commit\nthat changes ",[149,1003,557],{}," must pass the list in force.",[145,1006,1007,1008,1010,1011,1014,1015,1018,1019,1022],{},"An entry can also be a pattern: ",[149,1009,534],{}," matches any characters within one ",[149,1012,1013],{},"\u002F","\nsegment and ",[149,1016,1017],{},"?"," matches one character. ",[149,1020,1021],{},"\"*\""," on its own allows any branch.\nFor release branches with hotfixes:",[267,1024,1026],{"className":269,"code":1025,"language":271,"meta":272,"style":272},"environments:\n  production:\n    deploy-from: [main, \"*.x\"] # main, 26.6.x, 26.7.x, …\n",[149,1027,1028,1034,1040],{"__ignoreMap":272},[276,1029,1030,1032],{"class":278,"line":279},[276,1031,965],{"class":282},[276,1033,287],{"class":286},[276,1035,1036,1038],{"class":278,"line":290},[276,1037,972],{"class":282},[276,1039,287],{"class":286},[276,1041,1042,1044,1046,1048,1050,1052,1055,1057],{"class":278,"line":298},[276,1043,989],{"class":282},[276,1045,330],{"class":286},[276,1047,435],{"class":286},[276,1049,996],{"class":312},[276,1051,427],{"class":286},[276,1053,1054],{"class":312}," \"*.x\"",[276,1056,441],{"class":286},[276,1058,1059],{"class":405}," # main, 26.6.x, 26.7.x, …\n",[145,1061,1062,1063,1065],{},"Without ",[149,1064,557],{},", any commit on the origin may be deployed. Use branch\nprotection on the git host, because whatever reaches an allowed branch is\ntrusted.",[163,1067,1069],{"id":1068},"forward-a-remote-port","Forward a remote port",[145,1071,1072,1073,1076,1077,1079],{},"To reach a remote database or admin port from your machine, forward it to\n",[149,1074,1075],{},"localhost",". You need the ",[149,1078,248],{}," add-on for that service.",[267,1081,1083],{"className":580,"code":1082,"language":582,"meta":272,"style":272},"mm --environment production forward postgres                  # localhost:5432\nmm --environment production forward postgres:5432 --local 15432\nmm --environment production forward postgres redis            # several at once\n",[149,1084,1085,1102,1121],{"__ignoreMap":272},[276,1086,1087,1089,1091,1093,1096,1099],{"class":278,"line":279},[276,1088,590],{"class":589},[276,1090,844],{"class":598},[276,1092,500],{"class":312},[276,1094,1095],{"class":312}," forward",[276,1097,1098],{"class":312}," postgres",[276,1100,1101],{"class":405},"                  # localhost:5432\n",[276,1103,1104,1106,1108,1110,1112,1115,1118],{"class":278,"line":290},[276,1105,590],{"class":589},[276,1107,844],{"class":598},[276,1109,500],{"class":312},[276,1111,1095],{"class":312},[276,1113,1114],{"class":312}," postgres:5432",[276,1116,1117],{"class":598}," --local",[276,1119,1120],{"class":463}," 15432\n",[276,1122,1123,1125,1127,1129,1131,1133,1136],{"class":278,"line":298},[276,1124,590],{"class":589},[276,1126,844],{"class":598},[276,1128,500],{"class":312},[276,1130,1095],{"class":312},[276,1132,1098],{"class":312},[276,1134,1135],{"class":312}," redis",[276,1137,1138],{"class":405},"            # several at once\n",[145,1140,1141,1142,1145,1146,1149,1150,524,1153,1156],{},"Expected result: ",[149,1143,1144],{},"Forwarding 127.0.0.1:5432 -> production\u002Fpostgres:5432",". Point\nyour client at the local port; Ctrl-C stops every forward. Without a port, mm\nuses the service's ",[149,1147,1148],{},"http-port",", or the container side of its Compose ",[149,1151,1152],{},"ports",[149,1154,1155],{},"expose",". If the local port is busy, mm picks a free one and prints it.",[145,1158,1159,1160,1163,1164,535],{},"Each connection travels through the mm protocol to that service's container.\nThe host never opens SSH forwarding, and mm never connects to host ports or\nother machines. Forwards listen on ",[149,1161,1162],{},"127.0.0.1"," unless you pass ",[149,1165,1166],{},"--bind",[145,1168,1169],{},"Save forwards you use often. Saved forwards are private to your machine:",[267,1171,1173],{"className":580,"code":1172,"language":582,"meta":272,"style":272},"mm --environment production forward save prod-db postgres --local 15432 --auto\nmm forward prod-db            # run one by name\nmm forward up                 # start every forward saved with --auto\nmm forward list\nmm forward remove prod-db\n",[149,1174,1175,1201,1212,1224,1233],{"__ignoreMap":272},[276,1176,1177,1179,1181,1183,1185,1188,1191,1193,1195,1198],{"class":278,"line":279},[276,1178,590],{"class":589},[276,1180,844],{"class":598},[276,1182,500],{"class":312},[276,1184,1095],{"class":312},[276,1186,1187],{"class":312}," save",[276,1189,1190],{"class":312}," prod-db",[276,1192,1098],{"class":312},[276,1194,1117],{"class":598},[276,1196,1197],{"class":463}," 15432",[276,1199,1200],{"class":598}," --auto\n",[276,1202,1203,1205,1207,1209],{"class":278,"line":290},[276,1204,590],{"class":589},[276,1206,1095],{"class":312},[276,1208,1190],{"class":312},[276,1210,1211],{"class":405},"            # run one by name\n",[276,1213,1214,1216,1218,1221],{"class":278,"line":298},[276,1215,590],{"class":589},[276,1217,1095],{"class":312},[276,1219,1220],{"class":312}," up",[276,1222,1223],{"class":405},"                 # start every forward saved with --auto\n",[276,1225,1226,1228,1230],{"class":278,"line":306},[276,1227,590],{"class":589},[276,1229,1095],{"class":312},[276,1231,1232],{"class":312}," list\n",[276,1234,1235,1237,1239,1242],{"class":278,"line":316},[276,1236,590],{"class":589},[276,1238,1095],{"class":312},[276,1240,1241],{"class":312}," remove",[276,1243,1244],{"class":312}," prod-db\n",[145,1246,1247],{},"Forwarding needs a rootful Docker or Podman host for now; rootless runtimes\nreport that the container is not reachable.",[163,1249,1251],{"id":1250},"what-a-deploy-may-run","What a deploy may run",[145,1253,1254,1255,1258,1259,550,1262,1265,1266,550,1269,550,1272,550,1275,1278,1279,1282,1283,1286,1287,1290,1291,1294,1295,1013,1298,1300,1301,1304],{},"Trusting the repo means trusting it inside the host's limits. A remote host\nrefuses Compose features that would reach the host itself: ",[149,1256,1257],{},"privileged",",\ncapabilities beyond Docker's defaults, devices, host namespaces (",[149,1260,1261],{},"pid",[149,1263,1264],{},"ipc",",\n",[149,1267,1268],{},"uts",[149,1270,1271],{},"userns_mode",[149,1273,1274],{},"cgroup",[149,1276,1277],{},"network_mode: host","), ",[149,1280,1281],{},"cgroup_parent",",\nunconfined ",[149,1284,1285],{},"security_opt",", non-",[149,1288,1289],{},"net.*"," sysctls, bind or device ",[149,1292,1293],{},"driver_opts","\nvolumes, external volumes and networks, ",[149,1296,1297],{},"configs",[149,1299,733],{}," files outside the\nproject, and ",[149,1302,1303],{},"build:"," (remote hosts never build). Check before you push:",[267,1306,1308],{"className":580,"code":1307,"language":582,"meta":272,"style":272},"mm config validate --for-remote\n",[149,1309,1310],{"__ignoreMap":272},[276,1311,1312,1314,1317,1320],{"class":278,"line":279},[276,1313,590],{"class":589},[276,1315,1316],{"class":312}," config",[276,1318,1319],{"class":312}," validate",[276,1321,1322],{"class":598}," --for-remote\n",[145,1324,1325,1326,330],{},"Only a host admin can make an exception, for one feature of one service, in\n",[149,1327,1328],{},"\u002Fetc\u002Fmm\u002Fhost.yaml",[267,1330,1332],{"className":269,"code":1331,"language":271,"meta":272,"style":272},"projects:\n  019c527b-6242-7b43-bfd4-bd60e27c1de3:\n    allow:\n      - service: monitoring\u002Fnode-exporter # \u003Cstack>\u002F\u003Cservice>\n        features: [pid-host]\n",[149,1333,1334,1341,1348,1355,1370],{"__ignoreMap":272},[276,1335,1336,1339],{"class":278,"line":279},[276,1337,1338],{"class":282},"projects",[276,1340,287],{"class":286},[276,1342,1343,1346],{"class":278,"line":290},[276,1344,1345],{"class":282},"  019c527b-6242-7b43-bfd4-bd60e27c1de3",[276,1347,287],{"class":286},[276,1349,1350,1353],{"class":278,"line":298},[276,1351,1352],{"class":282},"    allow",[276,1354,287],{"class":286},[276,1356,1357,1359,1362,1364,1367],{"class":278,"line":306},[276,1358,309],{"class":286},[276,1360,1361],{"class":282}," service",[276,1363,330],{"class":286},[276,1365,1366],{"class":312}," monitoring\u002Fnode-exporter",[276,1368,1369],{"class":405}," # \u003Cstack>\u002F\u003Cservice>\n",[276,1371,1372,1375,1377,1379,1382],{"class":278,"line":316},[276,1373,1374],{"class":282},"        features",[276,1376,330],{"class":286},[276,1378,435],{"class":286},[276,1380,1381],{"class":312},"pid-host",[276,1383,479],{"class":286},[163,1385,1387],{"id":1386},"remove-a-developer","Remove a developer",[145,1389,1390,1391,1394],{},"Remove the user (",[149,1392,1393],{},"mm team remove NAME","), merge, and sync or deploy each\nenvironment. Their key stops working there at once, including in sshd.",[145,1396,1397],{},"For immediate effect before the repo catches up, a host admin can block a key:",[267,1399,1401],{"className":580,"code":1400,"language":582,"meta":272,"style":272},"mmd access block --project PROJECT_ID --environment production SHA256:FINGERPRINT\n",[149,1402,1403],{"__ignoreMap":272},[276,1404,1405,1408,1411,1413,1416,1419,1421,1423],{"class":278,"line":279},[276,1406,1407],{"class":589},"mmd",[276,1409,1410],{"class":312}," access",[276,1412,721],{"class":312},[276,1414,1415],{"class":598}," --project",[276,1417,1418],{"class":312}," PROJECT_ID",[276,1420,844],{"class":598},[276,1422,500],{"class":312},[276,1424,1425],{"class":312}," SHA256:FINGERPRINT\n",[145,1427,1428,1429,1432,1433,1436],{},"On a Swarm, run it on every manager: a block applies only to the host where\nyou set it. The block lifts by itself once a sync no longer lists the key, or\nwith ",[149,1430,1431],{},"mmd access unblock",". ",[149,1434,1435],{},"mmd access show"," lists users, blocks, and deployed\ncommits for every environment.",[145,1438,1439,1440,1443,1444,535],{},"On a Swarm manager, ",[149,1441,1442],{},"mmd swarm converge"," sets every mm node label from one\ndeclaration; see ",[157,1445,1447],{"href":1446},".\u002Fhow-to\u002Fswarm-cluster#set-every-label-at-once-on-a-manager","Set every label at once",[163,1449,1451],{"id":1450},"emergency-access","Emergency access",[145,1453,1454,1455,1457,1458,1461],{},"Break-glass keys in ",[149,1456,264],{}," are admin on every enrolled project. Use one\nwith ",[149,1459,1460],{},"MM_SSH_KEY"," to repair a users file that locks everyone out, then put the\nprivate key back offline.",[1463,1464,1465],"style",{},"html pre.shiki code .sWZmh, html code.shiki .sWZmh{--shiki-default:var(--mm-code-key)}html pre.shiki code .sIbZ0, html code.shiki .sIbZ0{--shiki-default:var(--mm-code-punctuation)}html pre.shiki code .sv8ni, html code.shiki .sv8ni{--shiki-default:var(--mm-code-string)}html pre.shiki code .sN9xe, html code.shiki .sN9xe{--shiki-default:var(--mm-code-fg)}html pre.shiki code .sP7nD, html code.shiki .sP7nD{--shiki-default:var(--mm-code-comment)}html pre.shiki code .s1Wbj, html code.shiki .s1Wbj{--shiki-default:var(--mm-code-constant)}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 .svrjQ, html code.shiki .svrjQ{--shiki-default:var(--mm-code-function)}html pre.shiki code .sbRf1, html code.shiki .sbRf1{--shiki-default:var(--mm-code-option)}",{"title":272,"searchDepth":290,"depth":290,"links":1467},[1468,1469,1470,1471,1472,1473,1474,1475,1476],{"id":165,"depth":290,"text":166},{"id":573,"depth":290,"text":574},{"id":774,"depth":290,"text":775},{"id":876,"depth":290,"text":877},{"id":949,"depth":290,"text":950},{"id":1068,"depth":290,"text":1069},{"id":1250,"depth":290,"text":1251},{"id":1386,"depth":290,"text":1387},{"id":1450,"depth":290,"text":1451},"Declare who may reach each remote environment in the repo, and apply it on deploy.","md",{},true,{"title":105,"description":1477},"docs\u002Fremote-access","P12d4mhPM8cepA9WKi38DgEqAYoP6aJ6-UKmJcU_wak",1794512546199]