A stripped-down Rust implementation of NERSC's SSH Proxy client that securely stores credentials in system credential storage and automatically generates TOTP codes.
- Features
- Installation
- Quick Start
- Configuration
- Usage
- How It Works
- Security
- Troubleshooting
- Development
- Comparison with Original
- Contributing
- License
- Secure credential storage using macOS Keychain or Linux kernel keyring
- Automatic TOTP generation from stored secret
- Async REST API calls using reqwest
- Minimal dependencies and clean code
- Proper file permissions (600 for private keys)
- Cross-platform support for macOS and Linux
- Certificate validation and automatic expiry display
- Operating System: macOS or Linux
- Rust: Latest stable version recommended (minimum 1.70+)
- SSH Tools:
ssh-keygenmust be available in your PATH
# Clone the repository
git clone https://github.com/aryabhatt/sshproxy-rust.git
cd sshproxy-rust
# Build and install
cargo build --release
cargo install --path .The binary will be installed to $HOME/.cargo/bin/sshproxy-rust
Install a specific version directly from GitHub:
# Install latest release
cargo install --git https://github.com/aryabhatt/sshproxy-rust
# Install specific version
cargo install --git https://github.com/aryabhatt/sshproxy-rust --tag v2.0.0Step 1: Store your NERSC password
sshproxy-rust --update-passwordYou will be prompted to enter your NERSC password securely.
Step 2: Store your NERSC TOTP secret
sshproxy-rust --update-secretYou will be prompted to enter your TOTP secret. This not the 6-digit code from authenticator app. Visit NERSC is generate a MFA Secret.
Note: Both credentials must be set before you can generate SSH keys.
Step 3: Generate SSH certificate
sshproxy-rustThis will generate your SSH key pair and certificate.
$ sshproxy-rust
Generating TOTP code...
Requesting certificate from NERSC...
✓ Certificate saved to ~/.ssh/nersc-cert.pub
✓ Private key saved to ~/.ssh/nersc
✓ Public key saved to ~/.ssh/nersc.pubThe tool saves SSH keys and certificates to the following locations:
- Private key:
~/.ssh/nersc - Certificate:
~/.ssh/nersc-cert.pub - Public key:
~/.ssh/nersc.pub
All keys are automatically set to 600 permissions (owner read/write only).
Credentials are stored securely in system-native credential storage:
-
macOS: Keychain
- Service:
NERSC(password) - Service:
NERSC_SECRET(TOTP secret) - Security level: Same as Safari passwords
- Service:
-
Linux: Kernel keyring
- Session keyring: Persists until logout
- For persistent storage across reboots, consider using
userkeyring or a password manager - Service names:
NERSCandNERSC_SECRET
Add the following to your ~/.ssh/config file:
Host perlmutter
User <your_nersc_username>
HostName perlmutter-p1.nersc.gov
IdentityFile ~/.ssh/nerscThen connect with simple commands:
ssh perlmuttersshproxy-rust [OPTIONS] [USERNAME]
Arguments:
[USERNAME] NERSC username [default: $USER environment variable]
Options:
-p, --update-password Update NERSC password in credential storage
--update-secret Update NERSC TOTP secret in credential storage
-h, --help Print help
-V, --version Print version
sshproxy-rustUses the $USER environment variable as the NERSC username.
sshproxy-rust yourusernamesshproxy-rust --update-passwordsshproxy-rust --update-secretsshproxy-rust --versionThe tool follows a six-step process to generate SSH credentials:
-
Credential Retrieval: Loads password and OTP secret from system credential storage for the current user
-
TOTP Generation: Generates current TOTP code (6-digit, 30-second interval) using SHA1 algorithm
-
API Request: POSTs to
https://sshproxy.nersc.gov/create_pair/default/with HTTP Basic Auth (username:password+OTP) -
Key Processing: Extracts private key and certificate from the combined response
-
File Management:
- Saves private key to
~/.ssh/nerscwith 600 permissions - Extracts and saves certificate to
~/.ssh/nersc-cert.pub - Generates and saves public key to
~/.ssh/nersc.pubusingssh-keygen
- Saves private key to
-
Validation: Displays certificate validity period (typically 24 hours) using
ssh-keygen -L
- Validity Period: NERSC certificates are typically valid for 24 hours
- Renewal: Simply re-run
sshproxy-rustto generate a new certificate when the old one expires - Automatic Check: The tool displays the validity period after generation
- ✅ No plaintext storage: Credentials stored in OS-native secure storage
- ✅ TOTP on-the-fly: TOTP codes generated dynamically, never stored
- ✅ Secure file permissions: Private keys automatically set to 600
- ✅ HTTPS-only: All API communication encrypted via TLS
- ✅ No credential logging: Passwords and secrets never logged
- macOS Keychain: Credentials protected by Keychain encryption, same security as Safari passwords
- Linux Kernel Keyring: Session-based storage, cleared on logout
- HTTPS Basic Auth: Password and OTP combined and sent via HTTPS Basic Authentication
- Private Key Protection: Files created with restrictive permissions from the start
- Keep your TOTP secret secure: Treat it like a password
- Rotate certificates regularly: Generate new certificates every 24 hours
- Use SSH config: Avoid typing credentials manually
- Monitor access: Check NERSC logs for unauthorized access
Cause: Password not stored in system credential storage.
Solution:
sshproxy-rust --update-passwordCause: TOTP secret not stored in system credential storage.
Solution:
sshproxy-rust --update-secretCause: OpenSSH tools not installed or not in PATH.
Solution:
- macOS: OpenSSH is pre-installed. Check your PATH.
- Linux: Install OpenSSH client:
# Debian/Ubuntu sudo apt-get install openssh-client # RHEL/CentOS/Fedora sudo dnf install openssh-clients
Cause: Incorrect file permissions or missing ~/.ssh/ directory.
Solution:
# Create .ssh directory if it doesn't exist
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Re-run sshproxy-rust (it will set correct permissions)
sshproxy-rustCause: NERSC certificates expire after 24 hours.
Solution:
# Generate a new certificate
sshproxy-rustCause: Incorrect password or TOTP secret.
Solution:
# Update password
sshproxy-rust --update-password
# Update TOTP secret
sshproxy-rust --update-secretCause: Application doesn't have Keychain access permission.
Solution:
- Open System Preferences → Security & Privacy → Privacy → Keychain
- Ensure Terminal or your terminal emulator has access
# Clone repository
git clone https://github.com/aryabhatt/sshproxy-rust.git
cd sshproxy-rust
# Build in debug mode
cargo build
# Build in release mode (optimized)
cargo build --release
# Run directly
cargo run -- --help# Build and open documentation
cargo doc --open
# Build documentation for all dependencies
cargo doc --open --document-private-itemsFeatures:
- Interactive password+OTP prompt
- Multiple output formats (PuTTY support)
- ssh-agent integration
- SOCKS proxy support
- No credential storage
- Manual OTP entry each time
Pros:
- More features
- Shell script (easy to read/modify)
Cons:
- No credential storage
- Manual OTP entry every time
- Less secure (credentials in memory/history)
Features:
- Secure credential storage
- Automatic TOTP generation
- Core functionality (key retrieval)
- Cross-platform binary
- Modern async architecture
Pros:
- Automated TOTP
- Secure credential storage
- Fast and lightweight
- Type-safe Rust implementation
Cons:
- No PuTTY format support (yet)
- No ssh-agent integration (yet)
- No SOCKS proxy support (yet)
Future Enhancements:
- ssh-agent integration
- PuTTY format export
- SOCKS proxy support
- Multiple scope support
- Custom output paths
Core dependencies:
- clap - Command-line argument parsing
- tokio - Async runtime
- reqwest - HTTP client for API requests
- security-framework - macOS Keychain access (macOS only)
- keyring - Linux kernel keyring access (Linux only)
- totp-lite - TOTP code generation
- data-encoding - Base32 decoding for TOTP secrets
- rpassword - Secure password input (no echo)
- dirs - Cross-platform home directory detection
Contributions are welcome! Here's how you can help:
- Check existing issues to avoid duplicates
- Open a new issue with:
- Description of the problem
- Steps to reproduce
- Expected vs actual behavior
- System information (OS, Rust version)
- Open an issue to discuss the feature
- Explain the use case and benefits
- Consider implementation complexity
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linters:
cargo test cargo clippy cargo fmt - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Rust standard conventions
- Run
cargo fmtbefore committing - Address all
cargo clippywarnings - Add tests for new functionality
- Update documentation as needed
BSD-3-Clause License (matching original sshproxy)
This project maintains the same license as the original NERSC sshproxy to ensure compatibility and proper attribution.
- NERSC Documentation: https://docs.nersc.gov/connect/mfa/
- API Documentation: https://aryabhatt.github.io/sshproxy-rust/sshproxy_rust/
- Original sshproxy: https://github.com/NERSC/sshproxy
A: NERSC certificates expire after 24 hours. You'll need to regenerate daily.
A: Not currently. The tool supports macOS and Linux only. Windows support may be added in the future.
A: Your TOTP secret is provided when you first set up MFA at NERSC. Check your authenticator app settings or contact NERSC support.
A: Not currently. The tool uses the standard ~/.ssh/nersc location. Custom paths may be added in a future release.
A: No, this is an independent implementation. For official tools, see NERSC's documentation.
Version: 2.0.0
Last Updated: 2024-01-15
Maintainer: @aryabhatt