{"id":730,"date":"2021-01-04T23:44:03","date_gmt":"2021-01-04T23:44:03","guid":{"rendered":"https:\/\/machine-learning.webcloning.com\/2021\/01\/04\/building-a-secure-search-application-with-access-controls-using-amazon-kendra\/"},"modified":"2021-01-04T23:44:03","modified_gmt":"2021-01-04T23:44:03","slug":"building-a-secure-search-application-with-access-controls-using-amazon-kendra","status":"publish","type":"post","link":"https:\/\/salarydistribution.com\/machine-learning\/2021\/01\/04\/building-a-secure-search-application-with-access-controls-using-amazon-kendra\/","title":{"rendered":"Building a secure search application with access controls using Amazon Kendra"},"content":{"rendered":"<div id=\"\">\n<p>For many enterprises, critical business information is often stored as unstructured data scattered across multiple content repositories. Not only is it challenging for organizations to make this information available to employees when they need it, but it\u2019s also difficult to do so securely so relevant information is available to the right employees or employee groups.<\/p>\n<p><a href=\"https:\/\/aws.amazon.com\/kendra\/\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon Kendra<\/a> is a highly accurate and easy-to-use intelligent search service powered by machine learning (ML). Amazon Kendra delivers secure search for enterprise applications and can make sure the results of a user\u2019s search query only include documents the user is authorized to read. In this post, we illustrate how to build an Amazon Kendra-powered search application supporting access controls that reflect the security model of an example organization.<\/p>\n<p>Amazon Kendra supports search filtering based on user access tokens that are provided by your search application, as well as document access control lists (ACLs) collected by the Amazon Kendra connectors. When user access tokens are applied, search results return links to the original document repositories and include a short description. Access control to the full document is still enforced by the original repository.<\/p>\n<p>In this post, we demonstrate token-based user access control in Amazon Kendra with Open ID. We use <a href=\"https:\/\/docs.aws.amazon.com\/cognito\/latest\/developerguide\/what-is-amazon-cognito.html\">Amazon Cognito<\/a> user pools to authenticate users and provide Open ID tokens. You can use a similar approach with other Open ID providers.<\/p>\n<h2>Application overview<\/h2>\n<p>This application is designed for guests and registered users to make search queries to a document repository, and results are returned only from those documents that are authorized for access by the user. Users are grouped based on their roles, and access control is at a group level. The following table outlines which documents each user is authorized to access for our use case. The documents being used in this example are a subset of AWS public documents.<\/p>\n<table border=\"1px\" cellpadding=\"5px\">\n<tbody>\n<tr>\n<td width=\"79\"><strong>User<\/strong><\/td>\n<td width=\"105\"><strong>Role<\/strong><\/td>\n<td width=\"106\"><strong>Group<\/strong><\/td>\n<td width=\"276\"><strong>Document Type Authorized for Access<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"79\"><\/td>\n<td width=\"105\">Guest<\/td>\n<td width=\"106\"><\/td>\n<td width=\"276\">Blogs<\/td>\n<\/tr>\n<tr>\n<td width=\"79\">Patricia<\/td>\n<td width=\"105\">IT Architect<\/td>\n<td width=\"106\">Customer<\/td>\n<td width=\"276\">Blogs, user guides<\/td>\n<\/tr>\n<tr>\n<td width=\"79\">James<\/td>\n<td width=\"105\">Sales Rep<\/td>\n<td width=\"106\">Sales<\/td>\n<td width=\"276\">Blogs, user guides, case studies<\/td>\n<\/tr>\n<tr>\n<td width=\"79\">John<\/td>\n<td width=\"105\">Marketing Exec<\/td>\n<td width=\"106\">Marketing<\/td>\n<td width=\"276\">Blogs, user guides, case studies, analyst reports<\/td>\n<\/tr>\n<tr>\n<td width=\"79\">Mary<\/td>\n<td width=\"105\">Solutions Architect<\/td>\n<td width=\"106\">Solutions Architect<\/td>\n<td width=\"276\">Blogs, user guides, case studies, analyst reports, whitepapers<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Architecture<\/h2>\n<p>The following diagram illustrates our solution architecture.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20202\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-1.jpg\" alt=\"The following diagram illustrates our solution architecture.\" width=\"626\" height=\"369\"><\/p>\n<p>The documents being queried are stored in an <a href=\"http:\/\/aws.amazon.com\/s3\" target=\"_blank\" rel=\"noopener noreferrer\">Amazon Simple Storage Service<\/a> (Amazon S3) bucket. Each document type has a separate folder: <code>blogs<\/code>, <code>case-studies<\/code>, <code>analyst-reports<\/code>, <code>user-guides<\/code>, and <code>white-papers<\/code>. This folder structure is contained in a folder named <code>Data<\/code>. Metadata files including the ACLs are included in a folder named <code>Meta<\/code>.<\/p>\n<p>We use the Amazon Kendra S3 connector to configure this S3 bucket as the data source. When the data source is synced with the Amazon Kendra index, it crawls and indexes all documents as well as collects the ACLs and document attributes from the metadata files. For this example, we use a custom attribute <code>DocumentType<\/code> to denote the type of the document.<\/p>\n<p>We use an Amazon Cognito user pool to authenticate registered users, and use an identity pool to authorize the application to use Amazon Kendra and Amazon S3. The user pool is configured as an Open ID provider in the Amazon Kendra index by configuring the signing URL of the user pool.<\/p>\n<p>When a registered user authenticates and logs in to the application to perform a query, the application sends the user\u2019s access token provided by the user pool to the Amazon Kendra index as a parameter in the query API call. For guest users, there is no authentication and therefore no access token is sent as a parameter to the query API. The results of a query API call without the access token parameter only return the documents without access control restrictions.<\/p>\n<p>When an Amazon Kendra index receives a query API call with a user access token, it decrypts the access token using the user pool signing URL and gets parameters such as <code>cognito:username<\/code> and <code>cognito:groups<\/code> associated with the user. The Amazon Kendra index filters the search results based on the stored ACLs and the information received in the user access token. These filtered results are returned in response to the query API call made by the application.<\/p>\n<p>The application, <a href=\"https:\/\/aws-ml-blog.s3.amazonaws.com\/artifacts\/building-a-secure-search-application-with-access-controls-kendra\/authapp.zip\">which the users can download with its source<\/a>, is written in ReactJS using components from the <a href=\"https:\/\/aws.amazon.com\/amplify\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS Amplify<\/a> framework. We use the AWS Amplify console to implement the continuous integration and continuous deployment pipelines. We use an <a href=\"http:\/\/aws.amazon.com\/cloudformation\" target=\"_blank\" rel=\"noopener noreferrer\">AWS CloudFormation<\/a> template to deploy the AWS infrastructure, which includes the following:<\/p>\n<p>In this post, we provide a step-by-step walkthrough to configure the backend infrastructure, build and deploy the application code, and use the application.<\/p>\n<h2>Prerequisites<\/h2>\n<p>To complete the steps in this post, make sure you have the following:<\/p>\n<h2>Preparing your S3 bucket as a data source<\/h2>\n<p>To prepare an S3 bucket as a data source, create an S3 bucket. In the terminal with the AWS CLI or <a href=\"https:\/\/aws.amazon.com\/cloudshell\/\">AWS CloudShell<\/a>, run the following commands to upload the documents and the metadata to the data source bucket:<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-bash\">aws s3 cp s3:\/\/aws-ml-blog\/artifacts\/building-a-secure-search-application-with-access-controls-kendra\/docs.zip .\r\nunzip docs.zip\r\naws s3 cp Data\/ s3:\/\/<strong>&lt;REPLACE-WITH-NAME-OF-S3-BUCKET&gt;<\/strong>\/Data\/ --recursive\r\naws s3 cp Meta\/ s3:\/\/<strong>&lt;REPLACE-WITH-NAME-OF-S3-BUCKET&gt;<\/strong>\/Meta\/ --recursive\r\n<\/code><\/pre>\n<\/div>\n<h2>Deploying the infrastructure as a CloudFormation stack<\/h2>\n<p>In a separate browser tab open the <a href=\"https:\/\/console.aws.amazon.com\/console\/\">AWS Management Console<\/a>, and make sure that you are logged in to your AWS account. Click the button below to launch the CloudFormation stack to deploy the infrastructure.<\/p>\n<p><a href=\"https:\/\/us-east-1.console.aws.amazon.com\/cloudformation\/home?region=us-east-1#\/stacks\/create\/review?templateURL=https:\/\/aws-ml-blog.s3.amazonaws.com\/artifacts\/building-a-secure-search-application-with-access-controls-kendra\/authapptemplate.yaml&amp;stackName=Kendra-Auth-App&amp;param_S3CodeBucket=aws-ml-blog&amp;param_S3CodeKey=artifacts\/building-a-secure-search-application-with-access-controls-kendra\/authapp.zip\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20275\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/31\/LaunchStack.jpg\" alt=\"\" width=\"107\" height=\"20\"><\/a><\/p>\n<p>You should see a page similar to the image below:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20278\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/31\/CFN-Create-Stack.png\" alt=\"\" width=\"839\" height=\"881\"><\/p>\n<p>For <strong>S3DataSourceBucket<\/strong>, enter your data source bucket name without the s3:\/\/ prefix, select <strong>I acknowledge that AWS CloudFormation might create IAM resources with custom names,<\/strong> and then choose <strong>Create stack<\/strong>.<\/p>\n<p>Stack creation can take 30\u201345 minutes to complete. While you wait, you can look at the different tabs, such as <strong>Events<\/strong>, <strong>Resources<\/strong>, and <strong>Template<\/strong>. You can monitor the stack creation status on the <strong>Stack info<\/strong> tab.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20206\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-5.jpg\" alt=\"You can monitor the stack creation status on the Stack info tab.\" width=\"800\" height=\"483\"><\/p>\n<p>When stack creation is complete, keep the <strong>Outputs<\/strong> tab open. We need values from the <strong>Outputs<\/strong> and <strong>Resources<\/strong> tabs in subsequent steps.<\/p>\n<h2>Reviewing Amazon Kendra configuration and starting the data source sync<\/h2>\n<p>In the following steps, we configure Amazon Kendra to enable secure token access and start the data source sync to begin crawling and indexing documents.<\/p>\n<ol>\n<li>On the <a href=\"https:\/\/console.aws.amazon.com\/kendra\/\">Amazon Kendra console<\/a>, choose the index <code>AuthKendraIndex<\/code>, which was created as part of the <code>CloudFormation<\/code> stack.<\/li>\n<\/ol>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20207\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-6.jpg\" alt=\"On the Amazon Kendra console, choose the index AuthKendraIndex, which was created as part of the CloudFormation stack.\" width=\"800\" height=\"354\"><\/p>\n<p>Under <strong>User access control<\/strong>, token-based user access control is enabled, the signing key object is set to the Open ID provider URL of the Amazon Cognito user pool, and the user name and group are set to <code>cognito:username<\/code> and <code>cognito:groups<\/code>, respectively.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20208\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-7.jpg\" alt=\"Under User access control, token-based user access control is enabled.\" width=\"800\" height=\"345\"><\/p>\n<ol start=\"2\">\n<li>In the navigation pane, choose <strong>Data sources<\/strong>.<\/li>\n<li>On the <strong>Settings tab<\/strong>, you can see the data source bucket being configured.<\/li>\n<li>Select the radio button for the data source and choose <strong>Sync now<\/strong>.<\/li>\n<\/ol>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20209\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-8.jpg\" alt=\"Choose Sync now.\" width=\"800\" height=\"350\"><\/p>\n<p>The data source sync can take 10\u201315 minutes to complete, but you don\u2019t have to wait to move to the next step.<\/p>\n<h2>Creating users and groups in the Amazon Cognito user pool<\/h2>\n<p>In the terminal with the AWS CLI or <a href=\"https:\/\/aws.amazon.com\/cloudshell\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS CloudShell<\/a>, run the following commands to create users and groups in the Amazon Cognito user pool to use for our application. You need to copy the contents of the <strong>Physical ID<\/strong> column in the <strong>UserPool<\/strong> row from the <strong>Resources<\/strong> tab of the CloudFormation stack. This is the user pool ID to use in the following steps. We set <code>AmazonKendra@2020<\/code> as the temporary password for all the users. This password is required when logging in for the first time, and Amazon Cognito enforces a password reset.<\/p>\n<div class=\"hide-language\">\n<pre><code class=\"lang-bash\">USER_POOL_ID=&lt;<strong>PASTE-USER-POOL-ID-HERE<\/strong>&gt;\r\naws cognito-idp create-group --group-name customer --user-pool-id ${USER_POOL_ID}\r\naws cognito-idp create-group --group-name AWS-Sales --user-pool-id ${USER_POOL_ID}\r\naws cognito-idp create-group --group-name AWS-Marketing --user-pool-id ${USER_POOL_ID}\r\naws cognito-idp create-group --group-name AWS-SA --user-pool-id ${USER_POOL_ID}\r\naws cognito-idp admin-create-user --user-pool-id ${USER_POOL_ID} --username patricia --temporary-password AmazonKendra@2020\r\naws cognito-idp admin-create-user --user-pool-id ${USER_POOL_ID} --username james  --temporary-password AmazonKendra@2020\r\naws cognito-idp admin-create-user --user-pool-id ${USER_POOL_ID} --username john  --temporary-password AmazonKendra@2020\r\naws cognito-idp admin-create-user --user-pool-id ${USER_POOL_ID} --username mary  --temporary-password AmazonKendra@2020\r\naws cognito-idp admin-add-user-to-group --user-pool-id ${USER_POOL_ID} --username patricia --group-name customer\r\naws cognito-idp admin-add-user-to-group --user-pool-id ${USER_POOL_ID} --username james --group-name AWS-Sales\r\naws cognito-idp admin-add-user-to-group --user-pool-id ${USER_POOL_ID} --username john --group-name AWS-Marketing\r\naws cognito-idp admin-add-user-to-group --user-pool-id ${USER_POOL_ID} --username mary --group-name AWS-SA\r\n<\/code><\/pre>\n<\/div>\n<h2>Building and deploying the app<\/h2>\n<p>Now we build and deploy the app using the following steps:<\/p>\n<ol>\n<li>On the <a href=\"https:\/\/console.aws.amazon.com\/amplify\/\">AWS Amplify<\/a> console, choose the app <code>AWSKendraAuthApp<\/code>.<\/li>\n<li>Choose <strong>Run build<\/strong>.<\/li>\n<\/ol>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20210\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-9.jpg\" alt=\"Choose Run build.\" width=\"800\" height=\"275\"><\/p>\n<p>You can monitor the build progress on the console.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20211\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-10.jpg\" alt=\"You can monitor the build progress on the console.\" width=\"800\" height=\"298\"><\/p>\n<p>Let the build continue and complete the steps: Provision, Build, Deploy, and Verify. After this, the application is deployed and ready to use.<\/p>\n<p>You can browse through the source code by opening up the CodeCommit repository. The important file to look at is <code>src\/App.tsx<\/code>.<\/p>\n<ol start=\"3\">\n<li>Choose the link on the left to start the application in a new browser tab.<\/li>\n<\/ol>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20212\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-11.jpg\" alt=\"Choose the link on the left to start the application in a new browser tab.\" width=\"800\" height=\"310\"><\/p>\n<h2>Trial run<\/h2>\n<p>We can now take a trial run of our app.<\/p>\n<ol>\n<li>On the login page, sign in with the username <code>patricia<\/code> and the temporary password <code>AmazonKendra@2020<\/code>.<\/li>\n<\/ol>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20213\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-12.jpg\" alt=\"On the login page, sign in with the username patricia and the temporary password AmazonKendra@2020.\" width=\"800\" height=\"546\"><\/p>\n<p>Amazon Cognito requires you to reset your password the first time you log in. After you log in, you can see the search field.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20214\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-13.jpg\" alt=\"Amazon Cognito requires you to reset your password the first time you log in. After you log in, you can see the search field.\" width=\"800\" height=\"387\"><\/p>\n<ol start=\"2\">\n<li>In the search field, enter a query, such as <code>what is serverless<\/code>?<\/li>\n<li>Expand <strong>Filter search results<\/strong> to see different document types.<\/li>\n<\/ol>\n<p>You can select different document types to filter the search results.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20214\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-13.jpg\" alt=\"You can select different document types to filter the search results.\" width=\"800\" height=\"387\"><\/p>\n<ol start=\"4\">\n<li>Sign out and repeat this process for other users that are created in the Cognito user pool, namely, <code>james<\/code>, <code>john<\/code>, and <code>mary<\/code>.<\/li>\n<\/ol>\n<p>You can also choose <strong>Continue as Guest <\/strong>to use the app without authenticating. However, this option only shows results from blogs.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-20215\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/ML-1021-14.jpg\" alt=\"You can also choose Continue as Guest to use the app without authenticating. However, this option only shows results from blogs.\" width=\"800\" height=\"310\"><\/p>\n<p>You can return back to the login screen by choosing <strong>Welcome Guest! Click here to sign up or sign in<\/strong>.<\/p>\n<h2>Using the application<\/h2>\n<p>You can use the application we developed by making a few search queries logged in as different users. To experience how access control works, issue the same query from different user accounts and observe the difference in the search results. The following users get results from different sources:<\/p>\n<ul>\n<li>\n<strong>Guests and anonymous users <\/strong>\u2013 Only blogs<\/li>\n<li>\n<strong>Patricia (Customer)<\/strong> \u2013 Blogs and user guides<\/li>\n<li>\n<strong>James (Sales)<\/strong> \u2013 Blogs, user guides, and case studies<\/li>\n<li>\n<strong>John (Marketing)<\/strong> \u2013 Blogs, user guides, case studies, and analyst reports<\/li>\n<li>\n<strong>Mary (Solutions Architect)<\/strong> \u2013 Blogs, user guides, case studies, analyst reports, and whitepapers<\/li>\n<\/ul>\n<p>We can make additional queries and observe the results. Some suggested queries include \u201cWhat is machine learning?\u201d, \u201cWhat is serverless?\u201d, and \u201cDatabases\u201d.<\/p>\n<h2>Cleaning up<\/h2>\n<p>To delete the infrastructure that was deployed as part of the CloudFormation stack, delete the stack from the AWS CloudFormation console. Stack deletion can take 20\u201330 minutes.<\/p>\n<p>When the stack status shows as <code>Delete Complete<\/code>, go to the <strong>Events<\/strong> tab and confirm that each of the resources has been removed. You can also cross-verify by checking on the respective management consoles for Amazon Kendra, Amazon Amplify, and the Amazon Cognito user pool and identity pool.<\/p>\n<p>You must delete your data source bucket separately, because it was not created as part of the CloudFormation stack.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this post, we demonstrated how you can create a secure search application using Amazon Kendra. Organizations who use an Open ID-compliant identity management system with a new or pre-existing Amazon Kendra index can now enable secure token access to make sure your intelligent search applications are aligned with your organizational security model. For more information about access control in Amazon Kendra, see <a href=\"https:\/\/docs.aws.amazon.com\/kendra\/latest\/dg\/create-index-access-control.html\" target=\"_blank\" rel=\"noopener noreferrer\">Controlling access to documents in an index<\/a>.<\/p>\n<hr>\n<h3>About the Author<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-20223 alignleft\" src=\"https:\/\/d2908q01vomqb2.cloudfront.net\/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59\/2020\/12\/24\/Abhinav-Jawadekar.jpg\" alt=\"Abhinav Jawadekar\" width=\"100\" height=\"133\"><strong>Abhinav Jawadekar<\/strong> is a Senior Partner Solutions Architect at Amazon Web Services. Abhinav works with AWS partners to help them in their cloud journey.<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/aws.amazon.com\/blogs\/machine-learning\/building-a-secure-search-application-with-access-controls-using-amazon-kendra\/<\/p>\n","protected":false},"author":0,"featured_media":731,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts\/730"}],"collection":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/comments?post=730"}],"version-history":[{"count":0,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/posts\/730\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/media\/731"}],"wp:attachment":[{"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/media?parent=730"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/categories?post=730"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salarydistribution.com\/machine-learning\/wp-json\/wp\/v2\/tags?post=730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}