added environment info from the client.

This commit is contained in:
Erik Brakkee 2024-08-10 13:00:48 +02:00
parent 8b4bcde9c9
commit f3d0074f17
12 changed files with 60 additions and 43 deletions

View File

@ -310,7 +310,7 @@ func main() {
defer wsConn.Close() defer wsConn.Close()
shell := chooseShell(shells) shell := chooseShell(shells)
_, err = comms.AgentInitialization(wsConn, comms.NewAgentInfo(shell)) _, err = comms.AgentInitialization(wsConn, comms.NewEnvironmentInfo(shell))
if err != nil { if err != nil {
log.Printf("ERROR: %v", err) log.Printf("ERROR: %v", err)
os.Exit(1) os.Exit(1)

View File

@ -170,7 +170,6 @@ func (key *AuthorizedPublicKeys) authorize(ctx ssh.Context, userProvidedKey ssh.
log.Printf("No valid public keys were found, login is impossible") log.Printf("No valid public keys were found, login is impossible")
// keep agent running, a user may still be logged in and could change the // keep agent running, a user may still be logged in and could change the
// authorizedk eys file // authorizedk eys file
// TODO: if no users are logged in, the agent should exit.
} }
for _, key := range keys { for _, key := range keys {
if publicKeyHandler(ctx, userProvidedKey, key) { if publicKeyHandler(ctx, userProvidedKey, key) {

View File

@ -61,11 +61,11 @@ func agentLabels(agent models.Agent) prometheus.Labels {
return prometheus.Labels{ return prometheus.Labels{
"guid": agent.Guid, "guid": agent.Guid,
"id": agent.PublicId, "id": agent.PublicId,
"username": agent.AgentInfo.Username, "username": agent.EnvironmentInfo.Username,
"hostname": agent.AgentInfo.Hostname, "hostname": agent.EnvironmentInfo.Hostname,
"pwd": agent.AgentInfo.Pwd, "pwd": agent.EnvironmentInfo.Pwd,
"os": agent.AgentInfo.OS, "os": agent.EnvironmentInfo.OS,
"shell": agent.AgentInfo.Shell, "shell": agent.EnvironmentInfo.Shell,
} }
} }

View File

@ -84,7 +84,7 @@ func main() {
Guid: strconv.Itoa(rand.Int()), Guid: strconv.Itoa(rand.Int()),
PublicId: "id", PublicId: "id",
StartTime: time.Now().In(japan), StartTime: time.Now().In(japan),
AgentInfo: comms.AgentInfo{ EnvironmentInfo: comms.EnvironmentInfo{
Username: "ci", Username: "ci",
Hostname: "container123", Hostname: "container123",
Pwd: "/home/ci", Pwd: "/home/ci",

View File

@ -137,6 +137,11 @@ func main() {
log.Printf("Error reported by server: %v", clientConnectionInfo.Message) log.Printf("Error reported by server: %v", clientConnectionInfo.Message)
os.Exit(1) os.Exit(1)
} }
err = comms.SendWithTimeout(channel, comms.NewEnvironmentInfo(os.Getenv("SHELL")))
if err != nil {
log.Printf("Could not send environment info to server")
os.Exit(1)
}
} }
dataConnection := wsConn dataConnection := wsConn

View File

@ -90,7 +90,7 @@ func NewCommChannel(role Role, wsConn io.ReadWriteCloser) (CommChannel, error) {
// Sending an event to the other side // Sending an event to the other side
func ListenForAgentEvents(channel GOBChannel, func ListenForAgentEvents(channel GOBChannel,
agentInfo func(agent AgentInfo), agentInfo func(agent EnvironmentInfo),
sessionInfo func(session SessionInfo), sessionInfo func(session SessionInfo),
expiryTimeUpdate func(session ExpiryTimeUpdate)) { expiryTimeUpdate func(session ExpiryTimeUpdate)) {
for { for {
@ -103,7 +103,7 @@ func ListenForAgentEvents(channel GOBChannel,
} }
switch v := result.Value.(type) { switch v := result.Value.(type) {
case AgentInfo: case EnvironmentInfo:
agentInfo(v) agentInfo(v)
case SessionInfo: case SessionInfo:
@ -142,7 +142,7 @@ func ListenForServerEvents(channel CommChannel) {
} }
} }
func AgentInitialization(conn io.ReadWriter, agentInto AgentInfo) (ServerInfo, error) { func AgentInitialization(conn io.ReadWriter, agentInto EnvironmentInfo) (ServerInfo, error) {
channel := NewGOBChannel(conn) channel := NewGOBChannel(conn)
err := CheckProtocolVersion(Agent, channel) err := CheckProtocolVersion(Agent, channel)
@ -160,18 +160,18 @@ func AgentInitialization(conn io.ReadWriter, agentInto AgentInfo) (ServerInfo, e
return serverInfo, err return serverInfo, err
} }
func ServerInitialization(conn io.ReadWriter, serverInfo ServerInfo) (AgentInfo, error) { func ServerInitialization(conn io.ReadWriter, serverInfo ServerInfo) (EnvironmentInfo, error) {
channel := NewGOBChannel(conn) channel := NewGOBChannel(conn)
err := CheckProtocolVersion(ConvergeServer, channel) err := CheckProtocolVersion(ConvergeServer, channel)
agentInfo, err := ReceiveWithTimeout[AgentInfo](channel) agentInfo, err := ReceiveWithTimeout[EnvironmentInfo](channel)
if err != nil { if err != nil {
return AgentInfo{}, err return EnvironmentInfo{}, err
} }
log.Println("Agent info received: ", agentInfo) log.Println("Agent info received: ", agentInfo)
err = SendWithTimeout(channel, serverInfo) err = SendWithTimeout(channel, serverInfo)
if err != nil { if err != nil {
return AgentInfo{}, nil return EnvironmentInfo{}, nil
} }
return agentInfo, err return agentInfo, err
} }

View File

@ -8,7 +8,7 @@ import (
"time" "time"
) )
const PROTOCOL_VERSION = 2 const PROTOCOL_VERSION = 3
func init() { func init() {
RegisterEventsWithGob() RegisterEventsWithGob()
@ -16,7 +16,7 @@ func init() {
// Agent to server events // Agent to server events
type AgentInfo struct { type EnvironmentInfo struct {
Username string Username string
Hostname string Hostname string
Pwd string Pwd string
@ -67,11 +67,11 @@ type ConvergeMessage struct {
Value interface{} Value interface{}
} }
func NewAgentInfo(shell string) AgentInfo { func NewEnvironmentInfo(shell string) EnvironmentInfo {
username, _ := user.Current() username, _ := user.Current()
host, _ := os.Hostname() host, _ := os.Hostname()
pwd, _ := os.Getwd() pwd, _ := os.Getwd()
return AgentInfo{ return EnvironmentInfo{
Username: username.Username, Username: username.Username,
Hostname: host, Hostname: host,
Pwd: pwd, Pwd: pwd,
@ -93,7 +93,7 @@ func NewExpiryTimeUpdate(expiryTime time.Time) ExpiryTimeUpdate {
func RegisterEventsWithGob() { func RegisterEventsWithGob() {
// Agent to ConvergeServer // Agent to ConvergeServer
gob.Register(AgentInfo{}) gob.Register(EnvironmentInfo{})
gob.Register(SessionInfo{}) gob.Register(SessionInfo{})
gob.Register(ExpiryTimeUpdate{}) gob.Register(ExpiryTimeUpdate{})
gob.Register(HeartBeat{}) gob.Register(HeartBeat{})

View File

@ -10,6 +10,6 @@ type Agent struct {
PublicId string PublicId string
StartTime time.Time StartTime time.Time
AgentInfo comms.AgentInfo EnvironmentInfo comms.EnvironmentInfo
ExpiryTime time.Time ExpiryTime time.Time
} }

View File

@ -1,6 +1,7 @@
package models package models
import ( import (
"converge/pkg/comms"
"time" "time"
) )
@ -10,4 +11,5 @@ type Client struct {
ClientId string ClientId string
StartTime time.Time StartTime time.Time
SessionType string SessionType string
EnvironmentInfo comms.EnvironmentInfo
} }

View File

@ -31,13 +31,13 @@ type ClientConnection struct {
client iowrappers2.ReadWriteAddrCloser client iowrappers2.ReadWriteAddrCloser
} }
func NewAgent(commChannel comms.CommChannel, publicId string, agentInfo comms.AgentInfo) *AgentConnection { func NewAgent(commChannel comms.CommChannel, publicId string, agentInfo comms.EnvironmentInfo) *AgentConnection {
return &AgentConnection{ return &AgentConnection{
Agent: models.Agent{ Agent: models.Agent{
Guid: strconv.Itoa(rand.Int()), Guid: strconv.Itoa(rand.Int()),
PublicId: publicId, PublicId: publicId,
StartTime: time.Now(), StartTime: time.Now(),
AgentInfo: agentInfo, EnvironmentInfo: agentInfo,
}, },
commChannel: commChannel, commChannel: commChannel,
} }
@ -101,9 +101,9 @@ func (admin *Admin) logStatus() {
lines = append(lines, fmt.Sprintf(format, agent.PublicId, lines = append(lines, fmt.Sprintf(format, agent.PublicId,
agent.StartTime.Format(time.DateTime), agent.StartTime.Format(time.DateTime),
agent.ExpiryTime.Format(time.DateTime), agent.ExpiryTime.Format(time.DateTime),
agent.AgentInfo.Username, agent.EnvironmentInfo.Username,
agent.AgentInfo.Hostname, agent.EnvironmentInfo.Hostname,
agent.AgentInfo.OS)) agent.EnvironmentInfo.OS))
} }
lines = append(lines, "") lines = append(lines, "")
format = "%-10s %-20s %-20s %-20s %-20s" format = "%-10s %-20s %-20s %-20s %-20s"
@ -145,7 +145,7 @@ func (admin *Admin) getFreeId(publicId string) (string, error) {
return "", fmt.Errorf("Could not allocate agent id based on requested public id '%s'", publicId) return "", fmt.Errorf("Could not allocate agent id based on requested public id '%s'", publicId)
} }
func (admin *Admin) addAgent(publicId string, agentInfo comms.AgentInfo, conn io.ReadWriteCloser) (*AgentConnection, error) { func (admin *Admin) addAgent(publicId string, agentInfo comms.EnvironmentInfo, conn io.ReadWriteCloser) (*AgentConnection, error) {
admin.mutex.Lock() admin.mutex.Lock()
defer admin.mutex.Unlock() defer admin.mutex.Unlock()
@ -287,8 +287,8 @@ func (admin *Admin) Register(publicId string, conn io.ReadWriteCloser) error {
go func() { go func() {
comms.ListenForAgentEvents(agent.commChannel.SideChannel, comms.ListenForAgentEvents(agent.commChannel.SideChannel,
func(info comms.AgentInfo) { func(info comms.EnvironmentInfo) {
agent.AgentInfo = info agent.EnvironmentInfo = info
admin.logStatus() admin.logStatus()
}, },
func(session comms.SessionInfo) { func(session comms.SessionInfo) {
@ -356,6 +356,11 @@ func (admin *Admin) Connect(wsProxyMode bool, publicId string, conn iowrappers2.
if err != nil { if err != nil {
return fmt.Errorf("Error sending connection info to client: %v", err) return fmt.Errorf("Error sending connection info to client: %v", err)
} }
clientEnvironment, err := comms.ReceiveWithTimeout[comms.EnvironmentInfo](channel)
if err != nil {
return fmt.Errorf("Error receiving environment info from client: %v", err)
}
client.EnvironmentInfo = clientEnvironment
} }
iowrappers2.SynchronizeStreams("client -- agent", client.client, client.agent) iowrappers2.SynchronizeStreams("client -- agent", client.client, client.agent)

View File

@ -47,10 +47,10 @@ templ State(state *models.State, location *time.Location) {
<td>{agent.PublicId}</td> <td>{agent.PublicId}</td>
<td>{agent.StartTime.In(location).Format(time.DateTime)}</td> <td>{agent.StartTime.In(location).Format(time.DateTime)}</td>
<td>{agent.ExpiryTime.In(location).Format(time.DateTime)}</td> <td>{agent.ExpiryTime.In(location).Format(time.DateTime)}</td>
<td>{agent.AgentInfo.Username}</td> <td>{agent.EnvironmentInfo.Username}</td>
<td>{agent.AgentInfo.Hostname}</td> <td>{agent.EnvironmentInfo.Hostname}</td>
<td>{agent.AgentInfo.OS}</td> <td>{agent.EnvironmentInfo.OS}</td>
<td>{agent.AgentInfo.Shell}</td> <td>{agent.EnvironmentInfo.Shell}</td>
</tr> </tr>
} }
</table> </table>
@ -70,6 +70,9 @@ templ State(state *models.State, location *time.Location) {
<th>start time</th> <th>start time</th>
<th>session type</th> <th>session type</th>
<th>rendez-vous id</th> <th>rendez-vous id</th>
<th>username</th>
<th>host</th>
<th>os</th>
</tr> </tr>
</thead> </thead>
for _, client := range state.Clients { for _, client := range state.Clients {
@ -78,6 +81,9 @@ templ State(state *models.State, location *time.Location) {
<td>{client.StartTime.In(location).Format(time.DateTime)}</td> <td>{client.StartTime.In(location).Format(time.DateTime)}</td>
<td>{client.SessionType}</td> <td>{client.SessionType}</td>
<td>{client.PublicId}</td> <td>{client.PublicId}</td>
<td>{client.EnvironmentInfo.Username}</td>
<td>{client.EnvironmentInfo.Hostname}</td>
<td>{client.EnvironmentInfo.OS}</td>
</tr> </tr>
} }
</table> </table>

View File

@ -178,7 +178,7 @@ templ Usage(access models.ConvergeAccess) {
<tr> <tr>
<td class="minimal-width"><label for="remote-shell">agent environment</label></td> <td class="minimal-width"><label for="remote-shell">agent environment</label></td>
<td> <td>
<input checked id="remote-shell-0" name="remote-shell" type="radio" value={BASH}> <label for="remote-shell-0">*.sh</label> <input checked id="remote-shell-0" name="remote-shell" type="radio" value={BASH}> <label for="remote-shell-0">bash, sh, zsh, ...</label>
<input id="remote-shell-1" name="remote-shell" type="radio" value={CMD}> <label for="remote-shell-1">command prompt</label> <input id="remote-shell-1" name="remote-shell" type="radio" value={CMD}> <label for="remote-shell-1">command prompt</label>
<input id="remote-shell-2" name="remote-shell" type="radio" value={POWERSHELL}> <label for="remote-shell-2">power shell</label> <input id="remote-shell-2" name="remote-shell" type="radio" value={POWERSHELL}> <label for="remote-shell-2">power shell</label>
</td> </td>