Как управлять своими проектами OpenStack при помощи доменов Keystone в релизе Havana
Автор Сергей КашабаДомены в OpenStack — это метод объединения проектов или арендаторов (как они назывались в Grizzly) в независимые группы. Кроме того, они позволяют вам ограничить доступ к определенному домену. Например, как вы, наверное, помните, когда домены не применялись, пользователь, которому была назначена роль администратора в одном проекте, являлся администратором всего кластера и мог выполнять любые операции. C появлением доменов вы можете назначить пользователю роль администратора в одном домене с привилегиями администратора только в этом домене.В данной статье будут вкратце рассмотрены некоторые ситуации, в которых домены могут вам помочь организовать свои проекты. Как только вы разберетесь с этим, мы перейдем к рассмотрению того, как на деле использовать домены с этой целью.
МотивацияВпервые мы столкнулись с доменами примерно год назад, когда один из наших корпоративных клиентов запросил функциональность, очень схожую с доменами OpenStack. Это было в рамках цикла Grizzly. Мы прочитали об этом и сказали: «Йо-хо-хо! Мы можем использовать функциональность доменов!». На тот момент она была только что введена.Но OpenStack — это … OpenStack, и данная функциональность поддерживалась не всеми требуемыми компонентами. Поэтому мы сделали патч для Keystone, чтобы реализовать запрашиваемые сценарии использования и решили вернуться к этому позже.
Спустя полгода вышел релиз Havana. Поскольку функциональность доменов весьма полезна для корпоративного сегмента, мы решили получить доказательство правильности концепции с использованием релиза vanilla Havana.
Мы хотели охватить следующие сценарии использования:1.Как администратор IaaS я должен иметь возможность создавать домены для агрегирования арендаторов (которые теперь называются проектами).
2.Как администратор IaaS я должен иметь возможность добавлять пользователя в роли администратора домена.
3.Как администратор домена я должен иметь возможность:
•Создавать, удалять, перемещать, обновлять и удалять проекты внутри данного домена. В списке проектов должен быть только проект этого домена.
•Выполнять CRUD-операции над пользователем применительно к ролям проекта.
4.В качестве источника имени пользователя/пароля должен использоваться LDAP.
5.Обязательно использовать только REST API. Ни UI, ни CLI не требуются.
На этот раз у нас получилось. Не скажу, что не было никаких проблем, но проект показал, что домены в релизе Havana, как минимум, могут применяться.
На старт, внимание, марш! Мы протестировали домены, используя ветвь stable/havana в Devstack. Файл localrc содержит только параметры для предоставления паролей.В процессе исследования мы выяснили, что CLI лишь отчасти готов к использованию доменов. Он предоставляет полную функциональность для обычного пользователя, но не всю для администрирования (Описание данной проблемы и состояния дел по ее решению можно найти здесь).
Для использования функциональности доменов нужно сделать следующее:1.Поменять формат маркера на UUID (файл keystone.conf, раздел [signing], token_format = UUID). У Glance есть проблемы с маркерами PKI (как минимум, с маркерами v3), и при аутентификации выдается ошибка «body is too large»(«слишком большое тело») при использовании PKI, заданной по умолчанию (проблема возникает не только при использовании доменов).
2.Применить корректный файл policy.json для keystone. Проверка доменов не поддерживается в заданном по умолчанию файле политик. Мы повторно использовали файл, который идет в комплекте с keystone из git, а затем внесли в него изменения.
3.Изменить настройки Nova, Glance-api и конфигурационных файлов paste.registry в Glance для возможности использования аутентификации V3.0 путем добавления «auth_version = v3.0» в раздел [filter: authtoken]. В тестовом окружении мы использовали только Nova и Glance для запуска VM. Если вы используете и другие сервисы, не забудьте внести изменения в соответствующие конфигурационные файлы. Если этого не сделать, клиенты Nova и Glance будут проверять маркеры V2 и выдавать ошибку «Only default domain is allowed over the V2.0» («В V2.0 может быть использован только домен, установленный по умолчанию»).
4.Обновить конечные точки keystone, чтобы сервис identity указывал на v3, а не v2.0.
5.Перезапустить сервисы, в настройки которых были внесены изменения.
Обратите внимание на то, что по требованию клиента мы использовали только интерфейс REST и не использовали клиенты CLI/PythonAPI/UI.
Как управлять доменами Потратив около недели на изучение доменов, я могу сказать, что есть два ключевых момента для понимания того, как они работают:1.Как создается маркер и, в частности, область маркера (token scope).2.Как запускаются политики.
В данной статье все примеры будут приведены с использованием команд curl. Это сделано по двум причинам. Во-первых, при написании данного документа CLI не поддерживал задание связанных с доменом параметров через командную строку. Во-вторых, что практически важнее, CLI не раскрывает некоторые детали, существенные для понимания того, как он работает.
Создание маркера Для начала надо создать маркер, что довольно просто. Это делается с помощью следующего запроса: curl -si -X POST -H «Content-Type: application/json» -d »{«auth»: {«scope»: {«domain»: {«id»: «XXXXX»}}, «identity»: {«password»: {«user»: {«domain»: {«name»: «default»}, «password»: «qwerty», «id»: «YYYYYY»}}, «methods»: [«password»]}}}» 127.0.0.1:5000/v3/auth/tokens | awk »/X-Subject-Token/ {print $2}»| tr -d »\r»
Здесь видна важная часть файла json, которая передается в качестве тела, — область (scope). Областью может быть либо домен, либо проект. Область маркера участвует в запуске политики, поэтому это важно понять и запомнить. Если интересно, можете заглянуть в function keystone/auth/controllers.py: AuthInfo._validate_and_normalize_scope_data, чтобы узнать код, использовавшийся при создании объекта, который затем применялся для генерации данных политики (policy credentials).
Запуск политики Запуск политики — дело более сложное. Это основной сценарий использования. К счастью, как только у вас будет четкое понимание того, как это происходит, вы сможете выполнять большинство операций в сфере доменов. При запуске политики используются три новых ключевых слова: credential, policy и target. Теперь посмотрим, в чем заключается создание и использование каждого из них.Учетные данные (Credentials) Объект credential — это словарь, создаваемый на основе маркера и включающий область полученного маркера, а также роли, назначенные пользователю.Политика (Policy) Политика — это просто набор правил, объединенных согласно логике OR/AND. В будущих релизах она должна стать более удобочитаемой, но пока мы будем применять используемый в настоящее время формат. Ниже представлены отдельные фрагменты политики в качестве примера вышесказанного.«admin_required»: [[«role: admin»]],
«owner»: [[«user_id:%(user_id)s»], [«user_id:%(target.entity.user_id)s»]],
«identity: get_project»: [[«rule: admin_required», «domain_id:%(target.project.domain_id)s»]],
«identity: list_projects»: [[«rule: admin_required», «domain_id:%(domain_id)s»]],
«identity: list_user_projects»: [[«rule: owner»], [«rule: admin_required», «domain_id:%(domain_id)s»]],
Все должно быть заключено в квадратные скобки ([]).
Минимальный фрагмент правила (можно назвать его «атомарным» правилом) — это стринг с двоеточием в качества разделителя (»:»). Это может быть:1.Ссылка на другое правило. В этом случае левая часть — это «правило», а правая — имя правила.
2.Определение логики проверки правильности. В этом случае левая часть определяет ключ, который находится в объекте credential, а правая часть — что-то, что находится в «target». Также это может быть константа. Это можно выразить как credentials_object[left_side] == right_side % target_object.
Несколько атомарных правил могут быть объединены с использованием запятой (,). Это означает, что эти правила объединены на основе логики AND (например: [«rule: admin_required», «domain_id:%(domain_id)s»]). Назовем это «правилом and».
Если имеется два набора правил, заключенных в [], то они объединяются на основе логики OR. Например, [[«rule: owner»], [«rule: admin_required»]] означает, что правило выполняется, если выполняется правило владельца или правило, требуемое администратором.
Если правило использует другое правило, то правило, заключенное в скобки, нужно описать таким же образом.
Подведем итог: пример «identity: list_user_projects»: [[«rule: owner»], [«rule: admin_required», «domain_id:%(domain_id)s»]] означает «список проектов пользователя разрешен, только если выполняется правило с именем «owner» ИЛИ выполняется и правило, требуемое администратором, И domain_id из области маркера равен domain id из target». Теперь речь пойдет о цели.
Цель (Target) Объект target также является словарем, создаваемым на основе следующего: •строка запроса (query string) из запроса (request); •запускаемые объекты.
Например: •Если мы пытаемся получить информацию о проекте, то целью является этот проект
•Если мы пытаемся назначить для проекта пользователя с определенной ролью, то целью является роль+проект+пользователь.
•Если мы пытаемся перечислить все проекты, то значение цели будет пустым (Сначала это меня огорчило, т.к. я думал, что некоторые из операций, запрашиваемых нашими клиентами, были недоступны в релизе Havana. Но нам повезло, я ошибался.).
•Если мы пытаемся перечислить все проекты, применяя фильтр по определенному значению (наприме, по domains_id), то цель включает все фильтры (Это было для меня сюрпризом, но оказалось очень полезным).
Пример запроса:
curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:5000/v3/projects? domain_id=$OS_DOMAIN_ID
В данном запросе в цель входит только domain_id. Правилом, которое следует включить в файл policy.json, может быть «identity: list_projects»: [[«rule: admin_required», «domain_id:%(domain_id)s»]].
Зная все это, вы можете легко управлять доступом, внося изменения в файл policy.json.Кроме того, в keystone/policy/backends/rules.py: enforce можно записывать отладочные сообщения для протоколирования учетных данных, правил и цели для более тщательного анализа. Этот метод помог мне понять, что происходит в некоторых сценариях использования.
Администратор облака (Cloud admin) По существующему файлу policy.json мне было непонятно, что означало правило «cloud_admin»: «cloud_admin»: «rule: admin_required and domain_id: admin_domain_id», «identity: get_domain»: «rule: cloud_admin»,
Проведя некоторое исследование, я выяснил, что это весьма изысканное обходное решение для определения «super administrator» без использования маркера сервиса. Вы просто создаете домен, который является «super domain», и указываете соответствующий ID в качестве значения admin_domain_id в правиле. Например, в devstack можно использовать «default», и указать домен, заданный по умолчанию, в качестве «super» администратора.Согласно обсуждению ключевых руководителей Keystone, понятие администратора облака является временным решением и будет заменено понятием администратора сервиса.
Поддержка Horizon В соответствии с блюпринтами Horizon также может поддерживать несколько доменов. Для этого нужно внести лишь незначительные изменения либо в settings.py, либо в local_setting (которые мы тестировали в нашей лаборатории): OPENSTACK_API_VERSIONS = {«identity»: 3}
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True#OPENSTACK_KEYSTONE_URL = «http://%s:5000/v2.0″ % OPENSTACK_HOSTOPENSTACK_KEYSTONE_URL = «http://%s:5000/v3″ % OPENSTACK_HOSTВнеся данные изменения, вы получите дополнительное поле ввода на этапе входа в систему для указания имени домена. К сожалению, действия администратора (такие как управление доменами и назначения) недоступны в Horizon при применении к keystone политики V3 (ссылка).Однако благодаря этому обычный пользователь, по крайней мере, имеет возможность использовать UI вместо отправки команд CURL.
Интерфейс командной строки (CLI)
В середине января 2014 г. поддержка доменов была добавлена в CLI, который теперь поддерживает следующий дополнительный набор опций: –os-domain-name
Имя домена запрашиваемой области авторизации уровня домена (Окружение: OS_DOMAIN_NAME).
–os-domain-id
ID домена запрашиваемой области авторизации уровня домена (Окружение: OS_DOMAIN_ID).
–os-user-domain-name
Имя домена пользователя (Окружение: OS_USER_DOMAIN_NAME).
–os-user-domain-id
ID домена пользователя (Окружение: OS_USER_DOMAIN_ID).
–os-project-domain-name
Имя домена проекта, который является запрашиваемой областью авторизации уровня домена (Окружение: OS_PROJECT_DOMAIN_NAME).
–os-project-domain-id
ID домена проекта, который является запрашиваемой областью авторизации уровня домена (Окружение: OS_PROJECT_DOMAIN_ID).При помощи данных параметров мы можем задать область маркера, домен проекта и домен пользователя.
Сводим все сказанное воедино Применив все вышеописанные изменения, вы сможете выполнять все требуемые функции. Ниже представлен список curl-команд. Напоминаю, что мне нужно было обеспечить запуск ТОЛЬКО запросов REST, чтобы функциональность работала при данном тестировании.Предварительные условия: Для удобного анализа ответов json я использовал инструмент jq.sudo apt-get install jq
Также у нас были созданы пользователи (из LDAP): user0, demo
Пример: Тест выглядит следующим образом:#export start variables.
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_SERVICE_TOKEN=openstack
#list domains
curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains | jq ».domains»
#or
openstack –os-identity-api-version 3 –os-url 127.0.0.1:35357/v3 –os-token openstack domain list
#create domain
curl -sX POST -H «X-Auth-Token:$OS_SERVICE_TOKEN» -H «Content-Type: application/json» -d »{«domain»: {«enabled»: true, «name»: «dom0″}}» 127.0.0.1:35357/v3/domains | jq ».»
#list show domain0
curl -s -X GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains? name=dom0 | jq ».domains»
#assign user as an domain admin
#get user id
curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/users? name=user0 | jq ».users»
export OS_USER_ID=curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/users? name=user0 | jq '.users[].id' |tr -d '»'
curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains? name=dom0 | jq ».domains»
export OS_DOMAIN_ID=curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains? name=dom0 | jq '.domains[].id' |tr -d '»'
curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/roles? name=admin | jq ».roles»
curl -sX PUT -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains/$OS_DOMAIN_ID/users/$OS_USER_ID/roles/bc485df1732140928ad44804a1c9b546
curl -sX GET -H «X-Auth-Token:$OS_SERVICE_TOKEN» 127.0.0.1:35357/v3/domains/$OS_DOMAIN_ID/users/$OS_USER_ID/roles/ | jq ».roles»
#Authenticate as an domain admin
export OS_MYTOKEN=curl -si -X POST -H «Content-Type: application/json» -d »{\«auth\»: {\«scope\»: {\«domain\»: {\«id\»: \»$OS_DOMAIN_ID\»}}, \«identity\»: {\«password\»: {\«user\»: {\«domain\»: {\«name\»: \«default\»}, \«password\»: \«qwerty\», \«id\»: \»$OS_USER_ID\»}}, \«methods\»: [\«password\»]}}}» 127.0.0.1:5000/v3/auth/tokens | awk '/X-Subject-Token/ {print $2}'| tr -d '\r'
#create project
curl -sX POST -H «X-Auth-Token:$OS_MYTOKEN» -H «Content-Type: application/json» -d »{\«project\»: {\«name\»: \«dom0p0\», \«enabled\»: true, \«domain_id\»: \»$OS_DOMAIN_ID\», \«description\»: \»\»}}» 127.0.0.1:5000/v3/projects |jq ».»
curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:5000/v3/projects? domain_id=$OS_DOMAIN_ID\&name=dom0p0 |jq ».projects»
export OS_PROJECT_ID=curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:5000/v3/projects? domain_id=$OS_DOMAIN_ID\&name=dom0p0 | jq '.projects[].id' |tr -d '»'
#add user to project
curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:35357/v3/users? name=demo | jq ».users»
export OS_DEMOUSER_ID=curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:35357/v3/users? name=demo | jq '.users[].id' |tr -d '»'
curl -sX GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:35357/v3/roles? name=Member | jq ».roles»
curl -X PUT -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:5000/v3/projects/$OS_PROJECT_ID/users/$OS_DEMOUSER_ID/roles/c861b57d824d4619a739823d863064b6
curl -X GET -H «X-Auth-Token:$OS_MYTOKEN» 127.0.0.1:5000/v3/projects/$OS_PROJECT_ID/users/$OS_DEMOUSER_ID/roles/ |jq ».roles»
#authenticate as a user
export OS_DEMOTOKEN_ID=curl -si -X POST -H «Content-Type: application/json» -d »{\«auth\»: {\«scope\»: {\«project\»:{\«id\»: \»$OS_PROJECT_ID\», \«domain\»: {\«id\»: \»$OS_DOMAIN_ID\»}}}, \«identity\»: {\«password\»: {\«user\»: {\«domain\»: {\«name\»: \«default\»}, \«password\»: \«openstack\», \«id\»: \»$OS_DEMOUSER_ID\»}}, \«methods\»: [\«password\»]}}}» 127.0.0.1:5000/v3/auth/tokens | awk '/X-Subject-Token/ {print $2}'| tr -d '\r'
#run the VM
curl -si -X POST -H «X-Auth-Token:$OS_DEMOTOKEN_ID» -H «Content-Type: application/json» -d »{«server»: {«flavorRef»:»1″, «name»: «ksn», «imageRef»: «c0843d76–0cc8–4a19-a9e3–169afd3aace2″}}» 127.0.0.1:8774/v2/$OS_PROJECT_ID/servers
Открытые вопросы В целом это можно назвать успехом, но все же у нас осталась пара нерешенных вопросов:1.Неясно, может ли Horizon управлять операциями администратора при применении политики V3 к keystone.2.Невозможно удалить домен, если вы назначили какому-либо проекту домена пользователя из другого домена. Проблема.
Выводы Подводя итоги, можно сказать, что для использования функциональности доменов в Horizon, необходимо для начала убедиться, что вы используете Keystone API версии V3 и что вы поменяли схему аутентификации на UUID. Затем нужно создать маркеры, после чего создать и запустить соответствующие политики. Выполнив это, вы можете использовать команды из приведенного списка для создания и использования доменов, также можно использовать Horizon или новые параметры CLI.Оригинал статьи на английском языке.