{"id":10549,"date":"2016-08-30T09:10:45","date_gmt":"2016-08-30T07:10:45","guid":{"rendered":"https:\/\/blog.zhaw.ch\/icclab\/?p=10549"},"modified":"2016-08-30T13:16:32","modified_gmt":"2016-08-30T11:16:32","slug":"trust-delegation-in-openstack-using-keystone-trusts","status":"publish","type":"post","link":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/","title":{"rendered":"Trust delegation in Openstack using Keystone trusts"},"content":{"rendered":"<p>In one of our blog posts we presented a basic <a href=\"https:\/\/blog.zhaw.ch\/icclab\/extending-the-openstack-dashboard-to-support-delay-tolerant-workload\/\">tool<\/a> which extends the Openstack Nova client and supports executing API calls at some point in the future. Much has evolved since then: the tool is not just a wrapper around Openstack clients anymore and instead we rebuilt it in the context of the <a href=\"https:\/\/wiki.openstack.org\/wiki\/Mistral\">Openstack Mistral<\/a> project which provides very nice workflow as service capabilities &#8211; this will be elaborated a bit more in a future blog post. During this process we came across a very interesting feature in Keystone which we were not aware of &#8211; <a href=\"https:\/\/wiki.openstack.org\/wiki\/Keystone\/Trusts\">Trusts<\/a>. Trusts is a mechanism in Keystone which enables delegation of roles and even impersonation of users from a <i>trustor<\/i> to a <i>\u00a0trustee; <\/i>it has many uses but is particularly useful in an Openstack administration context<i>.<\/i> In this blog post we will cover basic command line instructions to create \u00a0and use trusts.<\/p>\n<p><!--more--><\/p>\n<h1>Setting up<\/h1>\n<p>First of all &#8211; trusts are only available in Keystone <a href=\"http:\/\/docs.openstack.org\/developer\/python-keystoneclient\/using-api-v3.html\">v3<\/a>, v3 endpoints must be exposed for Keystone.<\/p>\n<p>Check your openstack-client and keystone version. We had issues where Keystone Trusts were not working due to an outdated client version. Here we use openstack-client version 3.0.1 and keystone 10.0.0. Versions can be checked as follows:<\/p>\n<pre><code>\r\n:# openstack --version\r\n:# keystone-manage --version\r\n<\/code>\r\n<\/pre>\n<p>The openstack client can be updated using pip as follows:<\/p>\n<pre><code>\r\n:# sudo pip install --upgrade python-openstackclient\r\n<\/code>\r\n<\/pre>\n<h1>Example of users and projects<\/h1>\n<p>For all the commands shown in this blog post we will use the following users and projects so it is easier for you to understand what each command does. Each user has admin and member roles in their respective projects &#8211; the admin user only has access to the admin project and the alt_demo user only has access to alt_demo project.<\/p>\n<pre>+----------------------------------+----------+\r\n| User ID \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0| Name \u00a0\u00a0\u00a0\u00a0|\r\n+----------------------------------+----------+\r\n| 54e64304fec34a06b20893b35acbdbfa | alt_demo |\r\n| a91584188d074a36886247eff94ee1de | admin \u00a0\u00a0\u00a0|\r\n+----------------------------------+----------+\r\n\r\n\r\n+----------------------------------+--------------------+\r\n| Project ID \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0| Name \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0|\r\n+----------------------------------+--------------------+\r\n| aec1f0c8e503439ebaf7a612dcb60d96 | admin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 |\r\n| ff777ec62c7842e280db0194a27bd3dc | alt_demo \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 |\r\n+----------------------------------+--------------------+\r\n<\/pre>\n<h1>Creating trusts<\/h1>\n<p>Creating a trust relationship between users is fairly straightforward. The basic premise is that one user can authorize another user to act on her behalf by creating an Openstack trust object. More concretely, the trustor creates a trust object which enables a trustee to act on her behalf: the trustee uses her own credentials and the trust_id and is then able to act on behalf of the trustor.<\/p>\n<p>The basic syntax of the command is shown below; This command returns a trust_id which can be used to authenticate operations in any Openstack service.<\/p>\n<p>Here, we assume that credentials are configured as environment variables as is standard practice, so we don\u2019t have to provide them as parameters in the command itself.<\/p>\n<p>openstack trust create &#8211;project &lt;project-id&gt; &#8211;role &lt;role-id&gt; &#8211;impersonate \u00a0&lt;trustor-user-id&gt; &lt;trustee-user-id&gt;<\/p>\n<pre><code>\r\n# Alt_demo user granting member access to alt_demo project for admin user\r\n\r\nopenstack trust create --impersonate --project ff777ec62c7842e280db0194a27bd3dc --role 9fe2ff9ee4384b1894a90878d3e92bab(*member role) 54e64304fec34a06b20893b35acbdbfa a91584188d074a36886247eff94ee1de\r\n<\/code>\r\n<\/pre>\n<p>In this case a trustor, alt_demo, gives a specific role, member, in a project, alt_demo, for a trustee, admin. The trustee, admin, then will be able to perform any Openstack operations in that project based on the role provided.<\/p>\n<p><i>Note that the trustor can only grant trusts of roles and projects for which it has authorization; e.g. if the trustor is only a member in a certain project he cannot provide delegated admin role for another user in that same project using trusts.<\/i><\/p>\n<p>The impersonate flag changes the attribute <i>user<\/i> in the token created using the trust_id, the user will be the trustor itself in case the flag is present otherwise the user in the token is the trustee.<\/p>\n<h1>Acting on the trustor\u2019s behalf<\/h1>\n<p>In order to use the trust_id provided by the command above first we need to remove any environment variables related to projects and domains. This information is already included in the token created by the trust_id (an exception is thrown if there is a conflict between the environment variables and the trust_id).<\/p>\n<p>To check for environment variables and remove them use the commands below:<\/p>\n<pre><code>\r\n:# env | grep OS\r\nOS_PROJECT_DOMAIN_ID=default\r\nOS_REGION_NAME=RegionOne\r\nOS_USER_DOMAIN_ID=default\r\nOS_PROJECT_NAME=admin\r\nOS_IDENTITY_API_VERSION=3\r\nOS_PASSWORD=REDACTED\r\nOS_AUTH_URL=http:\/\/127.0.0.1:5000\/v3\r\nOS_USERNAME=admin\r\nOS_TENANT_NAME=admin\r\n\r\n:# unset {VARIABLE_NAME}\r\n<\/code>\r\n<\/pre>\n<p>Without any project or domain variable in our environment now we are good to go using Openstack API calls!<\/p>\n<pre><code>\r\nopenstack --os-trust-id 99905e50d80749b5a24292e830fff10c server create --flavor 1 --image &lt;image-id&gt; Server-Test\r\n<\/code>\r\n<\/pre>\n<p>This command, executed with the trustee credentials, creates a VM in the project specified by the trust_id, which is associated with the trustor: the trustor can log into the Openstack web interface and will see this VM as if she had created it herself.<\/p>\n<p>In case you don\u2019t use environment variables there are very few changes to make in the API call:<\/p>\n<pre><code>\r\nopenstack --os-trust-id 99905e50d80749b5a24292e830fff10c --os-username admin --os-password REDACTED --os-auth-url http:\/\/127.0.0.1:5000\/v3 --os-region-name RegionOne server create --flavor 1 --image &lt;image-id&gt; Server-Test\r\n<\/code>\r\n<\/pre>\n<p>Adding these parameters after the command openstack will be the same as using environment variables allowing the admin user to create a VM in the alt_demo project.<\/p>\n<h1>Conclusion<\/h1>\n<p>In this blog post we gave an introduction to Keystone Trust and an example of how it can be used. Note that the trust mechanisms do not solve the general problem of Openstack admins being able to act on the user\u2019s behalf (eg creating VMs for the user based on snapshots etc) as the users still need to authorize them to do so, although there <a href=\"http:\/\/stackoverflow.com\/questions\/36571228\/openstack-can-admin-impersonate-as-another-user-to-create-a-vm\">known workarounds<\/a>. \u00a0However, it is very useful capability which is used in more complex configurations such as those where Openstack services need to act on behalf of a user.<\/p>\n<div class=\"pt-sm\">Schlagw\u00f6rter: <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/howto\/\">howto<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/keystone\/\">keystone<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/openstack\/\">openstack<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/trusts\/\">trusts<\/a><br><\/div>","protected":false},"excerpt":{"rendered":"<p>In one of our blog posts we presented a basic tool which extends the Openstack Nova client and supports executing API calls at some point in the future. Much has evolved since then: the tool is not just a wrapper around Openstack clients anymore and instead we rebuilt it in the context of the Openstack [&hellip;]<\/p>\n","protected":false},"author":101,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1,15,21],"tags":[181,454,240,803],"features":[],"class_list":["post-10549","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-howtos","category-openstack-2","tag-howto","tag-keystone","tag-openstack","tag-trusts"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Trust delegation in Openstack using Keystone trusts - Service Engineering (ICCLab &amp; SPLab)<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Trust delegation in Openstack using Keystone trusts\" \/>\n<meta property=\"og:description\" content=\"In one of our blog posts we presented a basic tool which extends the Openstack Nova client and supports executing API calls at some point in the future. Much has evolved since then: the tool is not just a wrapper around Openstack clients anymore and instead we rebuilt it in the context of the Openstack [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\" \/>\n<meta property=\"og:site_name\" content=\"Service Engineering (ICCLab &amp; SPLab)\" \/>\n<meta property=\"article:published_time\" content=\"2016-08-30T07:10:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-08-30T11:16:32+00:00\" \/>\n<meta name=\"author\" content=\"Bruno Grazioli\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bruno Grazioli\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\"},\"author\":{\"name\":\"Bruno Grazioli\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\"},\"headline\":\"Trust delegation in Openstack using Keystone trusts\",\"datePublished\":\"2016-08-30T07:10:45+00:00\",\"dateModified\":\"2016-08-30T11:16:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\"},\"wordCount\":834,\"commentCount\":1,\"keywords\":[\"howto\",\"keystone\",\"openstack\",\"trusts\"],\"articleSection\":[\"*.*\",\"HowTos\",\"OpenStack\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\",\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\",\"name\":\"Trust delegation in Openstack using Keystone trusts - Service Engineering (ICCLab &amp; SPLab)\",\"isPartOf\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#website\"},\"datePublished\":\"2016-08-30T07:10:45+00:00\",\"dateModified\":\"2016-08-30T11:16:32+00:00\",\"author\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\/\/blog.zhaw.ch\/icclab\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Trust delegation in Openstack using Keystone trusts\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#website\",\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/\",\"name\":\"Service Engineering (ICCLab &amp; SPLab)\",\"description\":\"A Blog of the ZHAW Zurich University of Applied Sciences\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.zhaw.ch\/icclab\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\",\"name\":\"Bruno Grazioli\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"caption\":\"Bruno Grazioli\"},\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/author\/gaea\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Trust delegation in Openstack using Keystone trusts - Service Engineering (ICCLab &amp; SPLab)","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/","og_locale":"en_US","og_type":"article","og_title":"Trust delegation in Openstack using Keystone trusts","og_description":"In one of our blog posts we presented a basic tool which extends the Openstack Nova client and supports executing API calls at some point in the future. Much has evolved since then: the tool is not just a wrapper around Openstack clients anymore and instead we rebuilt it in the context of the Openstack [&hellip;]","og_url":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/","og_site_name":"Service Engineering (ICCLab &amp; SPLab)","article_published_time":"2016-08-30T07:10:45+00:00","article_modified_time":"2016-08-30T11:16:32+00:00","author":"Bruno Grazioli","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Bruno Grazioli","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#article","isPartOf":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/"},"author":{"name":"Bruno Grazioli","@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba"},"headline":"Trust delegation in Openstack using Keystone trusts","datePublished":"2016-08-30T07:10:45+00:00","dateModified":"2016-08-30T11:16:32+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/"},"wordCount":834,"commentCount":1,"keywords":["howto","keystone","openstack","trusts"],"articleSection":["*.*","HowTos","OpenStack"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/","url":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/","name":"Trust delegation in Openstack using Keystone trusts - Service Engineering (ICCLab &amp; SPLab)","isPartOf":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/#website"},"datePublished":"2016-08-30T07:10:45+00:00","dateModified":"2016-08-30T11:16:32+00:00","author":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba"},"breadcrumb":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.zhaw.ch\/icclab\/trust-delegation-in-openstack-using-keystone-trusts\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/blog.zhaw.ch\/icclab\/"},{"@type":"ListItem","position":2,"name":"Trust delegation in Openstack using Keystone trusts"}]},{"@type":"WebSite","@id":"https:\/\/blog.zhaw.ch\/icclab\/#website","url":"https:\/\/blog.zhaw.ch\/icclab\/","name":"Service Engineering (ICCLab &amp; SPLab)","description":"A Blog of the ZHAW Zurich University of Applied Sciences","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.zhaw.ch\/icclab\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba","name":"Bruno Grazioli","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","caption":"Bruno Grazioli"},"url":"https:\/\/blog.zhaw.ch\/icclab\/author\/gaea\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/users\/101"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/comments?post=10549"}],"version-history":[{"count":4,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10549\/revisions"}],"predecessor-version":[{"id":10553,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10549\/revisions\/10553"}],"wp:attachment":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/media?parent=10549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/categories?post=10549"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/tags?post=10549"},{"taxonomy":"features","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/features?post=10549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}