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-examples.git
commit c615f06fc93408316294d0688abb011029996aae Author: Andrea Cosentino <anco...@gmail.com> AuthorDate: Fri Sep 2 14:25:20 2022 +0200 Added an AWS Secrets Manager Reloading of Camel Context example --- .../aws/aws-secrets-manager-reloading/README.adoc | 144 +++++++++++++++++++++ examples/aws/aws-secrets-manager-reloading/pom.xml | 118 +++++++++++++++++ .../org/apache/camel/example/MyApplication.java | 125 ++++++++++++++++++ .../org/apache/camel/example/MyRouteBuilder.java | 29 +++++ .../src/main/resources/application.properties | 32 +++++ .../src/main/resources/logback.xml | 30 +++++ examples/aws/pom.xml | 1 + 7 files changed, 479 insertions(+) diff --git a/examples/aws/aws-secrets-manager-reloading/README.adoc b/examples/aws/aws-secrets-manager-reloading/README.adoc new file mode 100644 index 00000000..8ccedf09 --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/README.adoc @@ -0,0 +1,144 @@ +== Camel Example AWS Secrets Manager Reloading + +This example shows how to use AWS Secrets Manager to retrieve a secret, update the secret and trigger a reload of the camel context. + +Also notice how you can configure Camel in the `application.properties` file. + +=== Setup + +- Store the secret + +In this example you'll need to use the AWS CLI to run some commands during the example. + +First of all we'll need to create a secret in AWS Secret Manager, named `SecretTest`. + +We'll run + +[source,sh] +---- +aws secretsmanager create-secret --name SecretTest --description "Create a secret" --region eu-west-1 --secret-string secret +---- + +- Setting up the AWS credentials as enviroment variables + +This example uses the ProfileCredentialsProvider from AWS SDK v2. So you'll need to have a configuration file, locally to your machine. + +In particular you'll need to have a file placed in `~/.aws/credentials` + +with a content like the following + +[source,sh] +---- +[default] +aws_access_key_id = accessKey +aws_secret_access_key = secretKey +---- + +[source,sh] +---- +export CAMEL_VAULT_AWS_REGION=<region> +export CAMEL_VAULT_AWS_USE_DEFAULT_CREDENTIALS_PROVIDER=true +---- + +Now you're ready to run the example. + +=== Build + +First compile the example by executing: + +[source,sh] +---- +$ mvn compile +---- + +=== How to run + +Then you can run this example using + +[source,sh] +---- +$ mvn camel:run +---- + +At this point you should see: + +[source,sh] +---- +14:02:19.031 [org.apache.camel.example.MyApplication.main()] INFO org.apache.camel.main.MainSupport - Apache Camel (Main) 3.19.0-SNAPSHOT is starting +14:02:19.121 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - Classpath scanning enabled from base package: org.apache.camel.example +14:02:19.204 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.e.DefaultBeanIntrospection - Invoked: 1 times (overall) [Method: setProperty, Target: org.apache.camel.vault.AwsVaultConfiguration@c3adfb, Arguments: [defaultCredentialsProvider, true]] +14:02:19.210 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.e.DefaultBeanIntrospection - Invoked: 2 times (overall) [Method: setProperty, Target: org.apache.camel.vault.AwsVaultConfiguration@c3adfb, Arguments: [region, eu-west-1]] +14:02:19.226 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - Auto-configuration summary +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.main.name=AWS-secrets-manager +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.main.jmxEnabled=false +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.main.beanIntrospectionLoggingLevel=INFO +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.main.contextReloadEnabled=true +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.vault.aws.defaultCredentialsProvider=true +14:02:19.227 [org.apache.camel.example.MyApplication.main()] INFO o.apache.camel.main.BaseMainSupport - [application.properties] camel.vault.aws.region=eu-west-1 +14:02:20.552 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.engine.AbstractCamelContext - Apache Camel 3.19.0-SNAPSHOT (AWS-secrets-manager) is starting +14:02:20.573 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.engine.AbstractCamelContext - Routes startup (started:1) +14:02:20.574 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.engine.AbstractCamelContext - Started route1 (timer://myTimer) +14:02:20.583 [org.apache.camel.example.MyApplication.main()] INFO o.a.c.i.engine.AbstractCamelContext - Apache Camel 3.19.0-SNAPSHOT (AWS-secrets-manager) started in 1s327ms (build:31ms init:1s275ms start:21ms JVM-uptime:3s) +14:02:20.720 [pool-1-thread-1] INFO o.apache.camel.example.MyApplication - Found 50 events +14:02:21.593 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:02:31.573 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:02:41.573 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:02:50.288 [pool-1-thread-1] INFO o.apache.camel.example.MyApplication - Found 0 events +14:02:51.573 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:03:01.573 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:03:11.573 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +---- + +The example is running and it is using the original secret value. Now, in a different terminal, run the following AWS CLI command: + +[source,sh] +---- +aws secretsmanager put-secret-value --secret-id SecretTest --region eu-west-1 --secret-string secretImproved +---- + +Now, get back, to the running Camel application and in the log you should see: + +[source,sh] +---- +. +. +. +14:03:50.303 [pool-1-thread-1] INFO o.apache.camel.example.MyApplication - Found 0 events +14:03:51.572 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:04:01.572 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:04:11.572 [Camel (AWS-secrets-manager) thread #1 - timer://myTimer] INFO route1 - Secret value is: secret +14:04:20.311 [pool-1-thread-1] INFO o.apache.camel.example.MyApplication - Found 1 events +14:04:20.312 [pool-1-thread-1] INFO o.apache.camel.example.MyApplication - Update for secret SecretTest detected, triggering a context reload +14:04:20.312 [pool-1-thread-1] INFO o.a.c.i.e.DefaultContextReloadStrategy - Reloading CamelContext (AWS-secrets-manager) triggered by: AWS-secrets-manager +14:04:21.608 [Camel (AWS-secrets-manager) thread #4 - timer://myTimer] INFO route1 - Secret value is: secretImproved +14:04:31.607 [Camel (AWS-secrets-manager) thread #4 - timer://myTimer] INFO route1 - Secret value is: secretImproved +. +. +. +. +---- + +The Camel context has been reloaded after we noticed a `PutSecretValue` API invocation for this specific secret, in this specific region, in the AWS CloudTrail service. + +Now, stop the application. + +=== Cleanup + +- Delete the secret + +Simply run + +[source,sh] +---- +aws secretsmanager delete-secret --secret-id SecretTest --region eu-west-1 --force-delete-without-recovery +---- + +=== Help and contributions + +If you hit any problem using Camel or have some feedback, then please +https://camel.apache.org/community/support/[let us know]. + +We also love contributors, so +https://camel.apache.org/community/contributing/[get involved] :-) + +The Camel riders! diff --git a/examples/aws/aws-secrets-manager-reloading/pom.xml b/examples/aws/aws-secrets-manager-reloading/pom.xml new file mode 100644 index 00000000..9d471953 --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/pom.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.camel.example</groupId> + <artifactId>camel-examples-aws-parent</artifactId> + <version>3.19.0-SNAPSHOT</version> + </parent> + + <artifactId>camel-example-aws-secrets-manager-reloading</artifactId> + <packaging>jar</packaging> + <name>Camel :: Example :: AWS Secrets Manager Reloading</name> + <description>An example for showing AWS Secrets Manager Camel component with reloading</description> + + <properties> + <category>Beginner</category> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Add Camel BOM --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-bom</artifactId> + <version>${camel.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-main</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-aws-secrets-manager</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-http</artifactId> + </dependency> + <dependency> + <groupId>software.amazon.awssdk</groupId> + <artifactId>cloudtrail</artifactId> + <version>2.17.266</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-timer</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jsonpath</artifactId> + </dependency> + + <!-- logging --> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>${log4j2-version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <version>${logback-version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback-version}</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.camel</groupId> + <artifactId>camel-maven-plugin</artifactId> + <version>${camel.version}</version> + <configuration> + <logClasspath>false</logClasspath> + <mainClass>org.apache.camel.example.MyApplication</mainClass> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyApplication.java b/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyApplication.java new file mode 100644 index 00000000..6447bd31 --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyApplication.java @@ -0,0 +1,125 @@ +/* + * 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.example; + +import org.apache.camel.main.Main; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.camel.spi.ContextReloadStrategy; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cloudtrail.CloudTrailClient; +import software.amazon.awssdk.services.cloudtrail.model.*; + +import java.time.Instant; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Main class that boot the Camel application + */ +public final class MyApplication { + + private static final Logger LOG = LoggerFactory.getLogger(MyApplication.class); + + public static Instant lastTime = null; + + private MyApplication() { + } + + public static void main(String[] args) throws Exception { + // use Camels Main class + Main main = new Main(MyApplication.class); + + // Task to check for secret updates + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + CloudTrailAnalyzerTask analyzerTask = new CloudTrailAnalyzerTask(main, "SecretTest"); + executor.scheduleAtFixedRate(analyzerTask, 1, 30, TimeUnit.SECONDS); + + // now keep the application running until the JVM is terminated (ctrl + c or sigterm) + main.run(args); + } + + protected static class CloudTrailAnalyzerTask implements Runnable { + private Main main; + private String secretName; + private static String eventSourceSecrets = "secretsmanager.amazonaws.com"; + + public CloudTrailAnalyzerTask(Main main, String secretName) { + this.main = main; + this.secretName = secretName; + } + + @Override + public void run() { + boolean triggerReloading = false; + Region regionValue = Region.of(main.getCamelContext().getPropertiesComponent().loadProperties().get("camel.vault.aws.region").toString()); + CloudTrailClient cloudTrailClient = CloudTrailClient.builder() + .region(regionValue) + .credentialsProvider(ProfileCredentialsProvider.create()) + .build(); + try { + LookupEventsRequest.Builder eventsRequestBuilder = LookupEventsRequest.builder() + .maxResults(100).lookupAttributes(LookupAttribute.builder().attributeKey(LookupAttributeKey.EVENT_SOURCE).attributeValue(eventSourceSecrets).build()); + + if (lastTime != null) { + eventsRequestBuilder.startTime(lastTime.plusMillis(1000)); + } + + LookupEventsRequest lookupEventsRequest = eventsRequestBuilder.build(); + + LookupEventsResponse response = cloudTrailClient.lookupEvents(lookupEventsRequest); + List<Event> events = response.events(); + + if (events.size() > 0) { + lastTime = events.get(0).eventTime(); + } + + LOG.info("Found " + events.size() + " events"); + for (Event event : events) { + if (event.eventSource().equalsIgnoreCase(eventSourceSecrets)) { + if (event.eventName().equalsIgnoreCase("PutSecretValue")) { + List<Resource> a = event.resources(); + for (Resource res : a) { + if (res.resourceName().contains(secretName)) { + LOG.info("Update for secret " + secretName + " detected, triggering a context reload"); + triggerReloading = true; + break; + } + } + } + } + } + + } catch (CloudTrailException e) { + throw e; + } + if (triggerReloading) { + if (main.getCamelContext() != null) { + ContextReloadStrategy reload = main.getCamelContext().hasService(ContextReloadStrategy.class); + if (reload != null) { + // trigger reload + reload.onReload(main.getCamelContext().getName()); + } + } + } + } + } + +} diff --git a/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyRouteBuilder.java b/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyRouteBuilder.java new file mode 100644 index 00000000..e2b51552 --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/src/main/java/org/apache/camel/example/MyRouteBuilder.java @@ -0,0 +1,29 @@ +/* + * 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.example; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.aws.secretsmanager.SecretsManagerConstants; + +public class MyRouteBuilder extends RouteBuilder { + + @Override + public void configure() throws Exception { + from("timer://myTimer?fixedRate=true&period=10000") + .log("Secret value is: {{aws:SecretTest}}"); + } +} diff --git a/examples/aws/aws-secrets-manager-reloading/src/main/resources/application.properties b/examples/aws/aws-secrets-manager-reloading/src/main/resources/application.properties new file mode 100644 index 00000000..e07f7e1d --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/src/main/resources/application.properties @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# here you can configure options on camel main +# https://camel.apache.org/components/next/others/main.html +camel.main.name = AWS-secrets-manager +camel.main.jmx-enabled = false + +# extended runtime statistics about bean introspection usage (java reflection) +camel.main.bean-introspection-logging-level=INFO + +# Generic properties +stock = AMZN +stockName = Amazon + +camel.vault.aws.defaultCredentialsProvider=true +camel.vault.aws.region=eu-west-1 +camel.main.context-reload-enabled = true diff --git a/examples/aws/aws-secrets-manager-reloading/src/main/resources/logback.xml b/examples/aws/aws-secrets-manager-reloading/src/main/resources/logback.xml new file mode 100644 index 00000000..a798d0b3 --- /dev/null +++ b/examples/aws/aws-secrets-manager-reloading/src/main/resources/logback.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<configuration> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <root level="INFO"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> diff --git a/examples/aws/pom.xml b/examples/aws/pom.xml index 4a047439..6deaab1c 100644 --- a/examples/aws/pom.xml +++ b/examples/aws/pom.xml @@ -38,6 +38,7 @@ <modules> <module>aws-secrets-manager</module> + <module>aws-secrets-manager-reloading</module> <module>main-endpointdsl-aws2</module> <module>main-endpointdsl-aws2-s3</module> <module>main-endpointdsl-aws2-s3-kafka</module>