mirror of https://github.com/istio/proxy.git
280 lines
9.6 KiB
C++
280 lines
9.6 KiB
C++
/* Copyright 2019 Istio Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "extensions/stackdriver/common/utils.h"
|
|
|
|
#include "absl/strings/str_join.h"
|
|
#include "extensions/common/util.h"
|
|
#include "extensions/stackdriver/common/constants.h"
|
|
#include "grpcpp/grpcpp.h"
|
|
|
|
namespace Extensions {
|
|
namespace Stackdriver {
|
|
namespace Common {
|
|
|
|
namespace {
|
|
|
|
const std::string getContainerName(
|
|
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
|
|
*containers) {
|
|
if (containers && containers->size() == 1) {
|
|
return flatbuffers::GetString(containers->Get(0));
|
|
}
|
|
|
|
return kIstioProxyContainerName;
|
|
}
|
|
|
|
std::string getNodeID(
|
|
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
|
|
*ip_addrs) {
|
|
if (!ip_addrs || ip_addrs->size() == 0) {
|
|
return "istio-proxy";
|
|
}
|
|
std::vector<std::string> ips;
|
|
ips.reserve(ip_addrs->size());
|
|
for (auto it = ip_addrs->begin(); it != ip_addrs->end(); ++it) {
|
|
ips.push_back(flatbuffers::GetString(*it));
|
|
}
|
|
|
|
return absl::StrJoin(ips, ",");
|
|
}
|
|
|
|
} // namespace
|
|
|
|
using google::api::MonitoredResource;
|
|
|
|
void buildEnvoyGrpcService(const StackdriverStubOption &stub_option,
|
|
GrpcService *grpc_service) {
|
|
if (!stub_option.insecure_endpoint.empty()) {
|
|
// Do not set up credential if insecure endpoint is provided. This is only
|
|
// for testing.
|
|
grpc_service->mutable_google_grpc()->set_target_uri(
|
|
stub_option.insecure_endpoint);
|
|
return;
|
|
}
|
|
grpc_service->mutable_google_grpc()->set_target_uri(
|
|
stub_option.secure_endpoint.empty() ? stub_option.default_endpoint
|
|
: stub_option.secure_endpoint);
|
|
if (stub_option.sts_port.empty()) {
|
|
// Security token exchange is not enabled. Use default Google credential.
|
|
grpc_service->mutable_google_grpc()
|
|
->mutable_channel_credentials()
|
|
->mutable_google_default();
|
|
return;
|
|
}
|
|
|
|
setSTSCallCredentialOptions(grpc_service->mutable_google_grpc()
|
|
->add_call_credentials()
|
|
->mutable_sts_service(),
|
|
stub_option.sts_port,
|
|
stub_option.test_token_path.empty()
|
|
? kSTSSubjectTokenPath
|
|
: stub_option.test_token_path);
|
|
auto initial_metadata = grpc_service->add_initial_metadata();
|
|
// When using p4sa/sts, google backend needs `x-goog-user-project` in initial
|
|
// metadata to differentiate which project the call should be accounted for.
|
|
initial_metadata->set_key("x-goog-user-project");
|
|
initial_metadata->set_value(stub_option.project_id);
|
|
|
|
auto *ssl_creds = grpc_service->mutable_google_grpc()
|
|
->mutable_channel_credentials()
|
|
->mutable_ssl_credentials();
|
|
if (!stub_option.test_root_pem_path.empty()) {
|
|
ssl_creds->mutable_root_certs()->set_filename(
|
|
stub_option.test_root_pem_path);
|
|
}
|
|
}
|
|
|
|
bool isRawGCEInstance(const ::Wasm::Common::FlatNode &node) {
|
|
auto platform_metadata = node.platform_metadata();
|
|
if (!platform_metadata) {
|
|
return false;
|
|
}
|
|
auto instance_id = platform_metadata->LookupByKey(kGCPGCEInstanceIDKey);
|
|
auto cluster_name = platform_metadata->LookupByKey(kGCPClusterNameKey);
|
|
return instance_id && !cluster_name;
|
|
}
|
|
|
|
std::string getGCEInstanceUID(const ::Wasm::Common::FlatNode &node) {
|
|
auto platform_metadata = node.platform_metadata();
|
|
if (!platform_metadata) {
|
|
return "";
|
|
}
|
|
|
|
auto project = platform_metadata->LookupByKey(kGCPProjectKey);
|
|
auto location = platform_metadata->LookupByKey(kGCPLocationKey);
|
|
auto instance_id = platform_metadata->LookupByKey(kGCPGCEInstanceIDKey);
|
|
|
|
auto name = node.name() ? node.name()->string_view() : std::string_view();
|
|
if (name.size() == 0 && instance_id) {
|
|
name = instance_id->value()->string_view();
|
|
}
|
|
|
|
if (name.size() > 0 && project && location) {
|
|
return absl::StrCat(
|
|
"//compute.googleapis.com/projects/",
|
|
::Wasm::Common::toAbslStringView(project->value()->string_view()),
|
|
"/zones/",
|
|
::Wasm::Common::toAbslStringView(location->value()->string_view()),
|
|
"/instances/", ::Wasm::Common::toAbslStringView(name));
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
std::string getOwner(const ::Wasm::Common::FlatNode &node) {
|
|
// do not override supplied owner
|
|
if (node.owner()) {
|
|
return flatbuffers::GetString(node.owner());
|
|
}
|
|
|
|
// only attempt for GCE Instances at this point. Support for other
|
|
// platforms will have to be added later. We also don't try to discover
|
|
// owners for GKE workload instances, as those should be handled by the
|
|
// sidecar injector.
|
|
if (isRawGCEInstance(node)) {
|
|
auto platform_metadata = node.platform_metadata();
|
|
if (!platform_metadata) {
|
|
return "";
|
|
}
|
|
auto created_by = platform_metadata->LookupByKey(kGCECreatedByKey.data());
|
|
if (created_by) {
|
|
return absl::StrCat(
|
|
"//compute.googleapis.com/",
|
|
::Wasm::Common::toAbslStringView(created_by->value()->string_view()));
|
|
}
|
|
|
|
return getGCEInstanceUID(node);
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void getMonitoredResource(const std::string &monitored_resource_type,
|
|
const ::Wasm::Common::FlatNode &local_node_info,
|
|
MonitoredResource *monitored_resource) {
|
|
if (!monitored_resource) {
|
|
return;
|
|
}
|
|
|
|
monitored_resource->set_type(monitored_resource_type);
|
|
auto platform_metadata = local_node_info.platform_metadata();
|
|
|
|
if (platform_metadata) {
|
|
auto project_key = platform_metadata->LookupByKey(kGCPProjectKey);
|
|
if (project_key) {
|
|
(*monitored_resource->mutable_labels())[kProjectIDLabel] =
|
|
flatbuffers::GetString(project_key->value());
|
|
}
|
|
}
|
|
|
|
if (monitored_resource_type == kGenericNode) {
|
|
// need location, namespace, node_id
|
|
if (platform_metadata) {
|
|
auto location_label = platform_metadata->LookupByKey(kGCPLocationKey);
|
|
if (location_label) {
|
|
(*monitored_resource->mutable_labels())[kLocationLabel] =
|
|
flatbuffers::GetString(location_label->value());
|
|
}
|
|
(*monitored_resource->mutable_labels())[kNamespaceLabel] =
|
|
flatbuffers::GetString(local_node_info.namespace_());
|
|
|
|
auto node_id = getNodeID(local_node_info.instance_ips());
|
|
(*monitored_resource->mutable_labels())[kNodeIDLabel] = node_id;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (monitored_resource_type == kGCEInstanceMonitoredResource) {
|
|
// gce_instance
|
|
if (platform_metadata) {
|
|
auto instance_id_label =
|
|
platform_metadata->LookupByKey(kGCPGCEInstanceIDKey);
|
|
if (instance_id_label) {
|
|
(*monitored_resource->mutable_labels())[kGCEInstanceIDLabel] =
|
|
flatbuffers::GetString(instance_id_label->value());
|
|
}
|
|
auto zone_label = platform_metadata->LookupByKey(kGCPLocationKey);
|
|
if (zone_label) {
|
|
(*monitored_resource->mutable_labels())[kZoneLabel] =
|
|
flatbuffers::GetString(zone_label->value());
|
|
}
|
|
}
|
|
} else {
|
|
// k8s_pod or k8s_container
|
|
if (platform_metadata) {
|
|
auto location_label = platform_metadata->LookupByKey(kGCPLocationKey);
|
|
if (location_label) {
|
|
(*monitored_resource->mutable_labels())[kLocationLabel] =
|
|
flatbuffers::GetString(location_label->value());
|
|
}
|
|
auto cluster_name = platform_metadata->LookupByKey(kGCPClusterNameKey);
|
|
if (cluster_name) {
|
|
(*monitored_resource->mutable_labels())[kClusterNameLabel] =
|
|
flatbuffers::GetString(cluster_name->value());
|
|
}
|
|
}
|
|
|
|
(*monitored_resource->mutable_labels())[kNamespaceNameLabel] =
|
|
flatbuffers::GetString(local_node_info.namespace_());
|
|
(*monitored_resource->mutable_labels())[kPodNameLabel] =
|
|
flatbuffers::GetString(local_node_info.name());
|
|
|
|
if (monitored_resource_type == kContainerMonitoredResource) {
|
|
// Fill in container_name of k8s_container monitored resource.
|
|
auto container = getContainerName(local_node_info.app_containers());
|
|
(*monitored_resource->mutable_labels())[kContainerNameLabel] = container;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setSTSCallCredentialOptions(
|
|
::envoy::config::core::v3::GrpcService_GoogleGrpc_CallCredentials_StsService
|
|
*sts_service,
|
|
const std::string &sts_port, const std::string &token_path) {
|
|
if (!sts_service) {
|
|
return;
|
|
}
|
|
sts_service->set_token_exchange_service_uri("http://localhost:" + sts_port +
|
|
"/token");
|
|
sts_service->set_subject_token_path(token_path);
|
|
sts_service->set_subject_token_type(kSTSSubjectTokenType);
|
|
sts_service->set_scope(kSTSScope);
|
|
}
|
|
|
|
void setSTSCallCredentialOptions(
|
|
::grpc::experimental::StsCredentialsOptions *sts_options,
|
|
const std::string &sts_port, const std::string &token_path) {
|
|
if (!sts_options) {
|
|
return;
|
|
}
|
|
sts_options->token_exchange_service_uri =
|
|
"http://localhost:" + sts_port + "/token";
|
|
sts_options->subject_token_path = token_path;
|
|
sts_options->subject_token_type = kSTSSubjectTokenType;
|
|
sts_options->scope = kSTSScope;
|
|
}
|
|
|
|
const std::string &unknownIfEmpty(const std::string &val) {
|
|
if (val.empty()) {
|
|
return kUnknownLabel;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
} // namespace Common
|
|
} // namespace Stackdriver
|
|
} // namespace Extensions
|