Я пытаюсь создать туннель SSH в вычислительном экземпляре из среды, в которой не установлено gcloud
(стандартная среда NodeJS App Engine).
Какие шаги необходимы для этого? Как это делает команда gcloud compute ssh
? Есть ли библиотека NodeJS, которая уже это делает?
Вы можете использовать ssh2 для этого в nodejs.
«gcloud Compute ssh» генерирует постоянные ключи SSH для пользователя. Открытый ключ хранится в метаданных ключей SSH проекта или экземпляра, а гостевая среда создает необходимого локального пользователя и помещает ~/.ssh/authorized_keys в свой домашний каталог. Вы можете вручную добавить свой публичный ключ в инстанс, а затем подключиться к нему по ssh с помощью нодовой ssh-библиотеки 1. Или вы можете установить сценарий запуска для экземпляра при его создании 2. Как указал Cloud Ace, вы можете использовать модуль ssh2 3 для совместимости с node.js.
На самом деле он использует что-то под названием «Вход в ОС» — он хранит открытый ключ для конкретной учетной записи службы и нет метаданные конкретного экземпляра виртуальной машины. Я надеялся, что есть что-то, что сделает все за меня (например, команда gcloud compute ssh
CLI)
Вход в ОС на самом деле рассматривается, согласно официальной документации, как расширенный метод подключения к экземпляру виртуальной машины. И не связано с тем, как работает «gcloud computing ssh». Но, как вы заметили, этому методу по-прежнему требуется библиотека gcloud для подключения к экземпляру. В официальной документации подробно описано, как работают эти методы, которые являются единственными доступными для подключения к экземпляру виртуальной машины GCP: cloud.google.com/compute/docs/instances/….
В общем, вам нужно будет зарезервировать и назначить статический внешний IP-адрес для начала (если только вы не пытаетесь использовать SSH из той же сети). И необходимо определить правило брандмауэра для порта tcp/22
, которое затем можно применить в качестве «метки» к сетевому интерфейсу, которому назначен этот внешний IP-адрес.
Наоборот работает с gcloud app instances ssh
:
SSH into the VM of an App Engine Flexible instance
что может потребовать меньших усилий и затрат на настройку, поскольку виртуальная машина GCP обычно gcloud
установлена.
На самом деле я искал SSH в обычной виртуальной машине, а не в виртуальной машине, управляемой App Engine.
Я создал пакет gcloud-ssh-туннель, который выполняет необходимые действия:
Why?
в пакете)Чтобы подключиться по SSH к экземпляру GCP, вам необходимо:
Первые 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,
});
Это еще не все, что делает
gcloud compute ssh
, он также создает и добавляет закрытый/открытый ключ, используя вход в ОС.