Skip to content

Commit

Permalink
eureka: supports credentials in EUREKA_SERVICE_URL (#3700)
Browse files Browse the repository at this point in the history
This adds support for credentials embedded in `EUREKA_SERVICE_URL` user
info, as is typically done in spring cloud.

Fixes #3697

Signed-off-by: Adrian Cole <adrian@tetrate.io>
  • Loading branch information
codefromthecrypt authored Jan 23, 2024
1 parent 10e0458 commit 41b4a37
Show file tree
Hide file tree
Showing 17 changed files with 318 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class ServerIntegratedBenchmark {

@Test void elasticsearch() throws Exception {
GenericContainer<?> elasticsearch =
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-elasticsearch7:3.0.1"))
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-elasticsearch7:3.0.4"))
.withNetwork(Network.SHARED)
.withNetworkAliases("elasticsearch")
.withLabel("name", "elasticsearch")
Expand All @@ -105,7 +105,7 @@ class ServerIntegratedBenchmark {

@Test void cassandra3() throws Exception {
GenericContainer<?> cassandra =
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-cassandra:3.0.1"))
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-cassandra:3.0.4"))
.withNetwork(Network.SHARED)
.withNetworkAliases("cassandra")
.withLabel("name", "cassandra")
Expand All @@ -119,7 +119,7 @@ class ServerIntegratedBenchmark {

@Test void mysql() throws Exception {
GenericContainer<?> mysql =
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-mysql:3.0.1"))
new GenericContainer<>(parse("ghcr.io/openzipkin/zipkin-mysql:3.0.4"))
.withNetwork(Network.SHARED)
.withNetworkAliases("mysql")
.withLabel("name", "mysql")
Expand Down
16 changes: 13 additions & 3 deletions docker/examples/docker-compose-eureka.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,22 @@ services:
eureka:
image: ghcr.io/openzipkin/zipkin-eureka:${TAG:-latest}
container_name: eureka
# Uncomment to expose the eureka port for testing
# ports:
# - 8761:8761
# Uncomment to require authentication
# environment:
# - EUREKA_USERNAME=username
# - EUREKA_PASSWORD=password
# Uncomment to expose the eureka port for testing
# ports:
# - 8761:8761

zipkin:
extends:
file: docker-compose.yml
service: zipkin
environment:
- EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2
# Uncomment to authenticate eureka
#- EUREKA_SERVICE_URL=http://username:password@eureka:8761/eureka/v2
- EUREKA_HOSTNAME=zipkin
depends_on:
eureka:
Expand All @@ -46,6 +52,8 @@ services:
entrypoint: start-frontend
environment:
- EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2
# Uncomment to authenticate eureka
#- EUREKA_SERVICE_URL=http://username:password@eureka:8761/eureka/v2
ports:
- 8081:8081
depends_on:
Expand All @@ -61,6 +69,8 @@ services:
entrypoint: start-backend
environment:
- EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2
# Uncomment to authenticate eureka
#- EUREKA_SERVICE_URL=http://username:password@eureka:8761/eureka/v2
depends_on:
zipkin:
condition: service_healthy
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ String brokerURL() {
// mostly waiting for https://github.com/testcontainers/testcontainers-java/issues/3537
static final class ActiveMQContainer extends GenericContainer<ActiveMQContainer> {
ActiveMQContainer() {
super(parse("ghcr.io/openzipkin/zipkin-activemq:3.0.1"));
super(parse("ghcr.io/openzipkin/zipkin-activemq:3.0.4"));
withExposedPorts(ACTIVEMQ_PORT);
waitStrategy = Wait.forListeningPorts(ACTIVEMQ_PORT);
withStartupTimeout(Duration.ofSeconds(60));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ KafkaCollector.Builder newCollectorBuilder(String topic, int streams) {
// mostly waiting for https://github.com/testcontainers/testcontainers-java/issues/3537
static final class KafkaContainer extends GenericContainer<KafkaContainer> {
KafkaContainer() {
super(parse("ghcr.io/openzipkin/zipkin-kafka:3.0.1"));
super(parse("ghcr.io/openzipkin/zipkin-kafka:3.0.4"));
waitStrategy = Wait.forHealthcheck();
// 19092 is for connections from the Docker host and needs to be used as a fixed port.
// TODO: someone who knows Kafka well, make ^^ comment better!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ int port() {
// mostly waiting for https://github.com/testcontainers/testcontainers-java/issues/3537
static final class RabbitMQContainer extends GenericContainer<RabbitMQContainer> {
RabbitMQContainer() {
super(parse("ghcr.io/openzipkin/zipkin-rabbitmq:3.0.1"));
super(parse("ghcr.io/openzipkin/zipkin-rabbitmq:3.0.4"));
withExposedPorts(RABBIT_PORT);
waitStrategy = Wait.forLogMessage(".*Server startup complete.*", 1);
withStartupTimeout(Duration.ofSeconds(60));
Expand Down
5 changes: 5 additions & 0 deletions zipkin-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,11 @@ If you are using a containerized environment, you may need to set `EUREKA_HOSTNA
detecting the wrong hostname. For example, if using docker-compose, set `EUREKA_HOSTNAME` to
zipkin's `container_name`.

If your Eureka server requires authentication, adjust `EUREKA_SERVICE_URL` accordingly. If user info
is present, those credentials will be used for BASIC authentication. For example, if the URL is
`https://myuser:mypassword@1.1.3.1/eureka/v2/`, requests to Eureka will authenticate with the user
"myuser" and password "mypassword".

Note: Eureka server registration only includes host and port details. Tracers need to resolve this
to the POST endpoint "/api/v2/spans".

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
*/
package zipkin2.server.internal.eureka;

import com.linecorp.armeria.common.auth.BasicToken;
import com.linecorp.armeria.server.eureka.EurekaUpdatingListener;
import com.linecorp.armeria.server.eureka.EurekaUpdatingListenerBuilder;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
Expand All @@ -30,21 +33,51 @@
*/
@ConfigurationProperties("zipkin.discovery.eureka")
class ZipkinEurekaDiscoveryProperties implements Serializable { // for Spark jobs
/** URL of the Eureka v2 endpoint. e.g. http://eureka:8761/eureka/v2 */
private String serviceUrl;
/**
* URL of the Eureka v2 endpoint. e.g. http://eureka:8761/eureka/v2
*
* <p>Note: When present, {@link URI#getUserInfo() userInfo} credentials will be used for BASIC
* authentication. For example, if the URL is "https://myuser:mypassword@1.1.3.1/eureka/v2/",
* requests to Eureka will authenticate with the user "myuser" and password "mypassword".
*/
private URI serviceUrl;
/** The appName property of this instance of zipkin. */
private String appName;
/** The instanceId property of this instance of zipkin. */
private String instanceId;
/** The hostName property of this instance of zipkin. */
private String hostname;

public String getServiceUrl() {
private BasicToken auth;

public URI getServiceUrl() {
return serviceUrl;
}

public void setServiceUrl(String serviceUrl) {
this.serviceUrl = emptyToNull(serviceUrl);
public void setServiceUrl(URI serviceUrl) {
if (serviceUrl == null || serviceUrl.toString().isEmpty()) {
this.serviceUrl = null;
return;
}
if (serviceUrl.getUserInfo() != null) {
String[] ui = serviceUrl.getUserInfo().split(":");
if (ui.length == 2) {
auth = BasicToken.ofBasic(ui[0], ui[1]);
}
}
this.serviceUrl = stripBaseUrl(serviceUrl);
}

// Strip the credentials and any invalid query or fragment from the URI:
// The Eureka API doesn't define any global query params or fragment.
// See https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
static URI stripBaseUrl(URI serviceUrl) {
try {
return new URI(serviceUrl.getScheme(), null, serviceUrl.getHost(), serviceUrl.getPort(),
serviceUrl.getPath(), null, null);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}

public String getAppName() {
Expand Down Expand Up @@ -72,7 +105,8 @@ public void setHostname(String hostname) {
}

EurekaUpdatingListenerBuilder toBuilder() {
final EurekaUpdatingListenerBuilder result = EurekaUpdatingListener.builder(serviceUrl);
EurekaUpdatingListenerBuilder result = EurekaUpdatingListener.builder(serviceUrl);
if (auth != null) result.auth(auth);
if (appName != null) result.appName(appName);
if (instanceId != null) result.instanceId(instanceId);
if (hostname != null) result.hostname(hostname);
Expand Down
4 changes: 3 additions & 1 deletion zipkin-server/src/main/resources/zipkin-server-shared.yml
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,10 @@ logging:
com.datastax.oss.driver.internal.core.time.Clock: 'WARN'
# Unless it's serious we don't want to know
com.linecorp.armeria: 'WARN'
# # But allow to say it's ready to serve requests
# # But log when ready to serve requests
com.linecorp.armeria.server.Server: 'INFO'
# # and when registered in Eureka
com.linecorp.armeria.server.eureka.EurekaUpdatingListener: 'INFO'
# kafka is quite chatty, so we switch everything off by default
org.apache.kafka: 'OFF'
# # investigate /api/v2/dependencies
Expand Down

This file was deleted.

Loading

0 comments on commit 41b4a37

Please sign in to comment.