Skip to content

Commit

Permalink
Merge pull request #79 from camunda/wip/optional-secrets
Browse files Browse the repository at this point in the history
Make secrets fetching optional
  • Loading branch information
Poundex authored Feb 14, 2025
2 parents c6fd2cc + 4df02e5 commit 5b03094
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 10 deletions.
6 changes: 4 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ camunda.client.auth.client-id=<client id>
camunda.client.auth.client-secret=<client secret>
camunda.client.cluster-id=<cluster id>
camunda.client.region=<region>
camunda.rpa.zeebe.secrets.secrets-endpoint=https://cluster-api.cloud.camunda.io
----

.Example custom/dev SaaS configuration
Expand All @@ -63,7 +64,8 @@ camunda.rpa.zeebe.secrets.secrets-endpoint=https://cluster-api.cloud.dev.ultrawo
----

TIP: When creating an API client in the Camunda Cloud Console, the autogenerated configuration file provided contains
all the necessary configuration for connecting to production Camunda SaaS stacks, and can be used as-is.
most of the necessary configuration for connecting to production Camunda SaaS stacks, it is only required to configure


==== Local-only Working

Expand Down Expand Up @@ -196,7 +198,7 @@ The RPA Worker makes the following environment variables available to the Robot

|camunda.rpa.zeebe.secrets.secrets-endpoint
|The endpoint providing the secrets service
|`https://cluster-api.cloud.camunda.io`
|_None_ (Secrets fetching disabled)

|===

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ class FunctionalTestConfiguration {
static class StaticPropertyProvidingInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getEnvironment().propertySources.addFirst(new MockPropertySource()

MockPropertySource properties = new MockPropertySource("mockProps")
.withProperty("camunda.rpa.scripts.dir", Files.createTempDirectory("rpaScripts"))
.withProperty("camunda.rpa.zeebe.auth-endpoint", "http://localhost:${AbstractFunctionalSpec.ZEEBE_MOCK_AUTH_PORT}")
.withProperty("camunda.rpa.zeebe.secrets.secrets-endpoint", "http://localhost:${AbstractFunctionalSpec.ZEEBE_MOCK_SECRETS_PORT}")
.withProperty("camunda.client.zeebe.base-url", "http://localhost:${AbstractFunctionalSpec.ZEEBE_MOCK_API_PORT}"))
.withProperty("camunda.client.zeebe.base-url", "http://localhost:${AbstractFunctionalSpec.ZEEBE_MOCK_API_PORT}")

applicationContext.environment.propertySources.with {
if(contains("secretsProps"))
addAfter("secretsProps", properties)
else
addFirst(properties)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import groovy.json.JsonOutput
import io.camunda.rpa.worker.AbstractFunctionalSpec
import okhttp3.mockwebserver.MockResponse
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContextInitializer
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.mock.env.MockPropertySource
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration

import java.util.concurrent.TimeUnit

Expand Down Expand Up @@ -126,4 +130,26 @@ class SecretsFunctionalSpec extends AbstractFunctionalSpec {
then:
zeebeAuth.takeRequest(2, TimeUnit.SECONDS)
}

@ContextConfiguration(initializers = [StaticPropertyProvidingInitializer])
static class NoSecretsFunctionalSpec extends AbstractFunctionalSpec {
@Autowired
SecretsService secretsService

void "Returns empty secrets when not enabled"() {
when:
Map<String, String> r = block secretsService.getSecrets()

then:
r == [:]
}

static class StaticPropertyProvidingInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getEnvironment().propertySources.addFirst(new MockPropertySource("secretsProps")
.withProperty("camunda.rpa.zeebe.secrets.secrets-endpoint", ""))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.springframework.web.reactive.function.client.WebClient;
import reactivefeign.webclient.WebReactiveFeign;

import java.util.Optional;

@Configuration
@RequiredArgsConstructor
class SecretsClientConfiguration {
Expand All @@ -16,7 +18,9 @@ class SecretsClientConfiguration {
public SecretsClient secretsClient(WebClient.Builder webClientBuilder) {
return WebReactiveFeign
.<SecretsClient>builder(webClientBuilder)
.target(SecretsClient.class, clientProperties.secretsEndpoint().toString());
.target(SecretsClient.class, Optional.ofNullable(clientProperties.secretsEndpoint())
.map(Object::toString)
.orElse("http://no-secrets/"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.Map;

@Service
Expand All @@ -19,7 +20,14 @@ public class SecretsService {
private final SecretsClientProperties secretsClientProperties;

public Mono<Map<String, String>> getSecrets() {
if( ! isSecretsApiEnabled())
return Mono.just(Collections.emptyMap());

return zeebeAuthenticationService.getAuthToken(secretsClientProperties.tokenAudience())
.flatMap(secretsClient::getSecrets);
}

private boolean isSecretsApiEnabled() {
return secretsClientProperties.secretsEndpoint() != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ camunda.rpa.robot.max-concurrent-jobs=1
camunda.rpa.robot.default-timeout=PT5M

camunda.rpa.zeebe.auth-endpoint=https://login.cloud.camunda.io/oauth
camunda.rpa.zeebe.secrets.secrets-endpoint=https://cluster-api.cloud.camunda.io
camunda.client.zeebe.audience=zeebe.camunda.io
camunda.rpa.zeebe.secrets.token-audience=secrets.camunda.io
camunda.client.region=unset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ class SecretsServiceSpec extends Specification implements PublisherUtils {

SecretsClient secretsClient = Mock()
ZeebeAuthenticationService zeebeAuthService = Mock()
SecretsClientProperties secretsClientProperties = new SecretsClientProperties(null, "secrets-token-audience")

@Subject
SecretsService service = new SecretsService(secretsClient, zeebeAuthService, secretsClientProperties)

void "Authenticates and fetches secrets"() {
given:
SecretsClientProperties secretsClientProperties = new SecretsClientProperties("http://secrets".toURI(), "secrets-token-audience")

@Subject
SecretsService service = new SecretsService(secretsClient, zeebeAuthService, secretsClientProperties)

when:
Map<String, Object> map = block service.getSecrets()

Expand All @@ -27,4 +29,22 @@ class SecretsServiceSpec extends Specification implements PublisherUtils {
map == [secretVar: 'secret-value']
}

void "Returns empty secrets when not enabled"() {
given:
SecretsClientProperties secretsClientProperties = new SecretsClientProperties(null, "secrets-token-audience")

@Subject
SecretsService service = new SecretsService(secretsClient, zeebeAuthService, secretsClientProperties)

when:
Map<String, Object> map = block service.getSecrets()

then:
0 * zeebeAuthService._
0 * secretsClient._

and:
map == [:]
}

}

0 comments on commit 5b03094

Please sign in to comment.