Skip to content

Commit

Permalink
mobile: Improve the gRPC initial metadata headers API for xDS (envoyp…
Browse files Browse the repository at this point in the history
…roxy#30691)

Initially, we introduced the setAuthenticationToken() method to the
XdsBuilder to enable setting authentication tokens (e.g. API keys) on
the xDS gRPC stream. However, authentication sometimes requires more
than one header to be added to the gRPC stream (e.g. `x-android-package`
and `x-android-cert` for API keys). Also, it's nice to have a general
API for adding gRPC metadata headers, not just authentication-specific
ones.

In this commit, we remove the setAuthenticationToken() API on
XdsBuilder, and replace it with a addInitialStreamMetadata() API.

Signed-off-by: Ali Beyad <[email protected]>
  • Loading branch information
abeyad authored Nov 2, 2023
1 parent 4e4eae1 commit 6c26a6d
Show file tree
Hide file tree
Showing 15 changed files with 112 additions and 98 deletions.
17 changes: 10 additions & 7 deletions mobile/library/cc/engine_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#endif

#include "source/common/http/matching/inputs.h"
#include "envoy/config/core/v3/base.pb.h"
#include "source/extensions/clusters/dynamic_forward_proxy/cluster.h"

#include "absl/strings/str_join.h"
Expand All @@ -46,9 +47,11 @@ namespace Platform {
XdsBuilder::XdsBuilder(std::string xds_server_address, const int xds_server_port)
: xds_server_address_(std::move(xds_server_address)), xds_server_port_(xds_server_port) {}

XdsBuilder& XdsBuilder::setAuthenticationToken(std::string token_header, std::string token) {
authentication_token_header_ = std::move(token_header);
authentication_token_ = std::move(token);
XdsBuilder& XdsBuilder::addInitialStreamHeader(std::string header, std::string value) {
envoy::config::core::v3::HeaderValue header_value;
header_value.set_key(std::move(header));
header_value.set_value(std::move(value));
xds_initial_grpc_metadata_.emplace_back(std::move(header_value));
return *this;
}

Expand Down Expand Up @@ -94,11 +97,11 @@ void XdsBuilder::build(envoy::config::bootstrap::v3::Bootstrap* bootstrap) const
->set_inline_string(ssl_root_certs_);
}

if (!authentication_token_header_.empty() && !authentication_token_.empty()) {
auto* auth_token_metadata = grpc_service.add_initial_metadata();
auth_token_metadata->set_key(authentication_token_header_);
auth_token_metadata->set_value(authentication_token_);
if (!xds_initial_grpc_metadata_.empty()) {
grpc_service.mutable_initial_metadata()->Assign(xds_initial_grpc_metadata_.begin(),
xds_initial_grpc_metadata_.end());
}

if (!sni_.empty()) {
auto& channel_args =
*grpc_service.mutable_google_grpc()->mutable_channel_args()->mutable_args();
Expand Down
17 changes: 9 additions & 8 deletions mobile/library/cc/engine_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>

#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
#include "envoy/config/core/v3/base.pb.h"

#include "source/common/protobuf/protobuf.h"

Expand Down Expand Up @@ -50,16 +51,17 @@ class XdsBuilder final {
// requests.
XdsBuilder(std::string xds_server_address, const int xds_server_port);

// Sets the authentication token in the gRPC headers used to authenticate to the xDS management
// Adds a header to the initial HTTP metadata headers sent on the gRPC stream.
//
// A common use for the initial metadata headers is for authentication to the xDS management
// server.
//
// For example, if using API keys to authenticate to Traffic Director on GCP (see
// https://cloud.google.com/docs/authentication/api-keys for details), invoke:
// builder.setAuthenticationToken("x-goog-api-key", api_key_token)
//
// `token_header`: the header name for which the the `token` will be set as a value.
// `token`: the authentication token.
XdsBuilder& setAuthenticationToken(std::string token_header, std::string token);
// builder.addInitialStreamHeader("x-goog-api-key", api_key_token)
// .addInitialStreamHeader("X-Android-Package", app_package_name)
// .addInitialStreamHeader("X-Android-Cert", sha1_key_fingerprint);
XdsBuilder& addInitialStreamHeader(std::string header, std::string value);

// Sets the PEM-encoded server root certificates used to negotiate the TLS handshake for the gRPC
// connection. If no root certs are specified, the operating system defaults are used.
Expand Down Expand Up @@ -110,8 +112,7 @@ class XdsBuilder final {

std::string xds_server_address_;
int xds_server_port_;
std::string authentication_token_header_;
std::string authentication_token_;
std::vector<envoy::config::core::v3::HeaderValue> xds_initial_grpc_metadata_;
std::string ssl_root_certs_;
std::string sni_;
std::string rtds_resource_name_;
Expand Down
11 changes: 5 additions & 6 deletions mobile/library/common/jni/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ std::string javaByteArrayToString(JNIEnv* env, jbyteArray j_data) {
return ret;
}

// Converts a java object array to C++ vector of of strings.
// Converts a java object array to C++ vector of strings.
std::vector<std::string> javaObjectArrayToStringVector(JNIEnv* env, jobjectArray entries) {
std::vector<std::string> ret;
// Note that headers is a flattened array of key/value pairs.
Expand Down Expand Up @@ -1321,7 +1321,7 @@ 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_auth_header, jstring xds_auth_token, jstring xds_root_certs, jstring xds_sni,
jobjectArray xds_grpc_initial_metadata, jstring xds_root_certs, jstring xds_sni,
jstring node_id, jstring node_region, jstring node_zone, jstring node_sub_zone,
jbyteArray serialized_node_metadata, jstring cds_resources_locator, jlong cds_timeout_seconds,
jboolean enable_cds) {
Expand All @@ -1345,10 +1345,9 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr
if (!native_xds_address.empty()) {
#ifdef ENVOY_GOOGLE_GRPC
Envoy::Platform::XdsBuilder xds_builder(std::move(native_xds_address), xds_port);
std::string native_xds_auth_header = getCppString(env, xds_auth_header);
if (!native_xds_auth_header.empty()) {
xds_builder.setAuthenticationToken(std::move(native_xds_auth_header),
getCppString(env, xds_auth_token));
auto initial_metadata = javaObjectArrayToStringPairVector(env, xds_grpc_initial_metadata);
for (const std::pair<std::string, std::string>& entry : initial_metadata) {
xds_builder.addInitialStreamHeader(entry.first, entry.second);
}
std::string native_root_certs = getCppString(env, xds_root_certs);
if (!native_root_certs.empty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ public enum TrustChainVerification {
public final Integer rtdsTimeoutSeconds;
public final String xdsAddress;
public final Integer xdsPort;
public final String xdsAuthHeader;
public final String xdsAuthToken;
public final Map<String, String> xdsGrpcInitialMetadata;
public final String xdsRootCerts;
public final String xdsSni;
public final String nodeId;
Expand Down Expand Up @@ -143,11 +142,9 @@ public enum TrustChainVerification {
* @param rtdsTimeoutSeconds the timeout for RTDS fetches.
* @param xdsAddress the address for the xDS management server.
* @param xdsPort the port for the xDS server.
* @param xdsAuthHeader the HTTP header to use for sending the
* authentication token to the xDS server.
* @param xdsAuthToken the token to send as the authentication
* header value to authenticate with the
* xDS server.
* @param xdsGrpcInitialMetadata The Headers (as key/value pairs) that must
* be included in the xDs gRPC stream's
* initial metadata (as HTTP headers).
* @param xdsRootCerts the root certificates to use for the TLS
* handshake during connection establishment
* with the xDS management server.
Expand Down Expand Up @@ -182,7 +179,7 @@ public EnvoyConfiguration(
Map<String, EnvoyKeyValueStore> keyValueStores, List<String> statSinks,
Map<String, Boolean> runtimeGuards, boolean enablePlatformCertificatesValidation,
String rtdsResourceName, Integer rtdsTimeoutSeconds, String xdsAddress, Integer xdsPort,
String xdsAuthHeader, String xdsAuthToken, String xdsRootCerts, String xdsSni, String nodeId,
Map<String, String> xdsGrpcInitialMetadata, String xdsRootCerts, String xdsSni, String nodeId,
String nodeRegion, String nodeZone, String nodeSubZone, Struct nodeMetadata,
String cdsResourcesLocator, Integer cdsTimeoutSeconds, boolean enableCds) {
JniLibrary.load();
Expand Down Expand Up @@ -245,8 +242,7 @@ public EnvoyConfiguration(
this.rtdsTimeoutSeconds = rtdsTimeoutSeconds;
this.xdsAddress = xdsAddress;
this.xdsPort = xdsPort;
this.xdsAuthHeader = xdsAuthHeader;
this.xdsAuthToken = xdsAuthToken;
this.xdsGrpcInitialMetadata = new HashMap<>(xdsGrpcInitialMetadata);
this.xdsRootCerts = xdsRootCerts;
this.xdsSni = xdsSni;
this.nodeId = nodeId;
Expand All @@ -271,6 +267,7 @@ public long createBootstrap() {
byte[][] runtimeGuards = JniBridgeUtility.mapToJniBytes(this.runtimeGuards);
byte[][] quicHints = JniBridgeUtility.mapToJniBytes(this.quicHints);
byte[][] quicSuffixes = JniBridgeUtility.stringsToJniBytes(quicCanonicalSuffixes);
byte[][] xdsGrpcInitialMetadata = JniBridgeUtility.mapToJniBytes(this.xdsGrpcInitialMetadata);

return JniLibrary.createBootstrap(
grpcStatsDomain, connectTimeoutSeconds, dnsRefreshSeconds, dnsFailureRefreshSecondsBase,
Expand All @@ -283,7 +280,7 @@ public long createBootstrap() {
streamIdleTimeoutSeconds, perTryIdleTimeoutSeconds, appVersion, appId,
enforceTrustChainVerification, filterChain, statsSinks,
enablePlatformCertificatesValidation, runtimeGuards, rtdsResourceName, rtdsTimeoutSeconds,
xdsAddress, xdsPort, xdsAuthHeader, xdsAuthToken, xdsRootCerts, xdsSni, nodeId, nodeRegion,
xdsAddress, xdsPort, xdsGrpcInitialMetadata, xdsRootCerts, xdsSni, nodeId, nodeRegion,
nodeZone, nodeSubZone, nodeMetadata.toByteArray(), cdsResourcesLocator, cdsTimeoutSeconds,
enableCds);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ public static native long createBootstrap(
long streamIdleTimeoutSeconds, long perTryIdleTimeoutSeconds, String appVersion, String appId,
boolean trustChainVerification, byte[][] filterChain, byte[][] statSinks,
boolean enablePlatformCertificatesValidation, byte[][] runtimeGuards, String rtdsResourceName,
long rtdsTimeoutSeconds, String xdsAddress, long xdsPort, String xdsAuthenticationHeader,
String xdsAuthenticationToken, String xdsRootCerts, String xdsSni, String nodeId,
String nodeRegion, String nodeZone, String nodeSubZone, byte[] nodeMetadata,
String cdsResourcesLocator, long cdsTimeoutSeconds, boolean enableCds);
long rtdsTimeoutSeconds, String xdsAddress, long xdsPort, byte[][] xdsGrpcInitialMetadata,
String xdsRootCerts, String xdsSni, String nodeId, String nodeRegion, String nodeZone,
String nodeSubZone, byte[] nodeMetadata, String cdsResourcesLocator, long cdsTimeoutSeconds,
boolean enableCds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ mEnableGzipDecompression, brotliEnabled(), mEnableSocketTag, mEnableInterfaceBin
platformFilterChain, stringAccessors, keyValueStores, statSinks, runtimeGuards,
mEnablePlatformCertificatesValidation,
/*rtdsResourceName=*/"", /*rtdsTimeoutSeconds=*/0, /*xdsAddress=*/"",
/*xdsPort=*/0, /*xdsAuthenticationHeader=*/"", /*xdsAuthenticationToken=*/"",
/*xdsPort=*/0, /*xdsGrpcInitialMetadata=*/Collections.emptyMap(),
/*xdsSslRootCerts=*/"",
/*xdsSni=*/"", mNodeId, mNodeRegion, mNodeZone, mNodeSubZone, Struct.getDefaultInstance(),
/*cdsResourcesLocator=*/"",
Expand Down
25 changes: 15 additions & 10 deletions mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ open class XdsBuilder(internal val xdsServerAddress: String, internal val xdsSer
private const val DEFAULT_XDS_TIMEOUT_IN_SECONDS: Int = 5
}

internal var authHeader: String? = null
internal var authToken: String? = null
internal var grpcInitialMetadata = mutableMapOf<String, String>()
internal var sslRootCerts: String? = null
internal var sni: String? = null
internal var rtdsResourceName: String? = null
Expand All @@ -47,16 +46,23 @@ open class XdsBuilder(internal val xdsServerAddress: String, internal val xdsSer
internal var cdsTimeoutInSeconds: Int = DEFAULT_XDS_TIMEOUT_IN_SECONDS

/**
* Sets the authentication HTTP header and token value for authenticating with the xDS management
* Adds a header to the initial HTTP metadata headers sent on the gRPC stream.
*
* A common use for the initial metadata headers is for authentication to the xDS management
* server.
*
* @param header The HTTP authentication header.
* @param token The authentication token to be sent in the header.
* For example, if using API keys to authenticate to Traffic Director on GCP (see
* https://cloud.google.com/docs/authentication/api-keys for details), invoke:
* builder.addInitialStreamHeader("x-goog-api-key", apiKeyToken)
* .addInitialStreamHeader("X-Android-Package", appPackageName)
* .addInitialStreamHeader("X-Android-Cert", sha1KeyFingerprint)
*
* @param header The HTTP header name to add to the initial gRPC stream's metadata.
* @param value The HTTP header value to add to the initial gRPC stream's metadata.
* @return this builder.
*/
fun setAuthenticationToken(header: String, token: String): XdsBuilder {
this.authHeader = header
this.authToken = token
fun addInitialStreamHeader(header: String, value: String): XdsBuilder {
this.grpcInitialMetadata.put(header, value)
return this
}

Expand Down Expand Up @@ -723,8 +729,7 @@ open class EngineBuilder(private val configuration: BaseConfiguration = Standard
xdsBuilder?.rtdsTimeoutInSeconds ?: 0,
xdsBuilder?.xdsServerAddress,
xdsBuilder?.xdsServerPort ?: 0,
xdsBuilder?.authHeader,
xdsBuilder?.authToken,
xdsBuilder?.grpcInitialMetadata ?: mapOf<String, String>(),
xdsBuilder?.sslRootCerts,
xdsBuilder?.sni,
nodeId,
Expand Down
7 changes: 3 additions & 4 deletions mobile/library/objective-c/EnvoyConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, nullable) NSString *nodeSubZone;
@property (nonatomic, strong, nullable) NSString *xdsServerAddress;
@property (nonatomic, assign) UInt32 xdsServerPort;
@property (nonatomic, strong, nullable) NSString *xdsAuthHeader;
@property (nonatomic, strong, nullable) NSString *xdsAuthToken;
@property (nonatomic, strong) NSDictionary<NSString *, NSString *> *xdsGrpcInitialMetadata;
@property (nonatomic, strong, nullable) NSString *xdsSslRootCerts;
@property (nonatomic, strong, nullable) NSString *xdsSni;
@property (nonatomic, strong, nullable) NSString *rtdsResourceName;
Expand Down Expand Up @@ -115,8 +114,8 @@ NS_ASSUME_NONNULL_BEGIN
nodeSubZone:(nullable NSString *)nodeSubZone
xdsServerAddress:(nullable NSString *)xdsServerAddress
xdsServerPort:(UInt32)xdsServerPort
xdsAuthHeader:(nullable NSString *)xdsAuthHeader
xdsAuthToken:(nullable NSString *)xdsAuthToken
xdsGrpcInitialMetadata:
(NSDictionary<NSString *, NSString *> *)xdsGrpcInitialMetadata
xdsSslRootCerts:(nullable NSString *)xdsSslRootCerts
xdsSni:(nullable NSString *)xdsSni
rtdsResourceName:(nullable NSString *)rtdsResourceName
Expand Down
13 changes: 6 additions & 7 deletions mobile/library/objective-c/EnvoyConfiguration.mm
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
nodeSubZone:(nullable NSString *)nodeSubZone
xdsServerAddress:(nullable NSString *)xdsServerAddress
xdsServerPort:(UInt32)xdsServerPort
xdsAuthHeader:(nullable NSString *)xdsAuthHeader
xdsAuthToken:(nullable NSString *)xdsAuthToken
xdsGrpcInitialMetadata:
(NSDictionary<NSString *, NSString *> *)xdsGrpcInitialMetadata
xdsSslRootCerts:(nullable NSString *)xdsSslRootCerts
xdsSni:(nullable NSString *)xdsSni
rtdsResourceName:(nullable NSString *)rtdsResourceName
Expand Down Expand Up @@ -170,8 +170,7 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
self.nodeSubZone = nodeSubZone;
self.xdsServerAddress = xdsServerAddress;
self.xdsServerPort = xdsServerPort;
self.xdsAuthHeader = xdsAuthHeader;
self.xdsAuthToken = xdsAuthToken;
self.xdsGrpcInitialMetadata = xdsGrpcInitialMetadata;
self.xdsSslRootCerts = xdsSslRootCerts;
self.xdsSni = xdsSni;
self.rtdsResourceName = rtdsResourceName;
Expand Down Expand Up @@ -272,9 +271,9 @@ - (instancetype)initWithGrpcStatsDomain:(nullable NSString *)grpcStatsDomain
#ifdef ENVOY_GOOGLE_GRPC
if (self.xdsServerAddress != nil) {
Envoy::Platform::XdsBuilder xdsBuilder([self.xdsServerAddress toCXXString], self.xdsServerPort);
if (self.xdsAuthHeader != nil) {
xdsBuilder.setAuthenticationToken([self.xdsAuthHeader toCXXString],
[self.xdsAuthToken toCXXString]);
for (NSString *header in self.xdsGrpcInitialMetadata) {
xdsBuilder.addInitialStreamHeader(
[header toCXXString], [[self.xdsGrpcInitialMetadata objectForKey:header] toCXXString]);
}
if (self.xdsSslRootCerts != nil) {
xdsBuilder.setSslRootCerts([self.xdsSslRootCerts toCXXString]);
Expand Down
Loading

0 comments on commit 6c26a6d

Please sign in to comment.