Skip to content

Commit 5c870c1

Browse files
authored
🐛Destination-dynamodb: enforce ssl connection (#18672)
* [16283] Destination-dynamodb: Added strict-encrypt version and enforced ssl connection on cloud
1 parent f7bef97 commit 5c870c1

File tree

10 files changed

+138
-5
lines changed

10 files changed

+138
-5
lines changed

airbyte-config/init/src/main/resources/seed/destination_definitions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
- name: DynamoDB
8888
destinationDefinitionId: 8ccd8909-4e99-4141-b48d-4984b70b2d89
8989
dockerRepository: airbyte/destination-dynamodb
90-
dockerImageTag: 0.1.5
90+
dockerImageTag: 0.1.7
9191
documentationUrl: https://docs.airbyte.com/integrations/destinations/dynamodb
9292
icon: dynamodb.svg
9393
releaseStage: alpha

airbyte-config/init/src/main/resources/seed/destination_specs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@
14601460
supported_destination_sync_modes:
14611461
- "overwrite"
14621462
- "append"
1463-
- dockerImage: "airbyte/destination-dynamodb:0.1.5"
1463+
- dockerImage: "airbyte/destination-dynamodb:0.1.7"
14641464
spec:
14651465
documentationUrl: "https://docs.airbyte.com/integrations/destinations/dynamodb"
14661466
connectionSpecification:

airbyte-integrations/connectors/destination-dynamodb/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ ENV APPLICATION destination-dynamodb
1616

1717
COPY --from=build /airbyte /airbyte
1818

19-
LABEL io.airbyte.version=0.1.5
19+
LABEL io.airbyte.version=0.1.7
2020
LABEL io.airbyte.name=airbyte/destination-dynamodb

airbyte-integrations/connectors/destination-dynamodb/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ plugins {
55
}
66

77
application {
8-
mainClass = 'io.airbyte.integrations.destination.dynamodb.DynamodbDestination'
8+
mainClass = 'io.airbyte.integrations.destination.dynamodb.DynamodbDestinationRunner'
99
applicationDefaultJvmArgs = ['-XX:+ExitOnOutOfMemoryError', '-XX:MaxRAMPercentage=75.0']
1010
}
1111

airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbChecker.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,18 @@ public static AmazonDynamoDB getAmazonDynamoDB(final DynamodbDestinationConfig d
7777
}
7878
}
7979

80+
/**
81+
* Checks that DynamoDb custom endpoint uses a variant that only uses HTTPS
82+
*
83+
* @param endpoint URL string representing an accessible S3 bucket
84+
*/
85+
public static boolean testCustomEndpointSecured(final String endpoint) {
86+
// if user does not use a custom endpoint, do not fail
87+
if (endpoint == null || endpoint.length() == 0) {
88+
return true;
89+
} else {
90+
return endpoint.startsWith("https://");
91+
}
92+
}
93+
8094
}

airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestination.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ public static void main(final String[] args) throws Exception {
2727
@Override
2828
public AirbyteConnectionStatus check(final JsonNode config) {
2929
try {
30-
DynamodbChecker.attemptDynamodbWriteAndDelete(DynamodbDestinationConfig.getDynamodbDestinationConfig(config));
30+
final DynamodbDestinationConfig dynamodbDestinationConfig =
31+
DynamodbDestinationConfig.getDynamodbDestinationConfig(config);
32+
33+
DynamodbChecker.attemptDynamodbWriteAndDelete(dynamodbDestinationConfig);
3134
return new AirbyteConnectionStatus().withStatus(AirbyteConnectionStatus.Status.SUCCEEDED);
3235
} catch (final Exception e) {
3336
LOGGER.error("Exception attempting to access the DynamoDB table: ", e);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
3+
*/
4+
5+
package io.airbyte.integrations.destination.dynamodb;
6+
7+
import io.airbyte.integrations.base.adaptive.AdaptiveDestinationRunner;
8+
9+
public class DynamodbDestinationRunner {
10+
11+
public static void main(final String[] args) throws Exception {
12+
AdaptiveDestinationRunner.baseOnEnv()
13+
.withOssDestination(DynamodbDestination::new)
14+
.withCloudDestination(DynamodbDestinationStrictEncrypt::new)
15+
.run(args);
16+
}
17+
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
3+
*/
4+
5+
package io.airbyte.integrations.destination.dynamodb;
6+
7+
import com.fasterxml.jackson.databind.JsonNode;
8+
import io.airbyte.protocol.models.AirbyteConnectionStatus;
9+
10+
public class DynamodbDestinationStrictEncrypt extends DynamodbDestination {
11+
12+
protected static final String NON_SECURE_URL_ERR_MSG = "Server Endpoint requires HTTPS";
13+
14+
public DynamodbDestinationStrictEncrypt() {
15+
super();
16+
}
17+
18+
@Override
19+
public AirbyteConnectionStatus check(final JsonNode config) {
20+
final DynamodbDestinationConfig dynamodbDestinationConfig =
21+
DynamodbDestinationConfig.getDynamodbDestinationConfig(config);
22+
23+
// enforce ssl connection
24+
if (!DynamodbChecker.testCustomEndpointSecured(dynamodbDestinationConfig.getEndpoint())) {
25+
return new AirbyteConnectionStatus()
26+
.withStatus(AirbyteConnectionStatus.Status.FAILED)
27+
.withMessage(NON_SECURE_URL_ERR_MSG);
28+
}
29+
30+
return super.check(config);
31+
}
32+
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
3+
*/
4+
5+
package io.airbyte.integrations.destination.dynamodb;
6+
7+
import static io.airbyte.integrations.destination.dynamodb.DynamodbDestinationStrictEncrypt.NON_SECURE_URL_ERR_MSG;
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
10+
import com.fasterxml.jackson.databind.JsonNode;
11+
import com.google.common.collect.ImmutableMap;
12+
import io.airbyte.commons.io.IOs;
13+
import io.airbyte.commons.json.Jsons;
14+
import io.airbyte.protocol.models.AirbyteConnectionStatus;
15+
import io.airbyte.protocol.models.AirbyteConnectionStatus.Status;
16+
import java.nio.file.Files;
17+
import java.nio.file.Path;
18+
import org.junit.jupiter.api.Test;
19+
20+
public class DynamodbDestinationStrictEncryptTest {
21+
22+
protected static final Path secretFilePath = Path.of("secrets/config.json");
23+
24+
/**
25+
* Test that check passes if user is using HTTPS connection
26+
*/
27+
@Test
28+
public void checkPassCustomEndpointIsHttpsOnly() {
29+
final DynamodbDestination destinationWithHttpsOnlyEndpoint = new DynamodbDestinationStrictEncrypt();
30+
final AirbyteConnectionStatus status = destinationWithHttpsOnlyEndpoint.check(getBaseConfigJson());
31+
assertEquals(Status.SUCCEEDED, status.getStatus());
32+
}
33+
34+
/**
35+
* Test that check fails if user is using a non-secure (http) connection
36+
*/
37+
@Test
38+
public void checkFailCustomEndpointIsHttpsOnly() {
39+
final DynamodbDestination destinationWithHttpsOnlyEndpoint = new DynamodbDestinationStrictEncrypt();
40+
final AirbyteConnectionStatus status = destinationWithHttpsOnlyEndpoint.check(getUnsecureConfig());
41+
assertEquals(AirbyteConnectionStatus.Status.FAILED, status.getStatus());
42+
assertEquals(NON_SECURE_URL_ERR_MSG, status.getMessage());
43+
}
44+
45+
protected JsonNode getBaseConfigJson() {
46+
if (!Files.exists(secretFilePath)) {
47+
throw new IllegalStateException("Secret config file doesn't exist. Get a valid secret (for airbyter: "
48+
+ "get secret from GSM) and put to ../destination-dynamodb/secrets/secret.json file");
49+
}
50+
return Jsons.deserialize(IOs.readFile(secretFilePath));
51+
}
52+
53+
protected JsonNode getUnsecureConfig() {
54+
return Jsons.jsonNode(ImmutableMap.builder()
55+
.put("dynamodb_endpoint", "http://testurl.com:9000")
56+
.put("dynamodb_table_name_prefix", "integration-test")
57+
.put("dynamodb_region", "us-east-2")
58+
.put("access_key_id", "dummy_access_key_id")
59+
.put("secret_access_key", "dummy_secret_access_key")
60+
.build());
61+
}
62+
63+
}

docs/integrations/destinations/dynamodb.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ This connector by default uses 10 capacity units for both Read and Write in Dyna
6161

6262
| Version | Date | Pull Request | Subject |
6363
| :--- | :--- | :--- | :--- |
64+
| 0.1.7 | 2022-11-03 | [\#18672](https://github.com/airbytehq/airbyte/pull/18672) | Added strict-encrypt cloud runner |
65+
| 0.1.6 | 2022-11-01 | [\#18672](https://github.com/airbytehq/airbyte/pull/18672) | Enforce to use ssl connection |
6466
| 0.1.5 | 2022-08-05 | [\#15350](https://github.com/airbytehq/airbyte/pull/15350) | Added per-stream handling |
6567
| 0.1.4 | 2022-06-16 | [\#13852](https://github.com/airbytehq/airbyte/pull/13852) | Updated stacktrace format for any trace message errors |
6668
| 0.1.3 | 2022-05-17 | [12820](https://github.com/airbytehq/airbyte/pull/12820) | Improved 'check' operation performance |

0 commit comments

Comments
 (0)