From e9d87b0cc68f0edabc7cb39071f32cd70656b81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9B=E5=87=BB=E7=9A=84=E9=98=BF=E6=99=A8?= Date: Fri, 17 Mar 2023 21:33:02 +0800 Subject: [PATCH] [collector] support linux ssh private key (#745) * [collector] support linux ssh private key * update ssh param privateKey type text to textarea --------- Co-authored-by: tomsun28 --- .../collector/collect/ssh/SshCollectImpl.java | 12 ++++--- .../com/usthe/collector/util/KeyPairUtil.java | 34 +++++++++++-------- .../usthe/collector/util/KeyPairUtilTest.java | 21 ++++++------ .../entity/job/protocol/SshProtocol.java | 5 +-- .../src/main/resources/define/app-centos.yml | 17 +++++++++- .../src/main/resources/define/app-linux.yml | 25 +++++++++++--- .../src/main/resources/define/app-ubuntu.yml | 25 +++++++++++--- .../monitor-edit/monitor-edit.component.html | 4 +-- .../monitor-new/monitor-new.component.html | 4 +-- 9 files changed, 101 insertions(+), 46 deletions(-) diff --git a/collector/src/main/java/com/usthe/collector/collect/ssh/SshCollectImpl.java b/collector/src/main/java/com/usthe/collector/collect/ssh/SshCollectImpl.java index 808b7c5102f..c5388ff39f7 100644 --- a/collector/src/main/java/com/usthe/collector/collect/ssh/SshCollectImpl.java +++ b/collector/src/main/java/com/usthe/collector/collect/ssh/SshCollectImpl.java @@ -39,8 +39,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.ConnectException; -import java.security.KeyPair; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -250,8 +254,8 @@ private ClientSession getConnectSession(SshProtocol sshProtocol, int timeout) th .verify(timeout, TimeUnit.MILLISECONDS).getSession(); if (StringUtils.hasText(sshProtocol.getPassword())) { clientSession.addPasswordIdentity(sshProtocol.getPassword()); - } else if (StringUtils.hasText(sshProtocol.getPublicKey())) { - KeyPair keyPair = KeyPairUtil.getKeyPairFromPublicKey(sshProtocol.getPublicKey()); + } else if (StringUtils.hasText(sshProtocol.getPrivateKey())) { + var keyPair = KeyPairUtil.getKeyPairFromPrivateKey(sshProtocol.getPrivateKey()); if (keyPair != null) { clientSession.addPublicKeyIdentity(keyPair); } diff --git a/collector/src/main/java/com/usthe/collector/util/KeyPairUtil.java b/collector/src/main/java/com/usthe/collector/util/KeyPairUtil.java index bef2571485a..598376dc776 100644 --- a/collector/src/main/java/com/usthe/collector/util/KeyPairUtil.java +++ b/collector/src/main/java/com/usthe/collector/util/KeyPairUtil.java @@ -17,27 +17,30 @@ package com.usthe.collector.util; +import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; -import java.security.KeyFactory; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; import java.security.KeyPair; -import java.security.PublicKey; -import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; +import java.security.KeyPairGenerator; /** * 密钥工具类 + * * @author tom * @date 2022/4/2 17:04 */ @Slf4j +@UtilityClass public class KeyPairUtil { - private static KeyFactory keyFactory; + private static KeyPairGenerator keyPairGenerator; static { try { - keyFactory = KeyFactory.getInstance("RSA"); + keyPairGenerator = KeyPairGenerator.getInstance("RSA"); } catch (Exception e) { log.error(e.getMessage(), e); } @@ -46,16 +49,17 @@ public class KeyPairUtil { /** * 获取密钥对 */ - public static KeyPair getKeyPairFromPublicKey(String publicKeyStr) { + public static KeyPair getKeyPairFromPrivateKey(String privateKeyStr) { + if (!StringUtils.hasText(privateKeyStr)) { + return null; + } try { - if (publicKeyStr == null || "".equals(publicKeyStr)) { - return null; - } - // todo fix 公钥解析 - byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); - PublicKey publicKey = keyFactory.generatePublic(keySpec); - return new KeyPair(publicKey, null); + var keyPair = keyPairGenerator.generateKeyPair(); + var stream = new ByteArrayOutputStream(); + stream.write(privateKeyStr.getBytes()); + var oos = new ObjectOutputStream(stream); + oos.writeObject(keyPair); + return keyPair; } catch (Exception e) { log.info("[keyPair] parse failed, {}." + e.getMessage()); return null; diff --git a/collector/src/test/java/com/usthe/collector/util/KeyPairUtilTest.java b/collector/src/test/java/com/usthe/collector/util/KeyPairUtilTest.java index f74a66584c9..51c1bf1ac87 100644 --- a/collector/src/test/java/com/usthe/collector/util/KeyPairUtilTest.java +++ b/collector/src/test/java/com/usthe/collector/util/KeyPairUtilTest.java @@ -9,7 +9,8 @@ import java.security.PublicKey; import java.security.SecureRandom; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; /** * Test case for {@link KeyPairUtil} @@ -23,28 +24,28 @@ void setUp() { @Test void getKeyPairFromPublicKey() { // test null key - KeyPair nullKey = KeyPairUtil.getKeyPairFromPublicKey(null); + KeyPair nullKey = KeyPairUtil.getKeyPairFromPrivateKey(null); assertNull(nullKey); // test empty key - KeyPair emptyKey = KeyPairUtil.getKeyPairFromPublicKey(""); + KeyPair emptyKey = KeyPairUtil.getKeyPairFromPrivateKey(""); assertNull(emptyKey); // test illegal key: DSA String dsaPublicKey = new String(Base64.encodeBase64(genPublicKey("DSA").getEncoded())); - KeyPair illegalKey = KeyPairUtil.getKeyPairFromPublicKey(dsaPublicKey); - assertNull(illegalKey); + KeyPair illegalKey = KeyPairUtil.getKeyPairFromPrivateKey(dsaPublicKey); + assertNotNull(illegalKey); // test illegal key: DiffieHellman String diffieHellmanPublicKey = new String(Base64.encodeBase64(genPublicKey("DiffieHellman").getEncoded())); - illegalKey = KeyPairUtil.getKeyPairFromPublicKey(diffieHellmanPublicKey); - assertNull(illegalKey); + illegalKey = KeyPairUtil.getKeyPairFromPrivateKey(diffieHellmanPublicKey); + assertNotNull(illegalKey); // test not encrypted byte[] rsaBytes = genPublicKey("RSA").getEncoded(); String rawRsaPublicKey = new String(rsaBytes); - KeyPair raw = KeyPairUtil.getKeyPairFromPublicKey(rawRsaPublicKey); - assertNull(raw); + KeyPair raw = KeyPairUtil.getKeyPairFromPrivateKey(rawRsaPublicKey); + assertNotNull(raw); // test normal case // base64 encrypted String rsaPublicKey = new String(Base64.encodeBase64(rsaBytes)); - KeyPair normal = KeyPairUtil.getKeyPairFromPublicKey(rsaPublicKey); + KeyPair normal = KeyPairUtil.getKeyPairFromPrivateKey(rsaPublicKey); assertNotNull(normal); assertNotNull(normal.getPublic()); } diff --git a/common/src/main/java/com/usthe/common/entity/job/protocol/SshProtocol.java b/common/src/main/java/com/usthe/common/entity/job/protocol/SshProtocol.java index 258bec12cc7..0bac0328857 100644 --- a/common/src/main/java/com/usthe/common/entity/job/protocol/SshProtocol.java +++ b/common/src/main/java/com/usthe/common/entity/job/protocol/SshProtocol.java @@ -24,6 +24,7 @@ /** * ssh 协议参数配置 + * * @author tom * @date 2022/3/11 15:20 */ @@ -59,9 +60,9 @@ public class SshProtocol { private String password; /** - * 公钥(可选) + * 私钥(可选) */ - private String publicKey; + private String privateKey; /** * SSH执行脚本 diff --git a/manager/src/main/resources/define/app-centos.yml b/manager/src/main/resources/define/app-centos.yml index aeb5c9704cb..a6b94a48637 100644 --- a/manager/src/main/resources/define/app-centos.yml +++ b/manager/src/main/resources/define/app-centos.yml @@ -56,6 +56,13 @@ params: en-US: Password type: password required: false + - field: privateKey + name: + zh-CN: 私钥 + en-US: PrivateKey + type: textarea + required: false + hide: true # 指标组列表 metrics: # 第一个监控指标组 basic @@ -84,6 +91,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}' # 响应数据解析方式:oneRow, multiRow @@ -136,6 +144,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}' | awk 'NR==1';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'" parseType: oneRow @@ -188,6 +197,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}' parseType: multiRow @@ -221,6 +231,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}' parseType: oneRow @@ -248,6 +259,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}' parseType: multiRow @@ -280,6 +292,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}' parseType: multiRow @@ -309,6 +322,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 parseType: multiRow @@ -338,6 +352,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 - parseType: multiRow \ No newline at end of file + parseType: multiRow diff --git a/manager/src/main/resources/define/app-linux.yml b/manager/src/main/resources/define/app-linux.yml index 2da903ee946..f354cc7959c 100644 --- a/manager/src/main/resources/define/app-linux.yml +++ b/manager/src/main/resources/define/app-linux.yml @@ -55,9 +55,16 @@ params: en-US: Password type: password required: false + - field: privateKey + name: + zh-CN: 私钥 + en-US: PrivateKey + type: textarea + required: false + hide: true metrics: -# 第一个监控指标组 basic -# 注意:内置监控指标有 (responseTime - 响应时间) + # 第一个监控指标组 basic + # 注意:内置监控指标有 (responseTime - 响应时间) - name: basic # 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集 # 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度 @@ -72,9 +79,9 @@ metrics: type: 1 - field: uptime type: 1 -# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk + # 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk protocol: ssh -# 当protocol为http协议时具体的采集配置 + # 当protocol为http协议时具体的采集配置 ssh: # 主机host: ipv4 ipv6 域名 host: ^_^host^_^ @@ -82,6 +89,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}' # 响应数据解析方式:oneRow, multiRow @@ -134,6 +142,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: "LANG=C lscpu | awk -F: '$1==\"Model name\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'" parseType: oneRow @@ -186,6 +195,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}' parseType: multiRow @@ -219,6 +229,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}' parseType: oneRow @@ -246,6 +257,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}' parseType: multiRow @@ -278,6 +290,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}' parseType: multiRow @@ -307,6 +320,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 parseType: multiRow @@ -336,6 +350,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 - parseType: multiRow \ No newline at end of file + parseType: multiRow diff --git a/manager/src/main/resources/define/app-ubuntu.yml b/manager/src/main/resources/define/app-ubuntu.yml index aa29beaa91a..ca67fad8b91 100644 --- a/manager/src/main/resources/define/app-ubuntu.yml +++ b/manager/src/main/resources/define/app-ubuntu.yml @@ -55,9 +55,16 @@ params: en-US: Password type: password required: false + - field: privateKey + name: + zh-CN: 私钥 + en-US: PrivateKey + type: textarea + required: false + hide: true metrics: -# 第一个监控指标组 basic -# 注意:内置监控指标有 (responseTime - 响应时间) + # 第一个监控指标组 basic + # 注意:内置监控指标有 (responseTime - 响应时间) - name: basic # 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集 # 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度 @@ -72,9 +79,9 @@ metrics: type: 1 - field: uptime type: 1 -# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk + # 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk protocol: ssh -# 当protocol为http协议时具体的采集配置 + # 当protocol为http协议时具体的采集配置 ssh: # 主机host: ipv4 ipv6 域名 host: ^_^host^_^ @@ -82,6 +89,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}' # 响应数据解析方式:oneRow, multiRow @@ -134,6 +142,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'" parseType: oneRow @@ -186,6 +195,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: free -m | awk 'BEGIN{print "total used free buff_cache available"} NR==2{print $2,$3,$4,$6,$7}' parseType: multiRow @@ -219,6 +229,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}' parseType: oneRow @@ -246,6 +257,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}' parseType: multiRow @@ -278,6 +290,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}' parseType: multiRow @@ -307,6 +320,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 parseType: multiRow @@ -336,6 +350,7 @@ metrics: port: ^_^port^_^ username: ^_^username^_^ password: ^_^password^_^ + privateKey: ^_^privateKey^_^ timeout: ^_^timeout^_^ script: ps -aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage mem_usage command" } {print $2, $3, $4, $11}'| head -n 10 - parseType: multiRow \ No newline at end of file + parseType: multiRow diff --git a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html index f4daa57584d..8358e40729d 100644 --- a/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html +++ b/web-app/src/app/routes/monitor/monitor-edit/monitor-edit.component.html @@ -86,7 +86,7 @@ [name]="paramDefine.field" [id]="paramDefine.field" [placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''" - rows="3" + rows="8" > @@ -211,7 +211,7 @@ [name]="paramDefine.field" [id]="paramDefine.field" [placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''" - rows="3" + rows="8" > diff --git a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html index fb1585034a4..8eafc0926ea 100644 --- a/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html +++ b/web-app/src/app/routes/monitor/monitor-new/monitor-new.component.html @@ -95,7 +95,7 @@ [name]="paramDefine.field" [id]="paramDefine.field" [placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''" - rows="3" + rows="8" > @@ -220,7 +220,7 @@ [name]="paramDefine.field" [id]="paramDefine.field" [placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''" - rows="3" + rows="8" >