Repository navigation
Conversation
…host The public key of every device host is its own line STF_ZMQ_CURVE_CLIENT_KEY_<HOST>=<key> of variables.env, which the STF units get with env_file; STF_ZMQ_CURVE_CLIENT_KEYS stays for compatibility. ./zebrunner.sh setup adds the variables added to variables.env again, as README.md describes, so the keys of the device hosts are kept. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ADB_RELAY_HOSTS of .env (<host>:<first>-<last>, comma separated) starts adb-relay, the nginx of stf-proxy in the network of the host, which relays the port ranges of the devices of the device hosts for adb connect of STF. zebrunner.sh writes configuration/adb-relay/relay-hosts.conf from it, skips invalid entries, overlapping ranges and ranges with a port of MCloud, and runs compose with the profile adb-relay; stop, down and shutdown always include the profile. The e2e device drops proxy_port and server_proxy_port. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ADB_RELAY_HOSTS takes <host>:<port> entries, a device host in several of them: the remote debug port of every Android device (min_port + 1) is the documented default. A range is still relayed, with a warning that it also makes the screens of the devices public (min_port, no sign-in of their own). A port of an earlier entry is skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ADB_RELAY=true makes adb-relay read the Android devices of STF every ADB_RELAY_SYNC_SECONDS (STF_TOKEN of variables.env, stf-proxy on the port of the host) and relay the remote debug port of every present device of AGENT_HOSTS (connectPort, the screen port + 1 of an older STF), never the screen ports, in ADB_RELAY_PORTS only; a port of two devices, of MCloud or of ADB_RELAY_HOSTS is skipped and logged. nginx reloads gracefully only when the servers change. The sync is configuration/adb-relay/adb-relay.sh with awk programs in the nginx image (no new image, no jq there). zebrunner.sh starts adb-relay also in the auto mode and checks its settings; ADB_RELAY_HOSTS stays a fixed list in addition. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
adb-relay runs on the network of the host: instead of all the secrets of variables.env it gets configuration/adb-relay/stf-token, which ./zebrunner.sh setup, start and restart write from STF_TOKEN in place (mode 600, empty without the auto mode, ignored by git, removed by shutdown). The relay reads it on every sync and logs when the STF API answers again after an error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The auto mode relays the remote debug port of every Android device of STF of AGENT_HOSTS, present or not (the device host refuses the port of an absent one): the servers of nginx change only when a device is added, removed or moved, so nginx reloads almost never. present is no longer read from the API. A port of two devices (e.g. a stale registration and a new device) is skipped for both and logged with their serials and the fix. ADB_RELAY_SYNC_SECONDS defaults to 300; README explains why the relay polls STF. Also fixes a broken sentence of the README. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… feat/node-enrollment # Conflicts: # README.md
…istry - zebrunner.sh: node-invite <label> <address> [minutes] prints the join string mcloud-join://<host>:<port>?label=&grid=&pin=&token= once (host: AGENTS_ADDRESS or the host of STF_URL, pin: base64 SHA-256 of the SPKI of the stf-proxy certificate by openssl or patch/spki_pin.py); nodes [list], nodes revoke (restarts the triproxies), nodes delete, nodes legacy-off (empties the legacy keys and AGENT_HOSTS, rotates NODE_REGISTRATION_TOKEN and STF_STORAGE_TOKEN, asks, restarts). The STF API is called through stf-proxy on the loopback address, STF_TOKEN goes to curl on stdin and is never printed. - stf-proxy: the screens are allowed by stf-api (auth_request of /api/v1/zebrunner/screen-auth with X-Original-URI, the cookie and the token only), the node gets the WebSocket headers only; the AGENT_HOSTS map is gone, AGENT_HOSTS goes to stf-api as the legacy list; the enrollment is limited to 6 a minute per address (burst 3, 429). - adb-relay: the auto mode relays the devices of GET /api/v1/nodes/relay to the registered addresses of the nodes; legacy nodes through ADB_RELAY_HOSTS. - README: the Nodes section (enrollment, join string, commands, revocation, migration, security), AGENT_HOSTS and the manual keys as legacy. - tests: the node commands with curl and docker stubs, the stf-proxy configuration in docker with a fake stf-api and node, the relay by the registry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- stf-api: --nodes-connect-sub/push/app-dealer/dev-dealer at NODES_HOST, the host of the join string (AGENTS_ADDRESS, the host of STF_URL for 0.0.0.0), written into .env by setup and start - variables.env: STF_NODES_API_URL=http://stf-api:3000 for the triproxies and the storage - stf-proxy: X-Stf-Internal-Token never reaches a node, the internal routes /api/v1/zebrunner/nodes are refused (403) - node-invite refuses the labels reserved by STF (enroll, invites, relay, verify); a clearer hint for the 400 answers of the registry - e2e: STF_REF=feat/node-enrollment by default until stf#1124 is merged Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Includes #276 and #277: this branch is
feat/adb-relaymerged withfeat/curve-client-key-vars. Review and merge those first, or merge this PR on its own.Behavior
./zebrunner.sh node-invite <label> <address> [<minutes>]asks STF for an invite (POST /api/v1/nodes/invites) and prints the join string once, with a note that it is a secret for./zebrunner.sh joinof mcloud-agent and how many minutes it stays valid:mcloud-join://<host>:<port>?label=<label>&grid=<host>:4446&pin=<pin>&token=<invite>hostisAGENTS_ADDRESSof.env. When that is0.0.0.0(every address), the host ofSTF_URLis used. stf-proxy, the grid (4446) and the triproxies (7160, 7250, 7260, 7270) are all published on that address.portisSTF_PORT.pinis the base64 SHA-256 of the DER SPKI ofconfiguration/stf-proxy/ssl/ssl.crt, made by openssl (LibreSSL works too) or by the newpatch/spki_pin.py. In the URL,+,/and=are percent-encoded. The pin is also printed on its own../zebrunner.sh nodes [list]shows a table: label, address, status, last seen, enrolled, and the first characters of the key../zebrunner.sh nodes revoke <label>revokes the node, then runsdocker restart stf-triproxy-app stf-triproxy-devto end its open ZeroMQ sessions../zebrunner.sh nodes delete <label>removes a node; STF accepts this for revoked nodes only../zebrunner.sh nodes legacy-off:STF_ZMQ_CURVE_CLIENT_KEYS, everySTF_ZMQ_CURVE_CLIENT_KEY_<HOST>andAGENT_HOSTS;NODE_REGISTRATION_TOKEN(48 characters) andSTF_STORAGE_TOKEN(64 characters) withrandom_string. The new values are never printed.variables.envis written in place and stays mode 600;<scheme of STF_URL>://127.0.0.1:STF_PORTwith-k.STF_TOKENis passed to curl through its stdin config (-K -), so it never appears in the process arguments and is never printed. The API returns generic errors, so the commands print a hint for each status (000, 400, 401, 403, 404, other)./d/<host>/<serial>/<port>/:auth_requestgoes to an internal location that proxies tostf-api/api/v1/zebrunner/screen-auth. That subrequest gets onlyCookie,Authorization,X-Original-URI $request_uri,HostandX-Forwarded-Proto(proxy_pass_request_headers off).proxy_pass_request_headers offand only the WebSocket headers.Cookie ""andAuthorization ""are set explicitly. NoX-Stf-*header can reach the node.AGENT_HOSTSmap andconfiguration/stf-proxy/agent-hosts.confare removed.AGENT_HOSTSis now passed to the environment ofstf-apias the legacy list.limit_reqonlocation ~* ^/api/v1/nodes/enroll: 6 requests a minute per IP, burst 3,nodelay, then 429. The match is case-insensitive and covers any suffix, because the Express router would accept/Enroll/too. These requests go tostf-api.GET /api/v1/nodes/relayand relays each device'sconnectPortto the registered address of its node. It skips loopback, link-local and multicast addresses as a second check, in addition to STF's. Its token is also passed to curl through stdin.Decisions
/api/v1/devicesplusAGENT_HOSTS) is removed: there, the device's address comes from the node itself, and the relay runs in the host's network. Legacy nodes go throughADB_RELAY_HOSTSuntil they are enrolled. The auto mode only exists in the still unreleased feat: optional adb relay of the device hosts in a private network #277, so no deployment depends on the old behavior.write_agent_hostsis replaced bycheck_agent_hosts. It only warns about invalid entries, andstartremoves the staleagent-hosts.conf.AGENT_HOSTS, because new deployments use enrollment. The value from the previous setup is kept.legacy-offalso emptiesAGENT_HOSTS. The contract does not list it, but it is the same legacy list and finishes the migration.Migration
The legacy settings (keys,
NODE_REGISTRATION_TOKEN,STF_STORAGE_TOKEN,AGENT_HOSTS) keep working next to enrolled nodes untilnodes legacy-off:STF_PROVIDER_HOSTas the address.nodesand check that every node is active.nodes legacy-off.AGENT_HOSTSmoves from stf-proxy to stf-api. The README section "Migration from the manual settings" has the details.Security
The new README "Nodes" section describes what enrollment protects and the risks that remain:
STF_TOKENkept out of process arguments and output.legacy-off; the rate limit is per IP; revocation has a window of up to 60 s.Settings for the STF registry of the nodes (zebrunner/stf#1124)
stf-apicommand:--nodes-connect-sub tcp://${NODES_HOST}:7250 --nodes-connect-push tcp://${NODES_HOST}:7270 --nodes-connect-app-dealer tcp://${NODES_HOST}:7160 --nodes-connect-dev-dealer tcp://${NODES_HOST}:7260.NODES_HOSTis a new.envsetting that./zebrunner.sh setupandstartwrite:AGENTS_ADDRESS, or the host ofSTF_URLwhen that is0.0.0.0. This is the same host as in the join string. An.envfrom an earlier release gets the line added bystart.--nodes-stf-urlis left at its default,STF_URLofvariables.env, which is the public URL.stf-apienvironment:AGENT_HOSTS(legacy) comes from.env.STF_STORAGE_TOKENandSTF_ZMQ_CURVE_SERVER_PUBLIC_KEYalready come fromvariables.env.variables.env.original:STF_NODES_API_URL=http://stf-api:3000, for the triproxies andstf-storage-temp. Every STF unit gets it throughenv_file, and setup keeps it./d/also setsX-Stf-Internal-Token "", on top of the header whitelist,Cookie ""andAuthorization "".location ~* ^/api/v1/zebrunner/nodes { return 403; }blocks the internal routes of the triproxies and the storage. It is case-insensitive and catches any suffix, double slashes and percent-encoding./_screen_authmatches the STF version and is stricter: it passes only the cookie,Authorization,X-Original-URI,HostandX-Forwarded-Proto.POST /api/v1/nodes/invites{label,address,ttlMinutes}returns 201{invite,label,address,expiresAt};GET /api/v1/nodesreturns{nodes:[{label,address,publicKey,status,createdAt,revokedAt,lastSeenAt}]};POST /api/v1/nodes/<label>/revokeandDELETE /api/v1/nodes/<label>return 200, or 400 for an unknown node or a node that is not revoked;GET /api/v1/nodes/relayreturns{devices:[{serial,label,address,connectPort}]}.node-inviterefusesenroll,invites,relayandverify.Dependencies
--nodes-connect-*options andSTF_NODES_API_URL. With an STF image that does not have it:mcn1.) on registration../zebrunner.sh joinreads the join string.E2E_REFSdefaults toSTF_REF=feat/node-enrollmentuntil stf#1124 is merged; remove the default once it is. The e2e device host is a legacy node, so the test setsAGENT_HOSTS.Tests
make lint: ok.make test: ok.zebrunner_testgains the node commands with stub curl and docker. It checks:legacy-off: decline (explicit and default), the rotation (lengths, new values, not printed, written in place, mode 600), empty keys andAGENT_HOSTS, the restart;auth_request, cleared headers, the limit zone and burst;AGENT_HOSTSgoes to stf-api, and stf-proxy has noagent-hostsmount.adb_relay_testis rewritten for/api/v1/nodes/relay.tests/stf_proxy_docker_test.sh(inDOCKER_TESTS):nginx -t, then the real generated config with a fake stf-api and node: 401/403 from screen-auth; the node gets no cookie,AuthorizationorX-Stf-*while the WebSocket headers pass; the subrequest gets no extra headers; enroll goes to stf-api and returns 200 200 200 200 then 429, also for/API/v1/Nodes/Enroll/; other API routes are not limited. All pass.adb_relay_docker_test(updated): all pass.stf_proxy_docker_testnow also checks that the internal token never reaches the node, and that/api/v1/zebrunner/nodes/*returns 403 (case variants,//,%6E) whilescreen-authis still reachable.zebrunner_testnow also checks:docker compose configof a set-up copy givesstf-apithe--nodes-connect-*options atNODES_HOST, andSTF_NODES_API_URLreaches both triproxies,stf-storage-tempandstf-api;NODES_HOSTfollowsAGENTS_ADDRESSor theSTF_URLhost, and is added to an old.env;compose_test(updated: screen-auth probe, noagent-hostsmount) could not run locally, becausepublic.ecr.aws/zebrunner/stf:3.1andmcloud-grid:3.1are not published yet. That was already the case before this PR.