-
Notifications
You must be signed in to change notification settings - Fork 0
Javaagent auth extension #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
0090eda
Add gcp-auth-extension for OTLP exporters
psx95 34ef8b8
Add README for auth extension
psx95 867147e
Udpate build.gradle
psx95 aa7e503
Add end-to-end smoketest
psx95 b767d98
Set header suppliers to enable dynamic token refresh
psx95 efd47ef
Remove hardcoded OTLP endpoint from extension
psx95 00d4dab
Enhance Integration Test - WIP
psx95 c6049e3
Fix integration test
psx95 eef7cb7
Remove the use of fixed ports
psx95 aeda53f
Do not enable GCP resource detector by default
psx95 58d4bad
Provide methods to support fallback value for config options
psx95 250b108
Update README to reflect effect of fallback option
psx95 122c7d7
Add unit test for extension
psx95 dacebad
Simplify the integration smoke test
psx95 2cd373e
Test cleanup
psx95 a267bbb
Make integration tests environment agnostic
psx95 6036833
Test code cleanup and doc fix
psx95 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Google Cloud Authentication Extension for OpenTelemetry Java Agent | ||
|
|
||
| The Google Cloud Auth Extension allows the users to export telemetry from their applications auto-instrumented using the OpenTelemetry Java Agent to Google Cloud using the built-in OTLP exporters. | ||
| The extension takes care of the necessary configuration required to authenticate to GCP to successfully export telemetry. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### Ensure the presence of Google Cloud Credentials on your machine/environment | ||
|
|
||
| ```shell | ||
| gcloud auth application-default login | ||
| ``` | ||
| Executing this command will save your application credentials to default path which will depend on the type of machine - | ||
| - Linux, macOS: `$HOME/.config/gcloud/application_default_credentials.json` | ||
| - Windows: `%APPDATA%\gcloud\application_default_credentials.json` | ||
|
|
||
| **NOTE: This method of authentication is not recommended for production environments.** | ||
|
|
||
| Next, export the credentials to `GOOGLE_APPLICATION_CREDENTIALS` environment variable - | ||
|
|
||
| For Linux & MacOS: | ||
| ```shell | ||
| export GOOGLE_APPLICATION_CREDENTIALS=$HOME/.config/gcloud/application_default_credentials.json | ||
| ``` | ||
|
|
||
| These credentials are built-in running in a Google App Engine, Google Cloud Shell or Google Compute Engine environment. | ||
|
|
||
| ### Configuring the extension | ||
|
|
||
| The extension can be configured either by environment variables or system properties. | ||
|
|
||
| Here is a list of configurable options for the extension: | ||
|
|
||
| - `GOOGLE_CLOUD_PROJECT`: Environment variable that represents the Google Cloud Project ID to which the telemetry needs to be exported. | ||
| - Can also be configured using `google.cloud.project` system property. | ||
| - If this option is not configured, the extension would infer GCP Project ID from the application default credentials. For more information on application default credentials, see [here](https://cloud.google.com/docs/authentication/application-default-credentials). | ||
|
|
||
| ## Usage | ||
|
|
||
| The OpenTelemetry Java Agent Extension can be easily added to any Java application by modifying the startup command to the application. | ||
| For more information on Extensions, see the [documentation here](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/examples/extension/README.md). | ||
|
|
||
| Below is a snippet showing how to add the extension to a Java application using the Gradle build system. | ||
|
|
||
| ```gradle | ||
| // Specify OpenTelemetry Autoinstrumentation Java Agent Path. | ||
| def otelAgentPath = <OpenTelemetry Java Agent location> | ||
| // Specify the path for Google Cloud Authentication Extension for the Java Agent. | ||
| def extensionPath = <Google Cloud Authentication Extension location> | ||
| def googleCloudProjectId = <Your Google Cloud Project ID> | ||
| def googleOtlpEndpoint = <Google Cloud OTLP endpoint> | ||
|
|
||
| application { | ||
| ... | ||
| "-javaagent:${otelAgentPath}", | ||
| "-Dotel.javaagent.extensions=${extensionPath}", | ||
| // Configure the GCP Auth extension using system properties. | ||
| // This can also be configured using environment variables. | ||
| "-Dgoogle.cloud.project=${googleCloudProjectId}", | ||
| // Configure auto instrumentation. | ||
| "-Dotel.exporter.otlp.traces.endpoint=${googleOtlpEndpoint}", | ||
| '-Dotel.java.global-autoconfigure.enabled=true', | ||
| // Optionally enable the built-in GCP resource detector | ||
| '-Dotel.resource.providers.gcp.enabled=true' | ||
| '-Dotel.traces.exporter=otlp', | ||
| '-Dotel.metrics.exporter=logging', | ||
| } | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /* | ||
| * Copyright 2024 Google LLC | ||
| * | ||
| * 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. | ||
| */ | ||
| plugins { | ||
| id 'java' | ||
| id 'java-library' | ||
| id 'com.github.johnrengelman.shadow' | ||
| id 'org.springframework.boot' version '2.7.18' | ||
| } | ||
|
|
||
| description = 'OpenTelemetry Java Agent Extension that enables authentication support for OTLP exporters' | ||
|
|
||
| tasks { | ||
| assemble.dependsOn(shadowJar) | ||
| } | ||
|
|
||
| shadowJar { | ||
| archiveFileName.set("gcp-auth-extension.jar") | ||
| } | ||
|
|
||
| jar { | ||
| // Disable standard jar | ||
| enabled = false | ||
| } | ||
|
|
||
| // Custom configurations used to facilitate running the integration test | ||
| configurations { | ||
| agent | ||
| } | ||
|
|
||
| dependencies { | ||
| annotationProcessor(libraries.auto_service) | ||
| // We use `compileOnly` dependency because during runtime all necessary classes are provided by javaagent itself. | ||
| compileOnly(libraries.auto_service_annotations) | ||
| compileOnly(libraries.opentelemetry_api) | ||
| compileOnly(libraries.opentelemetry_otlp_exporter) | ||
| compileOnly(libraries.opentelemetry_sdk_autoconf) | ||
| compileOnly(libraries.opentelemetry_autoconfigure_spi) | ||
|
|
||
| // Only dependencies added to `implementation` configuration will be picked up by Shadow plugin | ||
| // and added to the resulting jar for our extension's distribution. | ||
| implementation(libraries.google_auth) | ||
|
|
||
| // test dependencies | ||
| testRuntimeOnly(testLibraries.junit5_runtime) | ||
| testImplementation(testLibraries.junit5) | ||
| testImplementation(libraries.opentelemetry_api) | ||
| testImplementation(libraries.opentelemetry_otlp_exporter) | ||
| testImplementation(testLibraries.opentelemetry_sdk_testing) | ||
| testImplementation(testLibraries.mockito) | ||
| testImplementation(testLibraries.mockito_jupiter) | ||
| testImplementation(libraries.opentelemetry_sdk_autoconf) | ||
| // for implementing smoke test application | ||
| testImplementation(libraries.spring_boot_starter_web) | ||
| testImplementation(testLibraries.spring_boot_starter_test) | ||
| testImplementation("org.mock-server:mockserver-netty:5.15.0") | ||
| testImplementation("org.awaitility:awaitility:4.2.2") | ||
| testImplementation("io.opentelemetry.proto:opentelemetry-proto:1.4.0-alpha") | ||
| testImplementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.8.0") | ||
| // OTel instrumentation used in the sample app to facilitate integration testing | ||
| agent agentLibraries.agent | ||
| } | ||
|
|
||
| // task to copy and rename the Java Auto-Instrumentation Agent into 'libs' folder | ||
| tasks.register('copyAgent', Copy) { | ||
| into layout.buildDirectory.dir("libs") | ||
| from configurations.agent { | ||
| rename "opentelemetry-javaagent(.*).jar", "otel-agent.jar" | ||
| } | ||
| } | ||
|
|
||
| def builtLibsDir = layout.buildDirectory.dir("libs").get().toString() | ||
| def javaAgentJarPath = builtLibsDir + "/otel-agent.jar" | ||
| def authExtensionJarPath = builtLibsDir + "/gcp-auth-extension.jar" | ||
|
|
||
| // this task is run as part of the integration test so it is necessary to | ||
| // configure this | ||
| tasks.named('bootJar').configure { | ||
| dependsOn('copyAgent') | ||
| } | ||
|
|
||
| build { | ||
| // disable bootJar in build since it only runs as part of test | ||
| tasks.named('bootJar').configure { | ||
| enabled = false | ||
| } | ||
| } | ||
|
|
||
| test { | ||
| dependsOn 'shadowJar' | ||
| dependsOn 'copyAgent' | ||
| useJUnitPlatform() | ||
|
|
||
| def fakeCredsFilePath = project.file("src/test/resources/fakecreds.json").getAbsolutePath() | ||
|
|
||
| environment("GOOGLE_CLOUD_QUOTA_PROJECT", "quota-project-id") | ||
| environment("GOOGLE_APPLICATION_CREDENTIALS", fakeCredsFilePath.toString()) | ||
| jvmArgs = [ | ||
| "-javaagent:${javaAgentJarPath}", | ||
| "-Dotel.javaagent.extensions=${authExtensionJarPath}", | ||
| "-Dgoogle.cloud.project=my-gcp-project", | ||
| "-Dotel.java.global-autoconfigure.enabled=true", | ||
| "-Dotel.exporter.otlp.endpoint=http://localhost:4318", | ||
| "-Dotel.resource.providers.gcp.enabled=true", | ||
| "-Dotel.traces.exporter=otlp", | ||
| "-Dotel.bsp.schedule.delay=2000", | ||
| "-Dotel.metrics.exporter=none", | ||
| "-Dotel.logs.exporter=none", | ||
| "-Dotel.exporter.otlp.protocol=http/protobuf", | ||
| "-Dmockserver.logLevel=off" | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| release.enabled=false |
108 changes: 108 additions & 0 deletions
108
...-auth/src/main/java/com/google/cloud/opentelemetry/extension/auth/ConfigurableOption.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| /* | ||
| * Copyright 2024 Google LLC | ||
| * | ||
| * 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 com.google.cloud.opentelemetry.extension.auth; | ||
|
|
||
| import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; | ||
| import java.util.Locale; | ||
| import java.util.function.Supplier; | ||
|
|
||
| /** | ||
| * An enum representing configurable options for a GCP Authentication Extension. Each option has a | ||
| * user-readable name and can be configured using environment variables or system properties. | ||
| */ | ||
| public enum ConfigurableOption { | ||
| /** | ||
| * Represents the Google Cloud Project ID option. Can be configured using the environment variable | ||
| * `GOOGLE_CLOUD_PROJECT` or the system property `google.cloud.project`. | ||
| */ | ||
| GOOGLE_CLOUD_PROJECT("Google Cloud Project ID"); | ||
|
|
||
| private static final String OPTION_NOT_CONFIGURED_MSG = | ||
| "GCP Authentication Extension not configured properly: %s not configured. Configure it by exporting environment variable %s or system property %s"; | ||
|
|
||
| private final String userReadableName; | ||
| private final String environmentVariableName; | ||
| private final String systemPropertyName; | ||
|
|
||
| ConfigurableOption(String userReadableName) { | ||
| this.userReadableName = userReadableName; | ||
| this.environmentVariableName = this.name(); | ||
| this.systemPropertyName = | ||
| this.environmentVariableName.toLowerCase(Locale.ENGLISH).replace('_', '.'); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the environment variable name associated with this option. | ||
| * | ||
| * @return the environment variable name (e.g., GOOGLE_CLOUD_PROJECT) | ||
| */ | ||
| String getEnvironmentVariable() { | ||
| return this.environmentVariableName; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the system property name associated with this option. | ||
| * | ||
| * @return the system property name (e.g., google.cloud.project) | ||
| */ | ||
| String getSystemProperty() { | ||
| return this.systemPropertyName; | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves the configured value for this option. This method checks the environment variable | ||
| * first and then the system property. | ||
| * | ||
| * @return The configured value as a string, or throws an exception if not configured. | ||
| * @throws ConfigurationException if neither the environment variable nor the system property is | ||
| * set. | ||
| */ | ||
| String getConfiguredValue() throws ConfigurationException { | ||
psx95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| String envVar = System.getenv(this.getEnvironmentVariable()); | ||
| String sysProp = System.getProperty(this.getSystemProperty()); | ||
|
|
||
| if (envVar != null && !envVar.isEmpty()) { | ||
| return envVar; | ||
| } else if (sysProp != null && !sysProp.isEmpty()) { | ||
| return sysProp; | ||
| } else { | ||
| throw new ConfigurationException( | ||
| String.format( | ||
| OPTION_NOT_CONFIGURED_MSG, | ||
| this.userReadableName, | ||
| this.getEnvironmentVariable(), | ||
| this.getSystemProperty())); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves the value for this option, prioritizing environment variables and system properties. | ||
| * If neither an environment variable nor a system property is set for this option, the provided | ||
| * fallback function is used to determine the value. | ||
| * | ||
| * @param fallback A {@link Supplier} that provides the default value for the option when it is | ||
| * not explicitly configured via an environment variable or system property. | ||
| * @return The configured value for the option, obtained from the environment variable, system | ||
| * property, or the fallback function, in that order of precedence. | ||
| */ | ||
| String getConfiguredValueWithFallback(Supplier<String> fallback) { | ||
| try { | ||
| return this.getConfiguredValue(); | ||
| } catch (ConfigurationException e) { | ||
| return fallback.get(); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do users typically configure the agent through gradle?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the typical use case, however in this case, the command line args would look extremely similar.
The integration test showcases the agent configuration directly on command line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use cases vary as broadly as the ecosystem does.
I think it's good to include this here.