Skip to content
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

add the ability to use a secret persistence #6415

Merged
merged 37 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
cdfcd39
test exposing secrets in configrepo
jrhizor Sep 23, 2021
5f3d949
fix local persistence sql
jrhizor Sep 23, 2021
a09b411
working propagation, just without check/discover replacements and wit…
jrhizor Sep 24, 2021
5c337f5
switch if statement
jrhizor Sep 24, 2021
df73b87
set up secret persistence for google secrets manager
jrhizor Sep 25, 2021
d9fa73d
add ttl-based secret persistence for check/discover usage in the future
jrhizor Sep 25, 2021
489d2d5
set up check/discover to pass around necessary parts
jrhizor Sep 25, 2021
075f472
Revert "set up check/discover to pass around necessary parts"
jrhizor Sep 25, 2021
fb0ef64
working updates + check/discover operations
jrhizor Sep 25, 2021
8532a02
fix additional configs created on deletion
jrhizor Sep 25, 2021
0e79eb1
clean up docker compose file
jrhizor Sep 25, 2021
896a8d9
finish up configrepo
jrhizor Sep 25, 2021
13be907
make api path optional
jrhizor Sep 25, 2021
02dfbee
clean up schedulerapp and local testing persistence
jrhizor Sep 25, 2021
58a41ff
make optional in the worker app
jrhizor Sep 25, 2021
6e76768
add rest of feature flagging
jrhizor Sep 25, 2021
a279edb
fmt
jrhizor Sep 25, 2021
f25bb36
remove completed todo
jrhizor Sep 25, 2021
be25474
fix refactoring typo
jrhizor Sep 25, 2021
a32fd49
fix another refactoring typo
jrhizor Sep 25, 2021
5dfb0ef
fix compilation error in test case
jrhizor Sep 25, 2021
6bc4b3b
fix tests
jrhizor Sep 25, 2021
405cd1c
final cleanups
jrhizor Sep 25, 2021
8d5ceb7
fix conditional
jrhizor Sep 25, 2021
948f307
Merge branch 'master' into jrhizor/secrets-in-configrepo
jrhizor Sep 28, 2021
5c865ca
address a couple of things
jrhizor Sep 28, 2021
c91d597
add hydrator interface
jrhizor Sep 28, 2021
91e0cd0
add replaceAllConfigs
jrhizor Sep 29, 2021
5e74c50
specfetcher handling
jrhizor Sep 29, 2021
9f8a932
fix constructor
jrhizor Sep 29, 2021
e5ed837
fix test
jrhizor Sep 29, 2021
64097aa
Merge branch 'master' into jrhizor/secrets-in-configrepo
jrhizor Sep 29, 2021
702c5a7
fix typo
jrhizor Sep 29, 2021
37d101a
fix merge build error
jrhizor Sep 29, 2021
051f8b0
remove extra config
jrhizor Sep 29, 2021
a2dca1d
fix integration test
jrhizor Sep 29, 2021
b90f9e8
fix final piece
jrhizor Sep 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package io.airbyte.config.persistence;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.api.client.util.Preconditions;
import io.airbyte.commons.lang.MoreBooleans;
import io.airbyte.config.AirbyteConfig;
import io.airbyte.config.ConfigSchema;
Expand All @@ -37,6 +38,9 @@
import io.airbyte.config.StandardSync;
import io.airbyte.config.StandardSyncOperation;
import io.airbyte.config.StandardWorkspace;
import io.airbyte.config.persistence.split_secrets.SecretPersistence;
import io.airbyte.config.persistence.split_secrets.SecretsHelpers;
import io.airbyte.config.persistence.split_secrets.SplitSecretConfig;
import io.airbyte.protocol.models.ConnectorSpecification;
import io.airbyte.validation.json.JsonSchemaValidator;
import io.airbyte.validation.json.JsonValidationException;
Expand All @@ -52,9 +56,11 @@
public class ConfigRepository {

private final ConfigPersistence persistence;
private final Optional<SecretPersistence> secretPersistence;

public ConfigRepository(final ConfigPersistence persistence) {
public ConfigRepository(final ConfigPersistence persistence, final Optional<SecretPersistence> secretPersistence) {
this.persistence = persistence;
this.secretPersistence = secretPersistence;
}

public StandardWorkspace getStandardWorkspace(final UUID workspaceId, final boolean includeTombstone)
Expand Down Expand Up @@ -167,19 +173,75 @@ public void writeStandardDestinationDefinition(final StandardDestinationDefiniti
destinationDefinition);
}

public SourceConnection getSourceConnection(final UUID sourceId) throws JsonValidationException, IOException, ConfigNotFoundException {
public SourceConnection getSourceConnection(final UUID sourceId) throws JsonValidationException, ConfigNotFoundException, IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we call this getSourceConnectionWithoutSecrets?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's misleading for the standard case where no secrets persistence is used.

return persistence.getConfig(ConfigSchema.SOURCE_CONNECTION, sourceId.toString(), SourceConnection.class);
}

public SourceConnection getSourceConnectionWithSecrets(final UUID sourceId) throws JsonValidationException, IOException, ConfigNotFoundException {
final var source = getSourceConnection(sourceId);

if (secretPersistence.isPresent()) {
final var partialConfig = source.getConfiguration();
final var fullConfig = SecretsHelpers.combineConfig(partialConfig, secretPersistence.get());

source.setConfiguration(fullConfig);
}

return source;
}

private Optional<SourceConnection> getOptionalSourceConnection(final UUID sourceId) throws JsonValidationException, IOException {
try {
return Optional.of(getSourceConnection(sourceId));
} catch (ConfigNotFoundException e) {
return Optional.empty();
}
}

public void writeSourceConnection(final SourceConnection source, final ConnectorSpecification connectorSpecification)
throws JsonValidationException, IOException {
// actual validation is only for sanity checking
final JsonSchemaValidator validator = new JsonSchemaValidator();
validator.ensure(connectorSpecification.getConnectionSpecification(), source.getConfiguration());

if (secretPersistence.isPresent()) {
final var previousSourceConnection = getOptionalSourceConnection(source.getSourceId());
final var splitConfig = getSplitSourceConfig(previousSourceConnection, source, connectorSpecification);

// todo: should figure out how to do this more transactionally with getSplitSourceConfig /
// getSplitDestinationConfig
splitConfig.getCoordinateToPayload().forEach(secretPersistence.get()::write);

// todo: can we do this better without editing the input object? SourceConnection doesn't have a
// deepCopy but we could reserialize
source.setConfiguration(splitConfig.getPartialConfig());
}

persistence.writeConfig(ConfigSchema.SOURCE_CONNECTION, source.getSourceId().toString(), source);
}

private SplitSecretConfig getSplitSourceConfig(final Optional<SourceConnection> previousSource,
final SourceConnection source,
final ConnectorSpecification connectorSpecification) {
Preconditions.checkArgument(secretPersistence.isPresent());

if (previousSource.isPresent()) {
return SecretsHelpers.splitAndUpdateConfig(
source.getWorkspaceId(),
previousSource.get().getConfiguration(),
source.getConfiguration(),
connectorSpecification,
secretPersistence.get()::read);
} else {
return SecretsHelpers.splitConfig(
source.getWorkspaceId(),
source.getConfiguration(),
connectorSpecification);
}
}

// todo: what should list source connection return? full or partial?
// probably partial if it isn't used for migrations
public List<SourceConnection> listSourceConnection() throws JsonValidationException, IOException {
return persistence.listConfigs(ConfigSchema.SOURCE_CONNECTION, SourceConnection.class);
}
Expand All @@ -189,15 +251,71 @@ public DestinationConnection getDestinationConnection(final UUID destinationId)
return persistence.getConfig(ConfigSchema.DESTINATION_CONNECTION, destinationId.toString(), DestinationConnection.class);
}

public void writeDestinationConnection(final DestinationConnection destinationConnection, final ConnectorSpecification connectorSpecification)
public DestinationConnection getDestinationConnectionWithSecrets(final UUID destinationId)
throws JsonValidationException, IOException, ConfigNotFoundException {
final var destination = getDestinationConnection(destinationId);

if (secretPersistence.isPresent()) {
final var partialConfig = destination.getConfiguration();
final var fullConfig = SecretsHelpers.combineConfig(partialConfig, secretPersistence.get());

destination.setConfiguration(fullConfig);
}

return destination;

}

private Optional<DestinationConnection> getOptionalDestinationConnection(final UUID destinationId) throws JsonValidationException, IOException {
try {
return Optional.of(getDestinationConnection(destinationId));
} catch (ConfigNotFoundException e) {
return Optional.empty();
}
}

public void writeDestinationConnection(final DestinationConnection destination, final ConnectorSpecification connectorSpecification)
throws JsonValidationException, IOException {
// actual validation is only for sanity checking
final JsonSchemaValidator validator = new JsonSchemaValidator();
validator.ensure(connectorSpecification.getConnectionSpecification(), destinationConnection.getConfiguration());
validator.ensure(connectorSpecification.getConnectionSpecification(), destination.getConfiguration());

if (secretPersistence.isPresent()) {
final var previousDestination = getOptionalDestinationConnection(destination.getDestinationId());
final var splitConfig = getSplitDestinationConfig(previousDestination, destination, connectorSpecification);

persistence.writeConfig(ConfigSchema.DESTINATION_CONNECTION, destinationConnection.getDestinationId().toString(), destinationConnection);
splitConfig.getCoordinateToPayload().forEach(secretPersistence.get()::write);

// todo: can we do this better without editing the input object? DestinationCOnnection doesn't have
// a deepCopy but we could reserialize
destination.setConfiguration(splitConfig.getPartialConfig());
}

persistence.writeConfig(ConfigSchema.DESTINATION_CONNECTION, destination.getDestinationId().toString(), destination);
}

private SplitSecretConfig getSplitDestinationConfig(final Optional<DestinationConnection> previousDestination,
final DestinationConnection destination,
final ConnectorSpecification connectorSpecification) {
Preconditions.checkArgument(secretPersistence.isPresent());

if (previousDestination.isPresent()) {
return SecretsHelpers.splitAndUpdateConfig(
destination.getWorkspaceId(),
previousDestination.get().getConfiguration(),
destination.getConfiguration(),
connectorSpecification,
secretPersistence.get()::read);
} else {
return SecretsHelpers.splitConfig(
destination.getWorkspaceId(),
destination.getConfiguration(),
connectorSpecification);
}
}

// todo: what should list source connection return? full or partial?
// probably partial if it isn't used for migrations
public List<DestinationConnection> listDestinationConnection() throws JsonValidationException, IOException {
return persistence.listConfigs(ConfigSchema.DESTINATION_CONNECTION, DestinationConnection.class);
}
Expand Down Expand Up @@ -276,14 +394,17 @@ public List<DestinationOAuthParameter> listDestinationOAuthParam() throws JsonVa
return persistence.listConfigs(ConfigSchema.DESTINATION_OAUTH_PARAM, DestinationOAuthParameter.class);
}

// todo: support here
public void replaceAllConfigs(final Map<AirbyteConfig, Stream<?>> configs, final boolean dryRun) throws IOException {
persistence.replaceAllConfigs(configs, dryRun);
}

// todo: support here
public Map<String, Stream<JsonNode>> dumpConfigs() throws IOException {
return persistence.dumpConfigs();
}

// todo: support here
public void loadData(ConfigPersistence seedPersistence) throws IOException {
persistence.loadData(seedPersistence);
}
Expand Down

This file was deleted.

Loading