【问题标题】:How to send data into Elastic Cloud from Java?如何从 Java 将数据发送到 Elastic Cloud?
【发布时间】:2021-03-04 10:25:41
【问题描述】:

我想在 Java 应用程序的 Elastic Cloud 中运行的 Elastic Search 中插入(索引)一些数据。

为此,我编写了以下代码:

void sendStuffToElasticSearch() {
    RestHighLevelClient client = null;
    try {
        client = new RestHighLevelClient(
                RestClient.builder(CLOUD_ID)
        );

        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        builder.addHeader("Authorization", String.format("ApiKey %s",
                API_KEY));
        final RequestOptions requestOptions = builder.build();

        IndexRequest request = new IndexRequest("posts");
        request.id("1");
        String jsonString = "{" +
                "\"user\":\"kimchy\"," +
                "\"postDate\":\"2013-01-30\"," +
                "\"message\":\"trying out Elasticsearch\"" +
                "}";
        request.source(jsonString, XContentType.JSON);
        IndexResponse indexResponse = client.index(request, requestOptions);
        System.out.println("indexResponse");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(client);
    }
}

API_KEY 是我根据this tutorial 生成的密钥,它还说我需要将其发送到Authorization 标头中,格式如下:Authorization: ApiKey $EC_API_KEY

当我运行上述代码时,我收到以下错误:

org.elasticsearch.client.ResponseException: method [PUT], host [https://XXXXXXXXXX:9243], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 401 Unauthorized]
{"error":{"root_cause":[{"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}}],"type":"security_exception","reason":"missing authentication credentials for REST request [/posts/_doc/1?timeout=1m]","header":{"WWW-Authenticate":["Basic realm=\"security\" charset=\"UTF-8\"","Bearer realm=\"security\"","ApiKey"]}},"status":401}
        at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
        at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
        ... 30 more

如何解决这个问题,我。 e.以 Elastic Cloud 期望的方式提供所有与身份验证相关的数据?

我正在使用以下库:

    <properties>
        [...]
        <elastic-search-client.version>7.11.1</elastic-search-client.version>
    </properties>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>${elastic-search-client.version}</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elastic-search-client.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elastic-search-client.version}</version>
        </dependency>

更新 1: 建议的 API 密钥的 Base64 编码 here(参见下面的代码)没有帮助。

            RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
            builder.addHeader("Authorization", String.format("ApiKey %s",
                    Base64.getEncoder().encodeToString(API_KEY.getBytes(StandardCharsets.UTF_8))));
            final RequestOptions requestOptions = builder.build();

更新 2: 改变我创建客户端的方式,也没有帮助(见下文)。

            Header[] defaultHeaders =
                    new Header[]{new BasicHeader("Authorization",
                            String.format("ApiKey %s",API_KEY))};
            final RestClientBuilder builder1 = RestClient.builder(CLOUD_ID);
            builder1.setDefaultHeaders(defaultHeaders);
            client = new RestHighLevelClient(
                    builder1
            );

更新 3:我将提供的 API 密钥更改为

public static final String BASE64_API_KEY = Base64.getEncoder().encodeToString(String.format("%s:%s", ID, KEY).getBytes());

按照 Ricardo Ferreira 的建议。

现在我得到一个不同的错误:

org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/posts/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:admin/auto_create] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}
        at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:326)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:296)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:270)
        at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1621)
        ... 30 more

更新 4:

在我创建有问题的索引后,错误消息变为:

org.elasticsearch.client.ResponseException: method [PUT], host [XXXXXXXXXXXXXXXX], URI [/camunda-1/_doc/1?timeout=1m], status line [HTTP/1.1 403 Forbidden]
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"}],"type":"security_exception","reason":"action [indices:data/write/bulk[s]] is unauthorized for API key id [XXXXXXXXXXXXXXXX] of user [XXXXXXXXXXXXXXXX]"},"status":403}

【问题讨论】:

    标签: java elasticsearch authorization elastic-cloud


    【解决方案1】:

    它不起作用,因为您使用了错误的 API 密钥。 ?

    但别担心:这些事情经常发生。这肯定发生在我身上。

    您创建的 API 密钥用于向 Elasticsearch 服务发出 REST 请求,该服务是管理您的 Elasticsearch 和 Kibana 集群的实体。

    要使其正常工作,您需要专门从 Elasticsearch 创建一个 API 密钥。要创建一个,请转到 Dev Tools Console 并发出以下请求:

    POST _security/api_key
    {
       "name": "my-api-key",
       "expiration": "7d", 
       "role_descriptors": {
          "custom-role": {
             "cluster": ["all"],
             "index": [
                {
                   "names": [
                      "index-1",
                      "index-2"
                   ],
                   "privileges": ["all"]
                }
             ]
          }
       }
    }
    

    如果执行成功,你会得到如下响应:

    {
      "id" : "liKs_XcBrNsSAgwboCN9",
      "name" : "my-api-key",
      "expiration" : 1615473484899,
      "api_key" : "NC3ZeIb_SGWjGJRZVoOf2g"
    }
    

    记下idapi_key 字段。您将需要它们来创建授权标头:

    String apiKey = String.format("%s:%s", id, api_key);
    apiKey = Base64.getEncoder().encodeToString(apiKey.getBytes());
    String authorization = String.format("ApiKey %s", apiKey);
    

    在此之后,只需在您的 Java 代码中使用授权:

    builder.addHeader("Authorization", authorization);
    

    玩得开心?

    【讨论】:

    • 现在我设法让它工作了。再次感谢!
    • 您开始使用正确的 API Key 后的最后一个错误是索引权限。对吗?
    • 是的。我不得不将"index-1", "index-2" 中的索引名称更改为我的索引名称。
    • 干得好@Mentiflectax ✔️
    猜你喜欢
    • 2020-02-26
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 2017-05-30
    • 2021-09-15
    • 2017-04-13
    相关资源
    最近更新 更多