feat(zhulan): add restricted remote development cell

This commit is contained in:
冰朔 2026-08-13 14:32:40 +08:00
commit 366b8911e4
22 changed files with 4503 additions and 0 deletions

View file

@ -0,0 +1,41 @@
# BS-GZ-006 only: domain/TLS/reverse proxy. UI and all real services remain on BS-SG-003.
# The local upstream port must be supplied by a dedicated restricted tunnel.
location = /zhulan {
return 308 /zhulan/;
}
# Runtime-only verification is reachable from the BS-SG-003 loopback executor,
# never through the Guangzhou public projection.
location ^~ /zhulan/api/v1/runtime/ {
return 404;
}
location ^~ /zhulan/ {
proxy_pass http://127.0.0.1:17631/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Prefix /zhulan;
# Do not inherit a client-supplied X-Forwarded-For chain. The runtime uses
# this value for per-source rate limits.
proxy_set_header X-Forwarded-For $remote_addr;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
client_max_body_size 1m;
}
# RFC 8414 path-aware discovery aliases for issuer
# https://guanghulab.com/zhulan. These are metadata projections only.
location = /.well-known/oauth-authorization-server/zhulan {
proxy_pass http://127.0.0.1:17631/.well-known/oauth-authorization-server;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
location = /.well-known/oauth-protected-resource/zhulan/mcp {
proxy_pass http://127.0.0.1:17631/.well-known/oauth-protected-resource;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}

View file

@ -0,0 +1,110 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$(id -u)" -ne 0 ]]; then
echo "INSTALL_REQUIRES_ROOT" >&2
exit 1
fi
SOURCE_DIR="${1:-}"
TUNNEL_PUBLIC_KEY_FILE="${2:-}"
if [[ -z "$SOURCE_DIR" || ! -f "$SOURCE_DIR/deploy/guanghulab-zhulan.nginx.conf" ]]; then
echo "SOURCE_DIR_INVALID" >&2
exit 1
fi
if [[ -z "$TUNNEL_PUBLIC_KEY_FILE" || ! -f "$TUNNEL_PUBLIC_KEY_FILE" ]]; then
echo "TUNNEL_PUBLIC_KEY_FILE_INVALID" >&2
exit 1
fi
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-0-16-ubuntu}"
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-b2ecf109-1999-4643-b223-e67e24d7667d}"
ACTUAL_HOST="$(hostname)"
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
echo "TARGET_IDENTITY_MISMATCH" >&2
exit 1
fi
SITE_FILE="/etc/nginx/sites-enabled/guanghulab"
SNIPPET_FILE="/etc/nginx/snippets/guanghu-zhulan.conf"
SSHD_DROPIN="/etc/ssh/sshd_config.d/80-zhulan-proxy.conf"
PROXY_HOME="/var/lib/guanghu/zhulan-proxy"
AUTH_KEYS="$PROXY_HOME/.ssh/authorized_keys"
BACKUP_ROOT="/var/backups/guanghu/zhulan-front"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
if [[ ! -f "$SITE_FILE" ]]; then
echo "GUANGHULAB_SITE_NOT_FOUND" >&2
exit 1
fi
if ! grep -q 'include /etc/nginx/snippets/guanghu-ai-discovery.conf;' "$SITE_FILE"; then
echo "GUANGHULAB_INCLUDE_ANCHOR_NOT_FOUND" >&2
exit 1
fi
getent passwd zhulan-proxy >/dev/null || {
echo "PROXY_USER_MUST_BE_PRECREATED" >&2
exit 1
}
PUBLIC_KEY="$(tr -d '\r\n' <"$TUNNEL_PUBLIC_KEY_FILE")"
if [[ "$PUBLIC_KEY" != ssh-ed25519\ * ]]; then
echo "TUNNEL_PUBLIC_KEY_NOT_ED25519" >&2
exit 1
fi
install -d -o root -g root -m 0700 "$BACKUP_ROOT"
install -m 0644 "$SITE_FILE" "$BACKUP_ROOT/guanghulab-$STAMP"
[[ ! -f "$SNIPPET_FILE" ]] || install -m 0644 "$SNIPPET_FILE" "$BACKUP_ROOT/snippet-$STAMP"
[[ ! -f "$SSHD_DROPIN" ]] || install -m 0600 "$SSHD_DROPIN" "$BACKUP_ROOT/sshd-$STAMP"
install -d -o zhulan-proxy -g zhulan-proxy -m 0700 "$PROXY_HOME" "$PROXY_HOME/.ssh"
{
printf '%s %s\n' \
'restrict,port-forwarding,permitlisten="127.0.0.1:17631"' \
"$PUBLIC_KEY"
} >"$AUTH_KEYS.tmp"
chown zhulan-proxy:zhulan-proxy "$AUTH_KEYS.tmp"
chmod 0600 "$AUTH_KEYS.tmp"
mv "$AUTH_KEYS.tmp" "$AUTH_KEYS"
cat >"$SSHD_DROPIN.tmp" <<'EOF'
Match User zhulan-proxy
AuthenticationMethods publickey
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowAgentForwarding no
AllowTcpForwarding remote
GatewayPorts no
PermitListen 127.0.0.1:17631
PermitOpen none
PermitTTY no
X11Forwarding no
PermitTunnel no
PermitUserRC no
MaxSessions 0
EOF
chown root:root "$SSHD_DROPIN.tmp"
chmod 0600 "$SSHD_DROPIN.tmp"
mv "$SSHD_DROPIN.tmp" "$SSHD_DROPIN"
sshd -t
install -o root -g root -m 0644 \
"$SOURCE_DIR/deploy/guanghulab-zhulan.nginx.conf" "$SNIPPET_FILE"
if ! grep -q 'include /etc/nginx/snippets/guanghu-zhulan.conf;' "$SITE_FILE"; then
sed -i \
'/include \/etc\/nginx\/snippets\/guanghu-ai-discovery.conf;/a\ include /etc/nginx/snippets/guanghu-zhulan.conf;' \
"$SITE_FILE"
fi
if ! nginx -t; then
install -m 0644 "$BACKUP_ROOT/guanghulab-$STAMP" "$SITE_FILE"
nginx -t
echo "NGINX_VALIDATION_FAILED_ROLLED_BACK" >&2
exit 1
fi
systemctl reload ssh
systemctl reload nginx
printf '{"schema":"guanghu.zhulan-front-install-receipt/v1","development_id":"DEV-20260813-005","front_node":"BS-GZ-006","role":"DOMAIN_TLS_REVERSE_PROXY_ONLY","listener":"127.0.0.1:17631","installed_at":"%s"}\n' "$STAMP"

View file

@ -0,0 +1,191 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$(id -u)" -ne 0 ]]; then
echo "INSTALL_REQUIRES_ROOT" >&2
exit 1
fi
SOURCE_DIR="${1:-}"
if [[ -z "$SOURCE_DIR" || ! -f "$SOURCE_DIR/runtime/zhulan_cell.py" ]]; then
echo "SOURCE_DIR_INVALID" >&2
exit 1
fi
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-12-12-ubuntu}"
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-7a500f2d-9aed-4b93-b3b8-59c87c65d031}"
ACTUAL_HOST="$(hostname)"
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
echo "TARGET_IDENTITY_MISMATCH host=$ACTUAL_HOST dmi=$ACTUAL_DMI" >&2
exit 1
fi
if ! command -v bwrap >/dev/null 2>&1 || ! command -v apparmor_parser >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends apparmor bubblewrap
fi
INSTALL_ROOT="/opt/guanghu/zhulan-remote-cell"
STATE_ROOT="/var/lib/guanghu/zhulan-remote-cell"
WORKSPACE_ROOT="/srv/guanghu/zhulan-cell/workspaces"
CANDIDATE_ROOT="/srv/guanghu/zhulan-cell/candidates"
SECRET_ROOT="/etc/guanghu/secrets"
ENV_FILE="/etc/guanghu/zhulan-remote-cell.env"
SERVICE_FILE="/etc/systemd/system/zhulan-remote-cell.service"
EXECUTOR_SERVICE_FILE="/etc/systemd/system/zhulan-validation-executor.service"
APPARMOR_FILE="/etc/apparmor.d/zhulan-remote-cell-bwrap"
BACKUP_ROOT="/var/backups/guanghu/zhulan-remote-cell"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
getent passwd zhulan-runtime >/dev/null || {
echo "RUNTIME_USER_MUST_BE_PRECREATED" >&2
exit 1
}
install -d -o root -g root -m 0755 "$INSTALL_ROOT" "$BACKUP_ROOT"
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$STATE_ROOT"
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$WORKSPACE_ROOT"
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$CANDIDATE_ROOT"
install -d -o root -g zhulan-runtime -m 0750 "$SECRET_ROOT"
if [[ -d "$INSTALL_ROOT/runtime" ]]; then
tar -C "$INSTALL_ROOT" -czf "$BACKUP_ROOT/runtime-$STAMP.tgz" runtime ui policy.json 2>/dev/null || true
fi
if [[ -f "$ENV_FILE" ]]; then
install -m 0600 "$ENV_FILE" "$BACKUP_ROOT/env-$STAMP"
fi
if [[ -f "$SERVICE_FILE" ]]; then
install -m 0644 "$SERVICE_FILE" "$BACKUP_ROOT/service-$STAMP"
fi
if [[ -f "$EXECUTOR_SERVICE_FILE" ]]; then
install -m 0644 "$EXECUTOR_SERVICE_FILE" "$BACKUP_ROOT/executor-service-$STAMP"
fi
if [[ -f "$APPARMOR_FILE" ]]; then
install -m 0644 "$APPARMOR_FILE" "$BACKUP_ROOT/apparmor-$STAMP"
fi
install -d -o root -g root -m 0755 "$INSTALL_ROOT/runtime" "$INSTALL_ROOT/ui" "$INSTALL_ROOT/contracts"
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_cell.py" "$INSTALL_ROOT/runtime/zhulan_cell.py"
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_code_gate.py" "$INSTALL_ROOT/runtime/zhulan_code_gate.py"
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_validation_executor.py" "$INSTALL_ROOT/runtime/zhulan_validation_executor.py"
# Keep the distro bwrap binary non-setuid. A dedicated group-executable copy
# lets AppArmor grant userns only to this runtime path instead of weakening the
# host-wide unprivileged-userns policy or opening /usr/bin/bwrap for all users.
install -o root -g zhulan-runtime -m 0750 /usr/bin/bwrap "$INSTALL_ROOT/runtime/zhulan-bwrap"
install -o root -g root -m 0644 "$SOURCE_DIR/ui/index.html" "$INSTALL_ROOT/ui/index.html"
install -o root -g root -m 0644 "$SOURCE_DIR/ui/styles.css" "$INSTALL_ROOT/ui/styles.css"
install -o root -g root -m 0644 "$SOURCE_DIR/ui/app.js" "$INSTALL_ROOT/ui/app.js"
install -o root -g root -m 0644 "$SOURCE_DIR/policy.example.json" "$INSTALL_ROOT/policy.json"
install -o root -g root -m 0644 "$SOURCE_DIR/README.md" "$INSTALL_ROOT/README.md"
if [[ -d "$SOURCE_DIR/contracts" ]]; then
find "$SOURCE_DIR/contracts" -maxdepth 1 -type f -print0 | while IFS= read -r -d '' file; do
install -o root -g root -m 0444 "$file" "$INSTALL_ROOT/contracts/$(basename "$file")"
done
fi
# Install current Fifth Domain brains and Zhulan entry as read-only runtime
# contracts from the same exact repository checkout as this installer.
REPO_ROOT="$(cd "$SOURCE_DIR/../.." && pwd)"
SOURCE_COMMIT="${ZHULAN_SOURCE_COMMIT:-}"
if [[ -z "$SOURCE_COMMIT" ]] && git -C "$REPO_ROOT" rev-parse HEAD >/dev/null 2>&1; then
SOURCE_COMMIT="$(git -C "$REPO_ROOT" rev-parse HEAD)"
fi
if [[ ! "$SOURCE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "SOURCE_COMMIT_REQUIRED" >&2
exit 1
fi
for relative in \
"skills/shared/guanghu-ui-brain/SKILL.md" \
"skills/shared/guanghu-ui-brain/BRAIN.hdlp" \
"skills/shared/guanghu-client-ui-brain/SKILL.md" \
"skills/shared/guanghu-client-ui-brain/BRAIN.hdlp" \
"光之湖/ICE-GL-ZL-001-铸澜/WAKE.hdlp" \
"光之湖/ICE-GL-ZL-001-铸澜/INDEX.hdlp" \
"光之湖/ICE-GL-ZL-001-铸澜/CURRENT.hdlp" \
"光之湖/ICE-GL-ZL-001-铸澜/PERMANENT-MEMORY-WRITE-PROTOCOL.hdlp"; do
source_file="$REPO_ROOT/$relative"
if [[ ! -f "$source_file" ]]; then
echo "CONTRACT_SOURCE_MISSING $relative" >&2
exit 1
fi
safe_name="$(printf '%s' "$relative" | tr '/ ' '__')"
install -o root -g root -m 0444 "$source_file" "$INSTALL_ROOT/contracts/$safe_name"
done
printf '%s\n' "$SOURCE_COMMIT" >"$INSTALL_ROOT/contracts/REPOSITORY-SOURCE-SHA"
chmod 0444 "$INSTALL_ROOT/contracts/REPOSITORY-SOURCE-SHA"
SECRET_FILE="$SECRET_ROOT/zhulan-remote-cell.secret"
if [[ ! -f "$SECRET_FILE" ]]; then
umask 0177
openssl rand -hex 48 >"$SECRET_FILE"
fi
chown root:zhulan-runtime "$SECRET_FILE"
chmod 0640 "$SECRET_FILE"
install -o root -g zhulan-runtime -m 0640 "$SOURCE_DIR/deploy/zhulan-remote-cell.env.example" "$ENV_FILE"
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-remote-cell.service" "$SERVICE_FILE"
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-validation-executor.service" "$EXECUTOR_SERVICE_FILE"
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-bwrap.apparmor" "$APPARMOR_FILE"
apparmor_parser -r "$APPARMOR_FILE"
systemctl daemon-reload
systemctl enable zhulan-validation-executor.service
systemctl restart zhulan-validation-executor.service
for _ in $(seq 1 30); do
if [[ -S /run/guanghu/zhulan-validation/executor.sock ]]; then
break
fi
sleep 1
done
if [[ ! -S /run/guanghu/zhulan-validation/executor.sock ]]; then
systemctl status zhulan-validation-executor.service --no-pager >&2 || true
echo "VALIDATION_EXECUTOR_HEALTH_FAILED" >&2
exit 1
fi
systemctl enable zhulan-remote-cell.service
systemctl restart zhulan-remote-cell.service
for _ in $(seq 1 30); do
if curl --fail --silent --show-error --max-time 2 http://127.0.0.1:17631/health >"$STATE_ROOT/health.json.tmp"; then
mv "$STATE_ROOT/health.json.tmp" "$STATE_ROOT/health.json"
break
fi
sleep 1
done
if [[ ! -s "$STATE_ROOT/health.json" ]]; then
systemctl status zhulan-remote-cell.service --no-pager >&2 || true
echo "RUNTIME_HEALTH_FAILED" >&2
exit 1
fi
SOURCE_SHA256="$(find \
"$INSTALL_ROOT/runtime" \
"$INSTALL_ROOT/ui" \
"$INSTALL_ROOT/contracts" \
"$INSTALL_ROOT/policy.json" \
"$INSTALL_ROOT/README.md" \
-type f -print0 | sort -z | xargs -0 sha256sum | sha256sum | awk '{print $1}')"
cat >"$STATE_ROOT/install-receipt.json.tmp" <<EOF
{
"schema": "guanghu.zhulan-runtime-install-receipt/v1",
"development_id": "DEV-20260813-005",
"runtime_node": "BS-SG-003",
"front_node_role": "BS-GZ-006_PROXY_ONLY",
"installed_at": "$STAMP",
"source_tree_hash": "$SOURCE_SHA256",
"source_commit": "$SOURCE_COMMIT",
"service": "zhulan-remote-cell.service",
"validation_executor": "zhulan-validation-executor.service",
"listener": "127.0.0.1:17631",
"health": "PASS"
}
EOF
chown zhulan-runtime:zhulan-runtime "$STATE_ROOT/install-receipt.json.tmp"
chmod 0600 "$STATE_ROOT/install-receipt.json.tmp"
mv "$STATE_ROOT/install-receipt.json.tmp" "$STATE_ROOT/install-receipt.json"
cat "$STATE_ROOT/install-receipt.json"

View file

@ -0,0 +1,121 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$(id -u)" -ne 0 ]]; then
echo "INSTALL_REQUIRES_ROOT" >&2
exit 1
fi
FRONT_HOST="${1:-}"
KNOWN_HOSTS_SOURCE="${2:-}"
if [[ ! "$FRONT_HOST" =~ ^[0-9A-Fa-f:.]+$ ]]; then
echo "FRONT_HOST_MUST_BE_LITERAL_IP" >&2
exit 1
fi
if [[ -z "$KNOWN_HOSTS_SOURCE" || ! -f "$KNOWN_HOSTS_SOURCE" ]]; then
echo "KNOWN_HOSTS_SOURCE_INVALID" >&2
exit 1
fi
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-12-12-ubuntu}"
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-7a500f2d-9aed-4b93-b3b8-59c87c65d031}"
ACTUAL_HOST="$(hostname)"
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
echo "TARGET_IDENTITY_MISMATCH" >&2
exit 1
fi
CONFIG_ROOT="/etc/guanghu/zhulan-front-tunnel"
KEY_FILE="$CONFIG_ROOT/id_ed25519"
KNOWN_HOSTS="$CONFIG_ROOT/known_hosts"
SSH_CONFIG="$CONFIG_ROOT/ssh_config"
SERVICE_FILE="/etc/systemd/system/zhulan-front-tunnel.service"
if [[ ! -f "$KEY_FILE" || ! -f "$KEY_FILE.pub" ]]; then
echo "TUNNEL_IDENTITY_NOT_PREPARED" >&2
exit 1
fi
if ! getent passwd zhulan-tunnel >/dev/null; then
echo "TUNNEL_USER_NOT_PREPARED" >&2
exit 1
fi
install -o root -g zhulan-tunnel -m 0640 "$KNOWN_HOSTS_SOURCE" "$KNOWN_HOSTS"
if ! ssh-keygen -F "$FRONT_HOST" -f "$KNOWN_HOSTS" >/dev/null; then
echo "PINNED_FRONT_HOST_KEY_MISSING" >&2
exit 1
fi
EXPECTED_FRONT_HOST_KEY="${ZHULAN_EXPECTED_FRONT_HOST_KEY:-SHA256:P2EtuYFg8hptha4s0auP4yzp+Wg+H27bw4mdqzk1Cvk}"
ACTUAL_FRONT_HOST_KEY="$(ssh-keygen -F "$FRONT_HOST" -f "$KNOWN_HOSTS" | awk 'NF && $1 !~ /^#/ {print $2, $3}' | ssh-keygen -lf - 2>/dev/null | awk '{print $2}' | head -1)"
if [[ "$ACTUAL_FRONT_HOST_KEY" != "$EXPECTED_FRONT_HOST_KEY" ]]; then
echo "PINNED_FRONT_HOST_KEY_MISMATCH" >&2
exit 1
fi
cat >"$SSH_CONFIG.tmp" <<EOF
Host guanghu-zhulan-front
HostName $FRONT_HOST
User zhulan-proxy
Port 22
IdentityFile $KEY_FILE
IdentitiesOnly yes
UserKnownHostsFile $KNOWN_HOSTS
StrictHostKeyChecking yes
BatchMode yes
RequestTTY no
ExitOnForwardFailure yes
ServerAliveInterval 30
ServerAliveCountMax 3
RemoteForward 127.0.0.1:17631 127.0.0.1:17631
EOF
chown root:zhulan-tunnel "$SSH_CONFIG.tmp"
chmod 0640 "$SSH_CONFIG.tmp"
mv "$SSH_CONFIG.tmp" "$SSH_CONFIG"
cat >"$SERVICE_FILE.tmp" <<'EOF'
[Unit]
Description=Zhulan SG003 to GZ006 loopback-only reverse proxy tunnel
After=network-online.target zhulan-remote-cell.service
Wants=network-online.target
Requires=zhulan-remote-cell.service
[Service]
Type=simple
User=zhulan-tunnel
Group=zhulan-tunnel
ExecStart=/usr/bin/ssh -F /etc/guanghu/zhulan-front-tunnel/ssh_config -NT guanghu-zhulan-front
Restart=always
RestartSec=5
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ReadOnlyPaths=/etc/guanghu/zhulan-front-tunnel
StateDirectory=guanghu/zhulan-front-tunnel
[Install]
WantedBy=multi-user.target
EOF
chown root:root "$SERVICE_FILE.tmp"
chmod 0644 "$SERVICE_FILE.tmp"
mv "$SERVICE_FILE.tmp" "$SERVICE_FILE"
systemctl daemon-reload
systemctl enable --now zhulan-front-tunnel.service
for _ in $(seq 1 20); do
if systemctl is-active --quiet zhulan-front-tunnel.service; then
systemctl show zhulan-front-tunnel.service -p ActiveState -p SubState -p MainPID
exit 0
fi
sleep 1
done
systemctl status zhulan-front-tunnel.service --no-pager >&2 || true
exit 1

View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$(id -u)" -ne 0 ]]; then
echo "INSTALL_REQUIRES_ROOT" >&2
exit 1
fi
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-12-12-ubuntu}"
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-7a500f2d-9aed-4b93-b3b8-59c87c65d031}"
ACTUAL_HOST="$(hostname)"
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
echo "TARGET_IDENTITY_MISMATCH" >&2
exit 1
fi
CONFIG_ROOT="/etc/guanghu/zhulan-front-tunnel"
KEY_FILE="$CONFIG_ROOT/id_ed25519"
getent passwd zhulan-tunnel >/dev/null || {
echo "TUNNEL_USER_MUST_BE_PRECREATED" >&2
exit 1
}
install -d -o root -g zhulan-tunnel -m 0750 "$CONFIG_ROOT"
install -d -o zhulan-tunnel -g zhulan-tunnel -m 0700 /var/lib/guanghu/zhulan-front-tunnel
if [[ ! -f "$KEY_FILE" ]]; then
ssh-keygen -q -t ed25519 -N '' -C 'zhulan-sg003-to-gz006-loopback-only' -f "$KEY_FILE"
fi
chown root:zhulan-tunnel "$KEY_FILE" "$KEY_FILE.pub"
chmod 0640 "$KEY_FILE"
chmod 0644 "$KEY_FILE.pub"
ssh-keygen -lf "$KEY_FILE.pub"
echo "TUNNEL_PUBLIC_KEY_FILE=$KEY_FILE.pub"

View file

@ -0,0 +1,10 @@
# Ubuntu 24.04 restricts unprivileged user namespaces unless the executable
# has an AppArmor profile that explicitly allows userns. This profile applies
# only to the root-owned Zhulan bwrap copy; that binary is executable only by
# root and the zhulan-runtime group.
abi <abi/4.0>,
include <tunables/global>
profile zhulan-remote-cell-bwrap /opt/guanghu/zhulan-remote-cell/runtime/zhulan-bwrap flags=(unconfined) {
userns,
}

View file

@ -0,0 +1,17 @@
ZHULAN_BIND=127.0.0.1
ZHULAN_PORT=17631
ZHULAN_DB=/var/lib/guanghu/zhulan-remote-cell/state.sqlite3
ZHULAN_SECRET_FILE=/etc/guanghu/secrets/zhulan-remote-cell.secret
ZHULAN_POLICY=/opt/guanghu/zhulan-remote-cell/policy.json
ZHULAN_UI_DIR=/opt/guanghu/zhulan-remote-cell/ui
ZHULAN_WORKSPACE_ROOT=/srv/guanghu/zhulan-cell/workspaces
ZHULAN_CANDIDATE_ROOT=/srv/guanghu/zhulan-cell/candidates
ZHULAN_FORGEJO_VERIFY_URL=https://guanghulab.com/code/api/v1/user
ZHULAN_OWNER_LOGIN=bingshuo
ZHULAN_COOKIE_SECURE=1
ZHULAN_COOKIE_PATH=/zhulan/
ZHULAN_PUBLIC_CREATE_LIMIT=12
ZHULAN_OWNER_LOGIN_LIMIT=8
ZHULAN_OAUTH_REGISTER_LIMIT=20
ZHULAN_BWRAP=/opt/guanghu/zhulan-remote-cell/runtime/zhulan-bwrap
ZHULAN_VALIDATION_SOCKET=/run/guanghu/zhulan-validation/executor.sock

View file

@ -0,0 +1,37 @@
[Unit]
Description=Guanghu Zhulan Restricted Remote Development Cell
After=network-online.target zhulan-validation-executor.service
Wants=network-online.target
Requires=zhulan-validation-executor.service
[Service]
Type=simple
User=zhulan-runtime
Group=zhulan-runtime
EnvironmentFile=/etc/guanghu/zhulan-remote-cell.env
ExecStart=/usr/bin/python3 /opt/guanghu/zhulan-remote-cell/runtime/zhulan_cell.py
Restart=on-failure
RestartSec=3
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
RestrictNamespaces=user mnt pid net ipc uts
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
SystemCallArchitectures=native
ReadOnlyPaths=/opt/guanghu/zhulan-remote-cell /etc/guanghu/zhulan-remote-cell.env /etc/guanghu/secrets/zhulan-remote-cell.secret
ReadWritePaths=/var/lib/guanghu/zhulan-remote-cell
ReadWritePaths=/srv/guanghu/zhulan-cell/workspaces
ReadWritePaths=/srv/guanghu/zhulan-cell/candidates
StateDirectory=guanghu/zhulan-remote-cell
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,37 @@
[Unit]
Description=Zhulan local-only allowlisted validation executor
After=local-fs.target
Before=zhulan-remote-cell.service
[Service]
Type=simple
User=zhulan-runtime
Group=zhulan-runtime
EnvironmentFile=/etc/guanghu/zhulan-remote-cell.env
ExecStart=/usr/bin/python3 /opt/guanghu/zhulan-remote-cell/runtime/zhulan_validation_executor.py
Restart=always
RestartSec=3
UMask=0077
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=user mnt pid net ipc uts
SystemCallArchitectures=native
RuntimeDirectory=guanghu/zhulan-validation
RuntimeDirectoryMode=0700
ReadOnlyPaths=/opt/guanghu/zhulan-remote-cell /etc/guanghu/zhulan-remote-cell.env
ReadOnlyPaths=/srv/guanghu/zhulan-cell/workspaces
InaccessiblePaths=/etc/guanghu/secrets
ReadOnlyPaths=/var/lib/guanghu/zhulan-remote-cell
InaccessiblePaths=/srv/guanghu/zhulan-cell/candidates
[Install]
WantedBy=multi-user.target