Documentation Index
Fetch the complete documentation index at: https://wiki.krkn.tech/llms.txt
Use this file to discover all available pages before exploring further.
Shell Service
Hook provides a remote shell service that enables command execution, file upload, and file download on infrastructure nodes. The shell service runs on all Hook nodes and is accessible over the mesh network.
Overview
The Shell Service provides:
- Remote Command Execution - Execute shell commands on nodes
- File Upload - Upload files to remote nodes
- File Download - Download files from remote nodes
- ACL Protection - Permission-based access control
Architecture
Service Definition
service ShellService {
// Execute a shell command and return stdout/stderr
rpc ExecuteCommand(CommandRequest) returns (CommandResponse);
// Upload a file to the remote server
rpc UploadFile(UploadFileRequest) returns (UploadFileResponse);
// Download a file from the remote server
rpc DownloadFile(DownloadFileRequest) returns (DownloadFileResponse);
// Get service status
rpc Status(hook.common.Auth) returns (hook.common.StandardResponse);
}
Default Port
The shell service runs on port 61022 across all Hook services:
- Helm
- Corsair
- Nameserver
- Payload Server
Command Execution
Execute Command
grpcurl -d '{
"command": "ls",
"args": ["-la", "/var/log"],
"timeout_seconds": 30
}' node:61022 hook.shell.ShellService/ExecuteCommand
Command Request
message CommandRequest {
string command = 1; // The shell command to execute
repeated string args = 2; // Command arguments
map<string, string> env = 3; // Additional environment variables
string working_dir = 4; // Working directory (optional)
int64 timeout_seconds = 5; // Execution timeout (0 = no timeout)
}
Command Response
message CommandResponse {
hook.common.Error error = 1; // Error if command failed
string stdout = 2; // Standard output
string stderr = 3; // Standard error
int64 exit_code = 4; // Exit code of the command
bool timed_out = 5; // Whether the command timed out
}
Examples
# List files
grpcurl -d '{"command":"ls","args":["-la"]}' node:61022 hook.shell.ShellService/ExecuteCommand
# Check disk space
grpcurl -d '{"command":"df","args":["-h"]}' node:61022 hook.shell.ShellService/ExecuteCommand
# Run with working directory
grpcurl -d '{"command":"pwd","working_dir":"/var/log"}' node:61022 hook.shell.ShellService/ExecuteCommand
# Run with timeout
grpcurl -d '{"command":"sleep","args":["10"],"timeout_seconds":5}' node:61022 hook.shell.ShellService/ExecuteCommand
# Run complex command with bash
grpcurl -d '{"command":"bash","args":["-c","ps aux | grep hook"]}' node:61022 hook.shell.ShellService/ExecuteCommand
File Upload
Upload Request
message UploadFileRequest {
string path = 1; // Destination path on the server
bytes content = 2; // File content
int64 mode = 3; // File permissions (e.g., 0644, 0755)
bool overwrite = 4; // Whether to overwrite existing file
bool create_dirs = 5; // Whether to create parent directories
}
Upload Examples
# Upload a file
grpcurl -d '{
"path": "/tmp/script.sh",
"content": "IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8i",
"mode": 493,
"overwrite": true,
"create_dirs": true
}' node:61022 hook.shell.ShellService/UploadFile
# Response
{
"message": "file uploaded successfully to /tmp/script.sh",
"bytes_written": 24
}
Upload Response
message UploadFileResponse {
hook.common.Error error = 1; // Error if upload failed
string message = 2; // Success message
int64 bytes_written = 3; // Number of bytes written
}
File Download
Download Request
message DownloadFileRequest {
string path = 1; // Path to the file on the server
}
Download Examples
# Download a file
grpcurl -d '{"path":"/etc/hostname"}' node:61022 hook.shell.ShellService/DownloadFile
# Response
{
"content": "bXktaG9zdG5hbWUK",
"size": 12,
"mode": 420,
"modified_time": 1702800000
}
Download Response
message DownloadFileResponse {
hook.common.Error error = 1; // Error if download failed
bytes content = 2; // File content
int64 size = 3; // File size in bytes
int64 mode = 4; // File permissions
int64 modified_time = 5; // Last modified time (Unix timestamp)
}
Access Control
Required Permissions
Shell operations require SSH permissions:
var methodPermissions = map[string]acl.Permission{
"/hook.shell.ShellService/ExecuteCommand": acl.PermissionSSHExecute,
"/hook.shell.ShellService/UploadFile": acl.PermissionSSHExecute,
"/hook.shell.ShellService/DownloadFile": acl.PermissionSSHExecute,
"/hook.shell.ShellService/Status": acl.PermissionSSHView,
}
Network Isolation
The shell service is restricted to the mesh network:
// Shell gRPC only accessible from mesh network
fw.AddPortForIP(meshNetwork, "tcp:61022")
Service Startup
The shell service starts automatically on all Hook nodes:
shellGrpcServer, shellLis, started, err := shell.StartShellServiceIfNotRunning(
ctx,
logger,
shellAddr,
tlsCreds,
grpc.ChainUnaryInterceptor(shellinterceptors.ACLInterceptor(permissionChecker)),
)
Port Conflict Handling
If the port is already in use, the service skips startup:
func StartShellServiceIfNotRunning(...) (*grpc.Server, net.Listener, bool, error) {
if isPortInUse(listenAddr) {
logger.Info("shell service already running, skipping startup")
return nil, nil, false, nil
}
// Start service...
}
Over Mesh Network
Access shell service on mesh-connected nodes:
# From another mesh host, use mesh IP
grpcurl -d '{"command":"hostname"}' 10.100.0.5:61022 hook.shell.ShellService/ExecuteCommand
Next Steps