Как автоматически добавлять новые капли в вашу систему управления конфигурацией

Вступление

Используя службу метаданных DigitalOcean, администраторы могут предоставить инструкции, которые позволяют новым серверам настраиваться автоматически. Хотя это полезно, многим организациям нравится обрабатывать все свои конфигурации инфраструктуры с помощью инструмента управления конфигурацией, такого как Chef или Puppet.

В этом руководстве мы покажем, как загрузить сервер DigitalOcean с помощью службы метаданных и CloudInit для подключения к существующему развертыванию управления конфигурацией. Фактическая конфигурация сервера может затем обрабатываться службой управления конфигурацией. Мы покажем, как загрузить узлы Chef и Puppet.

Предпосылки

Для того, чтобы завершить это руководство, вы должны быть немного знакомы со службой метаданных DigitalOcean. Вы можете узнать больше о том, как вводить информацию и получать информацию из службы метаданных вthis guide.

В этом руководстве будет использоваться тип сценария под названиемcloud-config, который используется при первой загрузке службой CloudInit на вашей капле для выполнения настройки при первом запуске. Вы должны получить базовые знания о сценарияхcloud-config, их синтаксисе и поведении, чтобы лучше понять, как изменять сценарии, представленные в этом руководстве. Вы можете найти введение в сценарий облачной конфигурацииhere. В качестве более практического примера (наряду с некоторым обсуждением ограничений формата) вы можете прочитать наше руководство по выполнению некоторых основных задач с использованием cloud-confighere.

Использование сценариев Cloud-Config для начальной загрузки узла шеф-повара

Используя службу метаданных DigitalOcean, вы можете легко подключить свои новые серверы к существующей инфраструктуре, управляемой Chef, с помощью сценариевcloud-config.

Чтобы добавить новый сервер в эту систему, у вас уже должен быть настроен сервер Chef, с которым ваш новый сервер может связаться для получения инструкций по настройке. Если вам нужна помощь в развертывании сервера Chef и управляющей рабочей станции, вы можете начать работу сthis guide.

Генеральный план

Когда новый сервер подключен к сети, он должен быть переведен под контроль сервера Chef. Обычно это можно сделать, подключившись к новому серверу с помощью команды управленияknife и используя подкомандуbootstrap. Это позволит подключиться к новому серверу, установить клиент Chef и учетные данные проверки, которые позволят новому узлу подключиться к серверу Chef. После этого клиент Chef подключается к серверу, проверяет себя, получает новые учетные данные клиента, снимает свою конфигурацию с сервера и выполняет любые действия, необходимые для приведения себя в требуемое состояние.

В этом руководстве мы будем использовать сценарийcloud-config для замены шага начальной загрузки вручную, позволяя новому узлу автоматически подключаться к серверу Chef, проверять себя, получать учетные данные клиента и выполнять начальный запуск клиента Chef. Сервер сделает это автоматически при первой загрузке без какой-либо помощи со стороны администратора.

Сбор необходимых данных из файла конфигурации ножа

Чтобы наш сценарийcloud-config успешно загрузился, ему потребуется доступ к учетным данным, обычно доступным для командыknife. В частности, нам нужны следующие фрагменты информации:

  • Имя проверки шеф-повара

  • Ключ проверки

  • URL, по которому можно связаться с сервером Chef

Вся эта информация доступна в правильном формате в файле конфигурацииknife на рабочей станции, используемой для управления инфраструктурой Chef. Внутри репозитория Chef должен быть скрытый каталог с именем.chef, содержащий этот файл.

Предполагая, что ваше репозиторий Chef расположен в вашем домашнем каталоге на рабочей станции и называетсяchef-repo, вы можете вывести содержимое файла, набрав:

cat ~/chef-repo/.chef/knife.rb

Куски необходимой информации выделены ниже:

current_dir = File.dirname(__FILE__)
log_level                :info
log_location             STDOUT
node_name                "jellingwood"
client_key               "#{current_dir}/jellingwood.pem"
validation_client_name   "digitalocean-validator"
validation_key           "#{current_dir}/digitalocean-validator.pem"
chef_server_url          "https://your_server.com/organizations/digitalocean"
syntax_check_cache_path  "#{ENV['HOME']}/.chef/syntaxcache"
cookbook_path            ["#{current_dir}/../cookbooks"]

Имя проверки и URL-адрес сервера Chef можно получить непосредственно из файла как есть. Скопируйте эти значения, чтобы использовать их в файлеcloud-config.

validation_key указывает на место, где хранится фактический ключ. В приведенном выше примере это означает, что он находится в том же каталоге, что и файлknife.rb, и называетсяdigitalocean-validator.pem. Вероятно, это будет отличаться для вашей конфигурации.

Нам нужно содержимое этого файла, поэтому снова воспользуйтесь командойcat. Измените команду так, чтобы она указывала на местоположение, указанное для вашего ключа валидатора:

cat ~/chef-repo/.chef/digitalocean-validator.pem

Вы увидите закрытый ключ RSA:

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f
V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ
vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU

. . .

sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ
Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3
eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO
-----END RSA PRIVATE KEY-----

Скопируйте ключ проверки целиком, чтобы сразу же использовать его в сценарииcloud-config.

Базовая установка клиента Cloud-Config Chef

Если у вас есть данные выше, вы можете создать сценарий. Конфигурация Chef может быть выполнена с помощью специального модуляcloud-config под названиемchef. cloud-config должен содержать действительный YAML и должен иметь#cloud-config в качестве первой строки скрипта.

Начиная с, ваш скрипт будет выглядеть так:

#cloud-config
chef:

В документацииcloud-config утверждается, что клиент Chef можно установить либо из драгоценного камня Ruby, либо из пакета, либо с помощью традиционного метода установки «омнибус». Однако на практике методы gem и package обычно терпят неудачу, поэтому мы будем использовать метод «omnibus». Хотя обычно в этом нет необходимости, мы также явно перечислим расположение установщика omnibus.

Мы установимforce_install на «ложь». Таким образом, если по какой-либо причине клиент Chef уже установлен в образе (например, если вы развертываете из снимка), клиент не будет переустановлен. Пока что наш скрипт выглядит так:

#cloud-config
chef:
  install_type: "omnibus"
  omnibus_url: "https://www.opscode.com/chef/install.sh"
  force_install: false

Затем у нас есть возможность выбрать имя для нового сервера в инфраструктуре Chef с помощью директивыnode_name. Если вы не установите это, Chef будет использовать имя хоста сервера, так что это необязательно. Тем не менее, это должно быть уникальным в вашей среде шеф-повара.

После этого мы можем добавить всю информацию о подключении, которую мы взяли с нашей рабочей станции Chef. Мы установим опциюserver_url на расположение сервера Chef точно так же, как это было в файлеknife.rb. То же самое и с опциейvalidation_name.

В качестве ключа проверки мы будем использовать вертикальный символ YAML (|), чтобы ввести весь ключ проверки, который мы нашли на рабочей станции:

#cloud-config
chef:
  install_type: "omnibus"
  omnibus_url: "https://www.opscode.com/chef/install.sh"
  force_install: false
  node_name: "new_node"
  server_url: "https://your_server.com/organizations/digitalocean"
  validation_name: "digitalocean-validator"
  validation_key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f
    V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ
    vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU

    . . .

    sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ
    Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3
    eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO
    -----END RSA PRIVATE KEY-----

На этом этапе ваш сценарий имеет всю аутентификацию, необходимую для подключения к серверу Chef и создания учетных данных клиента.

Настройка среды шеф-повара, run_list и атрибутов

Хотя приведенные выше сведения предоставляют достаточно информации для подключения клиента к серверу Chef, мы не предоставили узлу никакой информации о том, как на самом деле настроить себя. Мы также можем предоставить эту информацию в скриптеcloud-config.

Чтобы указать среду, в которой должен быть размещен новый узел, используйте параметрenvironment. Если он не установлен, будет установлена ​​среда_default, которая является общим значением по умолчанию для узлов Chef, которым не была предоставлена ​​другая среда.

chef:
  environment: "staging"

Нашrun_list можно указать как простой список элементов, которые клиент должен применять по порядку. Это могут быть как рецепты, так и роли.

chef:
  run_list:
    - "recipe[lamp]"
    - "role[backend-web]"

Вы можете указать начальные атрибуты нового узла, используя иерархиюinitial_attributes. Это установит начальные атрибуты, которые повлияют на применениеrun_list:

chef:
  initial_attributes:
    lamp:
      apache:
        port: 80
      mysql:
        username: webclient
        pass: $#fjeaiop34S

При подключении к предыдущему сценариюcloud-config это может выглядеть примерно так:

#cloud-config
chef:
  install_type: "omnibus"
  omnibus_url: "https://www.opscode.com/chef/install.sh"
  force_install: false
  node_name: "new_node"
  server_url: "https://your_server.com/organizations/digitalocean"
  validation_name: "digitalocean-validator"
  validation_key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f
    V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ
    vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU

    . . .

    sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ
    Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3
    eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO
    -----END RSA PRIVATE KEY-----
  environment: "staging"
  run_list:
    - "recipe[lamp]"
    - "role[backend-web]"
  initial_attributes:
    lamp:
      apache:
        port: 80
      mysql:
        username: webclient
        pass: $#fjeaiop34S

Перенаправление вывода и настройка запуска клиента Chef

Приведенный выше сценарий содержит всю информацию, необходимую в разделеchef:. Однако есть еще несколько вещей, которые мы должны сделать, используя другие модулиcloud-config.

Во-первых, мы должны указать, что мы хотим перенаправить вывод каждой команды и подкоманды в выходной журнал процесса CloudInit. По умолчанию он находится в/var/log/cloud-init-output.log. Мы можем сделать это с помощью модуляoutput следующим образом:

output: {all: '| tee -a /var/log/cloud-init-output.log'}

Еще одна вещь, которую мы хотим сделать, - настроить клиент Chef так, чтобы он действительно работал после его установки и настройки. На момент написания этой статьи метод установки omnibus не делал этого автоматически.

Мы можем заставить это поведение, дождавшись, пока исполняемый файлchef-client не будет установлен на сервере, прежде чем вызывать команду. Используя простой циклbash, мы будем проверять наличие этого файла каждые пять секунд. Когда он будет найден, мы запустимchef-client, чтобы реализовать указанную нами начальную конфигурацию.

Модульruncmd можно использовать для выполнения произвольных команд. Это идеальное место для нашего циклаbash:

runcmd:
  - while [ ! -e /usr/bin/chef-client ]; do sleep 5; done; chef-client

Кроме того, при желании вы можете добавить еще одну директивуcloud-config для нулевого маршрута конечной точки метаданных после первой загрузки. Это полезно, потому что мы помещаем закрытый ключ в наши пользовательские данные. Без нулевой маршрутизации конечной точки метаданных это было бы доступно любому пользователю на сервере. Реализуйте это, добавив:

disable_ec2_metadata: true

Комбинируя их с созданным нами сценарием, мы можем получить полный сценарий, необходимый для начальной загрузки нашего узла и подключения его к нашей инфраструктуре Chef:

#cloud-config
chef:
  install_type: "omnibus"
  omnibus_url: "https://www.opscode.com/chef/install.sh"
  force_install: false
  node_name: "new_node"
  server_url: "https://your_server.com/organizations/digitalocean"
  validation_name: "digitalocean-validator"
  validation_key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f
    V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ
    vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU

    . . .

    sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ
    Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3
    eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO
    -----END RSA PRIVATE KEY-----
  environment: "staging"
  run_list:
    - "recipe[lamp]"
    - "role[backend-web]"
  initial_attributes:
    lamp:
      apache:
        port: 80
      mysql:
        username: webclient
        pass: $#fjeaiop34S
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
  - while [ ! -e /usr/bin/chef-client ]; do sleep 5; done; chef-client
disable_ec2_metadata: true

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

Использование сценариев Cloud-Config для начальной загрузки узла Puppet

Если ваша инфраструктура полагается на Puppet для управления конфигурацией, вы можете вместо этого использовать модульpuppet. Как и в примере Chef, при начальной загрузке узла Puppet используетсяcloud-config для подключения нового сервера к существующей инфраструктуре управления конфигурацией.

Прежде чем начать, вы должны настроить главный сервер Puppet для своей инфраструктуры. Если вам нужна помощь в настройке и запуске Puppet-сервера, ознакомьтесь сthis guide.

Генеральный план

Когда новый сервер Puppet подключается к сети, устанавливается агент Puppet, чтобы он мог обмениваться данными с главным сервером Puppet. Этот агент отвечает за получение и применение информации, которая определяет желаемое состояние узла. Для этого агент соединяется с мастером, загружает данные о себе, выводит текущий каталог, описывающий его желаемое состояние, и выполняет действия, необходимые для достижения этого состояния.

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

Используя наш скриптcloud-config, мы настроим наш новый сервер с информацией, необходимой ему для подключения к мастеру в первый раз. В этот момент он может получить сведения о конфигурации с главного сервера Puppet в виде каталога.

Сбор необходимых данных от Хозяина Марионеток

Первое, что нам нужно сделать перед созданием нашего файлаcloud-config, - это собрать данные с нашего главного сервера Puppet, которые нам нужно будет подключить. Нам нужно всего несколько кусочков информации.

Во-первых, вам нужно получить полное доменное имя (FQDN) главного сервера Puppet. Вы можете сделать это, набрав:

hostname -f

В большинстве случаев он должен возвращать что-то вроде этого:

puppet.example.com

Вы также можете проверить свой главный файл конфигурации Puppet, чтобы узнать, установлен ли параметрdns_alt_names:

cat /etc/puppet/puppet.conf
. . .

dns_alt_names = puppet,puppet.example.com

. . .

Если SSL-сертификаты вашего Puppet master были созданы после установки этих параметров, они также могут быть использованы.

Другим предметом, который нам нужно собрать, является сертификат центра сертификации Хозяина Марионеток. Его можно найти либо в/var/lib/puppet/ssl/certs/ca.pem, либо в/var/lib/puppet/ssl/ca/ca_crt.pem:

sudo cat /var/lib/puppet/ssl/certs/ca.pem

Результаты будут выглядеть примерно так:

-----BEGIN CERTIFICATE-----
MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw
ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx
GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC

. . .

arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP
rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe
l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR
UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg==
-----END CERTIFICATE-----

Скопируйте сертификат полностью. Мы будем включать это в наш файлcloud-config, чтобы наши новые серверы могли проверить, что они подключаются к правильному мастеру Puppet.

Получив эти данные, вы можете приступить к созданию файлаcloud-config, чтобы новый сервер мог подключиться к существующей инфраструктуре Puppet.

Базовая установка Puppet Node Cloud-Config

Конфигурацияcloud-config для новых узлов Puppet довольно проста. Вся конфигурация, специфичная для Puppet, находится в разделе файлаpuppet:. Как и в любом файлеcloud-config, самая первая строка должна содержать#cloud-config сама по себе:

#cloud-config
puppet:

Под этим есть только два подраздела. Первый - это клавишаca_cert. При этом будет использоваться символ канала для запуска текстового блока YAML, чтобы сертификат CA мог быть задан полностью как блок с отступом:

#cloud-config
puppet:
  ca_cert: |
    -----BEGIN CERTIFICATE-----
    MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw
    ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx
    GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC

    . . .

    arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP
    rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe
    l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR
    UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg==
    -----END CERTIFICATE-----

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

Второй раздел под зонтикомpuppet: - это разделconf:. Используется для указания пар ключ-значение, которые будут добавлены в общий файлpuppet.conf. Пары "ключ-значение" должны быть размещены под заголовками разделов, как в файлеpuppet.conf.

Например, по крайней мере, новый сервер должен знать адрес главного сервера Puppet. В файлеpuppet.conf это находится в разделе[agent], например:

. . .

[agent]
server = puppet.example.com

. . .

Чтобы указать это в синтаксисеcloud-config, вы должны добавить это к тому, что у нас есть:

#cloud-config
puppet:
  ca_cert: |
    -----BEGIN CERTIFICATE-----
    MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw
    ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx
    GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC

    . . .

    arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP
    rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe
    l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR
    UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg==
    -----END CERTIFICATE-----
  conf:
    agent:
      server: "puppet.example.com"

Обратите внимание, что разделconf: соответствует разделуca_cert, а не дочернему элементу. Это необходимый минимум для подключения к Хозяину Марионеток. Любые дополнительные элементы конфигурации, найденные вpuppet.conf, могут быть добавлены аналогичным образом, сначала создав уровень для имени раздела, а затем определив пару ключ-значение.

После этого мы должны перенаправить весь будущий вывод в файлcloud-init-output.log и добавить строкуruncmd, сопоставимую с той, которую мы добавили для конфигурации Chef. Это будет ждать, пока агент Puppet не будет установлен, а затем включить и перезапустить его. Мы также можем обнулить конечную точку метаданных после первого запуска, как мы делали в разделе Chef. Эти строки директивыcloud-config должны быть размещены вне любых других разделов модуля:

. . .

  conf:
    agent:
      server: "puppet.example.com"
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
  - while [ ! -e /usr/bin/puppet ]; do sleep 5; done; puppet agent --enable; service puppet restart
disable_ec2_metadata: true

С помощью этой информации новый сервер может подключиться к главному серверу Puppet, а затем сгенерировать запрос подписи сертификата клиента для передачи главному серверу. По умолчанию клиентские сертификаты должны быть подписаны вручную на мастере Puppet. Как только это будет сделано, в следующий интервал обновления агента Puppet (по умолчанию каждые 30 минут) узел будет извлекать свою конфигурацию из мастера Puppet. Чуть позже мы продемонстрируем, как реализовать относительно безопасный механизм автоподписи, чтобы избежать этой задержки.

Определение Certname для узла

Одно из значений, которое может быть помещено в файлpuppet.conf нового сервера, является уникальным случаем. В файлеcloud-config параметрcertname может заменять значения из среды, если заданы определенные переменные. Следующие переменные распознаются:

  • %i: идентификатор экземпляра сервера. Он будет взят изhttp://169.254.169.254/metadata/v1/id при создании сервера. Он соответствует идентификатору капли, используемому для уникальной идентификации капель.

  • %f: полное доменное имя сервера.

Имея это в виду, обычная настройкаcertname будет выглядеть так:

#cloud-config
puppet:

. . .

  conf:
    agent:
      server: "puppet.example.com"
      certname: "%i.%f"

Это дастcertname с шаблоном, подобным этому:

   |-Droplet ID
   |
   |            |-Fully Qualified Domain Name
   |            |
|-----||-------------------|
123456.testnode.example.com

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

Реализовать автоподписание сертификата марионетки

Если вы хотите внедрить систему автоматической подписи сертификатов, чтобы избежать необходимости вмешательства администратора, есть несколько вариантов. Сначала вы должны настроить это на своем главном сервере Puppet.

В файлеpuppet.conf на главном сервере Puppet вы можете установить параметрautosign в разделе[master] файла. Это может принимать несколько разных значений:

  • true: это укажет главному серверу Puppet подписывать каждый входящий запрос сертификата без каких-либо проверок. Это очень опасно в реальной среде, потому что любой хост может подписать CSR и войти в вашу инфраструктуру.

  • <whitelist_filename>: Второй вариант - указать файл, который будет функционировать как белый список хостов или регулярных выражений хостов. Хозяин Puppet проверит запросы на подпись сертификата по этому списку, чтобы увидеть, должен ли сертификат быть подписан. Это снова не рекомендуется, так как имена сертификатов могут быть легко подделаны.

  • <policy_executable>: третий вариант - указать сценарий или исполняемый файл, который можно запустить, чтобы определить, должен ли быть подписан запрос на подпись сертификата. Puppet передаст имя сертификата в качестве аргумента, а весь CSR - через стандартный ввод. Если статус выхода равен 0, сертификат подписывается. Если указан другой статус, сертификат будет подписанnot.

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

Чтобы продемонстрировать автоматическую подпись на основе политик, вы можете добавить переменнуюcertname к вашемуcloud-config, которая включает переменную идентификатора экземпляра%i. Мы будем использовать%i.%f, чтобы он также включал выбранное имя хоста:

#cloud-config
puppet:
  conf:
    agent:
      server: "puppet.example.com"
      certname: "%i.%f"
  ca_cert: |

   . . .

Ваш полныйcloud-config теперь может выглядеть примерно так:

#cloud-config
puppet:
  conf:
    agent:
      server: "puppet.example.com"
      certname: "%i.%f"
  ca_cert: |
    -----BEGIN CERTIFICATE-----
    MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw
    ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx
    GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC

    . . .

    arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP
    rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe
    l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR
    UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg==
    -----END CERTIFICATE-----
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
  - while [ ! -e /usr/bin/puppet ]; do sleep 5; done; puppet agent --enable; service puppet restart
disable_ec2_metadata: true

На главном сервере Puppet нам нужно будет настроить скрипт проверки. Поскольку Ruby уже установлен для Puppet, мы можем создать простой скрипт на Ruby.

Поскольку мы используем формат%i.%f дляcertname, мы можем проверить, соответствует ли первая частьcertname (часть перед первой точкой) действительному идентификатору капли для нашей учетной записи. . Это просто простая проверка, которая на практике не делает намного больше, чем файл белого списка. Тем не менее, вы можете адаптировать эту идею, чтобы быть гораздо более сложной, если хотите.

Для этого нам потребуется персональный токен доступа из раздела «Приложения и API» панели управления DigitalOcean. Вам также нужно будет установить одну из библиотек DigitalOcean Ruby. Ниже мы покажем вам несколько упрощенных скриптов, которые используют клиенты DigitalOcean RubyBarge иDropletKit.

Если вы хотите использовать клиент Barge, установите гем на своем Puppet master, набрав:

sudo gem install barge

Следующий сценарий можно использовать для проверки, соответствует ли первая частьcertname в запросе подписи сертификата действительному идентификатору капли:

#!/usr/bin/env ruby

require 'barge'

TOKEN = 'YOUR_DIGITALOCEAN_API_TOKEN'

droplet_ids = []
certname = ARGV[0]
id_string = certname.slice(0...(certname.index('.')))
id_to_check = id_string.to_i

client = Barge::Client.new(access_token: TOKEN)
droplets = client.droplet.all

droplets.droplets.each do |droplet|
        droplet_ids << droplet.id
end

Kernel.exit(droplet_ids.include?(id_to_check))

Если вы вместо этого хотите использовать DropletKit, официальный клиент DigitalOcean Ruby, вы можете установить гем, набрав:

sudo gem install droplet_kit

Обратите внимание, что гем DropletKit действителен только для Ruby 2.0 и выше, поэтому это может быть невозможно при использовании версии Ruby, поставляемой с Puppet.

Скрипт для DropletKit можно адаптировать так:

#!/usr/bin/env ruby

require 'droplet_kit'

TOKEN = 'YOUR_DIGITALOCEAN_API_TOKEN'

droplet_ids = []
certname = ARGV[0]
id_string = certname.slice(0...(certname.index('.')))
id_to_check = id_string.to_i

client = DropletKit::Client.new(access_token: TOKEN)
droplets = client.droplets.all

droplets.each do |droplet|
        droplet_ids << droplet.id
end

Kernel.exit(droplet_ids.include?(id_to_check))

Вы можете поместить скрипт, соответствующий установленному вами гему, в файл с именем/etc/puppet/validate.rb и пометить его как исполняемый, набрав:

sudo chmod +x /etc/puppet/validate.rb

Затем вы можете добавить следующее в свой файлpuppet.conf (расположенный в/etc/puppet/puppet.conf, если вы используете Puppet с открытым исходным кодом):

. . .

[master]
autosign = /etc/puppet/validate.rb

. . .

Перезапустите службу Apache для реализации новой политики подписывания:

sudo service apache2 restart

Теперь, когда ваш мастер Puppet получит запросы на подпись сертификата, он проверит, соответствует ли первая часть имени сертификата действительному имени капли в вашей учетной записи. Это грубый пример того, как вы можете проверять запросы, используя исполняемый файл.

Заключение

Используя сценарииcloud-config, вы можете легко загрузить свои новые серверы и передать их существующим системам управления конфигурацией. Это позволяет вам немедленно контролировать свою инфраструктуру с помощью существующих инструментов, прежде чем вносить важные изменения, выходящие за рамки вашего решения для управления.

Related