SSH для экземпляра Google Compute с использованием NodeJS, без gcloud

Я пытаюсь создать туннель SSH в вычислительном экземпляре из среды, в которой не установлено gcloud (стандартная среда NodeJS App Engine).

Какие шаги необходимы для этого? Как это делает команда gcloud compute ssh? Есть ли библиотека NodeJS, которая уже это делает?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
478
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вы можете использовать ssh2 для этого в nodejs.

Это еще не все, что делает gcloud compute ssh, он также создает и добавляет закрытый/открытый ключ, используя вход в ОС.

Oded Niv 30.05.2019 11:48

«gcloud Compute ssh» генерирует постоянные ключи SSH для пользователя. Открытый ключ хранится в метаданных ключей SSH проекта или экземпляра, а гостевая среда создает необходимого локального пользователя и помещает ~/.ssh/authorized_keys в свой домашний каталог. Вы можете вручную добавить свой публичный ключ в инстанс, а затем подключиться к нему по ssh с помощью нодовой ssh-библиотеки 1. Или вы можете установить сценарий запуска для экземпляра при его создании 2. Как указал Cloud Ace, вы можете использовать модуль ssh2 3 для совместимости с node.js.


На самом деле он использует что-то под названием «Вход в ОС» — он хранит открытый ключ для конкретной учетной записи службы и нет метаданные конкретного экземпляра виртуальной машины. Я надеялся, что есть что-то, что сделает все за меня (например, команда gcloud compute ssh CLI)

Oded Niv 30.05.2019 11:53

Вход в ОС на самом деле рассматривается, согласно официальной документации, как расширенный метод подключения к экземпляру виртуальной машины. И не связано с тем, как работает «gcloud computing ssh». Но, как вы заметили, этому методу по-прежнему требуется библиотека gcloud для подключения к экземпляру. В официальной документации подробно описано, как работают эти методы, которые являются единственными доступными для подключения к экземпляру виртуальной машины GCP: cloud.google.com/compute/docs/instances/….

Lozano 30.05.2019 16:39

В общем, вам нужно будет зарезервировать и назначить статический внешний IP-адрес для начала (если только вы не пытаетесь использовать SSH из той же сети). И необходимо определить правило брандмауэра для порта tcp/22, которое затем можно применить в качестве «метки» к сетевому интерфейсу, которому назначен этот внешний IP-адрес.

Наоборот работает с gcloud app instances ssh:

SSH into the VM of an App Engine Flexible instance

что может потребовать меньших усилий и затрат на настройку, поскольку виртуальная машина GCP обычно gcloud установлена.

На самом деле я искал SSH в обычной виртуальной машине, а не в виртуальной машине, управляемой App Engine.

Oded Niv 30.05.2019 11:54
Ответ принят как подходящий

Я создал пакет gcloud-ssh-туннель, который выполняет необходимые действия:

  1. Создайте закрытый/открытый ключ, используя сшпк
  2. Импортирует открытый ключ, используя API входа в ОС
  3. SSH с использованием ssh2 (и специально создать туннель, потому что это был тот вариант использования, который мне был нужен — см. раздел Why? в пакете)
  4. Удалите открытый ключ, используя API входа в ОС (чтобы не переполнить учетную запись или оставить доступ безопасности)

Чтобы подключиться по SSH к экземпляру GCP, вам необходимо:

  1. Включить Вход в ОС
  2. Создайте учетную запись службы и назначьте ей роль «Вход администратора ОС Compute».
  3. Создайте ключ SSH и импортируйте его в учетную запись службы.
  4. Используйте этот ключ SSH и имя пользователя POSIX.

Первые 2 шага уже ссылаются на документацию.

Создайте SSH-ключ:

import {
  generatePrivateKey,
} from 'sshpk';

const keyPair = generatePrivateKey('ecdsa');

const privateKey = keyPair.toString();
const publicKey = keyPair.toPublic().toString();

Ключ импорта:

const osLoginServiceClient = new OsLoginServiceClient({
  credentials: googleCredentials,
});

const [result] = await osLoginServiceClient.importSshPublicKey({
  parent: osLoginServiceClient.userPath(googleCredentials.client_email),
  sshPublicKey: {
    expirationTimeUsec: ((Date.now() + 10 * 60 * 1_000) * 1_000).toString(),
    key: publicKey,
  },
});

SSH с помощью ключа:

const ssh = new NodeSSH();

await ssh.connect({
  host,
  privateKey,
  username: loginProfile.posixAccounts[0].username,
});

В этом примере я использую node-ssh, но вы можете использовать что угодно.

Единственная другая загвоздка в том, что вам нужно выяснить общедоступный хост. Реализация для этого выглядит так:

const findFirstPublicIp = async (
  googleCredentials: GoogleCredentials,
  googleZone: string,
  googleProjectId: string,
  instanceName: string,
) => {
  const instancesClient = new InstancesClient({
    credentials: googleCredentials,
  });

  const instances = await instancesClient.get({
    instance: instanceName,
    project: googleProjectId,
    zone: googleZone,
  });

  for (const instance of instances) {
    if (!instance || !('networkInterfaces' in instance) || !instance.networkInterfaces) {
      throw new Error('Unexpected result.');
    }

    for (const networkInterface of instance.networkInterfaces) {
      if (!networkInterface || !('accessConfigs' in networkInterface) || !networkInterface.accessConfigs) {
        throw new Error('Unexpected result.');
      }

      for (const accessConfig of networkInterface.accessConfigs) {
        if (accessConfig.natIP) {
          return accessConfig.natIP;
        }
      }
    }
  }

  throw new Error('Could not locate public instance IP address.');
};

Наконец, для очистки вам нужно вызвать deleteSshPublicKey с именем ключа, который вы импортировали:

const fingerprint = crypto
  .createHash('sha256')
  .update(publicKey)
  .digest('hex');

const sshPublicKey = loginProfile.sshPublicKeys?.[fingerprint];

if (!sshPublicKey) {
  throw new Error('Could not locate SSH public key with a matching fingerprint.');
}

const ssh = new NodeSSH();

await ssh.connect({
  host,
  privateKey,
  username: loginProfile.posixAccounts[0].username,
});

await osLoginServiceClient.deleteSshPublicKey({
  name: sshPublicKey.name,
});

Другие вопросы по теме