Skip to content

Conversation

@cwperks
Copy link
Member

@cwperks cwperks commented Jan 20, 2026

Description

This PR fixes an issue connecting to a prometheus connector.

Before:

➜  curl -XPOST localhost:9200/_plugins/_query/_datasources -H 'Content-Type:application/json' --data-binary '{
  "name" : "my_prometheus",
    "connector": "prometheus",
    "properties" : {
      "prometheus.uri" : "http://localhost:9090"
    }
}'
"Created DataSource with name my_prometheus"%
➜  curl http://localhost:9200/_plugins/_directquery/_resources/my_prometheus/api/v1/metadata
{
  "status": 500,
  "error": {
    "type": "SecurityException",
    "reason": "There was internal problem at backend",
    "details": "Denied access to: localhost:9090, domain ProtectionDomain  (file:/usr/share/opensearch/plugins/opensearch-ubi/opensearch-ubi-3.5.0.0.jar \u003cno signer certificates\u003e)\n java.net.URLClassLoader@2a30b0cb\n \u003cno principals\u003e\n java.security.Permissions@420bdb83 (\n)\n\n"
  }
}

After:

➜  curl -XPOST localhost:9200/_plugins/_query/_datasources -H 'Content-Type:application/json' --data-binary '{
  "name" : "my_prometheus",
    "connector": "prometheus",
    "properties" : {
      "prometheus.uri" : "http://localhost:9090"
    }
}'
"Created DataSource with name my_prometheus"%
➜  curl http://localhost:9200/_plugins/_directquery/_resources/my_prometheus/api/v1/metadata
{
  "status": 400,
  "error": {
    "type": "PrometheusClientException",
    "reason": "Invalid Request",
    "details": "Error while getting resources for METADATA: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:9090"
  }
}

Full Stack Trace

opensearch-node1-1       | java.lang.SecurityException: Denied access to: localhost:9090, domain ProtectionDomain  (file:/usr/share/opensearch/plugins/opensearch-ubi/opensearch-ubi-3.5.0.0.jar <no signer certificates>)
opensearch-node1-1       |  java.net.URLClassLoader@2a30b0cb
opensearch-node1-1       |  <no principals>
opensearch-node1-1       |  java.security.Permissions@420bdb83 (
opensearch-node1-1       | )
opensearch-node1-1       |
opensearch-node1-1       |
opensearch-node1-1       | 	at java.base/java.net.Socket.connect(Socket.java:640)
opensearch-node1-1       | 	at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
opensearch-node1-1       | 	at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
opensearch-node1-1       | 	at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
opensearch-node1-1       | 	at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
opensearch-node1-1       | 	at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
opensearch-node1-1       | 	at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
opensearch-node1-1       | 	at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
opensearch-node1-1       | 	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
opensearch-node1-1       | 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
opensearch-node1-1       | 	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
opensearch-node1-1       | 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
opensearch-node1-1       | 	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
opensearch-node1-1       | 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
opensearch-node1-1       | 	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
opensearch-node1-1       | 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
opensearch-node1-1       | 	at org.opensearch.sql.common.interceptors.URIValidatorInterceptor.intercept(URIValidatorInterceptor.java:33)
opensearch-node1-1       | 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
opensearch-node1-1       | 	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
opensearch-node1-1       | 	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
opensearch-node1-1       | 	at org.opensearch.sql.prometheus.client.PrometheusClientImpl.getAllMetrics(PrometheusClientImpl.java:178)
opensearch-node1-1       | 	at org.opensearch.sql.prometheus.query.PrometheusQueryHandler.getResources(PrometheusQueryHandler.java:136)
opensearch-node1-1       | 	at org.opensearch.sql.prometheus.query.PrometheusQueryHandler.getResources(PrometheusQueryHandler.java:32)
opensearch-node1-1       | 	at org.opensearch.sql.directquery.DirectQueryExecutorServiceImpl.lambda$getDirectQueryResources$0(DirectQueryExecutorServiceImpl.java:81)
opensearch-node1-1       | 	at java.base/java.util.Optional.map(Optional.java:260)

Check List

  • New functionality includes testing.
  • New functionality has been documented.
  • New functionality has javadoc added.
  • New functionality has a user manual doc added.
  • New PPL command checklist all confirmed.
  • API changes companion pull request created.
  • Commits are signed per the DCO using --signoff or -s.
  • Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

…r.doPrivilegedChecked

Signed-off-by: Craig Perkins <cwperx@amazon.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Summary by CodeRabbit

  • Chores
    • Updated internal security handling for Prometheus and Alertmanager data retrieval to run sensitive HTTP requests under privileged checks; no public APIs or behaviors were changed.

Walkthrough

Wrapped Prometheus and Alertmanager HTTP request executions in AccessController.doPrivilegedChecked(...) calls inside the Prometheus client implementation, so HTTP calls run within a privilege-checked context. No public APIs or signatures were changed.

Changes

Cohort / File(s) Summary
Prometheus/Alertmanager client privilege wrapping
direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java
Added org.opensearch.secure_sm.AccessController import and replaced direct .newCall(request).execute() usages with AccessController.doPrivilegedChecked(() -> ...execute()) across multiple methods (e.g., queryRange, query, getLabels, getLabel, getAllMetrics, getSeries, queryExemplars, getAlerts, getRules, and Alertmanager request handlers). No public signatures changed.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Client Code
    participant PromClient as PrometheusClientImpl
    participant AccessCtrl as AccessController
    participant HttpClient as OkHttpClient
    participant PromServer as Prometheus/Alertmanager

    Caller->>PromClient: invoke query / getAlerts / ...
    PromClient->>AccessCtrl: doPrivilegedChecked { execute HTTP call }
    AccessCtrl->>HttpClient: invoke .newCall(request).execute()
    HttpClient->>PromServer: HTTP request
    PromServer-->>HttpClient: HTTP response
    HttpClient-->>AccessCtrl: response
    AccessCtrl-->>PromClient: privileged result
    PromClient-->>Caller: return response/result
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: wrapping Prometheus HTTP calls with AccessController.doPrivilegedChecked to fix a SecurityException when connecting to Prometheus.
Description check ✅ Passed The description directly relates to the changeset, providing before/after error outputs and stack traces showing the SecurityException and how the fix resolves it.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

joshuali925
joshuali925 previously approved these changes Jan 20, 2026
Copy link
Member

@joshuali925 joshuali925 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java`:
- Line 179: Add a centralized helper in PrometheusClientImpl named something
like executePrivileged(Request request, OkHttpClient client) that wraps
AccessController.doPrivilegedChecked(() -> client.newCall(request).execute())
and throws IOException; then replace every direct call to
prometheusHttpClient.newCall(request).execute() and
alertmanagerHttpClient.newCall(request).execute() across methods queryRange,
query, getLabels, getLabel, getAllMetrics, getSeries, queryExemplars, getAlerts,
getRules, getAlertmanagerAlerts, getAlertmanagerAlertGroups,
getAlertmanagerReceivers, getAlertmanagerSilences, and
createAlertmanagerSilences to call executePrivileged(request,
prometheusHttpClient) or executePrivileged(request, alertmanagerHttpClient)
respectively so the security wrapper is applied consistently.

logger.debug("queryUrl: " + queryUrl);
Request request = new Request.Builder().url(queryUrl).build();
Response response = this.prometheusHttpClient.newCall(request).execute();
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all HTTP call sites in the file that may need the same fix
echo "=== HTTP calls using prometheusHttpClient ==="
rg -n "prometheusHttpClient\.newCall" direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java

echo ""
echo "=== HTTP calls using alertmanagerHttpClient ==="
rg -n "alertmanagerHttpClient\.newCall" direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java

echo ""
echo "=== Calls already wrapped with doPrivilegedChecked ==="
rg -n "doPrivilegedChecked" direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java

Repository: opensearch-project/sql

Length of output: 1543


🏁 Script executed:

#!/bin/bash
# Extract method signatures to confirm they are distinct methods
echo "=== Method signatures at the call sites ==="
rg -B 5 "prometheusHttpClient\.newCall|alertmanagerHttpClient\.newCall" direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java | grep -E "^\s*(public|private)\s+|prometheusHttpClient\.newCall|alertmanagerHttpClient\.newCall" | head -50

Repository: opensearch-project/sql

Length of output: 1308


🏁 Script executed:

#!/bin/bash
# Extract method signatures more clearly
echo "=== Method signatures with line numbers ==="
rg -B 10 "prometheusHttpClient\.newCall|alertmanagerHttpClient\.newCall" \
  direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java \
  | grep -E "^\s*[0-9]+-\s*(public|private)" | head -20

Repository: opensearch-project/sql

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Read the file with line numbers to see the method context
head -330 direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java | tail -150 | cat -n

Repository: opensearch-project/sql

Length of output: 7759


🏁 Script executed:

#!/bin/bash
# Read the first part of the file to see queryRange and other methods
head -200 direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java | cat -n

Repository: opensearch-project/sql

Length of output: 9152


🏁 Script executed:

#!/bin/bash
# Check context around line 179 for any comments explaining the wrapper
sed -n '168,183p' direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java | cat -n

Repository: opensearch-project/sql

Length of output: 993


Inconsistent application of the security fix across HTTP call sites.

The AccessController.doPrivilegedChecked wrapper is applied only to getAllMetrics (line 179), but 13 other methods in this class make HTTP calls using the same pattern (prometheusHttpClient.newCall(request).execute() or alertmanagerHttpClient.newCall(request).execute()). If the SecurityException is triggered by socket connections in getAllMetrics, it will likely occur in other methods making identical HTTP calls:

  • queryRange (line 95)
  • query (line 130)
  • getLabels (line 150)
  • getLabel (line 165)
  • getSeries (line 198)
  • queryExemplars (line 215)
  • getAlerts (line 226)
  • getRules (line 239)
  • getAlertmanagerAlerts (line 252)
  • getAlertmanagerAlertGroups (line 265)
  • getAlertmanagerReceivers (line 277)
  • getAlertmanagerSilences (line 289)
  • createAlertmanagerSilences (line 305)

Extract a helper method to centralize the privileged execution and apply it consistently:

Suggested approach
private Response executePrivileged(Request request, OkHttpClient client) throws IOException {
    return AccessController.doPrivilegedChecked(() -> client.newCall(request).execute());
}

Then use it consistently across all HTTP call sites:

-Response response = this.prometheusHttpClient.newCall(request).execute();
+Response response = executePrivileged(request, this.prometheusHttpClient);
🤖 Prompt for AI Agents
In
`@direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java`
at line 179, Add a centralized helper in PrometheusClientImpl named something
like executePrivileged(Request request, OkHttpClient client) that wraps
AccessController.doPrivilegedChecked(() -> client.newCall(request).execute())
and throws IOException; then replace every direct call to
prometheusHttpClient.newCall(request).execute() and
alertmanagerHttpClient.newCall(request).execute() across methods queryRange,
query, getLabels, getLabel, getAllMetrics, getSeries, queryExemplars, getAlerts,
getRules, getAlertmanagerAlerts, getAlertmanagerAlertGroups,
getAlertmanagerReceivers, getAlertmanagerSilences, and
createAlertmanagerSilences to call executePrivileged(request,
prometheusHttpClient) or executePrivileged(request, alertmanagerHttpClient)
respectively so the security wrapper is applied consistently.

Copy link
Collaborator

@RyanL1997 RyanL1997 Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the change. The change itself looks good to me, however, I'm also curious the following:

  • among all these components in the above list, why only the Prometheus got impacted?
  • why this just be spotted by now?

cc @cwperks @joshuali925 @lezzago

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

among all these components in the above list, why only the Prometheus got impacted?

the components in the above list are also for prometheus. I just included them in this PR

I don't know why only Prometheus got impacted, or if any other components got impacted

why this just be spotted by now?

This issue does not occur with core + sql, it needs some other plugins that intercepts and filters requests to trigger. We found it when testing the distribution with all plugins installed

@LantaoJin
Copy link
Member

@Swiddis can you help to review this? I remember you had a PR to remove all privilegedcheck wrappers in 3.x branch. Is the current fixing valid?

Swiddis
Swiddis previously approved these changes Feb 2, 2026
Signed-off-by: Joshua Li <joshuali925@gmail.com>
@joshuali925 joshuali925 dismissed stale reviews from Swiddis and themself via 5cd034c February 2, 2026 20:48
@joshuali925
Copy link
Member

seems github CI is down right now https://www.githubstatus.com/

@Swiddis Swiddis merged commit 914de99 into opensearch-project:main Feb 2, 2026
12 of 49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants