Skip to content

Commit

Permalink
mobile: Adds the ability to configure the SNI for the xDS connection (e…
Browse files Browse the repository at this point in the history
…nvoyproxy#28520)

Signed-off-by: Ali Beyad <[email protected]>
  • Loading branch information
abeyad authored Jul 20, 2023
1 parent 0eeeef3 commit ac42ba0
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 12 deletions.
10 changes: 10 additions & 0 deletions mobile/library/cc/engine_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ XdsBuilder& XdsBuilder::setSslRootCerts(std::string root_certs) {
return *this;
}

XdsBuilder& XdsBuilder::setSni(std::string sni) {
sni_ = std::move(sni);
return *this;
}

XdsBuilder& XdsBuilder::addRuntimeDiscoveryService(std::string resource_name,
const int timeout_in_seconds) {
rtds_resource_name_ = std::move(resource_name);
Expand Down Expand Up @@ -96,6 +101,11 @@ void XdsBuilder::build(envoy::config::bootstrap::v3::Bootstrap* bootstrap) const
jwt.set_json_key(jwt_token_);
jwt.set_token_lifetime_seconds(jwt_token_lifetime_in_seconds_);
}
if (!sni_.empty()) {
auto& channel_args =
*grpc_service.mutable_google_grpc()->mutable_channel_args()->mutable_args();
channel_args["grpc.default_authority"].set_string_value(sni_);
}

if (!rtds_resource_name_.empty()) {
auto* layered_runtime = bootstrap->mutable_layered_runtime();
Expand Down
6 changes: 6 additions & 0 deletions mobile/library/cc/engine_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ class XdsBuilder final {
// connection. If no root certs are specified, the operating system defaults are used.
XdsBuilder& setSslRootCerts(std::string root_certs);

// Sets the SNI (https://datatracker.ietf.org/doc/html/rfc6066#section-3) on the TLS handshake
// and the authority HTTP header. If not set, the SNI is set by default to the xDS server address
// and the authority HTTP header is not set.
XdsBuilder& setSni(std::string sni);

// Adds Runtime Discovery Service (RTDS) to the Runtime layers of the Bootstrap configuration,
// to retrieve dynamic runtime configuration via the xDS management server.
//
Expand Down Expand Up @@ -105,6 +110,7 @@ class XdsBuilder final {
std::string jwt_token_;
int jwt_token_lifetime_in_seconds_ = DefaultJwtTokenLifetimeSeconds;
std::string ssl_root_certs_;
std::string sni_;
std::string rtds_resource_name_;
int rtds_timeout_in_seconds_ = DefaultXdsTimeout;
bool enable_cds_ = false;
Expand Down
10 changes: 7 additions & 3 deletions mobile/library/common/jni/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1287,9 +1287,9 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr
jboolean trust_chain_verification, jobjectArray filter_chain, jobjectArray stat_sinks,
jboolean enable_platform_certificates_validation, jobjectArray runtime_guards,
jstring rtds_resource_name, jlong rtds_timeout_seconds, jstring xds_address, jlong xds_port,
jstring xds_jwt_token, jlong xds_jwt_token_lifetime, jstring xds_root_certs, jstring node_id,
jstring node_region, jstring node_zone, jstring node_sub_zone, jstring cds_resources_locator,
jlong cds_timeout_seconds, jboolean enable_cds) {
jstring xds_jwt_token, jlong xds_jwt_token_lifetime, jstring xds_root_certs, jstring xds_sni,
jstring node_id, jstring node_region, jstring node_zone, jstring node_sub_zone,
jstring cds_resources_locator, jlong cds_timeout_seconds, jboolean enable_cds) {
Envoy::Platform::EngineBuilder builder;

configureBuilder(
Expand All @@ -1316,6 +1316,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr
if (!native_root_certs.empty()) {
xds_builder.setSslRootCerts(std::move(native_root_certs));
}
std::string native_sni = getCppString(env, xds_sni);
if (!native_sni.empty()) {
xds_builder.setSni(std::move(native_sni));
}
std::string native_rtds_resource_name = getCppString(env, rtds_resource_name);
if (!native_rtds_resource_name.empty()) {
xds_builder.addRuntimeDiscoveryService(std::move(native_rtds_resource_name),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public enum TrustChainVerification {
public final String xdsJwtToken;
public final Integer xdsJwtTokenLifetime;
public final String xdsRootCerts;
public final String xdsSni;
public final String nodeId;
public final String nodeRegion;
public final String nodeZone;
Expand Down Expand Up @@ -139,6 +140,8 @@ public enum TrustChainVerification {
* @param xdsRootCerts the root certificates to use for the TLS
* handshake during connection establishment
* with the xDS management server.
* @param xdsSni the SNI (server name identification) to
* use for the TLS handshake.
* @param nodeId the node ID in the Node metadata.
* @param nodeRegion the node region in the Node metadata.
* @param nodeZone the node zone in the Node metadata.
Expand All @@ -165,9 +168,9 @@ public EnvoyConfiguration(
Map<String, EnvoyKeyValueStore> keyValueStores, List<String> statSinks,
Map<String, Boolean> runtimeGuards, boolean enablePlatformCertificatesValidation,
String rtdsResourceName, Integer rtdsTimeoutSeconds, String xdsAddress, Integer xdsPort,
String xdsJwtToken, Integer xdsJwtTokenLifetime, String xdsRootCerts, String nodeId,
String nodeRegion, String nodeZone, String nodeSubZone, String cdsResourcesLocator,
Integer cdsTimeoutSeconds, boolean enableCds) {
String xdsJwtToken, Integer xdsJwtTokenLifetime, String xdsRootCerts, String xdsSni,
String nodeId, String nodeRegion, String nodeZone, String nodeSubZone,
String cdsResourcesLocator, Integer cdsTimeoutSeconds, boolean enableCds) {
JniLibrary.load();
this.grpcStatsDomain = grpcStatsDomain;
this.connectTimeoutSeconds = connectTimeoutSeconds;
Expand Down Expand Up @@ -224,6 +227,7 @@ public EnvoyConfiguration(
this.xdsJwtToken = xdsJwtToken;
this.xdsJwtTokenLifetime = xdsJwtTokenLifetime;
this.xdsRootCerts = xdsRootCerts;
this.xdsSni = xdsSni;
this.nodeId = nodeId;
this.nodeRegion = nodeRegion;
this.nodeZone = nodeZone;
Expand Down Expand Up @@ -254,8 +258,8 @@ public long createBootstrap() {
streamIdleTimeoutSeconds, perTryIdleTimeoutSeconds, appVersion, appId,
enforceTrustChainVerification, filter_chain, stats_sinks,
enablePlatformCertificatesValidation, runtime_guards, rtdsResourceName, rtdsTimeoutSeconds,
xdsAddress, xdsPort, xdsJwtToken, xdsJwtTokenLifetime, xdsRootCerts, nodeId, nodeRegion,
nodeZone, nodeSubZone, cdsResourcesLocator, cdsTimeoutSeconds, enableCds);
xdsAddress, xdsPort, xdsJwtToken, xdsJwtTokenLifetime, xdsRootCerts, xdsSni, nodeId,
nodeRegion, nodeZone, nodeSubZone, cdsResourcesLocator, cdsTimeoutSeconds, enableCds);
}

static class ConfigurationException extends RuntimeException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ public static native long createBootstrap(
boolean trustChainVerification, byte[][] filterChain, byte[][] statSinks,
boolean enablePlatformCertificatesValidation, byte[][] runtimeGuards, String rtdsResourceName,
long rtdsTimeoutSeconds, String xdsAddress, long xdsPort, String xdsJwtToken,
long xdsJwtTokenLifetime, String xdsRootCerts, String nodeId, String nodeRegion,
String nodeZone, String nodeSubZone, String cdsResourcesLocator, long cdsTimeoutSeconds,
boolean enableCds);
long xdsJwtTokenLifetime, String xdsRootCerts, String xdsJni, String nodeId,
String nodeRegion, String nodeZone, String nodeSubZone, String cdsResourcesLocator,
long cdsTimeoutSeconds, boolean enableCds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ mEnableDrainPostDnsRefresh, quicEnabled(), mEnableGzipDecompression, brotliEnabl
keyValueStores, statSinks, runtimeGuards, mEnablePlatformCertificatesValidation,
/*rtdsResourceName=*/"", /*rtdsTimeoutSeconds=*/0, /*xdsAddress=*/"",
/*xdsPort=*/0, /*xdsJwtToken=*/"", /*xdsJwtTokenLifetime=*/0, /*xdsSslRootCerts=*/"",
mNodeId, mNodeRegion, mNodeZone, mNodeSubZone, /*cdsResourcesLocator=*/"",
/*xdsSni=*/"", mNodeId, mNodeRegion, mNodeZone, mNodeSubZone, /*cdsResourcesLocator=*/"",
/*cdsTimeoutSeconds=*/0, /*enableCds=*/false);
}
}
16 changes: 16 additions & 0 deletions mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ open class XdsBuilder (
internal var jwtToken: String? = null
internal var jwtTokenLifetimeInSeconds: Int = DEFAULT_JWT_TOKEN_LIFETIME_IN_SECONDS
internal var sslRootCerts: String? = null
internal var sni: String? = null
internal var rtdsResourceName: String? = null
internal var rtdsTimeoutInSeconds: Int = DEFAULT_XDS_TIMEOUT_IN_SECONDS
internal var enableCds: Boolean = false
Expand Down Expand Up @@ -86,6 +87,20 @@ open class XdsBuilder (
return this
}

/**
* Sets the SNI (https://datatracker.ietf.org/doc/html/rfc6066#section-3) on the TLS handshake
* and the authority HTTP header. If not set, the SNI is set by default to the xDS server address
* and the authority HTTP header is not set.
*
* @param sni The SNI value.
*
* @return this builder.
*/
fun setSni(sni: String): XdsBuilder {
this.sni = sni
return this
}

/**
* Adds Runtime Discovery Service (RTDS) to the Runtime layers of the Bootstrap configuration,
* to retrieve dynamic runtime configuration via the xDS management server.
Expand Down Expand Up @@ -719,6 +734,7 @@ open class EngineBuilder(
xdsBuilder?.jwtToken,
xdsBuilder?.jwtTokenLifetimeInSeconds ?: 0,
xdsBuilder?.sslRootCerts,
xdsBuilder?.sni,
nodeId,
nodeRegion,
nodeZone,
Expand Down
2 changes: 2 additions & 0 deletions mobile/library/objective-c/EnvoyConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, nullable) NSString *xdsJwtToken;
@property (nonatomic, assign) UInt32 xdsJwtTokenLifetimeSeconds;
@property (nonatomic, strong, nullable) NSString *xdsSslRootCerts;
@property (nonatomic, strong, nullable) NSString *xdsSni;
@property (nonatomic, strong, nullable) NSString *rtdsResourceName;
@property (nonatomic, assign) UInt32 rtdsTimeoutSeconds;
@property (nonatomic, assign) BOOL enableCds;
Expand Down Expand Up @@ -111,6 +112,7 @@ NS_ASSUME_NONNULL_BEGIN
xdsJwtToken:(nullable NSString *)xdsJwtToken
xdsJwtTokenLifetimeSeconds:(UInt32)xdsJwtTokenLifetimeSeconds
xdsSslRootCerts:(nullable NSString *)xdsSslRootCerts
xdsSni:(nullable NSString *)xdsSni
rtdsResourceName:(nullable NSString *)rtdsResourceName
rtdsTimeoutSeconds:(UInt32)rtdsTimeoutSeconds
enableCds:(BOOL)enableCds
Expand Down
5 changes: 5 additions & 0 deletions mobile/library/objective-c/EnvoyConfiguration.mm
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
xdsJwtToken:(nullable NSString *)xdsJwtToken
xdsJwtTokenLifetimeSeconds:(UInt32)xdsJwtTokenLifetimeSeconds
xdsSslRootCerts:(nullable NSString *)xdsSslRootCerts
xdsSni:(nullable NSString *)xdsSni
rtdsResourceName:(nullable NSString *)rtdsResourceName
rtdsTimeoutSeconds:(UInt32)rtdsTimeoutSeconds
enableCds:(BOOL)enableCds
Expand Down Expand Up @@ -168,6 +169,7 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
self.xdsJwtToken = xdsJwtToken;
self.xdsJwtTokenLifetimeSeconds = xdsJwtTokenLifetimeSeconds;
self.xdsSslRootCerts = xdsSslRootCerts;
self.xdsSni = xdsSni;
self.rtdsResourceName = rtdsResourceName;
self.rtdsTimeoutSeconds = rtdsTimeoutSeconds;
self.cdsResourcesLocator = cdsResourcesLocator;
Expand Down Expand Up @@ -267,6 +269,9 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
if (self.xdsSslRootCerts != nil) {
xdsBuilder.setSslRootCerts([self.xdsSslRootCerts toCXXString]);
}
if (self.xdsSni != nil) {
xdsBuilder.setSni([self.xdsSni toCXXString]);
}
if (self.rtdsResourceName != nil) {
xdsBuilder.addRuntimeDiscoveryService([self.rtdsResourceName toCXXString],
self.rtdsTimeoutSeconds);
Expand Down
20 changes: 20 additions & 0 deletions mobile/library/swift/EngineBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ open class XdsBuilder: NSObject {
var jwtToken: String?
var jwtTokenLifetimeInSeconds: UInt32 = XdsBuilder.defaultJwtTokenLifetimeInSeconds
var sslRootCerts: String?
var sni: String?
var rtdsResourceName: String?
var rtdsTimeoutInSeconds: UInt32 = 0
var enableCds: Bool = false
Expand Down Expand Up @@ -68,6 +69,19 @@ open class XdsBuilder: NSObject {
return self
}

/// Sets the SNI (https://datatracker.ietf.org/doc/html/rfc6066#section-3) on the TLS handshake
/// and the authority HTTP header. If not set, the SNI is set by default to the xDS server address
/// and the authority HTTP header is not set.
///
/// - parameter sni: The SNI (server name identification) value.
///
/// - returns: This builder.
@discardableResult
public func setSni(sni: String) -> Self {
self.sni = sni
return self
}

/// Adds Runtime Discovery Service (RTDS) to the Runtime layers of the Bootstrap configuration,
/// to retrieve dynamic runtime configuration via the xDS management server.
///
Expand Down Expand Up @@ -743,6 +757,7 @@ open class EngineBuilder: NSObject {
var xdsJwtToken: String?
var xdsJwtTokenLifetimeSeconds: UInt32 = 0
var xdsSslRootCerts: String?
var xdsSni: String?
var rtdsResourceName: String?
var rtdsTimeoutSeconds: UInt32 = 0
var enableCds: Bool = false
Expand All @@ -755,6 +770,7 @@ open class EngineBuilder: NSObject {
xdsJwtToken = self.xdsBuilder?.jwtToken
xdsJwtTokenLifetimeSeconds = self.xdsBuilder?.jwtTokenLifetimeInSeconds ?? 0
xdsSslRootCerts = self.xdsBuilder?.sslRootCerts
xdsSni = self.xdsBuilder?.sni
rtdsResourceName = self.xdsBuilder?.rtdsResourceName
rtdsTimeoutSeconds = self.xdsBuilder?.rtdsTimeoutInSeconds ?? 0
enableCds = self.xdsBuilder?.enableCds ?? false
Expand Down Expand Up @@ -805,6 +821,7 @@ open class EngineBuilder: NSObject {
xdsJwtToken: xdsJwtToken,
xdsJwtTokenLifetimeSeconds: xdsJwtTokenLifetimeSeconds,
xdsSslRootCerts: xdsSslRootCerts,
xdsSni: xdsSni,
rtdsResourceName: rtdsResourceName,
rtdsTimeoutSeconds: rtdsTimeoutSeconds,
enableCds: enableCds,
Expand Down Expand Up @@ -909,6 +926,9 @@ private extension EngineBuilder {
if let xdsSslRootCerts = xdsBuilder.sslRootCerts {
cxxXdsBuilder.setSslRootCerts(xdsSslRootCerts.toCXX())
}
if let xdsSni = xdsBuilder.sni {
cxxXdsBuilder.setSni(xdsSni.toCXX())
}
if let rtdsResourceName = xdsBuilder.rtdsResourceName {
cxxXdsBuilder.addRuntimeDiscoveryService(rtdsResourceName.toCXX(),
Int32(xdsBuilder.rtdsTimeoutInSeconds))
Expand Down
8 changes: 8 additions & 0 deletions mobile/test/cc/unit/envoy_config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ TEST(TestConfig, XdsConfig) {
xds_builder.setJwtAuthenticationToken(/*token=*/"my_jwt_token",
/*token_lifetime_in_seconds=*/500);
xds_builder.setSslRootCerts(/*root_certs=*/"my_root_cert");
xds_builder.setSni(/*sni=*/"fake-td.googleapis.com");
engine_builder.setXds(std::move(xds_builder));
bootstrap = engine_builder.generateBootstrap();
auto& ads_config_with_tokens = bootstrap->dynamic_resources().ads_config();
Expand All @@ -313,6 +314,13 @@ TEST(TestConfig, XdsConfig) {
.service_account_jwt_access()
.token_lifetime_seconds(),
500);
EXPECT_EQ(ads_config_with_tokens.grpc_services(0)
.google_grpc()
.channel_args()
.args()
.at("grpc.default_authority")
.string_value(),
"fake-td.googleapis.com");
}

TEST(TestConfig, CopyConstructor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class EnvoyConfigurationTest {
xdsJwtToken: String = "",
xdsJwtTokenLifetimeSeconds: Int = 0,
xdsSslRootCerts: String = "",
xdsSni: String = "",
nodeId: String = "",
nodeRegion: String = "",
nodeZone: String = "",
Expand Down Expand Up @@ -154,6 +155,7 @@ class EnvoyConfigurationTest {
xdsJwtToken,
xdsJwtTokenLifetimeSeconds,
xdsSslRootCerts,
xdsSni,
nodeId,
nodeRegion,
nodeZone,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class EngineBuilderTest {
var xdsBuilder = XdsBuilder("fake_test_address", 0)
xdsBuilder.setJwtAuthenticationToken("my_jwt_token")
xdsBuilder.setSslRootCerts("my_root_certs")
xdsBuilder.setSni("fake_test_address");
xdsBuilder.addRuntimeDiscoveryService("some_rtds_resource")
xdsBuilder.addClusterDiscoveryService("xdstp://fake_test_address/envoy.config.cluster.v3.Cluster/xyz")
engineBuilder = EngineBuilder(Standard())
Expand All @@ -219,6 +220,7 @@ class EngineBuilderTest {
assertThat(engine.envoyConfiguration.xdsAddress).isEqualTo("fake_test_address")
assertThat(engine.envoyConfiguration.xdsJwtToken).isEqualTo("my_jwt_token")
assertThat(engine.envoyConfiguration.xdsRootCerts).isEqualTo("my_root_certs")
assertThat(engine.envoyConfiguration.xdsSni).isEqualTo("fake_test_address")
assertThat(engine.envoyConfiguration.rtdsResourceName).isEqualTo("some_rtds_resource")
assertThat(engine.envoyConfiguration.cdsResourcesLocator).isEqualTo("xdstp://fake_test_address/envoy.config.cluster.v3.Cluster/xyz")
}
Expand Down
15 changes: 15 additions & 0 deletions mobile/test/swift/EngineBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,21 @@ final class EngineBuilderTests: XCTestCase {
XCTAssertTrue(bootstrapDebugDescription.contains("cds_config {"))
XCTAssertTrue(bootstrapDebugDescription.contains("initial_fetch_timeout { seconds: 5 }"))
}

func testAddingXdsSecurityConfigurationWhenRunningEnvoy() {
let xdsBuilder = XdsBuilder(xdsServerAddress: "FAKE_SWIFT_ADDRESS", xdsServerPort: 0)
.setJwtAuthenticationToken(token: "fake_jwt_token", tokenLifetimeInSeconds: 12345)
.setSslRootCerts(rootCerts: "fake_ssl_root_certs")
.setSni(sni: "fake_sni_address")
.addRuntimeDiscoveryService(resourceName: "some_rtds_resource", timeoutInSeconds: 14325)
let bootstrapDebugDescription = EngineBuilder()
.addEngineType(MockEnvoyEngine.self)
.setXds(xdsBuilder)
.bootstrapDebugDescription()
XCTAssertTrue(bootstrapDebugDescription.contains("fake_jwt_token"))
XCTAssertTrue(bootstrapDebugDescription.contains("fake_ssl_root_certs"))
XCTAssertTrue(bootstrapDebugDescription.contains("fake_sni_address"))
}
#endif

func testXDSDefaultValues() {
Expand Down

0 comments on commit ac42ba0

Please sign in to comment.