Spec-Zone.ru › Chef 16

Авторизация

[править на GitHub]

Все взаимодействия с сервером Chef Infra Server должны быть аутентифицированы с использованием API сервера Chef Infra Server, который представляет собой REST-API, позволяющий отправлять запросы на сервер Chef Infra Server. Только аутентифицированные запросы будут авторизованы. В большинстве случаев, особенно при использовании knife, Chef Infra Client или веб-интерфейса сервера Chef Infra Server, использование API сервера Chef Infra Server является прозрачным. В некоторых случаях использование API сервера Chef Infra Server требует более подробного подхода, например, при отправке запроса на языке Ruby, с помощью плагина knife или при использовании cURL.

Процесс авторизации гарантирует, что сервер Chef Infra Server отвечает только на запросы от авторизованных пользователей. Сервер Chef Infra Server использует шифрование с открытым ключом. При конфигурации узла и/или рабочей станции для работы с Chef Infra Client создаются пары открытого и закрытого ключей. Открытый ключ хранится на сервере Chef Infra Server, а закрытый ключ возвращается пользователю для безопасного хранения. (Закрытый ключ — это файл .pem, расположенный в каталоге .chef или в /etc/chef. )

Как Chef Infra Client, так и knife используют API сервера Chef Infra Server при взаимодействии с сервером Chef Infra Server. chef-validator использует API сервера Chef Infra Server, но только во время первого запуска Chef Infra Client на узле.

Каждый запрос на сервер Chef Infra Server от этих исполняемых файлов подписывает специальную группу HTTP-заголовков с помощью закрытого ключа. Затем сервер Chef Infra Server использует открытый ключ для проверки заголовков и содержимого.

Открытые и закрытые ключи

Каждый запрос, отправляемый Chef Infra Client на сервер Chef Infra Server, должен быть аутентифицированным запросом, использующим API сервера Chef Infra Server и закрытый ключ. При отправке запроса Chef Infra Client на сервер Chef Infra Server, Chef Infra Client аутентифицирует каждый запрос, используя закрытый ключ, расположенный в /etc/chef/client.pem.

Использование ключей сервера Chef Infra Server

Процесс авторизации гарантирует, что сервер Chef Infra Server отвечает только на запросы от авторизованных пользователей. Сервер Chef Infra Server использует шифрование с открытым ключом. При конфигурации узла и/или рабочей станции для работы с Chef Infra Client создаются пары открытого и закрытого ключей. Открытый ключ хранится на сервере Chef Infra Server, а закрытый ключ возвращается пользователю для безопасного хранения. (Закрытый ключ — это файл .pem, расположенный в каталоге .chef или в /etc/chef. )

Как Chef Infra Client, так и knife используют API сервера Chef Infra Server при взаимодействии с сервером Chef Infra Server. chef-validator использует API сервера Chef Infra Server, но только во время первого запуска Chef Infra Client на узле.

Каждый запрос на сервер Chef Infra Server от этих исполняемых файлов подписывает специальную группу HTTP-заголовков с помощью закрытого ключа. Затем сервер Chef Infra Server использует открытый ключ для проверки заголовков и содержимого.

Chef Infra Client

Chef Infra Client аутентифицируется на сервере Chef Infra Server с помощью пар ключей RSA каждый раз, когда Chef Infra Client нуждается в доступе к данным, хранящимся на сервере Chef Infra Server. Это предотвращает доступ любого узла к данным, на которые у него нет прав, и гарантирует, что управлять могут только узлы, должным образом зарегистрированные на сервере Chef Infra Server.

Knife

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

Knife также может использовать подкоманду knife exec, чтобы отправлять конкретные аутентифицированные запросы на сервер Chef Infra Server. Плагины knife также могут отправлять аутентифицированные запросы на сервер Chef Infra Server, используя подкоманду knife exec.

chef-validator

Однако во время первого запуска Chef Infra Client этого закрытого ключа не существует. Вместо этого Chef Infra Client пытается использовать закрытый ключ, назначенный chef-validator, расположенный в /etc/chef/validation.pem. (Если по какой-либо причине chef-validator не может отправить аутентифицированный запрос на сервер Chef Infra Server, первый запуск Chef Infra Client завершится ошибкой.)

Во время первоначального запуска Chef Infra Client, Chef Infra Client регистрирует себя на сервере Chef Infra Server, используя закрытый ключ, назначенный chef-validator, после чего Chef Infra Client получит закрытый ключ client.pem для всех будущих аутентификационных запросов к серверу Chef Infra Server.

После успешного завершения первоначального запуска Chef Infra Client, chef-validator больше не требуется и может быть удален с узла. Используйте рецепт delete_validation из кулинарной книги chef-client (https://github.com/chef-cookbooks/chef-client) для удаления chef-validator.

Хранение ключей сервера Chef Infra Server

Ключи хранятся в разных местах, в зависимости от того, является ли местоположение узлом или рабочей станцией.

Узлы

Каждый узел хранит свой закрытый ключ локально. Этот закрытый ключ генерируется в ходе процесса инициализации, который изначально устанавливает Chef Infra Client на узел. При первом запуске Chef Infra Client на данном узле он использует chef-validator для аутентификации, но затем при каждом последующем запуске он использует закрытый ключ, сгенерированный для этого клиента сервером Chef Infra Server.

Рабочие станции

Каждая рабочая станция хранит свой закрытый ключ в chef-repo. Этот закрытый ключ генерируется сервером Chef Infra Server и должен быть скачан с сервера и скопирован в каталог .chef в chef-repo. Если требуется новый закрытый ключ, просто сгенерируйте его на сервере Chef Infra Server и скопируйте его обратно в chef-repo.

chef-repo — это каталог на вашей рабочей станции, который хранит все необходимое для определения вашей инфраструктуры с помощью Chef Infra:

  • Кулинарные книги (включая рецепты, атрибуты, пользовательские ресурсы, библиотеки и шаблоны)
  • Мешки с данными
  • Политики

Каталог chef-repo должен быть синхронизирован с системой управления версиями, такой как git. Все данные в chef-repo должны обрабатываться как исходный код.

Для загрузки данных на сервер Chef Infra Server из каталога chef-repo вы будете использовать команды chef и knife. После загрузки данных Chef Infra Client использует эти данные для управления узлами, зарегистрированными на сервере Chef Infra Server, и для обеспечения применения правильных кулинарных книг, политик и настроек к соответствующим узлам в правильном порядке.

Каталог .chef — это скрытый каталог, используемый для хранения файлов ключей проверки и, по желанию, файла config.rb.

Авторизация API сервера Chef Infra Server

Запросы API

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

Плагин knife можно использовать для отправки аутентифицированных запросов API на сервер Chef Infra Server с помощью следующих методов:

Метод Описание
rest.delete_rest Используется для удаления объекта с сервера Chef Infra Server.
rest.get_rest Используется для получения подробностей об объекте на сервере Chef Infra Server.
rest.post_rest Используется для добавления объекта на сервер Chef Infra Server.
rest.put_rest Используется для обновления объекта на сервере Chef Infra Server.

Например:

module MyCommands
  class MyNodeDelete < Chef::Knife
    #An implementation of knife node delete
    banner 'knife my node delete [NODE_NAME]'

    def run
      if name_args.length < 1
        show_usage
        ui.fatal('You must specify a node name.')
        exit 1
      end
      nodename = name_args[0]
      api_endpoint = "nodes/#{nodename}"
      # Again, we could just call rest.delete_rest
      nodey = rest.get_rest(api_endpoint)
      ui.confirm("Do you really want to delete #{nodey}")
      nodey.destroy
    end
  end
end

Из веб-интерфейса

Веб-интерфейс сервера Chef Infra Server использует API сервера Chef Infra Server для выполнения большинства операций. Это гарантирует, что запросы на аутентификацию на сервере Chef Infra Server будут авторизованы. Этот процесс авторизации выполняется автоматически и не требует управления со стороны пользователей размещенного сервера Chef Infra Server. Для локального сервера Chef Infra Server ключи аутентификации, используемые веб-интерфейсом, должны поддерживаться отдельными администраторами, ответственными за управление сервером.

Другие варианты

Наиболее распространенные способы взаимодействия с сервером Chef Infra Server с использованием API сервера Chef Infra Server абстрагируют API от пользователя. Тем не менее, API сервера Chef Infra Server можно использовать напрямую. В следующих разделах описаны некоторые из способов сделать это.

cURL

Запрос к API можно отправить с помощью cURL, для чего необходимы две утилиты: awk и openssl. Следующий пример демонстрирует, как можно отправить аутентифицированный запрос с помощью API сервера Chef Infra Server и cURL:

#!/usr/bin/env bash

_chef_dir () {
  # Helper function:
  # Recursive function that searches for chef configuration directory
  # It looks upward from the cwd until it hits /.  If no directory is found,
  # ~/.chef is chosen if it exists
  # You could simply hard-code the path below

  if [ "$PWD" = "/" ]; then
  if [ -d ".chef" ]; then
    echo "/.chef"
      elif [ -d "$HOME/.chef" ]; then
        echo "$HOME/.chef"
      fi
    return
  fi

  if [ -d '.chef' ];then
    echo "${PWD}/.chef"
  else
    (cd ..; _chef_dir)
  fi
}

_chomp () {
  # helper function to remove newlines
  awk '{printf "%s", $0}'
}

chef_api_request() {
  # This is the meat-and-potatoes, or rice-and-vegetables, your preference really.

  local method path body timestamp chef_server_url client_name hashed_body hashed_path
  local canonical_request headers auth_headers

  chef_server_url="https://api.opscode.com/organizations/my_org"
  # '/organizations/ORG_NAME' is needed
  if echo $chef_server_url | grep -q "/organizations/" ; then
    endpoint=/organizations/${chef_server_url#*/organizations/}${2%%\?*}
  else
    endpoint=${2%%\?*}
  fi
  path=${chef_server_url}$2
  client_name="chef_user"
  method=$1
  body=$3

  hashed_path=$(echo -n "$endpoint" | openssl dgst -sha1 -binary | openssl enc -base64)
  hashed_body=$(echo -n "$body" | openssl dgst -sha1 -binary | openssl enc -base64)
  timestamp=$(date -u "+%Y-%m-%dT%H:%M:%SZ")

  canonical_request="Method:$method\nHashed Path:$hashed_path\nX-Ops-Content-Hash:$hashed_body\nX-Ops-Timestamp:$timestamp\nX-Ops-UserId:$client_name"
  headers="-H X-Ops-Timestamp:$timestamp \
    -H X-Ops-Userid:$client_name \
    -H X-Chef-Version:0.10.4 \
    -H Accept:application/json \
    -H X-Ops-Content-Hash:$hashed_body \
    -H X-Ops-Sign:version=1.0"

  auth_headers=$(printf "$canonical_request" | openssl rsautl -sign -inkey \
    "$(_chef_dir)/${client_name}.pem" | openssl enc -base64 | _chomp |  awk '{ll=int(length/60);i=0; \
    while (i<=ll) {printf " -H X-Ops-Authorization-%s:%s", i+1, substr($0,i*60+1,60);i=i+1}}')

  case $method in
    GET)
      curl_command="curl $headers$auth_headers$path"
      $curl_command
      ;;
    *)
      echo "Unknown Method. I only know: GET" >&2
      return 1
      ;;
    esac
  }

 chef_api_request "$@"

После сохранения этого скрипта оболочки в файле с именем chef_api_request, используйте его следующим образом:

bash chef_api_request GET "/clients"

PyChef

Запрос к API можно отправить с помощью PyChef, который представляет собой библиотеку Python, соответствующую требованиям Mixlib::Authentication, что позволит легко взаимодействовать с сервером Chef Infra Server. Следующий пример демонстрирует, как можно отправить аутентифицированный запрос с помощью API сервера Chef Infra Server и PyChef:

from chef import autoconfigure, Node

api = autoconfigure()
n = Node('web1')
print n['fqdn']
n['myapp']['version'] = '1.0'
n.save()

и следующий пример демонстрирует, как отправлять запросы к API напрямую:

from chef import autoconfigure

api = autoconfigure()
print api.api_request('GET', '/clients')

В предыдущих примерах предполагается, что текущая рабочая директория такова, что PyChef может найти правильный файл конфигурации аналогично Chef Infra Client или knife. Для получения дополнительной информации о PyChef см.: https://github.com/coderanger/pychef.

Ruby

На системе с установленным Chef Infra Client используйте Ruby для отправки аутентифицированного запроса к серверу Chef Infra Server:

require 'chef/config'
require 'chef/log'
require 'chef/rest'

chef_server_url = 'https://chefserver.com'
client_name = 'clientname'
signing_key_filename = '/path/to/pem/for/clientname'

rest = Chef::REST.new(chef_server_url, client_name, signing_key_filename)
puts rest.get_rest('/clients')

или:

require 'mixlib/cli'
require 'chef'
require 'chef/node'
require 'chef/mixin/xml_escape'
require 'json'

config_file = 'c:/chef/client.rb'
Chef::Config.from_file(config_file)
Chef::Log.level = Chef::Config[:log_level]

def Usage()
  puts '/etc/chef/client.rb' # The config file location, e.g. ~/home/.chef/config.rb etc
  config_file = gets.chomp
  if (!File.exist?(config_file))
    puts 'config_file #{config_file} does not exist. Exiting.\n'
    exit
  end
  STDOUT.puts <<-EOF
    Choose options e.g. 1

    1 Display all nodes per environment
    2 Display all nodes in detail (can be slow if there a large number of nodes)
    9 Exit
  EOF
end

def ExecuteUserChoice()
  testoption = gets.chomp
  case testoption
  when '1'
    Execute(method(:DisplayNodesPerEnv))
  when '2'
    Execute(method(:DisplayNodesDetail))
  when '9'
    puts 'exit'
  else
    puts 'Unknown option #{testoption}. Exiting\n'
    exit
  end
end

def DisplayNodesPerEnv()
  Chef::Environment.list(false).each do |envr|
    print 'ENVIRONMENT: ', envr[0], '\n'
    Chef::Node.list_by_environment(envr[0], false).each do |node_info|
      print '\tNODE: ', node_info[0], '\n'
      print '\t\tURL: ', node_info[1], '\n'
    end
  end
end

def DisplayNodesDetail()
  Chef::Node.list(true).each do |node_array|
    node = node_array[1]
    print '#{node.name}\n'
    print '\t#{node['fqdn']}\n'
    print '\t#{node['kernel']['machine']}\n'
    print '\t#{node['kernel']['os']}\n'
    print '\t#{node['platform']}\n'
    print '\t#{node['platform_version']}\n'
    print '\t#{node.chef_environment}\n'
    print '\t#{node.run_list.roles}\n'
  end
end

def Execute(option)
  begin
    profilestart = Time.now
    option.call()
    profileend = Time.now
    timeofrun = profileend - profilestart
    print 'Time taken = #{timeofrun}'
  rescue Exception => ex
    print 'Error calling chef API'
    print ex.message
    print ex.backtrace.join('\n')
  end
end

Usage()
ExecuteUserChoice()

Другой способ использования Ruby с API сервера Chef Infra Server — это получение объектов с сервера Chef Infra Server и взаимодействие с возвращаемыми данными с помощью методов Ruby. В меру возможности API сервера Chef Infra Server будет возвращать объект соответствующего типа. Возвращаемый объект затем доступен для вызова другими методами. Например, метод api.get может быть использован для возвращения узла с именем foobar, а затем .destroy может быть использован для удаления этого узла:

silly_node = api.get('/nodes/foobar')
silly_node.destroy

Отладка проблем с авторизацией

В некоторых случаях Chef Infra Client может получить ответ 401 на запрос авторизации и ответ 403 на запрос авторизации. Ошибка авторизации может выглядеть следующим образом:

[Wed, 05 Oct 2011 15:43:34 -0700] INFO: HTTP Request Returned 401
Unauthorized: Failed to authenticate as node_name. Ensure that your node_name and client key are correct.

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

chef-client -l debug

При включенном отладочном выводе в логе будет запись, похожая на следующую:

[Wed, 05 Oct 2011 22:05:35 +0000] DEBUG: Signing the request as NODE_NAME

Если запрос на аутентификацию происходит во время первоначального запуска Chef Infra Client, проблема, скорее всего, в закрытом ключе.

Если аутентификация происходит на узле, есть ряд распространённых причин:

  • Файл client.pem содержит неверные данные. Это можно исправить, удалив файл client.pem и повторно запустив Chef Infra Client. При повторном запуске Chef Infra Client он снова попытается зарегистрироваться на Chef Infra Server и сгенерировать правильный ключ.
  • Значение node_name отличается от того, которое использовалось при первоначальном запуске Chef Infra Client. Это может произойти по нескольким причинам. Например, если в файле client.rb не указано правильное имя узла, а имя хоста недавно изменилось. Эту проблему можно решить, явно задав имя узла в файле client.rb или используя опцию -N для исполняемого файла Chef Infra Client.
  • Системные часы отклонились от реального времени более чем на 15 минут. Это можно исправить, синхронизировав часы с сервером Network Time Protocol (NTP).

Авторизация

Для получения дополнительной информации об авторизации Chef Infra Server см. Организации и группы.

API Chef Infra Server

Для получения дополнительной информации об использовании конечных точек API Chef Infra Server см. API Chef Infra Server.

© Chef Software, Inc.
Licensed under the Creative Commons Attribution 3.0 Unported License.
The Chef™ Mark and Chef Logo are either registered trademarks/service marks or trademarks/servicemarks of Chef, in the United States and other countries and are used with Chef Inc's permission.
We are not affiliated with, endorsed or sponsored by Chef Inc.
https://docs.chef.io/auth/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API