Skip to content

Commit

Permalink
HTTPS Support (prometheus#812)
Browse files Browse the repository at this point in the history
* HTTPS support

Signed-off-by: dhoard <doug.hoard@gmail.com>
  • Loading branch information
dhoard committed Jun 20, 2023
1 parent 1d1f1a2 commit cc599ed
Show file tree
Hide file tree
Showing 51 changed files with 1,227 additions and 13 deletions.
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,41 @@ httpServer:
- PBKDF2WithHmacSHA256 default iterations = `210000`
- default keyLength = `128` (bits)

## Generation of `passwordHash`
### Generation of `passwordHash`

- `sha1sum`, `sha256sum`, and `sha512sum` can be used to generate the `passwordHash`
- `openssl` can be used to generate a PBKDF2WithHmac based algorithm `passwordHash`

---

## HTTPS support (optional)

HTTPS support can be configured using either a JKS or PKCS12 format keystore.
- Keystore type is dependent on the Java version

### Configuration

1. Add configuration to your exporter YAML file

```yaml
httpServer:
ssl:
certificate:
alias: localhost
```

2. Add your certificate to the application's Java keystore

The exporter YAML file `alias` should match the certificate alias of certificate you want to use for the HTTPS server.

3. Define the application system properties for the Java keystore

```shell
-Djavax.net.ssl.keyStore=<keystore file> -Djavax.net.ssl.keyStorePassword=<keystore password>
```

---

## Integration Test Suite

The JMX exporter uses the [AntuBLUE Test Engine](https://github.com/antublue/test-engine) and [Testcontainers](https://www.testcontainers.org/) to run integration tests with different Java versions.
Expand Down
2 changes: 1 addition & 1 deletion integration_test_suite/integration_tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<jmx.core.root>../..</jmx.core.root>
<antublue.test.engine.version>4.1.0</antublue.test.engine.version>
<antublue.test.engine.version>4.1.2</antublue.test.engine.version>
<!-- smoke test containers -->
<docker.image.names/>
<!-- all test containers -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class BasicAuthenticationBaseTest extends BaseTest {
protected final String[] TEST_USERNAMES = new String[] { VALID_USERNAME, "prometheus", "bad", "", null };
protected final String[] TEST_PASSWORDS = new String[] { VALID_PASSWORD, "Secret", "bad", "", null };

protected final static PBKDF2WithHmacTestArgumentFilter PBKDF2WITHHMAC_TEST_PARAMETER_FILTER =
protected final static PBKDF2WithHmacTestArgumentFilter PBKDF2WITHHMAC_TEST_ARGUMENT_FILTER =
new PBKDF2WithHmacTestArgumentFilter();

private static class PBKDF2WithHmacTestArgumentFilter implements Predicate<TestArgument> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class BasicAuthenticationPBKDF2WithHmacSHA1Test extends BasicAuthenticati
@TestEngine.ArgumentSupplier
protected static Stream<TestArgument> arguments() {
System.out.println("here");
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_PARAMETER_FILTER);
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_ARGUMENT_FILTER);
}

@TestEngine.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class BasicAuthenticationPBKDF2WithHmacSHA256Test extends BasicAuthentica
*/
@TestEngine.ArgumentSupplier
protected static Stream<TestArgument> arguments() {
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_PARAMETER_FILTER);
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_ARGUMENT_FILTER);
}

@TestEngine.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class BasicAuthenticationPBKDF2WithHmacSHA512Test extends BasicAuthentica
*/
@TestEngine.ArgumentSupplier
protected static Stream<TestArgument> arguments() {
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_PARAMETER_FILTER);
return BasicAuthenticationBaseTest.arguments().filter(PBKDF2WITHHMAC_TEST_ARGUMENT_FILTER);
}

@TestEngine.Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright (C) 2023 The Prometheus jmx_exporter Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.prometheus.jmx.test.http.ssl;

import io.prometheus.jmx.test.Metric;
import io.prometheus.jmx.test.MetricsParser;
import io.prometheus.jmx.test.Mode;
import io.prometheus.jmx.test.TestArgument;
import io.prometheus.jmx.test.credentials.BasicAuthenticationCredentials;
import io.prometheus.jmx.test.http.authentication.BasicAuthenticationBaseTest;
import io.prometheus.jmx.test.support.ContentConsumer;
import io.prometheus.jmx.test.support.HealthyRequest;
import io.prometheus.jmx.test.support.HealthyResponse;
import io.prometheus.jmx.test.support.MetricsRequest;
import io.prometheus.jmx.test.support.MetricsResponse;
import io.prometheus.jmx.test.support.OpenMetricsResponse;
import io.prometheus.jmx.test.support.PrometheusMetricsResponse;
import io.prometheus.jmx.test.support.Response;
import org.antublue.test.engine.api.TestEngine;

import java.util.Collection;
import java.util.stream.Stream;

import static io.prometheus.jmx.test.support.MetricsAssertions.assertThatMetricIn;
import static io.prometheus.jmx.test.support.RequestResponseAssertions.assertThatResponseForRequest;
import static org.assertj.core.api.Assertions.assertThat;

public class SSLAndBasicAuthenticationPBKDF2WithHmacSHA512Test extends BasicAuthenticationBaseTest implements ContentConsumer {


private static final String BASE_URL = "https://localhost";

/**
* Method to get the list of TestArguments
*
* @return the return value
*/
@TestEngine.ArgumentSupplier
protected static Stream<TestArgument> arguments() {
return BasicAuthenticationBaseTest
.arguments()
.filter(PBKDF2WITHHMAC_TEST_ARGUMENT_FILTER)
.filter(testParameter -> !testParameter.dockerImageName().contains("eclipse-temurin:8-alpine"));
}

@TestEngine.Prepare
protected void setBaseUrl() {
testState.baseUrl(BASE_URL);
}

@TestEngine.Test
public void testHealthy() {
for (String username : TEST_USERNAMES) {
for (String password : TEST_PASSWORDS) {
Response expectedHealthyResponse = HealthyResponse.RESULT_401;

if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
expectedHealthyResponse = HealthyResponse.RESULT_200;
}

assertThatResponseForRequest(
new HealthyRequest(testState.httpClient())
.withCredentials(new BasicAuthenticationCredentials(username, password)))
.isSuperset(expectedHealthyResponse);
}
}
}

@TestEngine.Test
public void testMetrics() {
for (String username : TEST_USERNAMES) {
for (String password : TEST_PASSWORDS) {
Response expectedMetricsResponse = MetricsResponse.RESULT_401;

if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
expectedMetricsResponse = MetricsResponse.RESULT_200;
}

Response actualMetricsResponse =
new MetricsRequest(testState.httpClient())
.withCredentials(new BasicAuthenticationCredentials(username, password))
.execute();

assertThat(actualMetricsResponse.isSuperset(expectedMetricsResponse));

if (actualMetricsResponse.code() == 200) {
actualMetricsResponse.dispatch(this);
}
}
}
}

@TestEngine.Test
public void testMetricsOpenMetricsFormat() {
for (String username : TEST_USERNAMES) {
for (String password : TEST_PASSWORDS) {
Response expectedMetricsResponse = OpenMetricsResponse.RESULT_401;

if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
expectedMetricsResponse = OpenMetricsResponse.RESULT_200;
}

Response actualMetricsResponse =
new MetricsRequest(testState.httpClient())
.withCredentials(new BasicAuthenticationCredentials(username, password))
.execute();

assertThat(actualMetricsResponse.isSuperset(expectedMetricsResponse));

if (actualMetricsResponse.code() == 200) {
actualMetricsResponse.dispatch(this);
}
}
}
}

@TestEngine.Test
public void testMetricsPrometheusFormat() {
for (String username : TEST_USERNAMES) {
for (String password : TEST_PASSWORDS) {
Response expectedMetricsResponse = PrometheusMetricsResponse.RESULT_401;

if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
expectedMetricsResponse = PrometheusMetricsResponse.RESULT_200;
}

Response actualMetricsResponse =
new MetricsRequest(testState.httpClient())
.withCredentials(new BasicAuthenticationCredentials(username, password))
.execute();

assertThat(actualMetricsResponse.isSuperset(expectedMetricsResponse));

if (actualMetricsResponse.code() == 200) {
actualMetricsResponse.dispatch(this);
}
}
}
}

@Override
public void accept(String content) {
Collection<Metric> metrics = MetricsParser.parse(content);

String buildInfoName =
testArgument.mode() == Mode.JavaAgent ? "jmx_prometheus_javaagent" : "jmx_prometheus_httpserver";

assertThatMetricIn(metrics)
.withName("jmx_exporter_build_info")
.withLabel("name", buildInfoName)
.exists();

assertThatMetricIn(metrics)
.withName("java_lang_Memory_NonHeapMemoryUsage_committed")
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_1_Disk_Usage_Table_size")
.withLabel("source", "/dev/sda1")
.withValue(7.516192768E9)
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_2_Disk_Usage_Table_pcent")
.withLabel("source", "/dev/sda2")
.withValue(0.8)
.exists();

assertThatMetricIn(metrics)
.withName("jvm_threads_state")
.exists(testArgument.mode() == Mode.JavaAgent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright (C) 2023 The Prometheus jmx_exporter Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.prometheus.jmx.test.http.ssl;

import io.prometheus.jmx.test.BaseTest;
import io.prometheus.jmx.test.Metric;
import io.prometheus.jmx.test.MetricsParser;
import io.prometheus.jmx.test.Mode;
import io.prometheus.jmx.test.TestArgument;
import io.prometheus.jmx.test.support.ContentConsumer;
import io.prometheus.jmx.test.support.HealthyRequest;
import io.prometheus.jmx.test.support.HealthyResponse;
import io.prometheus.jmx.test.support.MetricsRequest;
import io.prometheus.jmx.test.support.MetricsResponse;
import io.prometheus.jmx.test.support.OpenMetricsRequest;
import io.prometheus.jmx.test.support.OpenMetricsResponse;
import io.prometheus.jmx.test.support.PrometheusMetricsRequest;
import io.prometheus.jmx.test.support.PrometheusMetricsResponse;
import org.antublue.test.engine.api.TestEngine;

import java.util.Collection;
import java.util.stream.Stream;

import static io.prometheus.jmx.test.support.MetricsAssertions.assertThatMetricIn;
import static io.prometheus.jmx.test.support.RequestResponseAssertions.assertThatResponseForRequest;

public class SSLWithJKSKeyStoreMultipleCertificatesTest extends BaseTest implements ContentConsumer {

private static final String BASE_URL = "https://localhost";

/**
* Method to get the list of TestArguments
*
* @return the return value
*/
@TestEngine.ArgumentSupplier
protected static Stream<TestArgument> arguments() {
// Filter eclipse-temurin:8 based Alpine images due to missing TLS cipher suites
// https://github.com/adoptium/temurin-build/issues/3002
return BaseTest
.arguments()
.filter(testParameter -> !testParameter.dockerImageName().contains("eclipse-temurin:8-alpine"));
}

@TestEngine.Prepare
protected void setBaseUrl() {
testState.baseUrl(BASE_URL);
}

@TestEngine.Test
public void testHealthy() {
assertThatResponseForRequest(new HealthyRequest(testState.httpClient()))
.isSuperset(HealthyResponse.RESULT_200);
}

@TestEngine.Test
public void testMetrics() {
assertThatResponseForRequest(new MetricsRequest(testState.httpClient()))
.isSuperset(MetricsResponse.RESULT_200)
.dispatch(this);
}

@TestEngine.Test
public void testMetricsOpenMetricsFormat() {
assertThatResponseForRequest(new OpenMetricsRequest(testState.httpClient()))
.isSuperset(OpenMetricsResponse.RESULT_200)
.dispatch(this);
}

@TestEngine.Test
public void testMetricsPrometheusFormat() {
assertThatResponseForRequest(new PrometheusMetricsRequest(testState.httpClient()))
.isSuperset(PrometheusMetricsResponse.RESULT_200)
.dispatch(this);
}

@Override
public void accept(String content) {
Collection<Metric> metrics = MetricsParser.parse(content);

String buildInfoName =
testArgument.mode() == Mode.JavaAgent ? "jmx_prometheus_javaagent" : "jmx_prometheus_httpserver";

assertThatMetricIn(metrics)
.withName("jmx_exporter_build_info")
.withLabel("name", buildInfoName)
.exists();

assertThatMetricIn(metrics)
.withName("java_lang_Memory_NonHeapMemoryUsage_committed")
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_1_Disk_Usage_Table_size")
.withLabel("source", "/dev/sda1")
.withValue(7.516192768E9)
.exists();

assertThatMetricIn(metrics)
.withName("io_prometheus_jmx_tabularData_Server_2_Disk_Usage_Table_pcent")
.withLabel("source", "/dev/sda2")
.withValue(0.8)
.exists();

assertThatMetricIn(metrics)
.withName("jvm_threads_state")
.exists(testArgument.mode() == Mode.JavaAgent);
}
}
Loading

0 comments on commit cc599ed

Please sign in to comment.