Авторизация
API сервера Chef Infra обрабатывает все взаимодействие между клиентом Chef Infra или рабочей станцией Chef. API сервера Chef Infra — это аутентифицированный REST-API, что означает, что все запросы требуют аутентификации и авторизации. Инструменты Chef Infra, такие как knife и chef-server команды, используют API сервера Chef Infra за вас.
Процесс аутентификации гарантирует, что сервер Chef Infra отвечает только на запросы от доверенных пользователей или клиентов. Сервер Chef Infra использует шифрование с открытым ключом. Вы создаёте открытый и закрытый ключи при настройке клиента Chef Infra или настройке рабочей станции Chef.
- Сервер Chef Infra хранит открытый ключ
- Рабочая станция Chef сохраняет закрытый ключ в
~/.chef/ - Клиент Chef Infra сохраняет закрытый ключ в
/etc/chef
Клиент и рабочая станция Chef взаимодействуют с сервером Chef Infra, используя API сервера Chef Infra. Каждый раз, когда клиент или рабочая станция Chef делают запрос к серверу Chef Infra, они используют специальную группу HTTP-заголовков и подписывают остальную часть запроса с помощью своего закрытого ключа. Сервер Chef Infra затем использует открытый ключ для проверки заголовков и содержимого.
Открытые и закрытые ключи
Каждый запрос, отправляемый клиентом Chef Infra серверу Chef Infra, должен быть аутентифицированным запросом, использующим API сервера Chef Infra и закрытый ключ. Когда клиент Chef Infra отправляет запрос серверу Chef Infra, клиент Chef Infra аутентифицирует каждый запрос, используя закрытый ключ, расположенный в /etc/chef/client.pem.
Использование ключа сервера Chef Infra
Процесс аутентификации гарантирует, что сервер Chef Infra отвечает только на запросы от доверенных пользователей или клиентов. Сервер Chef Infra использует шифрование с открытым ключом. Вы создаёте открытый и закрытый ключи при настройке клиента Chef Infra или настройке рабочей станции Chef.
- Сервер Chef Infra хранит открытый ключ
- Рабочая станция Chef сохраняет закрытый ключ в
~/.chef/ - Клиент Chef Infra сохраняет закрытый ключ в
/etc/chef
Клиент и рабочая станция Chef взаимодействуют с сервером Chef Infra, используя API сервера Chef Infra. Каждый раз, когда клиент или рабочая станция Chef делают запрос к серверу Chef Infra, они используют специальную группу HTTP-заголовков и подписывают остальную часть запроса с помощью своего закрытого ключа. Сервер Chef Infra затем использует открытый ключ для проверки заголовков и содержимого.
Клиент Chef Infra
Клиент Chef Infra аутентифицируется у сервера Chef Infra с использованием пар открытых и закрытых ключей RSA каждый раз, когда клиент Chef Infra нуждается в доступе к данным, хранящимся на сервере Chef Infra. Это предотвращает доступ любого узла к данным, к которым он не должен иметь доступ, и гарантирует, что управлять могут только узлы, должным образом зарегистрированные на сервере Chef Infra.
Knife
Пары открытых и закрытых ключей RSA используются для аутентификации knife у сервера Chef Infra каждый раз, когда knife пытается получить доступ к серверу Chef Infra. Это гарантирует, что каждый экземпляр knife должным образом зарегистрирован на сервере Chef Infra и что изменения в данных могут вносить только доверенные пользователи.
Knife также может использовать подкоманду knife exec для выполнения конкретных аутентифицированных запросов к серверу Chef Infra. Плагины knife также могут выполнять аутентифицированные запросы к серверу Chef Infra, используя подкоманду knife exec.
chef-validator
Закрытый ключ ещё не существует в первый раз, когда клиент Chef Infra запускается с нового узла.
Во время первого запуска клиента Chef Infra:
- Клиент Chef Infra использует закрытый ключ chef-validator, расположенный в
/etc/chef/validation.pemдля регистрации у сервера Chef Infra - Сервер Chef Infra назначает клиенту Chef Infra закрытый ключ для всех будущих запросов на аутентификацию у сервера Chef Infra
- Клиент Chef Infra сохраняет закрытый ключ на узле как
/etc/chef/client.pem
Если запрос на взаимодействие с сервером Chef Infra с помощью ключа chef-validator завершится неудачей, то весь первый запуск клиента Chef Infra завершится неудачей.
После успешного первого запуска клиента Chef Infra удалите закрытый ключ chef-validator по адресу /etc/chef/validation.pem
Хранение ключей сервера Chef Infra
Ключи хранятся в разных местах, в зависимости от того, является ли местоположение узлом или рабочей станцией.
Узлы
Каждый узел хранит свой закрытый ключ локально. Этот закрытый ключ генерируется в рамках процесса загрузки, который изначально устанавливает клиент Chef Infra на узел. В первый раз при запуске клиента Chef Infra на этом узле он использует chef-validator для аутентификации, но затем при каждом последующем запуске он использует закрытый ключ, сгенерированный для этого клиента сервером Chef Infra.
Рабочие станции
Каждая рабочая станция хранит свой закрытый ключ в каталоге пользователя ~/.chef. Этот закрытый ключ генерируется сервером Chef Infra и должен быть загружен с сервера и скопирован в каталог ~/.chef вручную. Если вам нужен новый закрытый ключ, сгенерируйте его на сервере Chef Infra и снова скопируйте его в каталог ~/.chef.
Каталог chef-repo на вашей рабочей станции хранит всё необходимое для определения вашей инфраструктуры с помощью Chef Infra:
- Кулинарные книги (включая рецепты, атрибуты, пользовательские ресурсы, библиотеки и шаблоны)
- Мешки данных
- Файлы политики
Каталог chef-repo должен быть синхронизирован с системой управления версиями, например, git. Все данные в каталоге chef-repo следует рассматривать как исходный код.
Вы будете использовать команды chef и knife для загрузки данных на сервер Chef Infra из каталога chef-repo. После загрузки клиент Chef Infra использует эти данные для управления зарегистрированными узлами на сервере Chef Infra и для обеспечения правильного применения кулинарных книг, файлов политики и настроек к соответствующим узлам в правильном порядке.
Каталог .chef — это скрытый каталог, используемый для хранения файлов ключей валидации и, необязательно, файла config.rb.
Аутентификация API сервера Chef Infra
Запросы API
Плагин knife — это набор одной (или нескольких) подкоманд, которые могут быть добавлены к knife для поддержки дополнительной функциональности, которая не включена в базовый набор подкоманд knife. Многие плагины knife создаются членами сообщества Chef, и несколько из них создаются и поддерживаются компанией Chef.
Плагин knife может быть использован для выполнения аутентифицированных запросов API к серверу Chef Infra с помощью следующих методов:
| Метод | Описание |
|---|---|
rest.delete_rest | Используется для удаления объекта с сервера Chef Infra. |
rest.get_rest | Используется для получения деталей объекта на сервере Chef Infra. |
rest.post_rest | Используется для добавления объекта на сервер Chef Infra. |
rest.put_rest | Используется для обновления объекта на сервере Chef Infra. |
Например:
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 использует API сервера Chef Infra для выполнения большинства операций. Это гарантирует, что запросы на аутентификацию у сервера Chef Infra авторизованы. Этот процесс аутентификации выполняется автоматически и не требует управления со стороны пользователей размещённого сервера Chef Infra. Для локального сервера Chef Infra ключи аутентификации, используемые веб-интерфейсом, должны поддерживаться отдельными администраторами, ответственными за управление сервером.
Другие варианты
Наиболее распространённые способы взаимодействия с сервером Chef Infra с использованием API сервера Chef Infra абстрагируют API от пользователя. Тем не менее, API сервера Chef Infra можно использовать напрямую. В следующих разделах описываются некоторые из доступных способов.
cURL
Запрос API можно выполнить с помощью cURL, что представляет собой скрипт оболочки Bash, для которого требуются две утилиты: awk и openssl. Следующий пример демонстрирует, как можно выполнить аутентифицированный запрос с помощью API сервера Chef Infra и 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. Следующий пример демонстрирует, как можно выполнить аутентифицированный запрос с помощью API сервера Chef Infra и 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 или knife. Более подробную информацию о PyChef см. на странице: https://github.com/coderanger/pychef.
Ruby
На системе с установленным клиентом Chef Infra используйте Ruby для выполнения аутентифицированного запроса к серверу Chef Infra:
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 — получить объекты с сервера Chef Infra и затем взаимодействовать с возвращёнными данными с помощью методов Ruby. Всякий раз, когда это возможно, API сервера Chef Infra вернёт объект соответствующего типа. Возвращённый объект затем доступен для вызова другими методами. Например, метод api.get может быть использован для возвращения узла с именем foobar, а затем .destroy может быть использован для удаления этого узла:
silly_node = api.get('/nodes/foobar')
silly_node.destroy
Отладка проблем с аутентификацией
В некоторых случаях клиент Chef Infra может получить ответ 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 пытается пройти аутентификацию. Это часто можно найти в сообщениях журнала для этого клиента Chef Infra. Отладочная запись журналов может быть включена на клиенте Chef Infra с помощью следующей команды:
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/server/auth/