Repository navigation
feat(dev-box): merge user_config SSH keys, listen on port 22 - #172
Merged
Merged
Conversation
The box listened on 1022 while the dstack 0.5.x dev image used 22, so the connection recipe differed from the one users already have. Port 22 also matches what the gateway maps for `<app-id>-22.<gateway-domain>`, making gateway access the plain case again. Reflected in the README connect section; no other 1022 references were in this example.
Phala Cloud pushes workspace SSH keys into the guest's user_config, but
the box only read SSH_AUTHORIZED_KEYS, so those keys never worked and
the platform channel was dead weight.
The entrypoint now merges both channels and de-duplicates: the env key
stays valid even after a workspace key update, and a key present in both
is listed once. The user_config read goes through
/host/dstack/user_config, already reachable via the `/:host:rslave`
mount; dstack exposes it as a relative symlink into .host-shared, so it
resolves inside /host.
Tolerance is deliberate: a missing file, malformed JSON, a missing
field, a null, a non-string, or an empty value all mean "this channel
has no keys", because an unreadable platform file must not keep an
operator out. The non-zero exit stays reserved for losing both
channels.
jq streams, so `{"ssh_authorized_keys":"k"} garbage` prints the key and
then fails; clearing the whole assignment on failure discards that
partial key instead of trusting a config we just rejected.
The README only described SSH_AUTHORIZED_KEYS, so a reader could not tell where workspace keys come from, that the two sources merge instead of override, or that a workspace key change only lands on the next VM start. Also states the consequence plainly: either channel is a path to CVM root, the box trusts every key the platform delivers, and there is no switch to ignore user_config today. Which roles may change those keys is platform policy, not something this example enforces.
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.
Summary
dstack 0.6 ships no dev OS image, so
dev-box/replaces it — but it only accepted keys pasted throughSSH_AUTHORIZED_KEYS. Phala Cloud pushes workspace SSH keys into the guest'suser_config, so on a Cloud deployment those keys silently did nothing. This makes the box consume both channels, and movessshdto port 22 so connecting looks like the 0.5.x dev image again.Reopens for review; three commits, one per concern.
Changes
feat(dev-box): serve sshd on port 22sshd_configlistens on22; README connect recipe becomes<app-id>-22.<gateway-domain>:443feat(dev-box): merge user_config SSH keys with the env keysentrypoint.shmergesSSH_AUTHORIZED_KEYSanduser_config'sssh_authorized_keys, de-duplicateddocs(dev-box): document both SSH key channels and their trust boundaryKey behaviour:
/host/dstack/user_config— already reachable through the existing/:host:rslavemount. dstack exposes/dstack/user_configas a relative symlink to.host-shared/.user-config(dstack-utilsystem_setup::link_files), so it resolves inside/host; no extra mount or fallback path needed.null, non-string, empty value → "this channel has no keys". An unreadable platform file must not keep an operator out.exit 1stays reserved for losing both channels.{"ssh_authorized_keys":"k"} garbageprints the key and then fails, so the clearing is applied to the whole assignment (config_keys=$(jq …) || config_keys=) rather than inside the substitution — a partial key from a config we just rejected is discarded.command="…"options and comments survive. De-duplication is on the full cleaned line, so the same key with different restrictions is kept.Testing
shellcheck -s sh,sh -n,dash -nclean onentrypoint.sh./bin/shanddash: both sources with a duplicate, env-only with the file absent,user_config-only with env unset, both empty →exit 1, malformed JSON ({), valid object + trailing garbage, valid object + truncated second document, missing field,null, empty string, number/array/object/bool, top-level array, empty file, blank/whitespace-only lines, no trailing newline.authorized_keysline with options/leading/trailing spaces../dev.sh check-all— shellcheck portion clean for this example (repo's other examples keep their pre-existing warnings). The compose validation stage cannot run in the authoring environment (nodocker composeplugin, noyamllint); it fails identically onmainfor every example.Follow-ups (deliberately out of scope)
entrypoint.shandsshd_configare baked into the image, anddocker-compose.yamlstill pinssha-5a930ae. Until CI buildssha-<newcommit>and a digest-bump PR lands (same flow as fix(dev-box): pin image by digest #170), the published example still behaves the old way.dev-box/has no test file anddev.shhas no test entry point; testing the matrix properly needs the key collection extracted into its own script (an extraCOPYin theDockerfile), which is a separate change.