mscdex / ssh2

SSH2 client and server modules written in pure JavaScript for node.js
MIT License
5.51k stars 662 forks source link

Access virtual machine on Teleport #1391

Closed lucasfellipe3g closed 2 months ago

lucasfellipe3g commented 4 months ago

Hey!

I want to connect to a machine on the teleport via ssh, but I can't! I configured my ssh as follows and I need to know if there is any way. If anyone could help me, I would be grateful.

Host *.teleport teleport.amz.xxx.com
    UserKnownHostsFile "/Users/<user>/.tsh/known_hosts"
    IdentityFile "/Users/<user>/.tsh/keys/teleport.amz.xxx.com/key"
    CertificateFile "/Users/<user>/.tsh/keys/teleport.amz.xxx.com/key-ssh/teleport-cert.pub"
    HostKeyAlgorithms rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com

# Flags for all teleport hosts except the proxy
Host *.teleport !teleport.amz.xxx.com
    Port 3022
    ProxyCommand "/usr/local/bin/tsh" proxy ssh --cluster=teleport --proxy=teleport.amz.xxx.com:443 %r@%h:%p

Is there way? Help me, please!

mscdex commented 4 months ago

You're going to have to expand on "but I can't". Did you get an error? Is something not behaving as expected? Did a pet chew through your ethernet cable? Something else?

If you're trying to connection hop, there is an example in the README. For connection configuration, please also check the README.

lucasfellipe3g commented 4 months ago

Sorry, I tried of the following way:

export let connection: SSH2Client | null = null

export async function connect(app: FastifyInstance) {
  app.withTypeProvider<ZodTypeProvider>().post(
    '/ssh/connect',
    {
      schema: {
        body: z.object({
          host: z.string(),
          port: z.number(),
          username: z.string(),
          password: z.string().optional(),
        }),
      },
    },
    (request, reply) => {
      const { host, port, username, password } = request.body

      connection = new SSH2Client({
        captureRejections: true,
      })

      connection.on('ready', () => {
        return reply.status(201).send({ message: 'SSH connection established' })
      })

      connection.connect({
        host,
        port,
        username,
        password,
        privateKey: password ? '' : env.SSH_KEY,
        agent: process.env.SSH_AUTH_SOCK,
      })
    },
  )
}

When I call this route with the following parameters:

{
  "username": "user",
  "host": "lynx-dev.teleport",
  "port": 22
}

I receive this following error:

node:events:496
      throw er; // Unhandled 'error' event
      ^

Error: getaddrinfo ENOTFOUND lynx-dev.teleport
    at __node_internal_captureLargerStackTrace (node:internal/errors:563:5)
    at __node_internal_ (node:internal/errors:782:10)
    at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:118:26)
Emitted 'error' event on Client instance at:
    at Socket.<anonymous> (/Users/lucasfellipe/www/nash/management-server/node_modules/.pnpm/ssh2@1.15.0/node_modules/ssh2/lib/client.js:807:12)
    at Socket.emit (node:events:518:28)
    at Socket.emit (node:domain:488:12)
    at emitErrorNT (node:internal/streams/destroy:169:8)
    at emitErrorCloseNT (node:internal/streams/destroy:128:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'lynx-dev.teleport',
  level: 'client-socket'
}

Can you help me?

When I access via ssh, it works, with the following command: ssh user@lynx-dev.teleport

mscdex commented 4 months ago

ssh2 has nothing to do with OpenSSH configuration files. You will either need to find a module that can parse the file for you and use the resulting information with ssh2, or you will need to copy and translate the information from your configuration file into your connection configuration object passed to connect().

Additionally, I don't know what "teleport" is, so you will need to do one of two things:

  1. Figure out what your proxy command is doing to do the connection hopping yourself

  2. Use child_process.spawn() with your proxy command, create a Duplex/Transform wrapper stream such that the input is passed to child.stdin and the output comes from child.stdout, and then pass that wrapper stream to ssh2 as sock in the connection configuration object so it will use that for the underlying connection instead of a new TCP connection.

Crystal-RainSlide commented 2 months ago

You might use https://github.com/cyjake/ssh-config to parse your config.

But please just skip ssh2 for now (and maybe for the next 7 years or so). Since Teleport uses certificate for server authentication, and ssh2 don't support that: https://github.com/mscdex/ssh2/issues/551#issuecomment-567641103