feat: SSH terminal - the agent connects by SSH to another host (password, key file or its own keys) and the shell opens in a tab with the connection's progress shown; host keys trusted on first use, a changed one refused
This commit is contained in:
1 parent
5a204ae9bb
commit
5a4dc596d5
7 files changed
+515
-21
No files matched your search
@@ -3,8 +3,12 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
@@ -17,7 +21,9 @@ import (
|
||||
// same transport the agent uses), so it works through any reverse proxy without
|
||||
// WebSocket upgrade support.
|
||||
|
||||
// POST /api/panel/term/{agentID}/open - create a terminal session.
|
||||
// POST /api/panel/term/{agentID}/open - create a terminal session: a shell
|
||||
// on the agent, or with {"ssh": {...}} in the body a shell the agent opens
|
||||
// by SSH on another host.
|
||||
func (s *Server) handlePanelOpen(w http.ResponseWriter, r *http.Request) {
|
||||
agentID := r.PathValue("agentID")
|
||||
agent, err := s.db.GetAgent(agentID)
|
||||
@@ -26,6 +32,33 @@ func (s *Server) handlePanelOpen(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
SSH *proto.SSHTarget `json:"ssh"`
|
||||
}
|
||||
if r.ContentLength != 0 {
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 64<<10)).Decode(&body); err != nil && err != io.EOF {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if t := body.SSH; t != nil {
|
||||
t.Host, t.User = strings.TrimSpace(t.Host), strings.TrimSpace(t.User)
|
||||
if t.Port == 0 {
|
||||
t.Port = 22
|
||||
}
|
||||
if t.Host == "" || t.User == "" || t.Port < 1 || t.Port > 65535 || strings.ContainsAny(t.Host+t.User, " \t\r\n/") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{"error": "нужны хост, порт 1-65535 и пользователь"})
|
||||
return
|
||||
}
|
||||
sess := s.hub.CreateSSH(agentID, *t)
|
||||
if admin := s.currentAdmin(r); admin != nil {
|
||||
s.db.Audit(admin.ID, agentID, "open_ssh:"+t.User+"@"+net.JoinHostPort(t.Host, strconv.Itoa(t.Port)))
|
||||
}
|
||||
writeJSON(w, map[string]string{"session_id": sess.ID})
|
||||
return
|
||||
}
|
||||
sess := s.hub.CreateSession(agentID, agent.LoginUser)
|
||||
if admin := s.currentAdmin(r); admin != nil {
|
||||
s.db.Audit(admin.ID, agentID, "open_terminal:"+agent.TerminalUser())
|
||||
|
||||
Reference in new issue
Block a user