本文使用2个java库示例如何免密连接ssh执行命令。
JSch
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
主要逻辑很简单,可以通过密码和密钥的形式:
final JSch sch = new JSch();
// 密钥方式
sch.setKnownHosts("~/.ssh/known_hosts");
sch.addIdentity("~/.ssh/id_rsa", "~/.ssh/id_rsa.pub", null);
final Session session = sch.getSession("test", "10.10.10.111");
// 密码方式
// session.setPassword("password");
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
final Channel sftp = session.openChannel("sftp");
sftp.connect();
session.disconnect();
Apache mina sshd
https://github.com/apache/mina-sshd
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.5.0</version>
<optional>true</optional>
</dependency>
参考jenkins实现
public static void main(String[] args) throws IOException {
final String pk = readPemFile(new File("/home/test/.ssh/id_rsa"));
sshConnection("10.10.10.111", 22, "test", false, pk);
}
/**
* 读取文件内容
*/
public static String readPemFile(File f) throws IOException {
try (InputStream is = Files.newInputStream(f.toPath());
DataInputStream dis = new DataInputStream(is)) {
byte[] bytes = new byte[(int) f.length()];
dis.readFully(bytes);
return new String(bytes);
} catch (InvalidPathException e) {
throw new IOException(e);
}
}
/**
* 获取密钥对
*/
static KeyPair getKeyPairFromString(String pk) throws IOException, NoSuchAlgorithmException {
final KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
final KeyPair keyPair = rsa.generateKeyPair();
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write(pk.getBytes());
final ObjectOutputStream o = new ObjectOutputStream(stream);
o.writeObject(keyPair);
return keyPair;
}
/**
* SSH连接
*/
private static int sshConnection(String host, int port, String user,
final boolean strictHostKey, String privateKey) throws IOException {
try (SshClient client = SshClient.setUpDefaultClient()) {
KnownHostsServerKeyVerifier verifier = new DefaultKnownHostsServerKeyVerifier(new ServerKeyVerifier() {
@Override
public boolean verifyServerKey(ClientSession clientSession, SocketAddress remoteAddress,
PublicKey serverKey) {
return !strictHostKey;
}
}, true);
client.setServerKeyVerifier(verifier);
client.start();
ConnectFuture cf = client.connect(user, host, port);
cf.await();
try (ClientSession session = cf.getSession()) {
// 这里可以加多个
// for (KeyPair pair : provider.getKeys()) {
// session.addPublicKeyIdentity(pair);
// }
// 只要主机配了免密,这里不加也可以
session.addPublicKeyIdentity(getKeyPairFromString(privateKey));
session.auth().verify(10000L);
// 这里命令可以传进来
try (ClientChannel channel = session.createExecChannel("ls /")) {
channel.setIn(new NoCloseInputStream(System.in));
channel.setOut(new NoCloseOutputStream(System.out));
channel.setErr(new NoCloseOutputStream(System.err));
WaitableFuture wf = channel.open();
wf.await();
Set<ClientChannelEvent> waitMask =
channel.waitFor(Collections.singletonList(ClientChannelEvent.CLOSED), 0L);
if (waitMask.contains(ClientChannelEvent.TIMEOUT)) {
System.err.println("超时");
}
return channel.getExitStatus();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
client.stop();
}
}
return 0;
}