This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 7d487548dc4 CAMEL-21905 - Camel-IBM-Secrets-Manager: Implement secret refresh by using IBM Event Streams as destination of notifications (#17626) 7d487548dc4 is described below commit 7d487548dc4a1341a6e8080df3767860bbd12b01 Author: Andrea Cosentino <anco...@gmail.com> AuthorDate: Mon Mar 31 15:09:00 2025 +0200 CAMEL-21905 - Camel-IBM-Secrets-Manager: Implement secret refresh by using IBM Event Streams as destination of notifications (#17626) Signed-off-by: Andrea Cosentino <anco...@gmail.com> --- .../main/camel-main-configuration-metadata.json | 8 + components/camel-ibm-secrets-manager/pom.xml | 12 + .../apache/camel/periodic-task/ibm-secret-refresh | 2 + .../vault/IBMEventStreamReloadTriggerTask.java | 268 +++++++++++++++++++++ .../vault/IBMSecretsManagerVaultConfiguration.java | 105 ++++++++ ...SecretsManagerVaultConfigurationConfigurer.java | 45 ++++ ...agerVaultConfigurationPropertiesConfigurer.java | 53 ++++ .../camel-main-configuration-metadata.json | 8 + core/camel-main/src/main/docs/main.adoc | 10 +- .../camel/main/DefaultConfigurationConfigurer.java | 18 ++ 10 files changed, 528 insertions(+), 1 deletion(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index b2d72d5918c..215b956e8ae 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -392,6 +392,14 @@ { "name": "camel.vault.hashicorp.port", "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.hashicorp.scheme", "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.hashicorp.token", "description": "Token to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamBootstrapServers", "description": "Specify the Bootstrap servers for consuming notification on IBM Event Stream. Multiple servers can be separated by comma.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamGroupId", "description": "Specify the Consumer Group ID to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamPassword", "description": "Specify the password to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamTopic", "description": "Specify the topic name for consuming notification on IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamUsername", "description": "Specify the username to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.refreshEnabled", "description": "Whether to automatically reload Camel upon secrets being updated in IBM.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, + { "name": "camel.vault.ibm.refreshPeriod", "description": "The period (millis) between checking AWS for updated secrets.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 30000 }, + { "name": "camel.vault.ibm.secrets", "description": "Specify the secret names (or pattern) to check for updates. Multiple secrets can be separated by comma.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.ibm.serviceUrl", "description": "Service URL to access IBM Secrets Manager vault", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.ibm.token", "description": "Token to access IBM Secrets Manager vault", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.kubernetes.refreshEnabled", "description": "Whether to automatically reload Camel upon secrets being updated in Kubernetes Cluster.", "sourceType": "org.apache.camel.vault.KubernetesVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/components/camel-ibm-secrets-manager/pom.xml b/components/camel-ibm-secrets-manager/pom.xml index d4d31bbb0c3..bf48c8c7262 100644 --- a/components/camel-ibm-secrets-manager/pom.xml +++ b/components/camel-ibm-secrets-manager/pom.xml @@ -48,6 +48,18 @@ <artifactId>secrets-manager</artifactId> <version>${ibm-secrets-manager-version}</version> </dependency> + + <!-- kafka java client --> + <dependency> + <groupId>org.apache.kafka</groupId> + <artifactId>kafka-clients</artifactId> + <version>${kafka-version}</version> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> <!-- for testing --> <dependency> diff --git a/components/camel-ibm-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/ibm-secret-refresh b/components/camel-ibm-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/ibm-secret-refresh new file mode 100644 index 00000000000..3633c451afc --- /dev/null +++ b/components/camel-ibm-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/ibm-secret-refresh @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.ibm.secrets.manager.vault.IBMEventStreamReloadTriggerTask diff --git a/components/camel-ibm-secrets-manager/src/main/java/org/apache/camel/component/ibm/secrets/manager/vault/IBMEventStreamReloadTriggerTask.java b/components/camel-ibm-secrets-manager/src/main/java/org/apache/camel/component/ibm/secrets/manager/vault/IBMEventStreamReloadTriggerTask.java new file mode 100644 index 00000000000..21b010c2626 --- /dev/null +++ b/components/camel-ibm-secrets-manager/src/main/java/org/apache/camel/component/ibm/secrets/manager/vault/IBMEventStreamReloadTriggerTask.java @@ -0,0 +1,268 @@ +/* + * 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.camel.component.ibm.secrets.manager.vault; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.SecretsManager; +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.component.ibm.secrets.manager.IBMSecretsManagerPropertiesFunction; +import org.apache.camel.spi.ContextReloadStrategy; +import org.apache.camel.spi.PropertiesComponent; +import org.apache.camel.spi.PropertiesFunction; +import org.apache.camel.spi.annotations.PeriodicTask; +import org.apache.camel.support.PatternHelper; +import org.apache.camel.support.service.ServiceSupport; +import org.apache.camel.util.ObjectHelper; +import org.apache.camel.vault.IBMSecretsManagerVaultConfiguration; +import org.apache.kafka.clients.CommonClientConfigs; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.config.SaslConfigs; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Period task which checks if IBM secrets has been updated and can trigger Camel to be reloaded. + */ +@PeriodicTask("ibm-secret-refresh") +public class IBMEventStreamReloadTriggerTask extends ServiceSupport implements CamelContextAware, Runnable { + + private static final String CAMEL_VAULT_IBM_EVENTSTREAM_BOOTSTRAP_SERVERS_ENV + = "CAMEL_VAULT_IBM_EVENTSTREAM_BOOTSTRAP_SERVERS"; + private static final String CAMEL_VAULT_IBM_EVENTSTREAM_TOPIC_ENV = "CAMEL_VAULT_IBM_EVENTSTREAM_TOPIC"; + private static final String CAMEL_VAULT_IBM_EVENTSTREAM_USERNAME_ENV = "CAMEL_VAULT_IBM_EVENTSTREAM_USERNAME"; + private static final String CAMEL_VAULT_IBM_EVENTSTREAM_PASSWORD_ENV = "CAMEL_VAULT_IBM_EVENTSTREAM_PASSWORD"; + private static final String CAMEL_VAULT_IBM_EVENTSTREAM_CONSUMER_GROUPID_ENV + = "CAMEL_VAULT_IBM_EVENTSTREAM_CONSUMER_GROUP_ID"; + + private CamelContext camelContext; + + private SecretsManager client; + private String secretGroup; + private boolean reloadEnabled = true; + private String secrets; + private IBMSecretsManagerPropertiesFunction propertiesFunction; + private volatile Instant lastTime; + private volatile Instant lastCheckTime; + private volatile Instant lastReloadTime; + private final Map<String, Instant> updates = new HashMap<>(); + KafkaConsumer<String, String> kafkaConsumer; + private static final String IBM_SECRETS_MANAGER_SECRET_ROTATED_EVENT = "secret_rotated"; + + private static final Logger LOG = LoggerFactory.getLogger(IBMEventStreamReloadTriggerTask.class); + + @Override + protected void doStart() throws Exception { + super.doStart(); + + // auto-detect secrets in-use + PropertiesComponent pc = camelContext.getPropertiesComponent(); + PropertiesFunction pf = pc.getPropertiesFunction("ibm"); + if (pf instanceof IBMSecretsManagerPropertiesFunction) { + propertiesFunction = (IBMSecretsManagerPropertiesFunction) pf; + LOG.debug("Auto-detecting secrets from properties-function: {}", pf.getName()); + } + // specific secrets + secrets = camelContext.getVaultConfiguration().ibmSecretsManager().getSecrets(); + if (ObjectHelper.isEmpty(secrets) && propertiesFunction == null) { + throw new IllegalArgumentException("Secrets must be configured on IBM vault configuration"); + } + + String bootstrapServers = System.getenv(CAMEL_VAULT_IBM_EVENTSTREAM_BOOTSTRAP_SERVERS_ENV); + String groupId = System.getenv(CAMEL_VAULT_IBM_EVENTSTREAM_CONSUMER_GROUPID_ENV); + String topic = System.getenv(CAMEL_VAULT_IBM_EVENTSTREAM_TOPIC_ENV); + String username = System.getenv(CAMEL_VAULT_IBM_EVENTSTREAM_USERNAME_ENV); + String password = System.getenv(CAMEL_VAULT_IBM_EVENTSTREAM_PASSWORD_ENV); + + if (ObjectHelper.isEmpty(bootstrapServers) && ObjectHelper.isEmpty(groupId) && ObjectHelper.isEmpty(topic) + && ObjectHelper.isEmpty(password)) { + IBMSecretsManagerVaultConfiguration ibmVaultConfiguration + = getCamelContext().getVaultConfiguration().ibmSecretsManager(); + if (ObjectHelper.isNotEmpty(ibmVaultConfiguration)) { + bootstrapServers = ibmVaultConfiguration.getEventStreamBootstrapServers(); + groupId = ibmVaultConfiguration.getEventStreamGroupId(); + topic = ibmVaultConfiguration.getEventStreamTopic(); + if (ObjectHelper.isEmpty(username)) { + if (ObjectHelper.isNotEmpty(ibmVaultConfiguration.getEventStreamUsername())) { + username = ibmVaultConfiguration.getEventStreamUsername(); + } else { + username = "token"; + } + } + password = ibmVaultConfiguration.getEventStreamPassword(); + } + } else { + throw new RuntimeCamelException( + "Using the IBM Secrets Refresh Task requires setting IBM Event Stream bootstrap servers, topic, groupId, username and password as application properties or environment variables"); + } + + // create consumer configs + Map<String, Object> configs = new HashMap<>(); + configs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + configs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configs.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + configs.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest"); + configs.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); + configs.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL"); + configs.put(SaslConfigs.SASL_MECHANISM, "PLAIN"); + configs.put(SaslConfigs.SASL_JAAS_CONFIG, + "org.apache.kafka.common.security.plain.PlainLoginModule required username=" + username + " password=" + + password + ";"); + + // create consumer + Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); + kafkaConsumer = new KafkaConsumer<String, String>(configs); + + kafkaConsumer.subscribe(Arrays.asList(topic)); + } + + @Override + public void run() { + + lastCheckTime = Instant.now(); + boolean triggerReloading = false; + ObjectMapper mapper = new ObjectMapper(); + + while (true) { + ConsumerRecords<String, String> records = kafkaConsumer.poll(Duration.ofMillis(100)); + + for (ConsumerRecord<String, String> record : records) { + JsonNode recordJson; + String secretType; + try { + recordJson = mapper.readTree(record.value()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + JsonNode payload = recordJson.get("data"); + if (payload != null) { + secretType = payload.get("event_type").asText(); + if (secretType != null) { + if (secretType.equalsIgnoreCase(IBM_SECRETS_MANAGER_SECRET_ROTATED_EVENT)) { + ArrayNode secretsRotated = (ArrayNode) payload.get("secrets"); + for (JsonNode secret : secretsRotated) { + if (secret != null) { + String name = secret.get("secret_name").asText(); + if (matchSecret(name)) { + updates.put(name, Instant.parse(secret.get("event_time").asText())); + if (isReloadEnabled()) { + LOG.info("Update for IBM secret: {} detected, triggering CamelContext reload", + name); + triggerReloading = true; + } + if (triggerReloading) { + ContextReloadStrategy reload = camelContext.hasService(ContextReloadStrategy.class); + if (reload != null) { + // trigger reload + lastReloadTime = Instant.now(); + reload.onReload(this); + } + triggerReloading = false; + } + break; + } + } + } + } + } + } + + } + } + + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + /** + * Whether Camel should be reloaded on IBM secret updated + */ + public void setReloadEnabled(boolean reloadEnabled) { + this.reloadEnabled = reloadEnabled; + } + + /** + * A map of the updated secrets with the latest updated time. + */ + public Map<String, Instant> getUpdates() { + return Collections.unmodifiableMap(updates); + } + + /** + * Last time this task checked IBM for updated secrets. + */ + public Instant getLastCheckTime() { + return lastCheckTime; + } + + /** + * Last time IBM secrets update triggered reload. + */ + public Instant getLastReloadTime() { + return lastReloadTime; + } + + public boolean isReloadEnabled() { + return reloadEnabled; + } + + protected boolean matchSecret(String name) { + Set<String> set = new HashSet<>(); + if (secrets != null) { + Collections.addAll(set, secrets.split(",")); + } + if (propertiesFunction != null) { + set.addAll(propertiesFunction.getSecrets()); + } + + for (String part : set) { + boolean result = name.contains(part) || PatternHelper.matchPattern(name, part); + LOG.trace("Matching secret id: {}={} -> {}", name, part, result); + if (result) { + return true; + } + } + + return false; + } +} diff --git a/core/camel-api/src/main/java/org/apache/camel/vault/IBMSecretsManagerVaultConfiguration.java b/core/camel-api/src/main/java/org/apache/camel/vault/IBMSecretsManagerVaultConfiguration.java index d6272066732..3a8c326f5a3 100644 --- a/core/camel-api/src/main/java/org/apache/camel/vault/IBMSecretsManagerVaultConfiguration.java +++ b/core/camel-api/src/main/java/org/apache/camel/vault/IBMSecretsManagerVaultConfiguration.java @@ -27,6 +27,22 @@ public class IBMSecretsManagerVaultConfiguration extends VaultConfiguration { private String token; @Metadata private String serviceUrl; + @Metadata + private boolean refreshEnabled; + @Metadata(defaultValue = "30000") + private long refreshPeriod = 30000; + @Metadata + private String secrets; + @Metadata + private String eventStreamTopic; + @Metadata + private String eventStreamBootstrapServers; + @Metadata + private String eventStreamUsername; + @Metadata + private String eventStreamPassword; + @Metadata + private String eventStreamGroupId; public String getToken() { return token; @@ -49,4 +65,93 @@ public class IBMSecretsManagerVaultConfiguration extends VaultConfiguration { public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } + + public boolean isRefreshEnabled() { + return refreshEnabled; + } + + /** + * Whether to automatically reload Camel upon secrets being updated in IBM. + */ + public void setRefreshEnabled(boolean refreshEnabled) { + this.refreshEnabled = refreshEnabled; + } + + public long getRefreshPeriod() { + return refreshPeriod; + } + + /** + * The period (millis) between checking AWS for updated secrets. + */ + public void setRefreshPeriod(long refreshPeriod) { + this.refreshPeriod = refreshPeriod; + } + + public String getSecrets() { + return secrets; + } + + /** + * Specify the secret names (or pattern) to check for updates. Multiple secrets can be separated by comma. + */ + public void setSecrets(String secrets) { + this.secrets = secrets; + } + + public String getEventStreamTopic() { + return eventStreamTopic; + } + + /** + * Specify the topic name for consuming notification on IBM Event Stream + */ + public void setEventStreamTopic(String eventStreamTopic) { + this.eventStreamTopic = eventStreamTopic; + } + + public String getEventStreamBootstrapServers() { + return eventStreamBootstrapServers; + } + + /** + * Specify the Bootstrap servers for consuming notification on IBM Event Stream. Multiple servers can be separated + * by comma. + */ + public void setEventStreamBootstrapServers(String eventStreamBootstrapServers) { + this.eventStreamBootstrapServers = eventStreamBootstrapServers; + } + + public String getEventStreamUsername() { + return eventStreamUsername; + } + + /** + * Specify the username to access IBM Event Stream + */ + public void setEventStreamUsername(String eventStreamUsername) { + this.eventStreamUsername = eventStreamUsername; + } + + public String getEventStreamPassword() { + return eventStreamPassword; + } + + /** + * Specify the password to access IBM Event Stream + */ + public void setEventStreamPassword(String eventStreamPassword) { + this.eventStreamPassword = eventStreamPassword; + } + + public String getEventStreamGroupId() { + return eventStreamGroupId; + } + + /** + * Specify the Consumer Group ID to access IBM Event Stream + */ + public void setEventStreamGroupId(String eventStreamGroupId) { + this.eventStreamGroupId = eventStreamGroupId; + } } diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationConfigurer.java index 823622dd7fe..7512a316ab2 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationConfigurer.java @@ -27,6 +27,16 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "awsVaultConfiguration": target.setAwsVaultConfiguration(property(camelContext, org.apache.camel.vault.AwsVaultConfiguration.class, value)); return true; case "azurevaultconfiguration": case "azureVaultConfiguration": target.setAzureVaultConfiguration(property(camelContext, org.apache.camel.vault.AzureVaultConfiguration.class, value)); return true; + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": target.setEventStreamBootstrapServers(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamgroupid": + case "eventStreamGroupId": target.setEventStreamGroupId(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreampassword": + case "eventStreamPassword": target.setEventStreamPassword(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamtopic": + case "eventStreamTopic": target.setEventStreamTopic(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamusername": + case "eventStreamUsername": target.setEventStreamUsername(property(camelContext, java.lang.String.class, value)); return true; case "gcpvaultconfiguration": case "gcpVaultConfiguration": target.setGcpVaultConfiguration(property(camelContext, org.apache.camel.vault.GcpVaultConfiguration.class, value)); return true; case "hashicorpvaultconfiguration": @@ -37,6 +47,11 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "kubernetesConfigMapVaultConfiguration": target.setKubernetesConfigMapVaultConfiguration(property(camelContext, org.apache.camel.vault.KubernetesConfigMapVaultConfiguration.class, value)); return true; case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": target.setKubernetesVaultConfiguration(property(camelContext, org.apache.camel.vault.KubernetesVaultConfiguration.class, value)); return true; + case "refreshenabled": + case "refreshEnabled": target.setRefreshEnabled(property(camelContext, boolean.class, value)); return true; + case "refreshperiod": + case "refreshPeriod": target.setRefreshPeriod(property(camelContext, long.class, value)); return true; + case "secrets": target.setSecrets(property(camelContext, java.lang.String.class, value)); return true; case "serviceurl": case "serviceUrl": target.setServiceUrl(property(camelContext, java.lang.String.class, value)); return true; case "token": target.setToken(property(camelContext, java.lang.String.class, value)); return true; @@ -51,6 +66,16 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "awsVaultConfiguration": return org.apache.camel.vault.AwsVaultConfiguration.class; case "azurevaultconfiguration": case "azureVaultConfiguration": return org.apache.camel.vault.AzureVaultConfiguration.class; + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": return java.lang.String.class; + case "eventstreamgroupid": + case "eventStreamGroupId": return java.lang.String.class; + case "eventstreampassword": + case "eventStreamPassword": return java.lang.String.class; + case "eventstreamtopic": + case "eventStreamTopic": return java.lang.String.class; + case "eventstreamusername": + case "eventStreamUsername": return java.lang.String.class; case "gcpvaultconfiguration": case "gcpVaultConfiguration": return org.apache.camel.vault.GcpVaultConfiguration.class; case "hashicorpvaultconfiguration": @@ -61,6 +86,11 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "kubernetesConfigMapVaultConfiguration": return org.apache.camel.vault.KubernetesConfigMapVaultConfiguration.class; case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": return org.apache.camel.vault.KubernetesVaultConfiguration.class; + case "refreshenabled": + case "refreshEnabled": return boolean.class; + case "refreshperiod": + case "refreshPeriod": return long.class; + case "secrets": return java.lang.String.class; case "serviceurl": case "serviceUrl": return java.lang.String.class; case "token": return java.lang.String.class; @@ -76,6 +106,16 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "awsVaultConfiguration": return target.getAwsVaultConfiguration(); case "azurevaultconfiguration": case "azureVaultConfiguration": return target.getAzureVaultConfiguration(); + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": return target.getEventStreamBootstrapServers(); + case "eventstreamgroupid": + case "eventStreamGroupId": return target.getEventStreamGroupId(); + case "eventstreampassword": + case "eventStreamPassword": return target.getEventStreamPassword(); + case "eventstreamtopic": + case "eventStreamTopic": return target.getEventStreamTopic(); + case "eventstreamusername": + case "eventStreamUsername": return target.getEventStreamUsername(); case "gcpvaultconfiguration": case "gcpVaultConfiguration": return target.getGcpVaultConfiguration(); case "hashicorpvaultconfiguration": @@ -86,6 +126,11 @@ public class IBMSecretsManagerVaultConfigurationConfigurer extends org.apache.ca case "kubernetesConfigMapVaultConfiguration": return target.getKubernetesConfigMapVaultConfiguration(); case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": return target.getKubernetesVaultConfiguration(); + case "refreshenabled": + case "refreshEnabled": return target.isRefreshEnabled(); + case "refreshperiod": + case "refreshPeriod": return target.getRefreshPeriod(); + case "secrets": return target.getSecrets(); case "serviceurl": case "serviceUrl": return target.getServiceUrl(); case "token": return target.getToken(); diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationPropertiesConfigurer.java index 9a4c1ea3d2d..0ed7ff077cc 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/IBMSecretsManagerVaultConfigurationPropertiesConfigurer.java @@ -24,11 +24,19 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org Map<String, Object> map = new CaseInsensitiveMap(); map.put("AwsVaultConfiguration", org.apache.camel.vault.AwsVaultConfiguration.class); map.put("AzureVaultConfiguration", org.apache.camel.vault.AzureVaultConfiguration.class); + map.put("EventStreamBootstrapServers", java.lang.String.class); + map.put("EventStreamGroupId", java.lang.String.class); + map.put("EventStreamPassword", java.lang.String.class); + map.put("EventStreamTopic", java.lang.String.class); + map.put("EventStreamUsername", java.lang.String.class); map.put("GcpVaultConfiguration", org.apache.camel.vault.GcpVaultConfiguration.class); map.put("HashicorpVaultConfiguration", org.apache.camel.vault.HashicorpVaultConfiguration.class); map.put("IBMSecretsManagerVaultConfiguration", org.apache.camel.vault.IBMSecretsManagerVaultConfiguration.class); map.put("KubernetesConfigMapVaultConfiguration", org.apache.camel.vault.KubernetesConfigMapVaultConfiguration.class); map.put("KubernetesVaultConfiguration", org.apache.camel.vault.KubernetesVaultConfiguration.class); + map.put("RefreshEnabled", boolean.class); + map.put("RefreshPeriod", long.class); + map.put("Secrets", java.lang.String.class); map.put("ServiceUrl", java.lang.String.class); map.put("Token", java.lang.String.class); ALL_OPTIONS = map; @@ -42,6 +50,16 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "awsVaultConfiguration": target.setAwsVaultConfiguration(property(camelContext, org.apache.camel.vault.AwsVaultConfiguration.class, value)); return true; case "azurevaultconfiguration": case "azureVaultConfiguration": target.setAzureVaultConfiguration(property(camelContext, org.apache.camel.vault.AzureVaultConfiguration.class, value)); return true; + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": target.setEventStreamBootstrapServers(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamgroupid": + case "eventStreamGroupId": target.setEventStreamGroupId(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreampassword": + case "eventStreamPassword": target.setEventStreamPassword(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamtopic": + case "eventStreamTopic": target.setEventStreamTopic(property(camelContext, java.lang.String.class, value)); return true; + case "eventstreamusername": + case "eventStreamUsername": target.setEventStreamUsername(property(camelContext, java.lang.String.class, value)); return true; case "gcpvaultconfiguration": case "gcpVaultConfiguration": target.setGcpVaultConfiguration(property(camelContext, org.apache.camel.vault.GcpVaultConfiguration.class, value)); return true; case "hashicorpvaultconfiguration": @@ -52,6 +70,11 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "kubernetesConfigMapVaultConfiguration": target.setKubernetesConfigMapVaultConfiguration(property(camelContext, org.apache.camel.vault.KubernetesConfigMapVaultConfiguration.class, value)); return true; case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": target.setKubernetesVaultConfiguration(property(camelContext, org.apache.camel.vault.KubernetesVaultConfiguration.class, value)); return true; + case "refreshenabled": + case "refreshEnabled": target.setRefreshEnabled(property(camelContext, boolean.class, value)); return true; + case "refreshperiod": + case "refreshPeriod": target.setRefreshPeriod(property(camelContext, long.class, value)); return true; + case "secrets": target.setSecrets(property(camelContext, java.lang.String.class, value)); return true; case "serviceurl": case "serviceUrl": target.setServiceUrl(property(camelContext, java.lang.String.class, value)); return true; case "token": target.setToken(property(camelContext, java.lang.String.class, value)); return true; @@ -71,6 +94,16 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "awsVaultConfiguration": return org.apache.camel.vault.AwsVaultConfiguration.class; case "azurevaultconfiguration": case "azureVaultConfiguration": return org.apache.camel.vault.AzureVaultConfiguration.class; + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": return java.lang.String.class; + case "eventstreamgroupid": + case "eventStreamGroupId": return java.lang.String.class; + case "eventstreampassword": + case "eventStreamPassword": return java.lang.String.class; + case "eventstreamtopic": + case "eventStreamTopic": return java.lang.String.class; + case "eventstreamusername": + case "eventStreamUsername": return java.lang.String.class; case "gcpvaultconfiguration": case "gcpVaultConfiguration": return org.apache.camel.vault.GcpVaultConfiguration.class; case "hashicorpvaultconfiguration": @@ -81,6 +114,11 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "kubernetesConfigMapVaultConfiguration": return org.apache.camel.vault.KubernetesConfigMapVaultConfiguration.class; case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": return org.apache.camel.vault.KubernetesVaultConfiguration.class; + case "refreshenabled": + case "refreshEnabled": return boolean.class; + case "refreshperiod": + case "refreshPeriod": return long.class; + case "secrets": return java.lang.String.class; case "serviceurl": case "serviceUrl": return java.lang.String.class; case "token": return java.lang.String.class; @@ -96,6 +134,16 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "awsVaultConfiguration": return target.getAwsVaultConfiguration(); case "azurevaultconfiguration": case "azureVaultConfiguration": return target.getAzureVaultConfiguration(); + case "eventstreambootstrapservers": + case "eventStreamBootstrapServers": return target.getEventStreamBootstrapServers(); + case "eventstreamgroupid": + case "eventStreamGroupId": return target.getEventStreamGroupId(); + case "eventstreampassword": + case "eventStreamPassword": return target.getEventStreamPassword(); + case "eventstreamtopic": + case "eventStreamTopic": return target.getEventStreamTopic(); + case "eventstreamusername": + case "eventStreamUsername": return target.getEventStreamUsername(); case "gcpvaultconfiguration": case "gcpVaultConfiguration": return target.getGcpVaultConfiguration(); case "hashicorpvaultconfiguration": @@ -106,6 +154,11 @@ public class IBMSecretsManagerVaultConfigurationPropertiesConfigurer extends org case "kubernetesConfigMapVaultConfiguration": return target.getKubernetesConfigMapVaultConfiguration(); case "kubernetesvaultconfiguration": case "kubernetesVaultConfiguration": return target.getKubernetesVaultConfiguration(); + case "refreshenabled": + case "refreshEnabled": return target.isRefreshEnabled(); + case "refreshperiod": + case "refreshPeriod": return target.getRefreshPeriod(); + case "secrets": return target.getSecrets(); case "serviceurl": case "serviceUrl": return target.getServiceUrl(); case "token": return target.getToken(); diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index b2d72d5918c..215b956e8ae 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -392,6 +392,14 @@ { "name": "camel.vault.hashicorp.port", "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.hashicorp.scheme", "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.hashicorp.token", "description": "Token to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamBootstrapServers", "description": "Specify the Bootstrap servers for consuming notification on IBM Event Stream. Multiple servers can be separated by comma.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamGroupId", "description": "Specify the Consumer Group ID to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamPassword", "description": "Specify the password to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamTopic", "description": "Specify the topic name for consuming notification on IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.eventStreamUsername", "description": "Specify the username to access IBM Event Stream", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.vault.ibm.refreshEnabled", "description": "Whether to automatically reload Camel upon secrets being updated in IBM.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, + { "name": "camel.vault.ibm.refreshPeriod", "description": "The period (millis) between checking AWS for updated secrets.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 30000 }, + { "name": "camel.vault.ibm.secrets", "description": "Specify the secret names (or pattern) to check for updates. Multiple secrets can be separated by comma.", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.ibm.serviceUrl", "description": "Service URL to access IBM Secrets Manager vault", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.ibm.token", "description": "Token to access IBM Secrets Manager vault", "sourceType": "org.apache.camel.vault.IBMSecretsManagerVaultConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.vault.kubernetes.refreshEnabled", "description": "Whether to automatically reload Camel upon secrets being updated in Kubernetes Cluster.", "sourceType": "org.apache.camel.vault.KubernetesVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 1c12659004f..5a058fd5029 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -469,11 +469,19 @@ The camel.vault.hashicorp supports 6 options, which are listed below. === Camel IBM Secrets Manager Vault configurations -The camel.vault.ibm supports 2 options, which are listed below. +The camel.vault.ibm supports 10 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== | Name | Description | Default | Type +| *camel.vault.ibm.eventStream{zwsp}BootstrapServers* | Specify the Bootstrap servers for consuming notification on IBM Event Stream. Multiple servers can be separated by comma. | | String +| *camel.vault.ibm.eventStream{zwsp}GroupId* | Specify the Consumer Group ID to access IBM Event Stream | | String +| *camel.vault.ibm.eventStream{zwsp}Password* | Specify the password to access IBM Event Stream | | String +| *camel.vault.ibm.eventStream{zwsp}Topic* | Specify the topic name for consuming notification on IBM Event Stream | | String +| *camel.vault.ibm.eventStream{zwsp}Username* | Specify the username to access IBM Event Stream | | String +| *camel.vault.ibm.refreshEnabled* | Whether to automatically reload Camel upon secrets being updated in IBM. | false | boolean +| *camel.vault.ibm.refreshPeriod* | The period (millis) between checking AWS for updated secrets. | 30000 | long +| *camel.vault.ibm.secrets* | Specify the secret names (or pattern) to check for updates. Multiple secrets can be separated by comma. | | String | *camel.vault.ibm.serviceUrl* | Service URL to access IBM Secrets Manager vault | | String | *camel.vault.ibm.token* | Token to access IBM Secrets Manager vault | | String |=== diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java index dc737733b20..001ad910e5b 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java @@ -749,6 +749,24 @@ public final class DefaultConfigurationConfigurer { scheduler.scheduledTask(r); } } + + if (vc.ibmSecretsManager().isRefreshEnabled()) { + Optional<Runnable> task = PluginHelper.getPeriodTaskResolver(camelContext) + .newInstance("ibm-secret-refresh", Runnable.class); + if (task.isPresent()) { + Runnable r = task.get(); + if (LOG.isDebugEnabled()) { + LOG.debug("Scheduling: {} ", r); + } + if (camelContext.hasService(ContextReloadStrategy.class) == null) { + // refresh is enabled then we need to automatically enable context-reload as well + ContextReloadStrategy reloader = new DefaultContextReloadStrategy(); + camelContext.addService(reloader); + } + PeriodTaskScheduler scheduler = PluginHelper.getPeriodTaskScheduler(camelContext); + scheduler.scheduledTask(r); + } + } } public static void afterPropertiesSet(final CamelContext camelContext) throws Exception {