Скрипт добавления серверов из Google Cloud в config ssh

в 16:17, , рубрики: GCP, Google Cloud Platform, python, ssh, Серверное администрирование

Аннотация. Статья про очень простой скрипт, формирующий из списка серверов когфиг для ssh Linux. Проверено на Ubunta 18, используется Goodle Cloud SDK, Python 2.7, Bash.

После резкого увеличения количества серверов, с которыми приходится работать, понял, хранилище паролей и CMDB уже не дают такого оперативного доступа, как в те времена, когда просто помнил все ip и реквизиты наизусть. Может быть и потому, что CMDB мы до конца еще так и не осилили. Но тем не менее решать проблему быстрого доступа по SSH к большому количеству серверов как-то надо.

Дальше — с точки зрения терминала Linux (выполнялось на Ubunta 18). Возможно, работает и в других дистрибутивах и, вероятно, даже есть аналог на Windows — не смотрел.

Главные требования:

  • Легко повторять. Администраторов несколько
    и нужна возможность настроить одинаково у всех. Плюс к тому допускаем удаленную работу — хоть у каждого ноутбук, но ситуация, когда работаешь не за своим привычным "давно настроенным и отлаженным" компьютером бывает.
  • Сервера добавляются, удаляются, меняют адреса. Это должно учитываться.

Для этого решил использовать alias хостов в настройках ssh, список серверов получать через gcloud cli клиент GCP, а автоматизировать все это с помощью Python 2.7 (потому что он в Ubuntu был по умолчанию и я решил его изучить для работы с данными). Сам скрипт с описанием под катом.

Постановка задачи

Идея была такая: вести список связи "алиасов" серверов и их актуальных адресов таким образом, чтобы при установке подключения можно было использовать только имя. При этом сам список периодически актуализировать из GCP по API.

В итоге задач стояло несколько:

  1. Подключение к хосту набирая только запоминающееся его имя (обычно имена мы формируем по строгим правилам, поэтому достаточно знать клиента и систему, чтобы почти наверняка угадать имя сервера). Имена могут быть реальными (если сервер полностью создан нами) или "алиасами" внутри нашей cmdb (если сервер создан клиентом и имя присвоено по правилам клиента). В любом случае, имя запомнить проще, чем адрес. Адрес еще и меняется.
  2. Получение списка актуальных хостов с действующими адресами. Т.к. основной площадкой является GCP и 90% серверов там, то данная задача будет решаться через их API, а не средствами мониторинга.
  3. Поиск по именам хостов. Их хоть и проще запомнить, но количество растет, а память не безгранична :) Да и новым администраторам так проще.
  4. Обновление связки алиас — адрес только при изменении адреса. Это необходимо для того, чтобы отказаться от полного переписывания всех связок. Это позволит хранить связки не только для серверов GCP. Пока что эта задача не решена :(

Описание решения

Алиас для подключения

Тут все довольно просто и решено не мной. Утилита ssh в Linux поддерживает настройку алиасов в конфиг файле.

Расположение файла: ~.ssh/config

Формат файла мы использовали очень банальный, но на самом деле возможности там намного шире:

HOST  алиас_сервера
   HostName  ip_или_имя-сервера

Подробнее о возможностях конфигурации можно прочитать тут, тут или в официальной документации.

Дальнейшие шаги

  1. Использовать разные ключи для подключения к разным группам хостов. Немного паранойи с точки зрения безопасности не повредит.
  2. Обеспечить резервирование этого файла для защиты от случайных изменений и ошибок скрипта обновления.

Поиск по именам хостов

Тут решение принадлежит совершенно не мне, а Ben Lobaugh и описано в его статье.
Коротко говорят, использовал sed, который для простоты запуска (уж очень длинное правило в параметрах) сокращено через alias:

alias sshhosts="sed -rn ‘s/^s*Hosts+(.*)s*/1/ip’ ~/.ssh/config"

Если надо найти хост по части названия, то этот скрипт отлично дополняется утилитой grep и в итоге получается так:

sshhost | grep 'Искомая-часть-названия-хоста'

Есть и другие варианты, например, как описано тут.

Автозаполнение имени хоста

Спасибо за решение onix74 !
Добавить в ~/.bash_completion строку:

complete -W "$(grep "^Host " ~/.ssh/config | grep -v "*" | sed 's/[^ ]* *(.*)/1/')" ssh

Для команды ssh будет работать автозаполнение по списку алиасов серверов. Т.е. можно использовать ssh для подстановки имени ssh-сервера. Работает в bash.

Дальнейшие шаги

Планирую поделить хосты на группы, чтобы можно было выбирать все сервера определенного клиента или с определенным приложением. Думается, такая возможность будет интересна для массового выполнения скриптов и подключения Ansible; а также для создания разных реквизитов подключения для разных групп. Но насколько это действительно имеет смысл еще предстоит выяснить.

Получить список хостов из GCP

В этом шаге все довольно просто, если не считать настройки параметров (хотя и тут дело опыта). Решил использовать GCloud SDK для получения данных, т.к. пока пользуюсь им редко, но предполагаю, что когда-то это позволит мне все меньше использовать графический интерфейс и значительно упростить рутину администрирования. Поэтому основной аргумент — получение опыта.
Вероятно, то же самое можно было бы сделать используя curl и REST API GCP, и тогда решение было бы более универсальным (т.к. GCloud SDK требуют отдельной установки и инициализации, которые не так уж сложны, но все равно требуются).

Для получения нужной информации пришлось использовать формат json. Хотя это существенно упростило дальнейшую обработку полученного ответа, но заставило немного поломать голову с настройкой параметров форматирования в SDK.
В итоге получил такую команду:

gcloud compute instances list --filter="status:running" --format="json(name, status, networkInterfaces[].accessConfigs[])"

Возвращает только активные на текущий момент сервера (к остальным нет смысла подключаться) с информацией об их имени и сетевом интерфейсе. Пока что используется только один внешний интерфейс для каждого сервера.

Итоговый результат прилетает в json:

[
---...----
  {
    "name": "название-сервера",
    "networkInterfaces": [
      {
        "accessConfigs": [
          {
            "kind": "compute#accessConfig",
            "name": "External NAT",
            "natIP": "ip-адрес",
            "networkTier": "PREMIUM",
            "type": "ONE_TO_ONE_NAT"
          }
        ]
      }
    ],
    "status": "RUNNING"
  },
----...---
]

Дальнейшие шаги

Найти формат, вывод которого позволит минимизировать или вообще устранить последующую обработку.

Скрипт создания списка алиасов по данным из GCP

Скрипт написал на python 2.7 по двум причинам:

  1. я решил изучить его для работы с данными;
  2. python 2.7 стоит по умолчанию на большинстве систем под управлением linux — не будет проблем с использованием в других местах. Учитывая, что даже win сейчас позволяет поставить вторую систему и использовать Ubuntu как терминал.

Алгоритм следующий:

  1. Получаем список серверов из Google Cloud с помощью SDK, инициируя выполнение команды в консоли из python.
  2. Разбираем полученный JSON в понятные python типы.
  3. На выход отдаем строки в формате, необходимом для настройки ssh (при необходимости выход скрипта перенаправляется в .ssh/config или в какой-то промежуточный файл).

Посмотреть скрипт

#!/usr/bin/python
import commands
import json

sComputeListOutput = commands.getoutput('gcloud compute instances list --filter="status:running" --format="json(name, status, networkInterfaces[].accessConfigs[])" ')
s = json.loads(sComputeListOutput)
for server in s:
    print 'HOST ',server['name']
    print '   HostName ',server['networkInterfaces'][0]['accessConfigs'][0]['natIP']

Обновление только измененных данных

Эта задача пока в работе. Планирую читать файл ssh/config в рамках того же скрипта, сравнивать с полученными значениями и потом записывать весь результат обратно. Или генерировать новый файл отдельно и проводить сравнение, используя какой-нибудь diff — это позволит вручную подтверждать все изменения.

Автор: Александр

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js