Skip to content

Commit

Permalink
Implementing issue #4766 (GCP Secret Manager Variable Resolver plugin)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcasters committed Jan 8, 2025
1 parent f080312 commit f42a1cb
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 7 deletions.
10 changes: 6 additions & 4 deletions core/src/main/java/org/apache/hop/core/variables/Variables.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.hop.core.config.HopConfig;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.exception.HopValueException;
import org.apache.hop.core.logging.LogChannel;
import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.value.ValueMetaBase;
import org.apache.hop.core.util.StringUtil;
Expand Down Expand Up @@ -198,10 +199,11 @@ private String substituteVariableResolvers(String input) {
//
VariableResolver resolver = serializer.load(name);
if (resolver == null) {
// return resolved;
//
throw new HopException(
"Variable Resolver '" + name + "' could not be found in the metadata");
if (LogChannel.GENERAL.isDetailed()) {
LogChannel.GENERAL.logDetailed(
"WARNING: Variable Resolver '" + name + "' could not be found in the metadata");
}
return resolved;
}
String resolvedArgument = resolver.getIResolver().resolve(argument, this);

Expand Down
4 changes: 2 additions & 2 deletions lib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@
<google-api-common.version>2.13.0</google-api-common.version>
<google-api-services-bigquery.version>v2-rev20240229-2.0.0</google-api-services-bigquery.version>
<google-api-services-storage.version>v1-rev20240311-2.0.0</google-api-services-storage.version>
<google-auth-library-credentials.version>1.12.1</google-auth-library-credentials.version>
<google-auth-library-oauth2-http.version>1.12.1</google-auth-library-oauth2-http.version>
<google-auth-library-credentials.version>1.30.0</google-auth-library-credentials.version>
<google-auth-library-oauth2-http.version>1.30.0</google-auth-library-oauth2-http.version>
<google-cloud-storage.version>2.15.0</google-cloud-storage.version>
<google-http-client.version>1.42.3</google-http-client.version>
<google-oauth-client.version>1.34.1</google-oauth-client.version>
Expand Down
11 changes: 11 additions & 0 deletions plugins/engines/beam/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<!-- Force a recent version of these libraries -->
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-credentials</artifactId>
<version>1.30.0</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.30.0</version>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
Expand Down
15 changes: 14 additions & 1 deletion plugins/tech/google/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
-->
<properties>
<commons-vfs2.version>2.9.0</commons-vfs2.version>
<google-analytics.version>0.32.0</google-analytics.version>
<google-analytics.version>0.65.0</google-analytics.version>
<google-api-client.version>2.2.0</google-api-client.version>
<google-api-drive.version>v3-rev20230610-2.0.0</google-api-drive.version>
<google-api-sheets.version>v4-rev20230526-2.0.0</google-api-sheets.version>
Expand All @@ -47,6 +47,13 @@

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.51.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.hop</groupId>
<artifactId>hop-libs</artifactId>
Expand Down Expand Up @@ -96,6 +103,12 @@
<version>${google-api-sqladmin.version}</version>
</dependency>

<!-- Google Secrets Manager dependencies -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-secretmanager</artifactId>
</dependency>

<!-- Google Cloud Storage VFS dependencies -->
<dependency>
<groupId>com.google.cloud</groupId>
Expand Down
10 changes: 10 additions & 0 deletions plugins/tech/google/src/assembly/assembly.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@

<include>com.google.analytics:google-analytics-data:jar</include>
<include>com.google.api.grpc:proto-google-analytics-data-v1beta:jar</include>

<include>com.google.cloud:google-cloud-secretmanager:jar</include>
<include>com.google.api.grpc:proto-google-cloud-secretmanager-v1beta2:jar</include>
<include>com.google.api.grpc:proto-google-iam-v1:jar</include>
<include>com.google.api.grpc:proto-google-cloud-secretmanager-v1:jar</include>
<include>io.grpc:grpc-inprocess:jar</include>
<include>io.grpc:grpc-s2a:jar</include>
<include>io.grpc:grpc-util:jar</include>
<include>com.google.auth:google-auth-library-oauth2-http:jar</include>

</includes>
<outputDirectory>plugins/tech/google/lib</outputDirectory>
</dependencySet>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.hop.core.variables.resolver;

import com.google.cloud.secretmanager.v1.AccessSecretVersionResponse;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings;
import com.google.cloud.secretmanager.v1.SecretVersionName;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.gui.plugin.GuiElementType;
import org.apache.hop.core.gui.plugin.GuiPlugin;
import org.apache.hop.core.gui.plugin.GuiWidgetElement;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.metadata.api.HopMetadataProperty;

@Getter
@Setter
@GuiPlugin
@VariableResolverPlugin(
id = "Variable-Resolver-GoogleSecretManager",
name = "Google Secret Manager Variable Resolver",
description = "Automatically look up values of secrets in Google Secret Manager",
documentationUrl =
"/variables/resolvers/google-secret-manager.html" // TODO: write this documentation
)
public class GooleSecretManagerVariableResolver implements IVariableResolver {

/** The name of the variable that will contain the expression in the pipeline. */
@GuiWidgetElement(
id = "projectId",
order = "0!",
label =
"i18n:org.apache.hop.core.variables.resolver:GooleSecretManagerVariableResolver.label.ProjectId",
type = GuiElementType.TEXT,
parentId = VariableResolver.GUI_PLUGIN_ELEMENT_PARENT_ID)
@HopMetadataProperty
private String projectId;

/** The name of the variable that will contain the expression in the pipeline. */
@GuiWidgetElement(
id = "locationId",
order = "02",
label =
"i18n:org.apache.hop.core.variables.resolver:GooleSecretManagerVariableResolver.label.LocationId",
type = GuiElementType.TEXT,
parentId = VariableResolver.GUI_PLUGIN_ELEMENT_PARENT_ID)
@HopMetadataProperty
private String locationId;

@Override
public void init() {
// Not used at this time. If performance is too bad for the client construction we can still do
// it.
// For now we assume that it's all just using web services anyway.
}

@Override
public String resolve(String secretId, IVariables variables) throws HopException {

if (StringUtils.isEmpty(secretId)) {
return secretId;
}

try {
SecretManagerServiceSettings.Builder settingsBuilder =
SecretManagerServiceSettings.newBuilder();
if (StringUtils.isNotEmpty(locationId)) {
String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId);
settingsBuilder.setEndpoint(apiEndpoint);
}
SecretManagerServiceSettings settings = settingsBuilder.build();

try (SecretManagerServiceClient client = SecretManagerServiceClient.create(settings)) {

String actualLocationId = variables.resolve(locationId);
String actualProjectId = variables.resolve(projectId);

// Get the secret version name.
//
SecretVersionName secretName;
if (StringUtils.isEmpty(actualLocationId)) {
secretName =
SecretVersionName.ofProjectSecretSecretVersionName(
actualProjectId, secretId, "latest");
} else {
secretName =
SecretVersionName.ofProjectLocationSecretSecretVersionName(
actualProjectId, actualLocationId, secretId, "latest");
}

// Get the payload for this version
//
AccessSecretVersionResponse response = client.accessSecretVersion(secretName);

// Create the secret.
return response.getPayload().getData().toStringUtf8();
}
} catch (Exception e) {
throw new HopException(
"Error looking up secret key '" + secretId + "' in Google Secret Manager", e);
}
}

@Override
public void setPluginId() {
// Nothing to set
}

@Override
public String getPluginId() {
return "Variable-Resolver-GoogleSecretManager";
}

@Override
public void setPluginName(String pluginName) {
// Nothing to set
}

@Override
public String getPluginName() {
return "Google Secret Manager Variable Resolver";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
#
GooleSecretManagerVariableResolver.label.ProjectId = Project ID
GooleSecretManagerVariableResolver.label.LocationId = Location ID (optional)

0 comments on commit f42a1cb

Please sign in to comment.