[PR #4015] [client,management] Rewrite the SSH feature #4054

Open
opened 2025-11-20 08:07:38 -05:00 by saavagebueno · 0 comments
Owner

Original Pull Request: https://github.com/netbirdio/netbird/pull/4015

State: closed
Merged: Yes


Describe your changes

NetBird SSH Client

  • Port forwarding
  • Windows support
  • Non-interactive commands
  • Single command execution over SSH

SSH Server

  • SFTP
  • Port forwarding (without user switching)
  • PTY (interactive, non-interactive)
  • Non-PTY (commands)
  • Windows support
  • JWT auth (user identity instead of machine identity, can be turned off)

New Flags

# server
--enable-ssh-local-port-forwarding
--enable-ssh-remote-port-forwarding
--enable-ssh-root
--enable-ssh-sftp
--disable-ssh-auth

# client
--ssh-jwt-cache-ttl

UI

  • Better organization
    image
image image

Changes

  • Default port changed to 22022
  • Redirect port 22 to 22022 when SSH server enabled
  • Remove implicit OpenSSH firewall port
  • Management now passes its jwks config to peers with enabled ssh server
  • SSH server peers verify incoming clients' jwt with max token age
  • SSH clients request jwts from the IdP and send these for authentication with remote ssh peers
  • Add netbird ssh detect command to detect if the remote peer is running the NetBird server
  • Add netbird ssh proxy command for native ssh and sftp clients. The proxy requests jwts just like netbird ssh, passes them for authentication and bridges the connection between the native client and the remote server.
  • Add jwt capability to the wasm ssh client

Auth Flows

  1. NetBird SSH Flow (netbird ssh <peer>)
flowchart TD
    A[User: netbird ssh &lt;peer&gt;] --> B[Connect to peer:22]
    B --> C[Detect Server Type]
    C --> D[Send 'netbird-detect' request]

    D --> E{Server Response}

    E -->|No NetBird identifier| F[Regular SSH Server]
    E -->|NetBird + JWT required| G[NetBird with JWT Auth]
    E -->|NetBird + No JWT| H[NetBird without JWT]

    F --> I[Standard SSH Connection]
    H --> I

    G --> J[Request JWT from NetBird daemon]

    J --> J1{Check JWT cache}
    J1 -->|Cache valid| J2[Use cached JWT token]
    J1 -->|No cache/expired| J3[OIDC flow:<br/>User authorizes via IDP callback]
    J3 --> J4[Receive & cache JWT token]
    J4 --> K[Connect to peer SSH server]
    J2 --> K

    K --> M[Send JWT authentication request]
    M --> N{JWT Valid?}

    N -->|No| O[Connection Rejected]
    N -->|Yes| P[SSH Session Established]
    I --> P

    P --> Q[Interactive Shell / Execute Command / Port Forwarding]

    style G fill:#f57c00,color:#fff
    style J fill:#1976d2,color:#fff
    style J1 fill:#1976d2,color:#fff
    style J3 fill:#e65100,color:#fff
    style P fill:#388e3c,color:#fff
  1. Native SSH Flow (e.g. openssh client)
flowchart TD
    A[User: ssh &lt;peer&gt;] --> B[OpenSSH loads config:<br/>/etc/ssh/ssh_config.d/99-netbird.conf]
    B --> D{Host matches NetBird pattern?}

    D -->|No| E[Standard SSH connection]

    D -->|Yes| F[Run detection check:<br/>netbird ssh detect &lt;peer&gt; 22]
    F --> G{Is NetBird SSH server?}

    G -->|No| E

    G -->|Yes - JWT required| H[Activate ProxyCommand:<br/>netbird ssh proxy &lt;peer&gt; 22]

    H --> I[Local SSH Proxy Started]
    I --> J[OpenSSH connects to proxy via stdio]

    J --> K[Proxy requests JWT from daemon]

    K --> K1{Check JWT cache}
    K1 -->|Cache valid| K2[Use cached JWT token]
    K1 -->|No cache/expired| K3[OIDC flow:<br/>User authorizes via IDP callback]
    K3 --> K4[Receive & cache JWT token]
    K4 --> L[Proxy connects to peer SSH server]
    K2 --> L

    L --> M[Proxy sends JWT authentication]

    M --> N{JWT Valid?}
    N -->|No| O[Connection Rejected]
    N -->|Yes| P[Proxy establishes session]

    P --> Q[Bidirectional forwarding:<br/>OpenSSH ↔ Proxy ↔ Peer SSH Server]

    Q --> R[User interacts with remote shell]

    style H fill:#f57c00,color:#fff
    style I fill:#1976d2,color:#fff
    style K fill:#1976d2,color:#fff
    style K1 fill:#1976d2,color:#fff
    style K3 fill:#e65100,color:#fff
    style Q fill:#388e3c,color:#fff

    classDef proxyBox fill:#1565c0,stroke:#0d47a1,stroke-width:2px,color:#fff
    class I,K,L,M,P,Q proxyBox

Fixes https://github.com/netbirdio/netbird/issues/4759 https://github.com/netbirdio/netbird/issues/4672 https://github.com/netbirdio/netbird/issues/4456 https://github.com/netbirdio/netbird/issues/4039 https://github.com/netbirdio/netbird/issues/3985 https://github.com/netbirdio/netbird/issues/2498 https://github.com/netbirdio/netbird/issues/4457

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)
  • Extended the README / documentation, if necessary

Documentation

Select exactly one:

  • I added/updated documentation for this change [ netbirdio/docs/pull/475 ]
  • Documentation is not needed for this change

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Summary by CodeRabbit

  • New Features
    • Complete SSH support: embedded SSH server and client (JWT-backed auth), SFTP, local/remote port forwarding, SSH proxy, host-key retrieval, session listing, SSH client config generation, server detection, and UI/WASM controls including SSH JWT cache TTL.
  • Bug Fixes
    • License check made quieter and more robust by suppressing noisy errors during scanning.
**Original Pull Request:** https://github.com/netbirdio/netbird/pull/4015 **State:** closed **Merged:** Yes --- ## Describe your changes ### NetBird SSH Client - Port forwarding - Windows support - Non-interactive commands - Single command execution over SSH ### SSH Server - SFTP - Port forwarding (without user switching) - PTY (interactive, non-interactive) - Non-PTY (commands) - Windows support - JWT auth (user identity instead of machine identity, can be turned off) ### New Flags ``` # server --enable-ssh-local-port-forwarding --enable-ssh-remote-port-forwarding --enable-ssh-root --enable-ssh-sftp --disable-ssh-auth # client --ssh-jwt-cache-ttl ``` ### UI - Better organization <img width="608" height="432" alt="image" src="https://github.com/user-attachments/assets/7e8f7415-7f7f-47f4-b945-d1e6135e8bd7" /> <img width="608" height="432" alt="image" src="https://github.com/user-attachments/assets/d463c3d3-0742-4700-91ca-29db0b47c1f4" /> <img width="608" height="432" alt="image" src="https://github.com/user-attachments/assets/8023d3de-f6fd-4c5d-8985-a49a452a6491" /> ### Changes - Default port changed to 22022 - Redirect port 22 to 22022 when SSH server enabled - Remove implicit OpenSSH firewall port - Management now passes its `jwks` config to peers with enabled ssh server - SSH server peers verify incoming clients' `jwt` with max token age - SSH clients request `jwt`s from the IdP and send these for authentication with remote ssh peers - Add `netbird ssh detect` command to detect if the remote peer is running the NetBird server - Add `netbird ssh proxy` command for native ssh and sftp clients. The proxy requests `jwt`s just like `netbird ssh`, passes them for authentication and bridges the connection between the native client and the remote server. - Add jwt capability to the wasm ssh client ### Auth Flows 1. NetBird SSH Flow (`netbird ssh <peer>`) ```mermaid flowchart TD A[User: netbird ssh &lt;peer&gt;] --> B[Connect to peer:22] B --> C[Detect Server Type] C --> D[Send 'netbird-detect' request] D --> E{Server Response} E -->|No NetBird identifier| F[Regular SSH Server] E -->|NetBird + JWT required| G[NetBird with JWT Auth] E -->|NetBird + No JWT| H[NetBird without JWT] F --> I[Standard SSH Connection] H --> I G --> J[Request JWT from NetBird daemon] J --> J1{Check JWT cache} J1 -->|Cache valid| J2[Use cached JWT token] J1 -->|No cache/expired| J3[OIDC flow:<br/>User authorizes via IDP callback] J3 --> J4[Receive & cache JWT token] J4 --> K[Connect to peer SSH server] J2 --> K K --> M[Send JWT authentication request] M --> N{JWT Valid?} N -->|No| O[Connection Rejected] N -->|Yes| P[SSH Session Established] I --> P P --> Q[Interactive Shell / Execute Command / Port Forwarding] style G fill:#f57c00,color:#fff style J fill:#1976d2,color:#fff style J1 fill:#1976d2,color:#fff style J3 fill:#e65100,color:#fff style P fill:#388e3c,color:#fff ``` 2. Native SSH Flow (e.g. openssh client) ```mermaid flowchart TD A[User: ssh &lt;peer&gt;] --> B[OpenSSH loads config:<br/>/etc/ssh/ssh_config.d/99-netbird.conf] B --> D{Host matches NetBird pattern?} D -->|No| E[Standard SSH connection] D -->|Yes| F[Run detection check:<br/>netbird ssh detect &lt;peer&gt; 22] F --> G{Is NetBird SSH server?} G -->|No| E G -->|Yes - JWT required| H[Activate ProxyCommand:<br/>netbird ssh proxy &lt;peer&gt; 22] H --> I[Local SSH Proxy Started] I --> J[OpenSSH connects to proxy via stdio] J --> K[Proxy requests JWT from daemon] K --> K1{Check JWT cache} K1 -->|Cache valid| K2[Use cached JWT token] K1 -->|No cache/expired| K3[OIDC flow:<br/>User authorizes via IDP callback] K3 --> K4[Receive & cache JWT token] K4 --> L[Proxy connects to peer SSH server] K2 --> L L --> M[Proxy sends JWT authentication] M --> N{JWT Valid?} N -->|No| O[Connection Rejected] N -->|Yes| P[Proxy establishes session] P --> Q[Bidirectional forwarding:<br/>OpenSSH ↔ Proxy ↔ Peer SSH Server] Q --> R[User interacts with remote shell] style H fill:#f57c00,color:#fff style I fill:#1976d2,color:#fff style K fill:#1976d2,color:#fff style K1 fill:#1976d2,color:#fff style K3 fill:#e65100,color:#fff style Q fill:#388e3c,color:#fff classDef proxyBox fill:#1565c0,stroke:#0d47a1,stroke-width:2px,color:#fff class I,K,L,M,P,Q proxyBox ``` ## Issue ticket number and link Fixes https://github.com/netbirdio/netbird/issues/4759 https://github.com/netbirdio/netbird/issues/4672 https://github.com/netbirdio/netbird/issues/4456 https://github.com/netbirdio/netbird/issues/4039 https://github.com/netbirdio/netbird/issues/3985 https://github.com/netbirdio/netbird/issues/2498 https://github.com/netbirdio/netbird/issues/4457 ## Stack <!-- branch-stack --> ### Checklist - [x] Is it a bug fix - [ ] Is a typo/documentation fix - [x] Is a feature enhancement - [x] It is a refactor - [x] Created tests that fail without the change (if possible) - [ ] Extended the README / documentation, if necessary ## Documentation Select exactly one: - [x] I added/updated documentation for this change [ netbirdio/docs/pull/475 ] - [ ] Documentation is **not needed** for this change --- > By submitting this pull request, you confirm that you have read and agree to the terms of the [Contributor License Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Complete SSH support: embedded SSH server and client (JWT-backed auth), SFTP, local/remote port forwarding, SSH proxy, host-key retrieval, session listing, SSH client config generation, server detection, and UI/WASM controls including SSH JWT cache TTL. * **Bug Fixes** * License check made quieter and more robust by suppressing noisy errors during scanning. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
saavagebueno added the pull-request label 2025-11-20 08:07:38 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SVI/netbird#4054