Open charlielj88 opened 2 years ago
Hello @charlielj88,
Thank you for opening and calling out the lack of documentation.
We should re-route this to the documentation repo for the site to be updated with the information. If you have an .ndjson file it means should use the saved_objects
API. For example:
curl -X POST "http://localhost:5601/api/saved_objects/_import?overwrite=true" -H "osd-xsrf: true" --form file=@foobar.ndjson
^ This supports uploading a ndjson file. I also believe it takes a json file as well.
So from your example:
curl -X POST "http://localhost:5601/api/saved_objects/_import?overwrite=true" -H "osd-xsrf: true" -k -u {id}:{password} --form file=@Metricbeat-kubernetes-overview.json
From the original post they most likely exported via the dashboards/export
, from the legacy application that API (and the import) was planned for deprecation.
I understand that the base you have defined for OpenSearch Dashboards is _dashboards
. I do see you have {opensearch url}:443
. Is that the port you are exposing? Are you able to get the {opensearch url}:443/_dashboards/api/status
? If not then either the port is not exposed for you or the user you are using does not have permissions for this API.
If you are able to utilize the saved_objects
API then let me know and we can re-route this to the doc repo for them to add information on using this API.
Thanks!
Hello @kavilla,
Thank you for your clarification, since I am using aws managed opensearch, the default opensearch dashboard url is appended with "/_dashboards". Yes I have tested port 443 is open and working.
I have tested "https://{aws_opensearch_url}/_dashboards/api/status" and it could successfully return me the correct response.
I have amended my original curl command accordingly as below,
curl -X POST "https://{aws_opensearch_url}/_dashboards/api/saved_objects/_import?overwrite=true" -H "osd-xsrf: true" -k -u {username}:{password} --form file=@Metricbeat-kubernetes-overview.json
However, I get the return response of "{"statusCode":401,"error":"Unauthorized","message":"Authentication required"}"
The {username} and {password} in the curl command are the ones I can use to login to opensearch dashboard. Is there anything I missed here?
Charlie
Hello @charlielj88,
Do you know if the user you are using has write access?
Hello @charlielj88,
Do you know if the user you are using has write access?
Hi @kavilla, yes, this is confirmed, as I use the same opensearch credentials for metricbeat to write into the index.
Charlie
@kavilla, I also noticed that if I directly import the saved_object from UI, I have the following error, which seems the json format is not supported,
Hello. I'm migrating from kibana spaces to opensearch-dashboards with multitenancy and i need a rest api to import dashboards for individual tenants.
api/saved-objects/_import/
is not taking ?security_tenant=tenant_one
running
curl -k -XPOST -H 'osd-xsrf: true' 'http://admin:admin@localhost:5601/api/saved_objects/_import/?security_tenant=tenant_one' -d "$(cat kibana_dashboard_one.json)"
yields
{"statusCode":400,"error":"Bad Request","message":"[request query.security_tenant]: definition for this key is missing"}
tenant is configured:
"global_tenant": {
"reserved": true,
"hidden": false,
"description": "Global tenant",
"static": true
},
"tenant_one": {
"reserved": false,
"hidden": false,
"description": "tenant one",
"static": false
},
"admin_tenant": {
"reserved": false,
"hidden": false,
"description": "Demo tenant for admin user",
"static": false
}
}
Any hints please on importing a dashboard for a specific tenant? Thank you.
@kavilla, I also noticed that if I directly import the saved_object from UI, I have the following error, which seems the json format is not supported,
Finally find a way to convert the json to ndjson and now at least I could import metricbeat dashboards from UI...
Hello everybody,
Managed to get it working. Below the steps:
Prerequisites:
admin
user and all required settings for multitenancyexport.ndjson
# curl -k -XPUT -H'content-type: application/json' https://admin:admin@localhost:9200/_plugins/_security/api/tenants/tenant_one -d '{"description": "tenant one"}'
{"status":"CREATED","message":"'tenant_one' created."}
# curl -k -XPUT -H'content-type: application/json' https://admin:admin@localhost:9200/_plugins/_security/api/tenants/tenant_two -d '{"description": "tenant two"}'
{"status":"CREATED","message":"'tenant_two' created."}
__user__
, i guess the value for private
# curl -k -XGET -u 'admin:admin' -c dashboards_cookie http://localhost:5601/api/login/
{ "data": { "user_name": "admin", "user_requested_tenant": "user", [...] } }
3. switch tenant. note the tenant is kept inside the cookie so we need to save it after this request
```bash
# curl -k -XPOST -b dashboards_cookie -c dashboards_cookie -H'osd-xsrf: true' -H'content-type: application/json' http://localhost:5601/api/v1/multitenancy/tenant -d '{"tenant": "tenant_one", "username": "admin"}'
# curl -k -XGET -b dashboards_cookie http://localhost:5601/api/v1/configuration/account | jq
{
"data": {
"user_name": "admin",
"user_requested_tenant": "tenant_one",
[...]
}
}
# curl -k -XPOST -H'osd-xsrf: true' -b dashboards_cookie http://localhost:5601/api/saved_objects/_import?overwrite=true --form file=@export.ndjson | jq
{
"successCount": 3,
"success": true,
"successResults": [
{
"type": "index-pattern",
"id": "96f0ec20-ec90-11ec-9191-4dc9d4cc1f7d",
"meta": {
"title": "*__dobby_docs",
"icon": "indexPatternApp"
}
},
{
"type": "visualization",
"id": "e4aca2a0-ed6d-11ec-9191-4dc9d4cc1f7d",
"meta": {
"title": "cucu_dash",
"icon": "visualizeApp"
}
},
{
"type": "dashboard",
"id": "edeca590-ed6d-11ec-9191-4dc9d4cc1f7d",
"meta": {
"title": "cucu_the_dash",
"icon": "dashboardApp"
}
}
]
}
Reagrds, C.
Any help/suggestion is highly appreciated.
I am having trouble importing .ndjson files using SavedObject API within a Lambda, what I am trying is to import a bunch of .ndjson files (dashboards, index-templates etc) at the time of creating a stack (via CDK) that includes Opensearch & Dashboard services. The Opensearch is configured for Cognito authentication and browser logins are working fine. However the lambda (with write access/role to Opensearch domain) is having trouble with API, https://${domain}/_dashboards/api/saved_objects/_import?overwrite=true
, the execution fails with a HTML response (guess this is a cognito sign-in form). The request is signed with Sigv4 (@aws-sdk/signature-v4
), I checked the
https://${domain}/_dashboards/api/status
and it works fine.
Does Opensearch dashboard service supports Lambda IAM role to access, I know Opensearch supports read/write from a Lambda using IAM role.
I am reading AWS developer guide - "Loading credentials for a Node.js Lambda function" (https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-lambda.html)
The execution role provides the Lambda function with the credentials it needs to run and to invoke other web services. As a result, you don't need to provide credentials to the Node.js code you write within a Lambda function.
The request has the headers set (not sure whether I am missing any header or Dashboard is looking for a specific header name)
{ "method":"POST", "hostname":"xxxxx-domain", "query":{}, "headers":{ "osd-xsrf":"true", "securitytenant":"Global", "accept":"*/*", "host":"xxxxx-domain", "Content-Length":"1221608", "x-amz-date":"20220927T114706Z", "x-amz-security-token":"IQa....", "x-amz-content-sha256":"a5067....", "authorization":"AWS4-HMAC-SHA256 Credential=AS.../20220927/us-east-1/es/aws4_request, SignedHeaders=accept;content-length;host;osd-xsrf;securitytenant;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=789..." } }
Any help/suggestion is highly appreciated.
I am having trouble importing .ndjson files using SavedObject API within a Lambda, what I am trying is to import a bunch of .ndjson files (dashboards, index-templates etc) at the time of creating a stack (via CDK) that includes Opensearch & Dashboard services. The Opensearch is configured for Cognito authentication and browser logins are working fine. However the lambda (with write access/role to Opensearch domain) is having trouble with API,
https://${domain}/_dashboards/api/saved_objects/_import?overwrite=true
, the execution fails with a HTML response (guess this is a cognito sign-in form). The request is signed with Sigv4 (@aws-sdk/signature-v4
), I checked thehttps://${domain}/_dashboards/api/status
and it works fine.Does Opensearch dashboard service supports Lambda IAM role to access, I know Opensearch supports read/write from a Lambda using IAM role.
I am reading AWS developer guide - "Loading credentials for a Node.js Lambda function" (https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-lambda.html)
The execution role provides the Lambda function with the credentials it needs to run and to invoke other web services. As a result, you don't need to provide credentials to the Node.js code you write within a Lambda function.
The request has the headers set (not sure whether I am missing any header or Dashboard is looking for a specific header name)
{ "method":"POST", "hostname":"xxxxx-domain", "query":{}, "headers":{ "osd-xsrf":"true", "securitytenant":"Global", "accept":"*/*", "host":"xxxxx-domain", "Content-Length":"1221608", "x-amz-date":"20220927T114706Z", "x-amz-security-token":"IQa....", "x-amz-content-sha256":"a5067....", "authorization":"AWS4-HMAC-SHA256 Credential=AS.../20220927/us-east-1/es/aws4_request, SignedHeaders=accept;content-length;host;osd-xsrf;securitytenant;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=789..." } }
You need to include the lambda execution role as 'Backend Role' in the corresponding Opensearch Dashboard Role.
Apologise @subramaniant06 , I failed to notice your response
I do have Lambda role mapped to all_access
backend role and this is also done via CDK code just after creating the domain and dashboard.
let requests: object[] = [{ method: 'PUT', path: '_plugins/_security/api/rolesmapping/all_access', body: { backend_roles: [ adminUserRoleArn, lambdaRoleArn ], hosts: [], users: [], } }]
That snippet may be confusing, but what I am doing is to configure roles in opensearch via set of requests thats executed via a CustomResource
.
How are you making this API call? from lambda? This is possible only if you assume the master user role that you used to enable the Fine grained access for Opensearch.
let requests: object[] = [{ method: 'PUT', path: '_plugins/_security/api/rolesmapping/all_access', body: { backend_roles: [ adminUserRoleArn, lambdaRoleArn ], hosts: [], users: [], } }]
I'm able to create tenants, roles, monitors, destinations etc using Custom Resource Lambda with master user role as execution role, AWS NodeHttpClient with Sigv4. However i'm not able to do the multi-part upload using NodeHttpClient to import the index patterns, dashboards and visualizations.
Guess we are in the same juncture of issue. The lambda execution role is set as masterUserArn
in fineGrainedAccessControl
of domain. I use Axios to wire roles/rolesmapping (which works fine) and multi-part upload of index patterns/dashboard/visualizations are failing for me as well with a HTML response.
The lambda that imports index-patterns/dashboards etc are triggered from S3 and creates an Axios multi-part request to import savedObjects. (this lambda has the same IAM role as the one that works with CustomResource). I am not sure what is happening in the background of Opensearch and unable to troubleshoot.
Below is the typescript code that handles CustomResource
request and index-pattern import request,
public async execute(
signer: SignatureV4, domain: string, apiPath: string, httpMethod: string, payload: any,
securityTenant?: string, filename?: string): Promise<AxiosResponse<any, any>> {
const method = httpMethod.toLowerCase();
// Payload is the body of request, incase of a file, we append with boundary and content-type
let payloads = [];
// Setup headers
let headers: Record<string, string> = {};
if (! apiPath.startsWith('/')) {
apiPath = `/${apiPath}`;
}
const url:URL = new URL(domain + apiPath);
const endpoint:string = url.hostname;
// Is this a OS plugin request ?
if (apiPath.startsWith('/_dashboards')) {
// Add XSRF request header
headers["osd-xsrf"] = "true";
}
// Add security tenant header
if (securityTenant) {
headers["securitytenant"] = securityTenant;
}
// Is this a file upload ?
if (filename) {
const name = path.basename(filename);
headers['accept'] = '*/*';
const boundary = '----------------------------Telemetry';
payloads.push(`Content-Type: multipart/form-data; boundary=${boundary}`);
payloads.push(boundary);
payloads.push(`Content-Disposition: form-data; name=”file”; filename=”${name}”;`);
payloads.push('Content-Type: application/x-ndjson');
payloads.push(payload);
payloads.push(`${boundary}--`);
} else {
// We treat all body as application/json content-type
headers["Content-Type"] = "application/json";
// Is payload a string type
if (typeof payload === "string") {
payloads.push(payload);
} else if (typeof payload === "object") {
// Convert object to string
payloads.push(JSON.stringify(payload));
}
}
// Concatenate all payload
const body:string = payloads.join("\r\n");
// Set host header with hostname
headers["host"] = url.hostname;
headers["Content-Length"] = `${Buffer.byteLength(body)}`;
// Construct http request instance
const httpRequest = new HttpRequest({
headers: headers,
path: apiPath,
method: httpMethod,
hostname: endpoint,
body: body
});
// Sign the http request
const signedRequest = await signer.sign(httpRequest, { signingDate: new Date().toUTCString()});
const config = { timeout: 60000, headers: signedRequest.headers, httpsAgent: agent };
if (method === 'put') {
// Use axios to issue request
return axios.put(url.toString(), signedRequest.body, config);
} else if (method === 'post') {
return axios.post(url.toString(), signedRequest.body, config);
} else {
throw new Error(`Unknown HTTP method or method ${method} not supported yet`);
}
}
by the way, I am using below API path for importing savedobjects, hope this is correct.
'/_dashboards/api/saved_objects/_import?overwrite=true';
Hello everybody,
Managed to get it working. Below the steps:
Prerequisites:
- opensearch 2.0.0 running on localhost:9200 with demo
admin
user and all required settings for multitenancy- openseach-dashboards 2.0.0 running on localhost:5601
- an exported dashboard to a file. mine was called
export.ndjson
- create tenants using opensearch documented REST API
# curl -k -XPUT -H'content-type: application/json' https://admin:admin@localhost:9200/_plugins/_security/api/tenants/tenant_one -d '{"description": "tenant one"}' {"status":"CREATED","message":"'tenant_one' created."} # curl -k -XPUT -H'content-type: application/json' https://admin:admin@localhost:9200/_plugins/_security/api/tenants/tenant_two -d '{"description": "tenant two"}' {"status":"CREATED","message":"'tenant_two' created."}
- login to opensearch-dashboards and save the cookie. note the current tenant is
__user__
, i guess the value forprivate
# curl -k -XGET -u 'admin:admin' -c dashboards_cookie http://localhost:5601/api/login/ # curl -k -XGET -b dashboards_cookie http://localhost:5601/api/v1/configuration/account | jq { "data": { "user_name": "admin", "user_requested_tenant": "__user__", [...] } }
- switch tenant. note the tenant is kept inside the cookie so we need to save it after this request
# curl -k -XPOST -b dashboards_cookie -c dashboards_cookie -H'osd-xsrf: true' -H'content-type: application/json' http://localhost:5601/api/v1/multitenancy/tenant -d '{"tenant": "tenant_one", "username": "admin"}' # curl -k -XGET -b dashboards_cookie http://localhost:5601/api/v1/configuration/account | jq { "data": { "user_name": "admin", "user_requested_tenant": "tenant_one", [...] } }
- push the dashboard using the same cookie
# curl -k -XPOST -H'osd-xsrf: true' -b dashboards_cookie http://localhost:5601/api/saved_objects/_import?overwrite=true --form file=@export.ndjson | jq { "successCount": 3, "success": true, "successResults": [ { "type": "index-pattern", "id": "96f0ec20-ec90-11ec-9191-4dc9d4cc1f7d", "meta": { "title": "*__dobby_docs", "icon": "indexPatternApp" } }, { "type": "visualization", "id": "e4aca2a0-ed6d-11ec-9191-4dc9d4cc1f7d", "meta": { "title": "cucu_dash", "icon": "visualizeApp" } }, { "type": "dashboard", "id": "edeca590-ed6d-11ec-9191-4dc9d4cc1f7d", "meta": { "title": "cucu_the_dash", "icon": "dashboardApp" } } ] }
Reagrds, C.
Hello,
I was able to achieve using the saved_objects
API with this method, except at step 2 where I had to use a slightly different request to login and get the cookie (I am using AWS OpenSearch 2.3, so the Dashboards API endpoint starts with _dashboards
):
curl -XPOST -c dashboards_cookie https://${os_endpoint}/_dashboards/auth/login -H "osd-xsrf: true" -H "Content-Type: application/json" -d '{"username":"${admin_username}","password":"${admin_password}"}'
Thanks, Nick
Hi guys.
Today I discovered another very confusing thing with importing dashboard to specific tenant.
If I make tenant NGSupport
(for example) and use credentials for OpenSearch Dashboard admin account, API return success, but it import not to the NGSupport
tenant, but to the Global
tenant.
$ curl -k -w ", HTTP:%{http_code}" -X POST -uadmin:REDACTED "http://localhost:5601/api/saved_objects/_import?overwrite=true" -H "securitytenant: NGSupport" -H "osd-xsrf: true" --form file=@TestDashboard.ndjson
{"successCount":3,"success":true,"successResults":[{"type":"index-pattern","id":"nginx-*","meta":{"title":"nginx-*","icon":"indexPatternApp"},"overwrite":true},{"type":"search","id":"149258c0-b816-11ed-89d4-ffdda45e5108","meta":{"title":"NginxRequests","icon":"discoverApp"}},{"type":"dashboard","id":"399571c0-b816-11ed-89d4-ffdda45e5108","meta":{"title":"NGSupport Dashboard","icon":"dashboardApp"}}]}, HTTP:200
Workaround for the problem is make dedicated internal user with read/write access to the tenant and using these credentials for importing.
I expecting, that:
If I login to OpenSearch Dashboard as admin, via GUI I can import any objects to any tenants without any problems. Why API calls are different?
Hello, this still seems to be an issue in OS 2.7.
I am trying to get a saved object up with the following method:
def import_saved_objects(os_endpoint_url, os_pass):
file_name = "security-lake-opensearch.ndjson"
with open(f"os_configuration_templates/{file_name}", encoding="utf-8") as f:
data = f.read()
path = f"{os_endpoint_url}/_dashboards/api/saved_objects/_import?createNewCopies=true"
headers = {"Content-Type": "application/json", "osd-xsrf": "true"}
with tempfile.NamedTemporaryFile("w+t") as f:
f.name = file_name
f.write(data)
f.seek(0)
response = requests.post(
path,
headers=headers,
auth = ("admin", os_pass),
timeout=90,
files={"file": f},
)
print(response)
The response is a 401 code from Opensearch. This file uploads fine from the gui.
Hi,
I am using metricbeat-oss version 7.10.2 with aws opensearch 1.2 (compatibility mode enabled so trick the metricbeat with version 7.10.2). The opensearch connection is working fine. However, when I tried to follow the workaround approach in another post (https://github.com/opensearch-project/OpenSearch-Dashboards/issues/831) to manually curl to import the pre-existing metricbeat dashboards to opensearch, I could not trigger the API call successfully,
curl -k -XPOST -u {id}:{password} -H "osd-xsrf: true" -H 'content-type: application/json' \ https://{opensearch url}:443/_dashboards/api/opensearch-dashboards/dashboards/import?exclude=index-patterh\&force=true \ -d@Metricbeat-kubernetes-overview.json
This API is quite puzzling to me, 1) when I executed the curl command, I get a "no matches found" error, and it seems the api does not exist. Not sure it's a version problem. 2) I could not find any documentation on this opensearch dashbaord API online including opensearch website 3) The dashboard in the api is in json format, however, opensearch dashbaord or kibana bashboard only accepts ndjson. How can this work?
Thank you. Charlie