Project 22: “The SSH Tunnel Agent” — Networking

Attribute Value
File KIRO_CLI_LEARNING_PROJECTS.md
Main Programming Language SSH Config
Coolness Level Level 4: Hardcore Tech Flex
Difficulty Level 3: Advanced
Knowledge Area Networking

What you’ll build: Run Kiro locally but execute commands remotely via ssh.

Why it teaches Hybrid Workflows: Brain local, execution remote.

Success criteria:

  • A deploy task runs end-to-end on a remote host.

Real World Outcome

You’ll have a hybrid workflow where Kiro runs on your local machine (with GUI, editor, browser) but executes commands on remote servers via SSH. This combines local intelligence with remote execution power:

Local Kiro, remote execution:

# On your laptop
$ cat ~/.kiro/config.json
{
  "remote_execution": {
    "enabled": true,
    "host": "prod-server.company.com",
    "user": "deploy",
    "tools": ["Bash", "Read", "Write", "Edit"]
  }
}

$ kiro "deploy the latest version to production"

[Kiro running locally] Analyzing deployment strategy...

[SSH Tunnel] Connecting to prod-server.company.com...
[SSH Tunnel] Forwarding Bash tool execution...

[Remote Bash] ssh deploy@prod-server.company.com
$ cd /var/www/app
$ git pull origin main
$ npm install --production
$ pm2 restart app
✓ Deployment complete

[Kiro running locally] Deployment successful. Health check passing.

Transparent remote file access:

$ kiro "show me the nginx config on the production server"

[Kiro] Reading remote file via SSH...

[Remote Read Tool]
ssh deploy@prod-server.company.com 'cat /etc/nginx/nginx.conf'

[Kiro displays config and suggests improvements]

$ kiro "update the worker_processes to 4"

[Remote Edit Tool]
ssh deploy@prod-server.company.com 'cat > /tmp/nginx.conf.new << EOF
worker_processes 4;
...
EOF && sudo mv /tmp/nginx.conf.new /etc/nginx/nginx.conf'

[Remote Bash]
ssh deploy@prod-server.company.com 'sudo nginx -s reload'

✓ Configuration updated and reloaded

SSH config for seamless tunneling:

$ cat ~/.ssh/config

Host prod-server
  HostName prod-server.company.com
  User deploy
  Port 22
  IdentityFile ~/.ssh/deploy_key
  ForwardAgent yes
  ControlMaster auto
  ControlPath ~/.ssh/control-%r@%h:%p
  ControlPersist 10m

Host staging-server
  HostName staging.company.com
  User deploy
  ProxyJump bastion.company.com
  LocalForward 5432 localhost:5432

This setup enables “brain local, muscle remote” workflows where you get local responsiveness with remote execution power.


The Core Question You’re Answering

“How do I leverage my local development environment while executing commands on remote production servers?”

Before you start coding, consider: Installing Kiro on every server is impractical and risky. Running Kiro locally but SSHing to execute each command is slow and error-prone. SSH tunneling with ControlMaster lets you maintain a single persistent connection, forward tool execution transparently, and keep your local editor/browser while working on remote systems. This project teaches you to build hybrid architectures that combine local and remote strengths.


Concepts You Must Understand First

Stop and research these before coding:

  1. SSH ControlMaster (Connection Multiplexing)
    • What is ControlMaster and how does it reuse SSH connections?
    • How do you configure ControlPath for persistent sockets?
    • What is ControlPersist and when does it close connections?
    • How do you debug stuck control sockets (-O check, -O exit)?
    • Book Reference: “SSH Mastery” by Michael W. Lucas - Ch. 8 (Multiplexing)
  2. Remote Command Execution Patterns
    • How do you execute a single command via SSH (ssh host 'command')?
    • How do you handle stdin/stdout redirection over SSH?
    • What’s the difference between ssh -t (pseudo-TTY) vs non-interactive?
    • How do you escape shell metacharacters in remote commands?
    • Book Reference: “Unix Network Programming” by W. Richard Stevens - Ch. 19 (Remote Execution)
  3. SSH Port Forwarding (Tunneling)
    • What is local forwarding (-L) vs remote forwarding (-R)?
    • How do you forward multiple ports simultaneously?
    • What is dynamic forwarding (-D) for SOCKS proxy?
    • How do you debug forwarding failures (-v verbose mode)?
    • Book Reference: “SSH Mastery” by Michael W. Lucas - Ch. 7 (Forwarding)
  4. Tool Execution Proxying
    • How do you intercept tool calls and route them to SSH?
    • Should you proxy all tools or only specific ones (Bash, Read, Write)?
    • How do you handle tool failures (network errors, timeouts)?
    • What about file path translation (local vs remote paths)?
    • Book Reference: Kiro CLI docs - Remote Execution Configuration

Questions to Guide Your Design

Before implementing, think through these:

  1. Tool Selection for Remote Execution
    • Which tools should execute remotely (Bash, Read, Write, Edit)?
    • Should Grep run remotely or locally after fetching files?
    • What about tools that need local state (TodoWrite, EnterPlanMode)?
    • How do you handle mixed workflows (some local, some remote)?
  2. Connection Management
    • Do you open a new SSH connection per tool call or reuse one?
    • How do you detect connection failures and retry?
    • Should you establish the connection lazily (on first use) or eagerly?
    • What’s the timeout for idle connections (ControlPersist)?
  3. Path Translation
    • How do you map local file paths to remote paths?
    • Do you assume identical directory structures?
    • How do you handle absolute vs relative paths?
    • What about symlinks that resolve differently locally vs remotely?
  4. Security and Permissions
    • Should you use password auth or key-based auth?
    • How do you handle sudo commands that require passwords?
    • Do you need to validate the remote host’s fingerprint?
    • How do you prevent command injection via shell escaping?

Thinking Exercise

Manual SSH Tunnel Execution Trace

Before writing code, trace how a tool call is proxied through SSH:

Scenario: Kiro executes a Bash command remotely

Step 1: User asks Kiro to deploy

$ kiro "deploy the app to production"

Kiro decides: Run `npm run build && pm2 restart app`

Step 2: Kiro invokes Bash tool

Tool: Bash
Arguments: {
  "command": "npm run build && pm2 restart app"
}

Step 3: Remote execution hook intercepts

// Hook detects remote execution is enabled
if (config.remote_execution.enabled) {
  if (config.remote_execution.tools.includes('Bash')) {
    execute_remotely(tool, args);
  }
}

Step 4: Build SSH command

ssh_command = [
  'ssh',
  '-o', 'ControlMaster=auto',
  '-o', 'ControlPath=~/.ssh/control-%r@%h:%p',
  '-o', 'ControlPersist=10m',
  'deploy@prod-server.company.com',
  'cd /var/www/app && npm run build && pm2 restart app'
]

Step 5: Execute via SSH

$ ssh deploy@prod-server.company.com 'cd /var/www/app && npm run build && pm2 restart app'

# SSH reuses existing connection via ControlMaster socket
# Output is streamed back to local Kiro

Step 6: Return result to Kiro

{
  "exitCode": 0,
  "stdout": "Build complete. PM2 restarted app.",
  "stderr": "",
  "duration": 12345
}

Questions while tracing:

  • How do you handle commands that need interactive input (sudo passwords)?
  • What if the SSH connection breaks mid-execution?
  • How do you capture real-time output (streaming vs buffered)?
  • What if the remote command takes hours—do you keep the connection open?

The Interview Questions They’ll Ask

Prepare to answer these:

  1. “Explain SSH ControlMaster and how it enables connection multiplexing. What are the performance benefits?”
  2. “How would you handle shell escaping when passing user-generated commands over SSH to prevent command injection?”
  3. “What are the differences between SSH local forwarding (-L), remote forwarding (-R), and dynamic forwarding (-D)? When would you use each?”
  4. “How would you design a retry mechanism for tool execution that fails due to transient network errors?”
  5. “Explain the security implications of SSH agent forwarding. How would you mitigate the risks?”
  6. “How would you implement path translation for tools that operate on files when local and remote directory structures differ?”

Hints in Layers

Hint 1: Configure SSH ControlMaster Add to ~/.ssh/config:

Host prod-server
  HostName prod-server.company.com
  User deploy
  ControlMaster auto
  ControlPath ~/.ssh/control-%r@%h:%p
  ControlPersist 10m

This creates a persistent connection socket that’s reused for all subsequent SSH commands.

Hint 2: Proxy Bash Tool Calls Intercept Bash tool and route to SSH:

# In a hook or wrapper script
original_command="$1"
ssh prod-server "cd /app && $original_command"

Hint 3: Test Connection Reuse Verify ControlMaster is working:

# First connection (slow, establishes socket)
time ssh prod-server 'echo hello'  # ~500ms

# Subsequent connections (fast, reuse socket)
time ssh prod-server 'echo hello'  # ~50ms

Hint 4: Handle Shell Escaping Use printf %q to safely escape commands:

safe_command=$(printf '%q' "$user_command")
ssh prod-server "bash -c $safe_command"

Books That Will Help

Topic Book Chapter
SSH Multiplexing “SSH Mastery” by Michael W. Lucas Ch. 8 (Multiplexing), Ch. 7 (Forwarding)
Remote Execution “Unix Network Programming” by W. Richard Stevens Ch. 19 (Remote Execution)
Shell Escaping “The Linux Command Line” by William Shotts Ch. 35 (Strings and Numbers)
SSH Configuration “SSH: The Secure Shell” by Barrett, Silverman, Byrnes Ch. 7 (Advanced Client Use)
Networking Basics “TCP/IP Illustrated, Volume 1” by W. Richard Stevens Ch. 2 (The Internet Protocol)

Common Pitfalls & Debugging

Problem 1: “Each SSH command takes 500ms, making Kiro unbearably slow”

  • Why: Opening new SSH connection for every command
  • Fix: Enable ControlMaster connection reuse:
    Host prod-server
      ControlMaster auto
      ControlPath ~/.ssh/control-%r@%h:%p
      ControlPersist 10m
    
  • Quick test: Time 10 rapid SSH commands—should be <100ms each after first

Problem 2: “Commands fail with ‘command not found’ on remote host”

  • Why: SSH non-interactive sessions don’t source .bashrc
  • Fix: Source profile or use login shell:
    ssh prod-server 'source ~/.bashrc && npm run build'
    # OR
    ssh -t prod-server 'npm run build'  # Force pseudo-TTY
    
  • Quick test: ssh prod-server 'echo $PATH' vs ssh -t prod-server 'echo $PATH'

Problem 3: “Command injection via user input”

  • Why: User command contains shell metacharacters (;, |, &&)
  • Fix: Use parameterized execution or escape properly:
    # BAD: ssh prod-server "rm $user_file"  # Injection risk
    # GOOD:
    safe_file=$(printf '%q' "$user_file")
    ssh prod-server "rm $safe_file"
    
  • Quick test: Try user_file="; rm -rf /" and verify it’s escaped

Problem 4: “Stuck control socket prevents new connections”

  • Why: ControlMaster socket is hung or orphaned
  • Fix: Kill stuck socket:
    ssh -O exit prod-server
    # OR manually:
    rm ~/.ssh/control-deploy@prod-server.company.com:22
    
  • Quick test: ssh -O check prod-server shows socket status

Problem 5: “Remote commands don’t stream output, buffered until completion”

  • Why: stdout is buffered when not connected to a TTY
  • Fix: Use stdbuf or script to force line buffering:
    ssh prod-server 'stdbuf -oL npm run build'
    # OR force pseudo-TTY:
    ssh -t prod-server 'npm run build'
    
  • Quick test: Long-running command should show incremental output

Definition of Done

  • SSH ControlMaster is configured for connection reuse
  • Bash tool calls are proxied to remote host via SSH
  • Read/Write/Edit tools can operate on remote files
  • Tool execution respects working directory on remote host
  • Shell commands are properly escaped to prevent injection
  • ControlPersist keeps connections open for 10 minutes
  • Failed SSH connections are retried with exponential backoff
  • Remote execution can be toggled on/off via config file
  • Path translation handles local vs remote directory structures
  • Streaming output works for long-running commands
  • Documentation explains SSH config setup and troubleshooting
  • Supports bastion/jump hosts for accessing internal servers