• Stars
    star
    227
  • Rank 175,900 (Top 4 %)
  • Language
    Clojure
  • Created over 14 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

SSH commands via jsch

Clojars Project cljdoc badge CircleCI

clj-ssh

SSH in clojure. Uses jsch. (See section RSA Private Key format if using openssl generated keys)

Usage

REPL

The clj-ssh.cli namespace provides some functions for ease of use at the REPL.

(use 'clj-ssh.cli)

Use ssh to execute a command, say ls, on a remote host "my-host",

(ssh "my-host" "ls")
  => {:exit 0 :out "file1\nfile2\n" :err "")

By default this will use the system ssh-agent to obtain your ssh keys, and it uses your current username, but this can be specified:

(ssh "my-host" "ls" :username "remote-user")
  => {:exit 0 :out "file1\nfile2\n" :err "")

Strict host key checking can be turned off:

(default-session-options {:strict-host-key-checking :no})

SFTP is also supported. For example, to copy a local file to a remote host "my-host":

(sftp "my-host" :put "/from/this/path" "to/this/path")

Note that any sftp commands that change the state of the sftp session (such as cd) do not work with the simplified interface, as a new session is created each time.

If your key has a passphrase, you will need to explicitly add your key either to the system's ssh-agent, or to clj-ssh's ssh-agent with the appropriate add-identity call.

Non REPL

The clj-ssh.ssh namespace should be used for SSH from functional code.

(let [agent (ssh-agent {})]
  (let [session (session agent "host-ip" {:strict-host-key-checking :no})]
    (with-connection session
      (let [result (ssh session {:in "echo hello"})]
        (println (result :out)))
      (let [result (ssh session {:cmd "ls"})]
        (println (second result)))))))

The above example shows using :in to pass commands to a shell, and using :cmd to exec a command without a shell. When using :cmd you can still pass a stream or a string to :in to be used as the process' standard input.

By default, the system ssh-agent is used, which means the ssh keys you use at the command line level should automatically be picked up (this should also work with pageant on windows).

You can forward the ssh-agent, which allows you to run ssh based commands on the remote host using the credentials in your local ssh-agent:

(let [agent (ssh-agent {})]
  (let [session (session agent "host-ip" {:strict-host-key-checking :no})]
    (with-connection session
      (let [result (ssh session {:in "ssh somehost ls" :agent-forwarding true})]
        (println (result :out))))))

If you prefer not to use the system ssh-agent, or one is not running on your system, then a local, isolated ssh-agent can be used.

(let [agent (ssh-agent {:use-system-ssh-agent false})]
  (add-identity agent {:private-key-path "/user/name/.ssh/id_rsa"})
  (let [session (session agent "host-ip" {:strict-host-key-checking :no})]
    (with-connection session
      (let [result (ssh session {:in "echo hello"})]
        (println (result :out)))))

SFTP is supported:

(let [agent (ssh-agent {})]
  (let [session (session agent "host-ip" {:strict-host-key-checking :no})]
    (with-connection session
      (let [channel (ssh-sftp session)]
        (with-channel-connection channel
          (sftp channel {} :cd "/remote/path")
          (sftp channel {} :put "/some/file" "filename"))))))

SSH tunneling is also supported:

    (let [agent (ssh-agent {})]
      (let [session (session agent "host-ip" {:strict-host-key-checking :no})]
        (with-connection session
          (with-local-port-forward [session 8080 80]
            (comment do something with port 8080 here)))))

Jump hosts can be used with the jump-session. Once the session is connected, the the-session function can be used to obtain a session that can be used with ssh-exec, etc. The the-session function can be used on a session returned by session, so you can write code that works with both a jump-session session and a single host session.

(let [s (jump-session
         (ssh-agent {})
         [{:hostname "host1" :username "user"
           :strict-host-key-checking :no}
          {:hostname "final-host" :username "user"
           :strict-host-key-checking :no}]
         {})]
  (with-connection s
    (ssh-exec (the-session s) "ls" "" "" {}))

Documentation

Annotated source. API.

RSA Private Key Format and clj-ssh

There have been changes to the header of RSA Private Keys. With the upgrade of com.jcraft/jsch to "0.1.55", the older openssh headers work with ssh will throw an authentication failure.

Older format

-----BEGIN OPENSSH PRIVATE KEY-----`

New RSA format

-----BEGIN RSA PRIVATE KEY-----

Old private keys can be easily converted to the new format, through the use of ssh-keygen's passphrase changing command. This will change the file in place.

ssh-keygen -p -f privateKeyFile -m pem -P passphrase -N passphrase

The -m flag will force the file to pem format, fixing the header.
The -P (for old passphrase) and -N (new passphrase) can be ommitted to generate an interactive query instead. (enter "" at either -P or -N to identify no passphrase)

Note: clj-ssh key generation

clj-ssh does have the ability to generate the public / private key pairs for both RSA and DSA (found in clj-ssh.ssh/generate-keypair).

Unlike ssh-keygen, the RSA passphrase on the private key will be limited to
DES-EDE3-CBC DEK format to encrypt/decrypt the passphrase if created within clj-ssh. ssh-keygen will likely use what is standard in your operating system's crypto suite, (e.g. AES-128-CBC)

FAQ

Q: What does "4: Failure @ com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2289)" during an sftp transfer signify?

A: Probably a disk full, or permission error.

TTY's and background processes

Some useful links about ssh and background processes:

Thanks to Ryan Stradling for these.

Installation

Via clojars and Leiningen.

:dependencies [clj-ssh "0.5.14"]

or your favourite maven repository aware tool.

Tests

The test rely on several keys being authorized on localhost:

ssh-keygen -f ~/.ssh/clj_ssh -t rsa -C "key for test clj-ssh" -N ""
ssh-keygen -f ~/.ssh/clj_ssh_pp -t rsa -C "key for test clj-ssh" -N "clj-ssh"
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
echo "from=\"localhost\" $(cat ~/.ssh/clj_ssh.pub)" >> ~/.ssh/authorized_keys
echo "from=\"localhost\" $(cat ~/.ssh/clj_ssh_pp.pub)" >> ~/.ssh/authorized_keys

The clj_ssh_pp key should have a passphrase, and should be registered with your ssh-agent.

ssh-add ~/.ssh/clj_ssh_pp

On OS X, use:

ssh-add -K ~/.ssh/clj_ssh_pp

Other Libraries

For plain ftp, you might want to look at clj-ftp.

License

Copyright © 2012 Hugo Duncan

Licensed under EPL

More Repositories

1

aleph

Asynchronous streaming communication for Clojure - web server, web client, and raw TCP/UDP
Clojure
2,544
star
2

kibit

There's a function for that!
Clojure
1,765
star
3

seesaw

Seesaw turns the Horror of Swing into a friendly, well-documented, Clojure library
Clojure
1,445
star
4

manifold

A compatibility layer for event-driven abstractions
Clojure
1,017
star
5

etaoin

Pure Clojure Webdriver protocol implementation
Clojure
913
star
6

marginalia

Ultra-lightweight literate programming for clojure inspired by docco
Clojure
816
star
7

secretary

A client-side router for ClojureScript.
Clojure
773
star
8

hickory

HTML as data
Clojure
634
star
9

claypoole

Claypoole: Threadpool tools for Clojure
Clojure
607
star
10

pretty

Library for helping print things prettily, in Clojure - ANSI fonts, formatted exceptions
Clojure
597
star
11

rewrite-clj

Rewrite Clojure code and edn
Clojure
576
star
12

potemkin

some ideas which are almost good
Clojure
568
star
13

pomegranate

A sane Clojure API for Maven Artifact Resolver + dynamic runtime modification of the classpath
Clojure
504
star
14

gloss

speaks in bytes, so you don't have to
Clojure
483
star
15

camel-snake-kebab

A Clojure[Script] library for word case conversions
Clojure
476
star
16

cljss

Clojure Style Sheets — CSS-in-JS for ClojureScript
Clojure
455
star
17

clooj

clooj, a lightweight IDE for clojure
Clojure
421
star
18

byte-streams

A Rosetta stone for JVM byte representations
Clojure
417
star
19

durable-queue

a disk-backed queue for clojure
Clojure
381
star
20

useful

Some Clojure functions we use all the time, and so can you.
Clojure
365
star
21

metrics-clojure

A thin façade around Coda Hale's metrics library.
Clojure
343
star
22

virgil

Recompile Java code without restarting the REPL
Clojure
302
star
23

citrus

State management library for Rum
Clojure
274
star
24

ordered

Ordered sets and maps, implemented in pure clojure
Clojure
253
star
25

dirigiste

centrally-planned object and thread pools
Java
204
star
26

iapetos

A Clojure Prometheus Client
Clojure
176
star
27

primitive-math

for the discerning arithmetician
Clojure
170
star
28

humanize

Produce human readable strings in clojure
Clojure
156
star
29

digest

Digest algorithms (md5, sha1 ...) for Clojure
Clojure
156
star
30

clj-yaml

YAML encoding and decoding for Clojure
Clojure
120
star
31

byte-transforms

methods for hashing, compressing, and encoding bytes
Clojure
104
star
32

ring-buffer

A persistent ring-buffer in Clojure
Clojure
96
star
33

tentacles

An Octocat is nothing without his tentacles
Clojure
80
star
34

fs

File system utilities for Clojure. (forked from Raynes/fs)
Clojure
72
star
35

lein-marginalia

A Marginalia plugin to Leiningen
HTML
69
star
36

meta

A meta-repo for clj-commons discussions
46
star
37

ring-gzip-middleware

GZIP your Ring responses
Clojure
41
star
38

rewrite-cljs

Traverse and rewrite Clojure/ClojureScript/EDN from ClojureScript
Clojure
41
star
39

formatter

Building blocks and discussion for building a common Clojure code formatter
36
star
40

vizdeps

Visualize Leiningen dependencies using Graphviz
Clojure
33
star
41

zprint-clj

Node.js wrapper for ZPrint Clojure source code formatter
Clojure
13
star
42

infra

Infrastructure for clj-commons
Clojure
2
star
43

clj-commons.github.io

Clojure Commons Site
HTML
1
star