Use gRPC to manage remote SSH clients
Example using docker compose
version: "3.8"
services:
ssh:
image: kainonly/ssh-microservice
restart: always
volumes:
- ./ssh:/app/config
ports:
- 6000:6000
- 8080:8080For configuration, please refer to config/config.example.yml and create config/config.yml
- debug
stringTurn on debugging, that isnet/http/pprof, and visit the addresshttp://localhost: 6060/debug/pprof - listen
stringgrpc server listening address - gateway
stringAPI gateway server listening address
The service is based on gRPC to view api/api.proto
syntax = "proto3";
package ssh;
option go_package = "ssh-microservice/gen/go/ssh";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
service API {
rpc Testing (Option) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/testing",
body: "*",
};
}
rpc Put (IOption) returns (google.protobuf.Empty) {
option (google.api.http) = {
put: "/client",
body: "*",
};
}
rpc Exec (Bash) returns (Output) {
option (google.api.http) = {
post: "/exec",
body: "*",
};
}
rpc Delete (ID) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/client",
};
}
rpc Get (ID) returns (Data) {
option (google.api.http) = {
get: "/client",
};
}
rpc All (google.protobuf.Empty) returns (IDs) {
option (google.api.http) = {
get: "/clients",
};
}
rpc Lists (IDs) returns (DataLists) {
option (google.api.http) = {
post: "/clients",
body: "*"
};
}
rpc Tunnels (TunnelsOption) returns (google.protobuf.Empty) {
option (google.api.http) = {
put: "/tunnels",
body: "*",
};
}
rpc FreePort (google.protobuf.Empty) returns (Port) {
option (google.api.http) = {
get: "/free_port",
};
}
}
message Option {
string host = 1;
uint32 port = 2;
string username = 3;
string password = 4;
string private_key = 5;
string passphrase = 6;
}
message IOption {
string id = 1;
Option option = 2;
}
message Bash {
string id = 1;
string bash = 2;
}
message Output {
bytes data = 1;
}
message ID {
string id = 1;
}
message Data {
string id = 1;
string host = 2;
uint32 port = 3;
string username = 4;
string connected = 5;
repeated Tunnel tunnels = 6;
}
message Tunnel {
string src_ip = 1;
uint32 src_port = 2;
string dst_ip = 3;
uint32 dst_port = 4;
}
message IDs {
repeated string ids = 1;
}
message DataLists {
repeated Data data = 1;
}
message TunnelsOption {
string id = 1;
repeated Tunnel tunnels = 2;
}
message Port {
uint32 data = 1;
}test for ssh client connection
- Option
- host
string - port
uint32 - username
string - password
stringpassword (default empty) - private_key
stringprivate key (Base64) - passphrase
stringkey passphrase (Base64)
- host
client := pb.NewAPIClient(conn)
response, err := client.Testing(
context.Background(),
&pb.Option{
Host: debug.Host,
Port: debug.Port,
Username: debug.Username,
Password: debug.Password,
PrivateKey: debug.PrivateKey,
Passphrase: debug.Passphrase,
},
)- POST
/testing
POST /testing HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"host":"dell",
"port":22,
"username":"root",
"private_key":"LS0......o="
}Update the ssh client configuration to the service
- IOption
- id
stringID - option
Option- host
string - port
uint32 - username
string - password
stringpassword (default empty) - private_key
stringprivate key (Base64) - passphrase
stringkey passphrase (Base64)
- host
- id
client := pb.NewAPIClient(conn)
response, err := client.Put(
context.Background(),
&pb.IOption{
Id: "debug",
Option: &pb.Option{
Host: debug.Host,
Port: debug.Port,
Username: debug.Username,
Password: debug.Password,
PrivateKey: debug.PrivateKey,
Passphrase: debug.Passphrase,
},
},
)- PUT
/client
PUT /client HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"id": "debug",
"option": {
"host": "dell",
"port": 22,
"username": "root",
"private_key": "LS0......o="
}
}Send commands to the server via ssh
- Bash
- id
stringID - bash
stringshell command
- id
- Output
- data command output result
client := pb.NewAPIClient(conn)
response, err := client.Exec(
context.Background(),
&pb.ExecParameter{
Identity: "debug",
Bash: "uptime",
},
)- POST
/exec
POST /exec HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"id": "debug",
"bash": "uptime"
}Remove an ssh client from the service
- ID
- id
stringID
- id
client := pb.NewAPIClient(conn)
response, err := client.Delete(
context.Background(),
&pb.ID{
Id: "debug",
},
)- DELETE
/client
DELETE /client?id=debug HTTP/1.1
Host: localhost:8080Get the details of an ssh client from the service
- ID
- id
stringID
- id
- Data
- id
stringID - host
string - port
uint32 - username
string - connected ssh connected client version
- tunnels
[]Tunnelssh tunnels- src_ip
stringorigin ip - src_port
uint32origin port - dst_ip
stringtarget ip - dst_port
uint32target port
- src_ip
- id
client := pb.NewAPIClient(conn)
response, err := client.Get(
context.Background(),
&pb.ID{
Id: "debug",
},
)- GET
/client
GET /client?id=debug HTTP/1.1
Host: localhost:8080Get all ssh client IDs from the service
- IDs
- ids
[]stringIDs
- ids
client := pb.NewAPIClient(conn)
response, err := client.All(
context.Background(),
&empty.Empty{},
)- GET
/clients
GET /clients HTTP/1.1
Host: localhost:8080Get the specified list ssh client details from the service
- IDs
- ids
[]stringIDs
- ids
- DataLists
- data
[]Data- id
stringID - host
string - port
uint32 - username
string - connected ssh connected client version
- tunnels
[]Tunnelssh tunnels- src_ip
stringorigin ip - src_port
uint32origin port - dst_ip
stringtarget ip - dst_port
uint32target port
- src_ip
- id
- data
client := pb.NewAPIClient(conn)
response, err := client.Lists(
context.Background(),
&pb.IDs{
Ids: []string{"debug", "debug-next"},
},
)- POST
/clients
POST /clients HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 39
{
"ids": [
"debug"
]
}Set up a tunnel for the ssh client
- TunnelsOption
- id
stringID - tunnels
[]Tunnelssh tunnels- src_ip
stringorigin ip - src_port
uint32origin port - dst_ip
stringtarget ip - dst_port
uint32target port
- src_ip
- id
client := pb.NewAPIClient(conn)
response, err := client.Tunnels(
context.Background(),
&pb.TunnelsOption{
Id: "debug-1",
Tunnels: []*pb.Tunnel{
{
SrcIp: "127.0.0.1",
SrcPort: 9200,
DstIp: "127.0.0.1",
DstPort: 9200,
},
{
SrcIp: "127.0.0.1",
SrcPort: 5601,
DstIp: "127.0.0.1",
DstPort: 5601,
},
},
},
)- PUT
/tunnels
PUT /tunnels HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"id": "debug",
"tunnels": [
{
"src_ip": "127.0.0.1",
"src_port": 9200,
"dst_ip": "127.0.0.1",
"dst_port": 9200
},
{
"src_ip": "127.0.0.1",
"src_port": 5601,
"dst_ip": "127.0.0.1",
"dst_port": 5601
}
]
}Get available ports on the host
- Port
- data
uint32port
- data
client := pb.NewAPIClient(conn)
response, err := client.FreePort(
context.Background(),
&empty.Empty{},
)- GET
/free_port
GET /free_port HTTP/1.1
Host: localhost:8080