Use host-managed SSH accounts for browser terminal
This commit is contained in:
@@ -107,21 +107,11 @@ Default endpoints:
|
|||||||
|
|
||||||
## Lab 3 Browser Terminal
|
## Lab 3 Browser Terminal
|
||||||
|
|
||||||
Linux and WSL deployments now require a managed `student` password hash before `./labctl up` or `./labctl preflight`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export COURSEWARE_STUDENT_PASSWORD_HASH="$(openssl passwd -6 'student-password')"
|
|
||||||
./labctl up
|
|
||||||
```
|
|
||||||
|
|
||||||
The deployment will:
|
The deployment will:
|
||||||
|
|
||||||
- create the managed `student` account
|
|
||||||
- create `/home/student/lab3`
|
|
||||||
- bind `sshd` to `127.0.0.1:22` only
|
- bind `sshd` to `127.0.0.1:22` only
|
||||||
- install WeTTY and expose it at `http://127.0.0.1:7681/wetty`
|
- install WeTTY and expose it at `http://127.0.0.1:7681/wetty`
|
||||||
|
- leave login identity management to the host, so any existing local account with password-based SSH access can sign in through the browser terminal
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ courseware_promptfoo_dir: "{{ courseware_lab6_dir }}"
|
|||||||
courseware_wiki_repo_dir: "{{ courseware_repos_dir }}/LLM-Labs"
|
courseware_wiki_repo_dir: "{{ courseware_repos_dir }}/LLM-Labs"
|
||||||
courseware_wiki_runtime_config_path: "{{ courseware_wiki_repo_dir }}/public/courseware-runtime.json"
|
courseware_wiki_runtime_config_path: "{{ courseware_wiki_repo_dir }}/public/courseware-runtime.json"
|
||||||
courseware_llama_cpp_bin_dir: "{{ courseware_repos_dir }}/llama.cpp/build/bin"
|
courseware_llama_cpp_bin_dir: "{{ courseware_repos_dir }}/llama.cpp/build/bin"
|
||||||
courseware_lab3_dir: "/home/student/lab3"
|
|
||||||
|
|
||||||
courseware_bind_host: "0.0.0.0"
|
courseware_bind_host: "0.0.0.0"
|
||||||
courseware_url_host: "127.0.0.1"
|
courseware_url_host: "127.0.0.1"
|
||||||
@@ -70,8 +69,6 @@ courseware_node_runtime_version: "20.20.2"
|
|||||||
courseware_wetty_spec: "wetty@2.5.0"
|
courseware_wetty_spec: "wetty@2.5.0"
|
||||||
courseware_wetty_base_path: "/wetty"
|
courseware_wetty_base_path: "/wetty"
|
||||||
courseware_wiki_repo: "https://git.zuccaro.me/bzuccaro/LLM-Labs.git"
|
courseware_wiki_repo: "https://git.zuccaro.me/bzuccaro/LLM-Labs.git"
|
||||||
courseware_student_username: "student"
|
|
||||||
courseware_student_password_hash: "{{ lookup('env', 'COURSEWARE_STUDENT_PASSWORD_HASH') | default('', true) }}"
|
|
||||||
|
|
||||||
courseware_open_webui_spec: "open-webui"
|
courseware_open_webui_spec: "open-webui"
|
||||||
courseware_embedding_atlas_spec: "embedding-atlas"
|
courseware_embedding_atlas_spec: "embedding-atlas"
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
- name: Fail when student password hash is not configured
|
|
||||||
fail:
|
|
||||||
msg: >-
|
|
||||||
Set COURSEWARE_STUDENT_PASSWORD_HASH in the environment before running ./labctl up.
|
|
||||||
Example:
|
|
||||||
export COURSEWARE_STUDENT_PASSWORD_HASH="$(openssl passwd -6 'student-password')"
|
|
||||||
when: courseware_student_password_hash | trim | length == 0
|
|
||||||
|
|
||||||
- name: Install terminal prerequisites
|
- name: Install terminal prerequisites
|
||||||
become: true
|
become: true
|
||||||
apt:
|
apt:
|
||||||
@@ -79,84 +71,6 @@
|
|||||||
- ansible_service_mgr != "systemd"
|
- ansible_service_mgr != "systemd"
|
||||||
- courseware_terminal_sshd_pid.rc != 0
|
- courseware_terminal_sshd_pid.rc != 0
|
||||||
|
|
||||||
- name: Ensure managed terminal user exists
|
|
||||||
become: true
|
|
||||||
user:
|
|
||||||
name: "{{ courseware_student_username }}"
|
|
||||||
password: "{{ courseware_student_password_hash }}"
|
|
||||||
shell: /bin/bash
|
|
||||||
create_home: true
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Ensure lab 3 workspace root exists
|
|
||||||
become: true
|
|
||||||
file:
|
|
||||||
path: "{{ courseware_lab3_dir }}"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Ensure lab 3 WhiteRabbitNeo workspace exists
|
|
||||||
become: true
|
|
||||||
file:
|
|
||||||
path: "{{ courseware_lab3_dir }}/WhiteRabbitNeo"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Write lab 3 workspace README
|
|
||||||
become: true
|
|
||||||
template:
|
|
||||||
src: lab3-workspace-readme.txt.j2
|
|
||||||
dest: "{{ courseware_lab3_dir }}/README.txt"
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Check for repo-local WhiteRabbitNeo base repo
|
|
||||||
stat:
|
|
||||||
path: "{{ courseware_root }}/assets/lab2/WhiteRabbitNeo-V3-7B"
|
|
||||||
register: courseware_lab3_base_repo_stat
|
|
||||||
|
|
||||||
- name: Check for repo-local WhiteRabbitNeo GGUF directory
|
|
||||||
stat:
|
|
||||||
path: "{{ courseware_root }}/assets/lab2/WhiteRabbitNeo_WhiteRabbitNeo-V3-7B-GGUF"
|
|
||||||
register: courseware_lab3_gguf_repo_stat
|
|
||||||
|
|
||||||
- name: Link WhiteRabbitNeo base repo into the student workspace when repo-local assets exist
|
|
||||||
become: true
|
|
||||||
file:
|
|
||||||
src: "{{ courseware_root }}/assets/lab2/WhiteRabbitNeo-V3-7B"
|
|
||||||
dest: "{{ courseware_lab3_dir }}/WhiteRabbitNeo/WhiteRabbitNeo-V3-7B"
|
|
||||||
state: link
|
|
||||||
force: true
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
when: courseware_lab3_base_repo_stat.stat.exists
|
|
||||||
|
|
||||||
- name: Link WhiteRabbitNeo GGUF directory into the student workspace when repo-local assets exist
|
|
||||||
become: true
|
|
||||||
file:
|
|
||||||
src: "{{ courseware_root }}/assets/lab2/WhiteRabbitNeo_WhiteRabbitNeo-V3-7B-GGUF"
|
|
||||||
dest: "{{ courseware_lab3_dir }}/WhiteRabbitNeo/WhiteRabbitNeo_WhiteRabbitNeo-V3-7B-GGUF"
|
|
||||||
state: link
|
|
||||||
force: true
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
when: courseware_lab3_gguf_repo_stat.stat.exists
|
|
||||||
|
|
||||||
- name: Link WhiteRabbitNeo download helper into the student workspace
|
|
||||||
become: true
|
|
||||||
file:
|
|
||||||
src: "{{ courseware_lab2_dir }}/download_whiterabbitneo-gguf.sh"
|
|
||||||
dest: "{{ courseware_lab3_dir }}/download_whiterabbitneo-gguf.sh"
|
|
||||||
state: link
|
|
||||||
force: true
|
|
||||||
owner: "{{ courseware_student_username }}"
|
|
||||||
group: "{{ courseware_student_username }}"
|
|
||||||
|
|
||||||
- name: Create contained WeTTY directory
|
- name: Create contained WeTTY directory
|
||||||
file:
|
file:
|
||||||
path: "{{ courseware_wetty_dir }}"
|
path: "{{ courseware_wetty_dir }}"
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
This workspace is managed for the Lab 3 browser terminal.
|
|
||||||
|
|
||||||
You should log in as:
|
|
||||||
- username: {{ courseware_student_username }}
|
|
||||||
|
|
||||||
Start here:
|
|
||||||
- working directory: {{ courseware_lab3_dir }}
|
|
||||||
|
|
||||||
Helpful paths:
|
|
||||||
- WhiteRabbitNeo helper: {{ courseware_lab3_dir }}/download_whiterabbitneo-gguf.sh
|
|
||||||
- repo-local base repo symlink: {{ courseware_lab3_dir }}/WhiteRabbitNeo/WhiteRabbitNeo-V3-7B
|
|
||||||
- repo-local GGUF symlink: {{ courseware_lab3_dir }}/WhiteRabbitNeo/WhiteRabbitNeo_WhiteRabbitNeo-V3-7B-GGUF
|
|
||||||
|
|
||||||
Some symlinks only appear after the corresponding repo-local lab assets are present.
|
|
||||||
@@ -6,7 +6,6 @@ PasswordAuthentication yes
|
|||||||
KbdInteractiveAuthentication no
|
KbdInteractiveAuthentication no
|
||||||
ChallengeResponseAuthentication no
|
ChallengeResponseAuthentication no
|
||||||
UsePAM yes
|
UsePAM yes
|
||||||
AllowUsers {{ courseware_student_username }}
|
|
||||||
AllowTcpForwarding no
|
AllowTcpForwarding no
|
||||||
X11Forwarding no
|
X11Forwarding no
|
||||||
PrintMotd no
|
PrintMotd no
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
{
|
{
|
||||||
"lab3TerminalUrl": "http://{{ courseware_url_host }}:{{ courseware_ports.wetty }}{{ courseware_wetty_base_path }}",
|
"lab3TerminalUrl": "http://{{ courseware_url_host }}:{{ courseware_ports.wetty }}{{ courseware_wetty_base_path }}"
|
||||||
"lab3Username": "{{ courseware_student_username }}",
|
|
||||||
"lab3WorkingDirectory": "{{ courseware_lab3_dir }}"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ TRANSFORMERLAB_DEFAULT_USER_EMAIL="{{ courseware_transformerlab_default_user_ema
|
|||||||
TRANSFORMERLAB_DEFAULT_USER_PASSWORD="{{ courseware_transformerlab_default_user_password }}"
|
TRANSFORMERLAB_DEFAULT_USER_PASSWORD="{{ courseware_transformerlab_default_user_password }}"
|
||||||
TRANSFORMERLAB_DEFAULT_USER_FIRST_NAME="{{ courseware_transformerlab_default_user_first_name }}"
|
TRANSFORMERLAB_DEFAULT_USER_FIRST_NAME="{{ courseware_transformerlab_default_user_first_name }}"
|
||||||
TRANSFORMERLAB_DEFAULT_USER_LAST_NAME="{{ courseware_transformerlab_default_user_last_name }}"
|
TRANSFORMERLAB_DEFAULT_USER_LAST_NAME="{{ courseware_transformerlab_default_user_last_name }}"
|
||||||
COURSEWARE_STUDENT_USERNAME="{{ courseware_student_username }}"
|
|
||||||
COURSEWARE_LAB3_DIR="{{ courseware_lab3_dir }}"
|
|
||||||
UNSLOTH_BIN="{{ ansible_env.HOME }}/.local/bin/unsloth"
|
UNSLOTH_BIN="{{ ansible_env.HOME }}/.local/bin/unsloth"
|
||||||
PROMPTFOO_DIR="{{ courseware_promptfoo_dir }}"
|
PROMPTFOO_DIR="{{ courseware_promptfoo_dir }}"
|
||||||
PROMPTFOO_BIN="{{ courseware_tools_dir }}/promptfoo/node_modules/.bin/promptfoo"
|
PROMPTFOO_BIN="{{ courseware_tools_dir }}/promptfoo/node_modules/.bin/promptfoo"
|
||||||
|
|||||||
@@ -49,31 +49,6 @@ Pinned component versions:
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
require_student_password_hash() {
|
|
||||||
local current_host_profile
|
|
||||||
|
|
||||||
current_host_profile=$(host_profile)
|
|
||||||
if [ "$current_host_profile" = "macos" ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${COURSEWARE_STUDENT_PASSWORD_HASH:-}" ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat <<'EOF' >&2
|
|
||||||
Missing COURSEWARE_STUDENT_PASSWORD_HASH.
|
|
||||||
|
|
||||||
Set a password hash for the managed `student` login before running this command. Example:
|
|
||||||
|
|
||||||
export COURSEWARE_STUDENT_PASSWORD_HASH="$(openssl passwd -6 'student-password')"
|
|
||||||
|
|
||||||
Then rerun:
|
|
||||||
./labctl up
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm_installation() {
|
confirm_installation() {
|
||||||
local response
|
local response
|
||||||
local tlab_version
|
local tlab_version
|
||||||
@@ -552,7 +527,6 @@ main() {
|
|||||||
case "$cmd" in
|
case "$cmd" in
|
||||||
up)
|
up)
|
||||||
confirm_installation
|
confirm_installation
|
||||||
require_student_password_hash
|
|
||||||
run_playbook up.yml
|
run_playbook up.yml
|
||||||
run_project_script "$ROOT_DIR/scripts/service_manager.sh" start all
|
run_project_script "$ROOT_DIR/scripts/service_manager.sh" start all
|
||||||
;;
|
;;
|
||||||
@@ -562,7 +536,6 @@ main() {
|
|||||||
;;
|
;;
|
||||||
preflight)
|
preflight)
|
||||||
confirm_installation
|
confirm_installation
|
||||||
require_student_password_hash
|
|
||||||
run_playbook up.yml --tags preflight
|
run_playbook up.yml --tags preflight
|
||||||
;;
|
;;
|
||||||
versions)
|
versions)
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ load_runtime_env() {
|
|||||||
: "${COURSEWARE_WIKI_PORT:=80}"
|
: "${COURSEWARE_WIKI_PORT:=80}"
|
||||||
: "${COURSEWARE_WETTY_PORT:=7681}"
|
: "${COURSEWARE_WETTY_PORT:=7681}"
|
||||||
: "${COURSEWARE_WETTY_BASE_PATH:=/wetty}"
|
: "${COURSEWARE_WETTY_BASE_PATH:=/wetty}"
|
||||||
: "${COURSEWARE_STUDENT_USERNAME:=student}"
|
|
||||||
: "${COURSEWARE_LAB3_DIR:=/home/student/lab3}"
|
|
||||||
: "${NODE_RUNTIME_BIN_DIR:=$COURSEWARE_STATE_DIR/tools/node-runtime/node_modules/node/bin}"
|
: "${NODE_RUNTIME_BIN_DIR:=$COURSEWARE_STATE_DIR/tools/node-runtime/node_modules/node/bin}"
|
||||||
: "${WETTY_BIN:=$COURSEWARE_STATE_DIR/tools/wetty/node_modules/.bin/wetty}"
|
: "${WETTY_BIN:=$COURSEWARE_STATE_DIR/tools/wetty/node_modules/.bin/wetty}"
|
||||||
: "${PROMPTFOO_DIR:=$COURSEWARE_STATE_DIR/lab6}"
|
: "${PROMPTFOO_DIR:=$COURSEWARE_STATE_DIR/lab6}"
|
||||||
|
|||||||
@@ -29,11 +29,6 @@ ensure_transformerlab_default_user() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_wetty_prereqs() {
|
check_wetty_prereqs() {
|
||||||
if ! id "$COURSEWARE_STUDENT_USERNAME" >/dev/null 2>&1; then
|
|
||||||
echo "Missing terminal user '$COURSEWARE_STUDENT_USERNAME'. Re-run ./labctl up after setting COURSEWARE_STUDENT_PASSWORD_HASH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -x "$WETTY_BIN" ]; then
|
if [ ! -x "$WETTY_BIN" ]; then
|
||||||
echo "Missing WeTTY binary at $WETTY_BIN. Re-run ./labctl up." >&2
|
echo "Missing WeTTY binary at $WETTY_BIN. Re-run ./labctl up." >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -44,11 +39,6 @@ check_wetty_prereqs() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "$COURSEWARE_LAB3_DIR" ]; then
|
|
||||||
echo "Missing lab workspace at $COURSEWARE_LAB3_DIR. Re-run ./labctl up." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! python3 - <<'PY'
|
if ! python3 - <<'PY'
|
||||||
import socket, sys
|
import socket, sys
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|||||||
Reference in New Issue
Block a user