Skip to content

Yubo-Cao/calsh

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

calsh

One-command SSH into Caltech HPC with the Duo step handled silently. Built on a generalist headless-Duo-Mobile CLI for Linux, with desktop notifications and verified-push (number challenge) support.

$ calsh
$ # ...you are now on login.hpc.caltech.edu. No phone tap. No prompt.

If you SSH into a Duo-protected host a dozen times a day, calsh is what you want.


What this is

A small toolkit that turns your Linux desktop into a registered Duo Mobile device. Once enrolled (5 minutes, see docs/ENROLLMENT.md), Duo pushes for your account can be approved by your laptop instead of your phone:

  • calsh — Caltech HPC SSH wrapper. The headline command.
  • duo — generalist Linux desktop wrapper. Subcommands: listen (interactive notifier), approve, deny, passcode (HOTP code generator for "type the code" prompts), status, enroll.
  • duo-approve — bounded single-shot auto-approver, the building block under calsh and similar SSH wrappers.
  • duo-headless — the Python CLI that speaks Duo's v2 push protocol.

It is not a daemon. It is bounded and on-demand. See why.

Demo

Caltech HPC, one command:

$ calsh 'squeue -u $USER'
JOBID PARTITION  NAME     ST   TIME  NODES NODELIST(REASON)
...

Generalist desktop UX, any Duo deployment:

$ duo listen
watching api-XXXXXXXX.duosecurity.com for 300s (poll every 2.0s, mode=interactive)

…then a system notification pops up showing the requesting service, host, and (for verified push) the 3-digit code, with Approve / Deny buttons. Click Approve → login goes through.

Verified push — both flavors:

Duo has two verified-push variants. duo listen handles both:

  1. Code shown on the device (number-match) — the push includes a 3-digit code; the notification body renders it boldly so you can confirm it matches the originating site before clicking Approve:

    Code: 47 app: Caltech HPC host: login.hpc.caltech.edu

  2. Code typed into the device — the originating site shows the code, you have to enter it. On Approve, a kdialog / zenity input box pops up:

    Enter the code shown by Caltech HPC on the originating site: [ ] [Cancel] [OK]

    You read the code off the browser, type it in, hit OK. duo listen POSTs approve with the code under the right Duo parameter names. Cancel → deny.

You can also bypass the prompt with duo approve --code 47 if you already know it.

HOTP passcode (for "type a code" prompts):

Some Duo prompts ask you to type a 6-digit code instead of (or in addition to) approving a push — older SSH banners, the "Passcode" option on the Universal Prompt, web logins where push is unavailable, etc. The activation response already gives us the HMAC secret for HOTP; duo passcode exposes it:

$ duo passcode
447293
counter=12; Duo accepts a window of ~10 codes ahead, so a missed code auto-resyncs the next time you authenticate

Counter is persisted in ~/.duo-headless/hotp_counter. If it drifts ahead of the server (you generated codes without using them and then generated >10 more), duo passcode --resync N rewinds the local counter. --peek shows the next code without advancing.

Install

git clone https://github.com/Yubo-Cao/calsh ~/projects/calsh
cd ~/projects/calsh
./install.sh

install.sh will:

  • Symlink bin/duo, bin/duo-approve, bin/duo-headless into ~/.local/bin/.
  • Symlink examples/caltech/calsh into ~/.local/bin/ (only if --with-caltech or you say yes when prompted).
  • Create ~/.duo-headless/.venv and install pycryptodome + requests into it.

Then enroll the device — see docs/ENROLLMENT.md.

Requirements

  • Linux desktop. This project is Linux-only by design — the UX leans on notify-send (libnotify), paplay, and standard XDG dirs. The core protocol logic works anywhere Python does, but we don't support or test on macOS or Windows.
  • Python 3.11+, with pip available.
  • OpenSSH client. (You probably already have this.)
  • zbarimg for QR decoding during enrollment (pacman -S zbar / apt install zbar-tools).
  • notify-send from libnotify ≥ 0.7.9 if you want desktop notifications. Older versions lack the -A action-button support that duo listen uses.
  • An existing Duo Mobile account that lets you self-enroll additional devices via a device-management portal.

Why on-demand, not a daemon

Earlier iterations of this tool ran as a systemd user service polling Duo every 5 seconds, 24/7. The Duo account got flagged and disabled after roughly three weeks of that. Detail in examples/systemd/README.md.

The current architecture polls only when you've actually triggered an auth event — typing calsh, running duo listen before clicking a login button, etc. Total request volume against Duo's endpoint becomes proportional to your actual login activity, which is what a real Duo Mobile device generates. No flagging, no spam, no risk to the account.

Security

Treat ~/.duo-headless/key.pem like an SSH private key. Anyone with it can answer Duo pushes as you. Detailed caveats in docs/PROTOCOL.md.

This tool weakens your 2FA posture compared to a phone with biometric prompts — a logged-in attacker on your laptop can now approve Duo pushes without touching your phone. That's the trade-off you're making for the convenience. Don't run this on a shared machine, and don't run it on a machine you wouldn't trust with your SSH keys.

If your employer or institution forbids unofficial Duo clients, respect that — this is for your own device on your own account, with whatever institutional policy applies on top.

Layout

calsh/
├── README.md                — you are here
├── LICENSE                  — MIT
├── install.sh               — one-shot installer
├── bin/                     — generic, install-target
│   ├── duo                  — desktop wrapper (listen/approve/deny/status/enroll)
│   ├── duo-approve          — single-shot bounded approver
│   └── duo-headless         — Python CLI (v2 push protocol)
├── examples/
│   ├── caltech/             — Caltech HPC integration
│   │   ├── calsh            — the ergonomic SSH wrapper
│   │   ├── ssh-alert.sh     — heavier alt with desktop-alert fallback
│   │   ├── ssh_config.sample
│   │   └── README.md
│   └── systemd/             — "we deliberately don't ship a daemon"
│       └── README.md
└── docs/
    ├── ARCHITECTURE.md      — the pieces and why they're shaped this way
    ├── ENROLLMENT.md        — first-time setup walkthrough
    └── PROTOCOL.md          — Duo v2 push protocol notes + credits

Credits

Protocol implementation owes a lot to:

If you like this repo, star theirs too. They did the protocol archaeology.

Contributing

Issues and PRs welcome, especially:

  • Verified-push response handling for deployments where the current answer=approve flow gets rejected because it expects the code in the response body.
  • Support for non-Caltech examples/ (other universities, employer deployments). Drop a parameterized calsh-equivalent in examples/<your-org>/ and document it.
  • Wayland-native notification quirks (some compositors don't propagate -A clicks back to stdout cleanly).

License

MIT. See LICENSE.

About

One-command Caltech HPC SSH with Duo handled silently. Linux desktop wrapper for headless Duo Mobile, with notifications + verified-push support. On-demand (no daemon).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors