Skip to content

Commit f7f7e3b

Browse files
committed
feat: add TLS support for BigDataTest services and examples
- Introduced TLS configuration for HDFS, Kafka Schema Registry, Kafka UI, LocalStack S3, and Fake GCS in `BigDataTestKit` and `AutoConfiguration`. - Implemented HTTP-to-HTTPS mapping and JVM TLS property management with configurable truststores. - Updated examples, JUnit extensions, and container factories to include TLS options and integration with HAProxy gateways. - Added BouncyCastle dependencies for certificate generation and management. - Enhanced README with updated TLS-enabled configuration examples. - Refactored core utilities to support dynamic TLS material generation, PEM file handling, and secure container setup.
1 parent aa0f655 commit f7f7e3b

15 files changed

Lines changed: 749 additions & 43 deletions

File tree

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ records = [
6565
]
6666
```
6767

68+
HTTP services can be exposed through an HAProxy TLS gateway from TOML:
69+
70+
```toml
71+
[services]
72+
localStackS3 = true
73+
74+
[localStackS3Tls]
75+
enabled = true
76+
domain = "localhost"
77+
```
78+
79+
The endpoint properties then return HTTPS URLs and JVM truststore settings such as `javax.net.ssl.trustStore`.
80+
6881
## Run Examples
6982

7083
Use the shared Gradle home when running this repository locally:

autoconfigure/src/main/kotlin/org/openprojectx/bigdata/test/autoconfigure/BigDataTestAutoConfiguration.kt

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.openprojectx.bigdata.test.autoconfigure
22

33
import org.openprojectx.bigdata.test.core.BigDataTestKit
44
import org.openprojectx.bigdata.test.core.HdfsOptions
5+
import org.openprojectx.bigdata.test.core.HttpTlsOptions
56
import org.openprojectx.bigdata.test.core.HiveMetastoreDistribution
67
import org.openprojectx.bigdata.test.core.HiveMetastoreOptions
78
import org.openprojectx.bigdata.test.core.KafkaOptions
@@ -37,13 +38,17 @@ class BigDataTestAutoConfiguration {
3738
)
3839
}
3940

40-
if (properties.tls.enabled) {
41+
if (properties.tls.enabled || properties.anyHttpTlsEnabled()) {
4142
builder.withTls(
4243
TlsOptions(
43-
enabled = true,
44+
enabled = properties.tls.enabled || properties.anyHttpTlsEnabled(),
45+
caCertPath = properties.tls.caCertPath,
46+
caKeyPath = properties.tls.caKeyPath,
47+
trustStorePath = properties.tls.trustStorePath,
48+
trustStorePassword = properties.tls.trustStorePassword,
49+
haproxyImage = properties.tls.haproxyImage,
4450
certPath = properties.tls.certPath,
4551
keyPath = properties.tls.keyPath,
46-
caCertPath = properties.tls.caCertPath,
4752
),
4853
)
4954
}
@@ -53,6 +58,7 @@ class BigDataTestAutoConfiguration {
5358
HdfsOptions(
5459
enabled = true,
5560
image = properties.hdfs.image,
61+
webTls = properties.hdfs.webTls.toCore(),
5662
kerberos = KerberosAuthOptions(
5763
enabled = properties.hdfs.kerberosEnabled,
5864
servicePrincipal = "nn/hdfs.example.com@${properties.kerberos.realm}",
@@ -110,8 +116,10 @@ class BigDataTestAutoConfiguration {
110116
image = properties.kafka.image,
111117
schemaRegistryEnabled = properties.kafka.schemaRegistryEnabled,
112118
schemaRegistryImage = properties.kafka.schemaRegistryImage,
119+
schemaRegistryTls = properties.kafka.schemaRegistryTls.toCore(),
113120
kafkaUiEnabled = properties.kafka.kafkaUiEnabled,
114121
kafkaUiImage = properties.kafka.kafkaUiImage,
122+
kafkaUiTls = properties.kafka.kafkaUiTls.toCore(),
115123
kerberos = KerberosAuthOptions(
116124
enabled = properties.kafka.kerberosEnabled,
117125
servicePrincipal = "kafka/broker1.example.com@${properties.kerberos.realm}",
@@ -127,13 +135,38 @@ class BigDataTestAutoConfiguration {
127135
}
128136

129137
if (properties.localstackS3.enabled) {
130-
builder.withLocalStackS3(ObjectStoreOptions(enabled = true, image = properties.localstackS3.image))
138+
builder.withLocalStackS3(
139+
ObjectStoreOptions(
140+
enabled = true,
141+
image = properties.localstackS3.image,
142+
tls = properties.localstackS3.tls.toCore(),
143+
),
144+
)
131145
}
132146

133147
if (properties.fakeGcs.enabled) {
134-
builder.withFakeGcs(ObjectStoreOptions(enabled = true, image = properties.fakeGcs.image))
148+
builder.withFakeGcs(
149+
ObjectStoreOptions(
150+
enabled = true,
151+
image = properties.fakeGcs.image,
152+
tls = properties.fakeGcs.tls.toCore(defaultDomain = "storage.googleapis.com"),
153+
),
154+
)
135155
}
136156

137157
return builder.build().also { it.start() }
138158
}
159+
160+
private fun BigDataTestProperties.HttpTls.toCore(defaultDomain: String = "localhost"): HttpTlsOptions =
161+
HttpTlsOptions(
162+
enabled = enabled,
163+
domain = domain.ifBlank { defaultDomain },
164+
)
165+
166+
private fun BigDataTestProperties.anyHttpTlsEnabled(): Boolean =
167+
hdfs.webTls.enabled ||
168+
kafka.schemaRegistryTls.enabled ||
169+
kafka.kafkaUiTls.enabled ||
170+
localstackS3.tls.enabled ||
171+
fakeGcs.tls.enabled
139172
}

autoconfigure/src/main/kotlin/org/openprojectx/bigdata/test/autoconfigure/BigDataTestProperties.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,27 @@ data class BigDataTestProperties(
2525

2626
data class Tls(
2727
var enabled: Boolean = false,
28+
var caCertPath: String? = null,
29+
var caKeyPath: String? = null,
30+
var trustStorePath: String? = null,
31+
var trustStorePassword: String = "changeit",
32+
var haproxyImage: String = "haproxy:3.0-alpine",
33+
@Deprecated("Use caCertPath")
2834
var certPath: String? = null,
35+
@Deprecated("Use caKeyPath")
2936
var keyPath: String? = null,
30-
var caCertPath: String? = null,
37+
)
38+
39+
data class HttpTls(
40+
var enabled: Boolean = false,
41+
var domain: String = "localhost",
3142
)
3243

3344
data class Hdfs(
3445
var enabled: Boolean = false,
3546
var image: String = "apache/hadoop:3.5.0",
3647
var kerberosEnabled: Boolean = false,
48+
var webTls: HttpTls = HttpTls(),
3749
)
3850

3951
data class HiveMetastore(
@@ -61,14 +73,17 @@ data class BigDataTestProperties(
6173
var image: String = "apache/kafka:4.1.2",
6274
var schemaRegistryEnabled: Boolean = false,
6375
var schemaRegistryImage: String = "confluentinc/cp-schema-registry:7.8.0",
76+
var schemaRegistryTls: HttpTls = HttpTls(),
6477
var kafkaUiEnabled: Boolean = false,
6578
var kafkaUiImage: String = "ghcr.io/kafbat/kafka-ui:latest",
79+
var kafkaUiTls: HttpTls = HttpTls(),
6680
var kerberosEnabled: Boolean = false,
6781
var kafkaUiKerberosEnabled: Boolean = false,
6882
)
6983

7084
data class ObjectStore(
7185
var enabled: Boolean = false,
7286
var image: String,
87+
var tls: HttpTls = HttpTls(),
7388
)
7489
}

core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ plugins {
44

55

66
dependencies {
7+
implementation(libs.bouncycastlePkix)
8+
implementation(libs.bouncycastleProvider)
79
api(libs.testcontainers)
810
api(libs.testcontainersPostgresql)
911
api(libs.testcontainersKafka)

core/src/main/kotlin/org/openprojectx/bigdata/test/core/BigDataService.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ enum class BigDataService(
1717
),
1818
),
1919
HDFS(
20-
defaultPorts = mapOf("namenode" to 8020, "web" to 9870),
21-
endpointProperties = setOf("fs.defaultFS", "spring.hadoop.fs-uri"),
20+
defaultPorts = mapOf("namenode" to 8020, "web" to 9870, "web-tls" to 443),
21+
endpointProperties = setOf("fs.defaultFS", "spring.hadoop.fs-uri", "dfs.namenode.https-address"),
2222
),
2323
HIVE_METASTORE(
2424
defaultPorts = mapOf("thrift" to 9083),
@@ -29,15 +29,15 @@ enum class BigDataService(
2929
endpointProperties = setOf("bootstrap.servers", "spring.kafka.bootstrap-servers", "bootstrap.servers.internal"),
3030
),
3131
SCHEMA_REGISTRY(
32-
defaultPorts = mapOf("http" to 8085),
32+
defaultPorts = mapOf("http" to 8085, "https" to 443),
3333
endpointProperties = setOf("schema.registry.url"),
3434
),
3535
KAFKA_UI(
36-
defaultPorts = mapOf("http" to 8080),
36+
defaultPorts = mapOf("http" to 8080, "https" to 443),
3737
endpointProperties = setOf("bigdata.test.kafka-ui.url"),
3838
),
3939
LOCALSTACK_S3(
40-
defaultPorts = mapOf("edge" to 4566),
40+
defaultPorts = mapOf("edge" to 4566, "https" to 443),
4141
endpointProperties = setOf(
4242
"spring.cloud.aws.s3.endpoint",
4343
"aws.endpoint-url.s3",
@@ -47,7 +47,7 @@ enum class BigDataService(
4747
),
4848
),
4949
FAKE_GCS(
50-
defaultPorts = mapOf("http" to 4443),
50+
defaultPorts = mapOf("http" to 4443, "https" to 443),
5151
endpointProperties = setOf("bigdata.test.gcs.endpoint", "google.cloud.storage.host"),
5252
),
5353
}

core/src/main/kotlin/org/openprojectx/bigdata/test/core/BigDataTestKitOptions.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,28 @@ data class KerberosAuthOptions(
3636

3737
data class TlsOptions(
3838
val enabled: Boolean = false,
39+
val caCertPath: String? = null,
40+
val caKeyPath: String? = null,
41+
val trustStorePath: String? = null,
42+
val trustStorePassword: String = "changeit",
43+
val haproxyImage: String = "haproxy:3.0-alpine",
44+
@Deprecated("Use caCertPath for the root CA certificate")
3945
val certPath: String? = null,
46+
@Deprecated("Use caKeyPath for the root CA private key")
4047
val keyPath: String? = null,
41-
val caCertPath: String? = null,
48+
)
49+
50+
data class HttpTlsOptions(
51+
val enabled: Boolean = false,
52+
val domain: String = "localhost",
4253
)
4354

4455
data class HdfsOptions(
4556
val enabled: Boolean = false,
4657
val image: String = "apache/hadoop:3.5.0",
4758
val nameNodePort: Int = 8020,
4859
val webPort: Int = 9870,
60+
val webTls: HttpTlsOptions = HttpTlsOptions(),
4961
val kerberos: KerberosAuthOptions = KerberosAuthOptions(
5062
servicePrincipal = "nn/hdfs.example.com@EXAMPLE.COM",
5163
keytabPath = "/kerby/keytabs/hdfs-namenode.keytab",
@@ -78,8 +90,10 @@ data class KafkaOptions(
7890
val image: String = "apache/kafka:4.1.2",
7991
val schemaRegistryEnabled: Boolean = false,
8092
val schemaRegistryImage: String = "confluentinc/cp-schema-registry:7.8.0",
93+
val schemaRegistryTls: HttpTlsOptions = HttpTlsOptions(),
8194
val kafkaUiEnabled: Boolean = false,
8295
val kafkaUiImage: String = "ghcr.io/kafbat/kafka-ui:latest",
96+
val kafkaUiTls: HttpTlsOptions = HttpTlsOptions(),
8397
val clusterId: String = "MkU3OEVBNTcwNTJENDM2Qk",
8498
val kerberos: KerberosAuthOptions = KerberosAuthOptions(
8599
servicePrincipal = "kafka/localhost@EXAMPLE.COM",
@@ -94,6 +108,7 @@ data class KafkaOptions(
94108
data class ObjectStoreOptions(
95109
val enabled: Boolean = false,
96110
val image: String = "localstack/localstack:4.14.0",
111+
val tls: HttpTlsOptions = HttpTlsOptions(),
97112
)
98113

99114

@@ -103,12 +118,17 @@ data class PortBindingOptions(
103118
val kerberosKdc: Int = 0,
104119
val hdfsNameNode: Int = 0,
105120
val hdfsWeb: Int = 0,
121+
val hdfsWebTls: Int = 0,
106122
val hiveMetastore: Int = 0,
107123
val kafka: Int = 0,
108124
val schemaRegistry: Int = 0,
125+
val schemaRegistryTls: Int = 0,
109126
val kafkaUi: Int = 0,
127+
val kafkaUiTls: Int = 0,
110128
val localStackS3: Int = 0,
129+
val localStackS3Tls: Int = 0,
111130
val fakeGcs: Int = 0,
131+
val fakeGcsTls: Int = 0,
112132
) {
113133
fun hostPort(containerPort: Int, configuredHostPort: Int): Int {
114134
require(configuredHostPort >= 0) { "Host port must be 0 for random binding or a positive fixed port" }

0 commit comments

Comments
 (0)