Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions dev-box/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,39 @@ volumes:
home:
```

Deploy with your public key or keys in `SSH_AUTHORIZED_KEYS`, in `authorized_keys` format with one key per line. The container exits with an error if the variable is empty.
## SSH keys

Two channels feed `/root/.ssh/authorized_keys`. They are merged and de-duplicated when the container starts, so a key in either channel gets you in, a key in both is listed once, and a key the platform manages never displaces the one you deployed with.

| Channel | Source | Use it for |
|---------|--------|------------|
| `SSH_AUTHORIZED_KEYS` | Environment variable in the compose file | A key you paste at deploy time |
| `user_config` | The `ssh_authorized_keys` field of the `user_config` Phala Cloud pushes into the guest; the host root is mounted at `/host`, so it reads `/host/dstack/user_config` | Workspace keys the platform keeps in sync |

Both channels grant root. Setting `SSH_AUTHORIZED_KEYS` and changing this app's workspace SSH keys both hand over the CVM, and the dev box trusts every key the platform delivers through `user_config`; there is no switch to ignore that channel today. Which workspace members and roles may change an app's SSH keys is decided by Phala Cloud's key management, not by this example.

Deploy with your public key or keys in `SSH_AUTHORIZED_KEYS`, in `authorized_keys` format with one key per line:

```bash
phala deploy -n my-app -c docker-compose.yaml \
--image dstack-0.6.1 \
-e SSH_AUTHORIZED_KEYS="$(cat ~/.ssh/id_ed25519.pub)"
```

On a plain dstack deployment, set `SSH_AUTHORIZED_KEYS` as an encrypted environment variable.
On a plain dstack deployment, set `SSH_AUTHORIZED_KEYS` as an encrypted environment variable. If your keys live in the Phala Cloud workspace instead, drop the `environment:` entry from the service: the dev box still picks them up from `user_config`.

`user_config` is optional and read defensively: a missing file, invalid JSON, a missing field, or an empty value all mean "this channel has no keys". The container exits with an error only when both channels turn up empty.

Keys added to your Phala Cloud workspace reach the guest's `user_config` only at CVM boot, so a workspace key change works on the next start of the VM, not immediately.

## Connect

`sshd` listens on port `1022`. Reach it through the dstack-gateway by adding this to `~/.ssh/config`:
`sshd` listens on port `22`, the same as the 0.5.x dev image. Reach it through the dstack-gateway by adding this to `~/.ssh/config`:

```
Host my-app
User root
ProxyCommand openssl s_client -quiet -connect <app-id>-1022.<gateway-domain>:443 -servername <app-id>-1022.<gateway-domain> -verify_hostname <app-id>-1022.<gateway-domain> -verify_return_error
ProxyCommand openssl s_client -quiet -connect <app-id>-22.<gateway-domain>:443 -servername <app-id>-22.<gateway-domain> -verify_hostname <app-id>-22.<gateway-domain> -verify_return_error
```

Replace `<app-id>` with your app ID and `<gateway-domain>` with the gateway base domain of the node the CVM runs on, for example `dstack-pha-prod15.phala.network`. Change `443` if your gateway uses a different port.
Expand Down
2 changes: 2 additions & 0 deletions dev-box/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ services:
uts: host
environment:
# One or more public keys, newline-separated (authorized_keys format).
# Merged with the platform-managed keys in /host/dstack/user_config;
# drop this line to rely on those alone.
- SSH_AUTHORIZED_KEYS=${SSH_AUTHORIZED_KEYS}
volumes:
- /:/host:rslave
Expand Down
44 changes: 41 additions & 3 deletions dev-box/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,50 @@
#!/bin/sh
# Authorized keys arrive on two channels with different purposes:
#
# SSH_AUTHORIZED_KEYS key pasted at deploy time, one per line
# user_config workspace keys the platform pushes to the CVM before
# it boots; the host root is mounted at /host, so the
# guest's /dstack/user_config is /host/dstack/user_config
#
# They are merged, not overridden: a key set in either channel works, and a
# platform-side key update never drops the deploy-time key. Duplicates are
# removed. Each channel is optional; only losing both is fatal.
set -eu
if [ -z "${SSH_AUTHORIZED_KEYS:-}" ]; then
echo "SSH_AUTHORIZED_KEYS is not set" >&2

# Overridable to exercise the merge logic outside a CVM.
USER_CONFIG=${USER_CONFIG:-/host/dstack/user_config}

env_keys=${SSH_AUTHORIZED_KEYS:-}

# A missing file or malformed JSON makes jq fail; `.ssh_authorized_keys // empty`
# turns a missing field and a null into no output, select() drops a non-string
# value, and an empty string comes out as an empty line that the blank-line
# filter below removes. Every path ends with this channel contributing no key.
#
# The assignment, not the jq call, is what swallows the failure: jq streams, so
# `{"ssh_authorized_keys":"k"} garbage` prints the key and then exits non-zero.
# Dropping output only inside the substitution would keep that partial key from
# a config we just decided not to trust, so a non-zero exit discards it all.
config_keys=$(
jq -r '.ssh_authorized_keys // empty | select(type == "string")' \
"$USER_CONFIG" 2>/dev/null
) || config_keys=

# Blank and whitespace-only lines would become empty authorized_keys entries.
keys=$(
printf '%s\n%s\n' "$env_keys" "$config_keys" |
sed -e 's/[[:space:]]*$//' -e '/^$/d' | sort -u
)

if [ -z "$keys" ]; then
echo "no SSH public keys in SSH_AUTHORIZED_KEYS or ${USER_CONFIG}" >&2
exit 1
fi

install -d -m 700 /root/.ssh
printf '%s\n' "$SSH_AUTHORIZED_KEYS" > /root/.ssh/authorized_keys
printf '%s\n' "$keys" > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
echo "authorized_keys: $(printf '%s\n' "$keys" | wc -l) key(s)" >&2
key=/etc/ssh/host-keys/ssh_host_ed25519_key
[ -f "$key" ] || ssh-keygen -q -t ed25519 -N '' -f "$key"
install -d -m 755 /run/sshd
Expand Down
2 changes: 1 addition & 1 deletion dev-box/sshd_config
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Port 1022
Port 22
HostKey /etc/ssh/host-keys/ssh_host_ed25519_key
AllowUsers root
PermitRootLogin prohibit-password
Expand Down
Loading