diff --git a/api/envoy/api/v2/auth/cert.proto b/api/envoy/api/v2/auth/cert.proto index 111a01767e642..98cad266f3e90 100644 --- a/api/envoy/api/v2/auth/cert.proto +++ b/api/envoy/api/v2/auth/cert.proto @@ -11,6 +11,8 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; + import "udpa/annotations/migrate.proto"; import "validate/validate.proto"; @@ -128,7 +130,7 @@ message TlsCertificate { core.DataSource certificate_chain = 1; // The TLS private key. - core.DataSource private_key = 2; + core.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be @@ -141,7 +143,7 @@ message TlsCertificate { // The password to decrypt the TLS private key. If this field is not set, it is assumed that the // TLS private key is not password encrypted. - core.DataSource password = 3; + core.DataSource password = 3 [(udpa.annotations.sensitive) = true]; // [#not-implemented-hide:] core.DataSource ocsp_staple = 4; @@ -174,7 +176,8 @@ message TlsSessionTicketKeys { // * Keep the session ticket keys at least as secure as your TLS certificate private keys // * Rotate session ticket keys at least daily, and preferably hourly // * Always generate keys using a cryptographically-secure random data source - repeated core.DataSource keys = 1 [(validate.rules).repeated = {min_items: 1}]; + repeated core.DataSource keys = 1 + [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } // [#next-free-field: 10] diff --git a/api/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto b/api/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto index 1a7a5140b1b35..c1737d3bc72f1 100644 --- a/api/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto +++ b/api/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto @@ -11,6 +11,7 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -136,7 +137,7 @@ message TlsCertificate { config.core.v3alpha.DataSource certificate_chain = 1; // The TLS private key. - config.core.v3alpha.DataSource private_key = 2; + config.core.v3alpha.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. @@ -150,7 +151,7 @@ message TlsCertificate { // The password to decrypt the TLS private key. If this field is not set, it is assumed that the // TLS private key is not password encrypted. - config.core.v3alpha.DataSource password = 3; + config.core.v3alpha.DataSource password = 3 [(udpa.annotations.sensitive) = true]; // [#not-implemented-hide:] config.core.v3alpha.DataSource ocsp_staple = 4; @@ -187,7 +188,8 @@ message TlsSessionTicketKeys { // * Keep the session ticket keys at least as secure as your TLS certificate private keys // * Rotate session ticket keys at least daily, and preferably hourly // * Always generate keys using a cryptographically-secure random data source - repeated config.core.v3alpha.DataSource keys = 1 [(validate.rules).repeated = {min_items: 1}]; + repeated config.core.v3alpha.DataSource keys = 1 + [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } // [#next-free-field: 10] diff --git a/docs/root/operations/admin.rst b/docs/root/operations/admin.rst index 698cca8e6c5ac..da5f2e265850a 100644 --- a/docs/root/operations/admin.rst +++ b/docs/root/operations/admin.rst @@ -125,6 +125,14 @@ modify different aspects of the server: messages. See the :ref:`response definition ` for more information. +.. warning:: + Configuration may include :ref:`TLS certificates `. Before + dumping the configuration, Envoy will attempt to redact the ``private_key`` and ``password`` + fields from any certificates it finds. This relies on the configuration being a strongly-typed + protobuf message. If your Envoy configuration uses deprecated ``config`` fields (of type + ``google.protobuf.Struct``), please update to the recommended ``typed_config`` fields (of type + ``google.protobuf.Any``) to ensure sensitive data is redacted properly. + .. warning:: The underlying proto is marked v2alpha and hence its contents, including the JSON representation, are not guaranteed to be stable. diff --git a/generated_api_shadow/envoy/api/v2/auth/cert.proto b/generated_api_shadow/envoy/api/v2/auth/cert.proto index 111a01767e642..98cad266f3e90 100644 --- a/generated_api_shadow/envoy/api/v2/auth/cert.proto +++ b/generated_api_shadow/envoy/api/v2/auth/cert.proto @@ -11,6 +11,8 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; + import "udpa/annotations/migrate.proto"; import "validate/validate.proto"; @@ -128,7 +130,7 @@ message TlsCertificate { core.DataSource certificate_chain = 1; // The TLS private key. - core.DataSource private_key = 2; + core.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be @@ -141,7 +143,7 @@ message TlsCertificate { // The password to decrypt the TLS private key. If this field is not set, it is assumed that the // TLS private key is not password encrypted. - core.DataSource password = 3; + core.DataSource password = 3 [(udpa.annotations.sensitive) = true]; // [#not-implemented-hide:] core.DataSource ocsp_staple = 4; @@ -174,7 +176,8 @@ message TlsSessionTicketKeys { // * Keep the session ticket keys at least as secure as your TLS certificate private keys // * Rotate session ticket keys at least daily, and preferably hourly // * Always generate keys using a cryptographically-secure random data source - repeated core.DataSource keys = 1 [(validate.rules).repeated = {min_items: 1}]; + repeated core.DataSource keys = 1 + [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } // [#next-free-field: 10] diff --git a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto index 0144a8182b93d..fb0779e1e086a 100644 --- a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto +++ b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3alpha/cert.proto @@ -11,6 +11,7 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -134,7 +135,7 @@ message TlsCertificate { config.core.v3alpha.DataSource certificate_chain = 1; // The TLS private key. - config.core.v3alpha.DataSource private_key = 2; + config.core.v3alpha.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. @@ -148,7 +149,7 @@ message TlsCertificate { // The password to decrypt the TLS private key. If this field is not set, it is assumed that the // TLS private key is not password encrypted. - config.core.v3alpha.DataSource password = 3; + config.core.v3alpha.DataSource password = 3 [(udpa.annotations.sensitive) = true]; // [#not-implemented-hide:] config.core.v3alpha.DataSource ocsp_staple = 4; @@ -185,7 +186,8 @@ message TlsSessionTicketKeys { // * Keep the session ticket keys at least as secure as your TLS certificate private keys // * Rotate session ticket keys at least daily, and preferably hourly // * Always generate keys using a cryptographically-secure random data source - repeated config.core.v3alpha.DataSource keys = 1 [(validate.rules).repeated = {min_items: 1}]; + repeated config.core.v3alpha.DataSource keys = 1 + [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } // [#next-free-field: 10] diff --git a/source/common/protobuf/BUILD b/source/common/protobuf/BUILD index b552b4795f58c..8b8c0d2156170 100644 --- a/source/common/protobuf/BUILD +++ b/source/common/protobuf/BUILD @@ -68,6 +68,7 @@ envoy_cc_library( "//source/common/common:utility_lib", "//source/common/config:api_type_oracle_lib", "//source/common/config:version_converter_lib", + "@com_github_cncf_udpa//udpa/annotations:pkg_cc_proto", "@envoy_api//envoy/annotations:pkg_cc_proto", "@envoy_api//envoy/type/v3alpha:pkg_cc_proto", ], diff --git a/source/common/protobuf/utility.cc b/source/common/protobuf/utility.cc index 24ff6d2158eec..279f816c795b8 100644 --- a/source/common/protobuf/utility.cc +++ b/source/common/protobuf/utility.cc @@ -16,6 +16,7 @@ #include "common/protobuf/well_known.h" #include "absl/strings/match.h" +#include "udpa/annotations/sensitive.pb.h" #include "yaml-cpp/yaml.h" namespace Envoy { @@ -613,6 +614,147 @@ std::string MessageUtil::CodeEnumToString(ProtobufUtil::error::Code code) { } } +namespace { + +// Forward declaration for mutually-recursive helper functions. +void redact(Protobuf::Message* message, bool ancestor_is_sensitive); + +using Transform = std::function; + +// To redact opaque types, namely `Any` and `TypedStruct`, we have to reify them to the concrete +// message types specified by their `type_url` before we can redact their contents. This is mostly +// identical between `Any` and `TypedStruct`, the only difference being how they are packed and +// unpacked. Note that we have to use reflection on the opaque type here, rather than downcasting +// to `Any` or `TypedStruct`, because any message we might be handling could have originated from +// a `DynamicMessageFactory`. +bool redactOpaque(Protobuf::Message* message, bool ancestor_is_sensitive, + absl::string_view opaque_type_name, Transform unpack, Transform repack) { + // Ensure this message has the opaque type we're expecting. + const auto* opaque_descriptor = message->GetDescriptor(); + if (opaque_descriptor->full_name() != opaque_type_name) { + return false; + } + + // Find descriptors for the `type_url` and `value` fields. The `type_url` field must not be + // empty, but `value` may be (in which case our work is done). + const auto* reflection = message->GetReflection(); + const auto* type_url_field_descriptor = opaque_descriptor->FindFieldByName("type_url"); + const auto* value_field_descriptor = opaque_descriptor->FindFieldByName("value"); + ASSERT(type_url_field_descriptor != nullptr && value_field_descriptor != nullptr && + reflection->HasField(*message, type_url_field_descriptor)); + if (!reflection->HasField(*message, value_field_descriptor)) { + return true; + } + + // Try to find a descriptor for `type_url` in the pool and instantiate a new message of the + // correct concrete type. + const std::string type_url(reflection->GetString(*message, type_url_field_descriptor)); + const std::string concrete_type_name(TypeUtil::typeUrlToDescriptorFullName(type_url)); + const auto* concrete_descriptor = + Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(concrete_type_name); + if (concrete_descriptor == nullptr) { + // If the type URL doesn't correspond to a known proto, don't try to reify it, just treat it + // like any other message. See the documented limitation on `MessageUtil::redact()` for more + // context. + ENVOY_LOG_MISC(warn, "Could not reify {} with unknown type URL {}", opaque_type_name, type_url); + return false; + } + Protobuf::DynamicMessageFactory message_factory; + std::unique_ptr typed_message( + message_factory.GetPrototype(concrete_descriptor)->New()); + + // Finally we can unpack, redact, and repack the opaque message using the provided callbacks. + unpack(typed_message.get(), reflection, value_field_descriptor); + redact(typed_message.get(), ancestor_is_sensitive); + repack(typed_message.get(), reflection, value_field_descriptor); + return true; +} + +bool redactAny(Protobuf::Message* message, bool ancestor_is_sensitive) { + return redactOpaque( + message, ancestor_is_sensitive, "google.protobuf.Any", + [message](Protobuf::Message* typed_message, const Protobuf::Reflection* reflection, + const Protobuf::FieldDescriptor* field_descriptor) { + // To unpack an `Any`, parse the serialized proto. + typed_message->ParseFromString(reflection->GetString(*message, field_descriptor)); + }, + [message](Protobuf::Message* typed_message, const Protobuf::Reflection* reflection, + const Protobuf::FieldDescriptor* field_descriptor) { + // To repack an `Any`, reserialize its proto. + reflection->SetString(message, field_descriptor, typed_message->SerializeAsString()); + }); +} + +// To redact a `TypedStruct`, we have to reify it based on its `type_url` to redact it. +bool redactTypedStruct(Protobuf::Message* message, bool ancestor_is_sensitive) { + return redactOpaque( + message, ancestor_is_sensitive, "udpa.type.v1.TypedStruct", + [message](Protobuf::Message* typed_message, const Protobuf::Reflection* reflection, + const Protobuf::FieldDescriptor* field_descriptor) { + // To unpack a `TypedStruct`, convert the struct from JSON. + jsonConvertInternal(reflection->GetMessage(*message, field_descriptor), + ProtobufMessage::getNullValidationVisitor(), *typed_message); + }, + [message](Protobuf::Message* typed_message, const Protobuf::Reflection* reflection, + const Protobuf::FieldDescriptor* field_descriptor) { + // To repack a `TypedStruct`, convert the message back to JSON. + jsonConvertInternal(*typed_message, ProtobufMessage::getNullValidationVisitor(), + *(reflection->MutableMessage(message, field_descriptor))); + }); +} + +// Recursive helper method for MessageUtil::redact() below. +void redact(Protobuf::Message* message, bool ancestor_is_sensitive) { + if (redactAny(message, ancestor_is_sensitive) || + redactTypedStruct(message, ancestor_is_sensitive)) { + return; + } + + const auto* descriptor = message->GetDescriptor(); + const auto* reflection = message->GetReflection(); + for (int i = 0; i < descriptor->field_count(); ++i) { + const auto* field_descriptor = descriptor->field(i); + + // Redact if this field or any of its ancestors have the `sensitive` option set. + const bool sensitive = ancestor_is_sensitive || + field_descriptor->options().GetExtension(udpa::annotations::sensitive); + + if (field_descriptor->type() == Protobuf::FieldDescriptor::TYPE_MESSAGE) { + // Recursive case: traverse message fields. + if (field_descriptor->is_repeated()) { + const int field_size = reflection->FieldSize(*message, field_descriptor); + for (int i = 0; i < field_size; ++i) { + redact(reflection->MutableRepeatedMessage(message, field_descriptor, i), sensitive); + } + } else if (reflection->HasField(*message, field_descriptor)) { + redact(reflection->MutableMessage(message, field_descriptor), sensitive); + } + } else if (sensitive) { + // Base case: replace strings and bytes with "[redacted]" and clear all others. + if (field_descriptor->type() == Protobuf::FieldDescriptor::TYPE_STRING || + field_descriptor->type() == Protobuf::FieldDescriptor::TYPE_BYTES) { + if (field_descriptor->is_repeated()) { + const int field_size = reflection->FieldSize(*message, field_descriptor); + for (int i = 0; i < field_size; ++i) { + reflection->SetRepeatedString(message, field_descriptor, i, "[redacted]"); + } + } else if (reflection->HasField(*message, field_descriptor)) { + reflection->SetString(message, field_descriptor, "[redacted]"); + } + } else { + reflection->ClearField(message, field_descriptor); + } + } + } +} + +} // namespace + +void MessageUtil::redact(Protobuf::Message& message) { + ::Envoy::redact(&message, /* ancestor_is_sensitive = */ false); +} + ProtobufWkt::Value ValueUtil::loadFromYaml(const std::string& yaml) { try { return parseYamlNode(YAML::Load(yaml)); diff --git a/source/common/protobuf/utility.h b/source/common/protobuf/utility.h index ee82b01f471fe..7acd7bee2b747 100644 --- a/source/common/protobuf/utility.h +++ b/source/common/protobuf/utility.h @@ -363,6 +363,27 @@ class MessageUtil { * @param code the protobuf error code */ static std::string CodeEnumToString(ProtobufUtil::error::Code code); + + /** + * Modifies a message such that all sensitive data (that is, fields annotated as + * `udpa.annotations.sensitive`) is redacted for display. String-typed fields annotated as + * `sensitive` will be replaced with the string "[redacted]", bytes-typed fields will be replaced + * with the bytes `5B72656461637465645D` (the ASCII / UTF-8 encoding of the string "[redacted]"), + * primitive-typed fields (including enums) will be cleared, and message-typed fields will be + * traversed recursively to redact their contents. + * + * LIMITATION: This works properly for strongly-typed messages, as well as for messages packed in + * a `ProtobufWkt::Any` with a `type_url` corresponding to a proto that was compiled into the + * Envoy binary. However it does not work for messages encoded as `ProtobufWkt::Struct`, since + * structs are missing the "sensitive" annotations that this function expects. Similarly, it fails + * for messages encoded as `ProtobufWkt::Any` with a `type_url` that isn't registered with the + * binary. If you're working with struct-typed messages, including those that might be hiding + * within strongly-typed messages, please reify them to strongly-typed messages using + * `MessageUtil::jsonConvert()` before calling `MessageUtil::redact()`. + * + * @param message message to redact. + */ + static void redact(Protobuf::Message& message); }; class ValueUtil { diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index 637007f0bc31e..5cbf13ae212e8 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -20,6 +20,7 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", "//source/common/config:version_converter_lib", + "//source/common/protobuf:utility_lib", "@envoy_api//envoy/admin/v3alpha:pkg_cc_proto", "@envoy_api//envoy/config/core/v3alpha:pkg_cc_proto", "@envoy_api//envoy/extensions/transport_sockets/tls/v3alpha:pkg_cc_proto", diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc index 3b6c940fbdfcf..e97bce679fb36 100644 --- a/source/common/secret/secret_manager_impl.cc +++ b/source/common/secret/secret_manager_impl.cc @@ -9,6 +9,7 @@ #include "common/common/assert.h" #include "common/common/logger.h" #include "common/config/version_converter.h" +#include "common/protobuf/utility.h" #include "common/secret/sds_api.h" #include "common/secret/secret_provider_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" @@ -125,36 +126,6 @@ SecretManagerImpl::findOrCreateTlsSessionTicketKeysContextProvider( secret_provider_context); } -// We clear private key, password, and session ticket encryption keys to avoid information leaking. -// TODO(incfly): switch to more generic scrubbing mechanism once -// https://github.com/envoyproxy/envoy/issues/4757 is resolved. -void redactSecret(envoy::extensions::transport_sockets::tls::v3alpha::Secret* secret) { - if (secret && - secret->type_case() == - envoy::extensions::transport_sockets::tls::v3alpha::Secret::TypeCase::kTlsCertificate) { - auto tls_certificate = secret->mutable_tls_certificate(); - if (tls_certificate->has_private_key() && - tls_certificate->private_key().specifier_case() != - envoy::config::core::v3alpha::DataSource::SpecifierCase::kFilename) { - tls_certificate->mutable_private_key()->set_inline_string("[redacted]"); - } - if (tls_certificate->has_password() && - tls_certificate->password().specifier_case() != - envoy::config::core::v3alpha::DataSource::SpecifierCase::kFilename) { - tls_certificate->mutable_password()->set_inline_string("[redacted]"); - } - } - if (secret && secret->type_case() == envoy::extensions::transport_sockets::tls::v3alpha::Secret:: - TypeCase::kSessionTicketKeys) { - for (auto& data_source : *secret->mutable_session_ticket_keys()->mutable_keys()) { - if (data_source.specifier_case() != - envoy::config::core::v3alpha::DataSource::SpecifierCase::kFilename) { - data_source.set_inline_string("[redacted]"); - } - } - } -} - ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { // TODO(htuch): unlike other config providers, we're recreating the original // Secrets below. This makes it hard to support API_RECOVER_ORIGINAL()-style @@ -171,7 +142,7 @@ ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { envoy::extensions::transport_sockets::tls::v3alpha::Secret dump_secret; dump_secret.set_name(cert_iter.first); dump_secret.mutable_tls_certificate()->MergeFrom(*tls_cert->secret()); - redactSecret(&dump_secret); + MessageUtil::redact(dump_secret); static_secret->mutable_secret()->PackFrom(dump_secret); } @@ -198,7 +169,7 @@ ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { for (const auto& key : session_ticket_keys->secret()->keys()) { dump_secret.mutable_session_ticket_keys()->add_keys()->MergeFrom(key); } - redactSecret(&dump_secret); + MessageUtil::redact(dump_secret); static_secret->mutable_secret()->PackFrom(dump_secret); } @@ -225,7 +196,7 @@ ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { if (secret_ready) { secret.mutable_tls_certificate()->MergeFrom(*tls_cert); } - redactSecret(&secret); + MessageUtil::redact(secret); dump_secret->mutable_secret()->PackFrom(secret); } @@ -276,7 +247,7 @@ ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { if (secret_ready) { secret.mutable_session_ticket_keys()->MergeFrom(*tls_stek); } - redactSecret(&secret); + MessageUtil::redact(secret); dump_secret->mutable_secret()->PackFrom(secret); } return config_dump; diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index f5479281843c9..1764e23e674ae 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -698,6 +698,7 @@ Http::Code AdminImpl::handlerConfigDump(absl::string_view url, Http::HeaderMap& } else { addAllConfigToDump(dump, mask); } + MessageUtil::redact(dump); response_headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.Json); response.add(MessageUtil::getJsonStringFromMessage(dump, true)); // pretty-print diff --git a/test/common/protobuf/BUILD b/test/common/protobuf/BUILD index 3fac0a5ae88b5..f139627fa7e7e 100644 --- a/test/common/protobuf/BUILD +++ b/test/common/protobuf/BUILD @@ -31,6 +31,7 @@ envoy_cc_test( "//test/mocks/protobuf:protobuf_mocks", "//test/mocks/server:server_mocks", "//test/proto:deprecated_proto_cc_proto", + "//test/proto:sensitive_proto_cc_proto", "//test/test_common:environment_lib", "//test/test_common:logging_lib", "//test/test_common:utility_lib", diff --git a/test/common/protobuf/utility_test.cc b/test/common/protobuf/utility_test.cc index 7e54f3d89d29c..8eed82f758dde 100644 --- a/test/common/protobuf/utility_test.cc +++ b/test/common/protobuf/utility_test.cc @@ -20,11 +20,13 @@ #include "test/mocks/protobuf/mocks.h" #include "test/mocks/server/mocks.h" #include "test/proto/deprecated.pb.h" +#include "test/proto/sensitive.pb.h" #include "test/test_common/environment.h" #include "test/test_common/logging.h" #include "test/test_common/utility.h" #include "gtest/gtest.h" +#include "udpa/type/v1/typed_struct.pb.h" namespace Envoy { @@ -264,6 +266,642 @@ TEST_F(ProtobufUtilityTest, LoadTextProtoFromFile_Failure) { "\" as a text protobuf (type envoy.config.bootstrap.v3alpha.Bootstrap)"); } +// String fields annotated as sensitive should be converted to the string "[redacted]". String +// fields that are neither annotated as sensitive nor contained in a sensitive message should be +// left alone. +TEST_F(ProtobufUtilityTest, RedactString) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_string: This field should be redacted. +sensitive_repeated_string: + - This field should be redacted (1 of 2). + - This field should be redacted (2 of 2). +insensitive_string: This field should not be redacted. +insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +sensitive_string: '[redacted]' +sensitive_repeated_string: + - '[redacted]' + - '[redacted]' +insensitive_string: This field should not be redacted. +insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Bytes fields annotated as sensitive should be converted to the ASCII / UTF-8 encoding of the +// string "[redacted]". Bytes fields that are neither annotated as sensitive nor contained in a +// sensitive message should be left alone. +TEST_F(ProtobufUtilityTest, RedactBytes) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_bytes: VGhlc2UgYnl0ZXMgc2hvdWxkIGJlIHJlZGFjdGVkLg== +sensitive_repeated_bytes: + - VGhlc2UgYnl0ZXMgc2hvdWxkIGJlIHJlZGFjdGVkICgxIG9mIDIpLg== + - VGhlc2UgYnl0ZXMgc2hvdWxkIGJlIHJlZGFjdGVkICgyIG9mIDIpLg== +insensitive_bytes: VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZC4= +insensitive_repeated_bytes: + - VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZCAoMSBvZiAyKS4= + - VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZCAoMiBvZiAyKS4= +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +sensitive_bytes: W3JlZGFjdGVkXQ== +sensitive_repeated_bytes: + - W3JlZGFjdGVkXQ== + - W3JlZGFjdGVkXQ== +insensitive_bytes: VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZC4= +insensitive_repeated_bytes: + - VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZCAoMSBvZiAyKS4= + - VGhlc2UgYnl0ZXMgc2hvdWxkIG5vdCBiZSByZWRhY3RlZCAoMiBvZiAyKS4= +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Ints annotated as sensitive should be cleared. Ints that are neither annotated as sensitive nor +// contained in a sensitive message should be left alone. Note that the same logic should apply to +// any primitive type other than strings and bytes, although we omit tests for that here. +TEST_F(ProtobufUtilityTest, RedactInts) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_int: 1 +sensitive_repeated_int: + - 1 + - 2 +insensitive_int: 1 +insensitive_repeated_int: + - 1 + - 2 +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +insensitive_int: 1 +insensitive_repeated_int: + - 1 + - 2 +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Messages annotated as sensitive should have all their fields redacted recursively. Messages that +// are neither annotated as sensitive nor contained in a sensitive message should be left alone. +TEST_F(ProtobufUtilityTest, RedactMessage) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_message: + insensitive_string: This field should be redacted because of its parent. + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 2). + - This field should be redacted because of its parent (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +sensitive_repeated_message: + - insensitive_string: This field should be redacted because of its parent (1 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 4). + - This field should be redacted because of its parent (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - insensitive_string: This field should be redacted because of its parent (2 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (3 of 4). + - This field should be redacted because of its parent (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +insensitive_message: + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +insensitive_repeated_message: + - insensitive_string: This field should not be redacted (1 of 2). + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - insensitive_string: This field should not be redacted (2 of 2). + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +sensitive_message: + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +sensitive_repeated_message: + - insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' + - insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +insensitive_message: + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +insensitive_repeated_message: + - insensitive_string: This field should not be redacted (1 of 2). + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - insensitive_string: This field should not be redacted (2 of 2). + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Messages packed into `Any` should be treated the same as normal messages. +TEST_F(ProtobufUtilityTest, RedactAny) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: This field should be redacted because of its parent. + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 2). + - This field should be redacted because of its parent (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +sensitive_repeated_any: + - '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: This field should be redacted because of its parent (1 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 4). + - This field should be redacted because of its parent (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: This field should be redacted because of its parent (2 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (3 of 4). + - This field should be redacted because of its parent (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: This field should be redacted. + sensitive_repeated_string: + - This field should be redacted (1 of 2). + - This field should be redacted (2 of 2). + sensitive_int: 1 + sensitive_repeated_int: + - 1 + - 2 + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +insensitive_repeated_any: + - '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: This field should be redacted (1 of 2). + sensitive_repeated_string: + - This field should be redacted (1 of 4). + - This field should be redacted (2 of 4). + sensitive_int: 1 + sensitive_repeated_int: + - 1 + - 2 + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: This field should be redacted (2 of 2). + sensitive_repeated_string: + - This field should be redacted (3 of 4). + - This field should be redacted (4 of 4). + sensitive_int: 2 + sensitive_repeated_int: + - 3 + - 4 + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +sensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +sensitive_repeated_any: + - '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' + - '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 +insensitive_repeated_any: + - '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: 1 + insensitive_repeated_int: + - 1 + - 2 + - '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: 2 + insensitive_repeated_int: + - 3 + - 4 +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Empty `Any` can be trivially redacted. +TEST_F(ProtobufUtilityTest, RedactEmptyAny) { + ProtobufWkt::Any actual; + TestUtility::loadFromYaml(R"EOF( +'@type': type.googleapis.com/envoy.test.Sensitive +)EOF", + actual); + + ProtobufWkt::Any expected = actual; + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Messages packed into `Any` with unknown type URLs are skipped. +TEST_F(ProtobufUtilityTest, RedactAnyWithUnknownTypeUrl) { + ProtobufWkt::Any actual; + // Note, `loadFromYaml` validates the type when populating `Any`, so we have to pass the real type + // first and substitute an unknown message type after loading. + TestUtility::loadFromYaml(R"EOF( +'@type': type.googleapis.com/envoy.test.Sensitive +sensitive_string: This field is sensitive, but we have no way of knowing. +)EOF", + actual); + actual.set_type_url("type.googleapis.com/envoy.unknown.Message"); + + ProtobufWkt::Any expected = actual; + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Messages packed into `TypedStruct` should be treated the same as normal messages. Note that +// ints are quoted as strings here because that's what happens in the JSON conversion. +TEST_F(ProtobufUtilityTest, RedactTypedStruct) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +sensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: This field should be redacted because of its parent. + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 2). + - This field should be redacted because of its parent (2 of 2). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' +sensitive_repeated_typed_struct: + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: This field should be redacted because of its parent (1 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (1 of 4). + - This field should be redacted because of its parent (2 of 4). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: This field should be redacted because of its parent (2 of 2). + insensitive_repeated_string: + - This field should be redacted because of its parent (3 of 4). + - This field should be redacted because of its parent (4 of 4). + insensitive_int: '2' + insensitive_repeated_int: + - '3' + - '4' +insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: This field should be redacted. + sensitive_repeated_string: + - This field should be redacted (1 of 2). + - This field should be redacted (2 of 2). + sensitive_int: '1' + sensitive_repeated_int: + - '1' + - '2' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' +insensitive_repeated_typed_struct: + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: This field should be redacted (1 of 2). + sensitive_repeated_string: + - This field should be redacted (1 of 4). + - This field should be redacted (2 of 4). + sensitive_int: '1' + sensitive_repeated_int: + - '1' + - '2' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: This field should be redacted (2 of 2). + sensitive_repeated_string: + - This field should be redacted (3 of 4). + - This field should be redacted (4 of 4). + sensitive_int: '2' + sensitive_repeated_int: + - '3' + - '4' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: '2' + insensitive_repeated_int: + - '3' + - '4' +)EOF", + actual); + + TestUtility::loadFromYaml(R"EOF( +sensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +sensitive_repeated_typed_struct: + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_string: '[redacted]' + insensitive_repeated_string: + - '[redacted]' + - '[redacted]' +insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 2). + - This field should not be redacted (2 of 2). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' +insensitive_repeated_typed_struct: + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (1 of 4). + - This field should not be redacted (2 of 4). + insensitive_int: '1' + insensitive_repeated_int: + - '1' + - '2' + - type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: '[redacted]' + sensitive_repeated_string: + - '[redacted]' + - '[redacted]' + insensitive_string: This field should not be redacted. + insensitive_repeated_string: + - This field should not be redacted (3 of 4). + - This field should not be redacted (4 of 4). + insensitive_int: '2' + insensitive_repeated_int: + - '3' + - '4' +)EOF", + expected); + + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Empty `TypedStruct` can be trivially redacted. +TEST_F(ProtobufUtilityTest, RedactEmptyTypedStruct) { + udpa::type::v1::TypedStruct actual; + TestUtility::loadFromYaml(R"EOF( +type_url: type.googleapis.com/envoy.test.Sensitive +)EOF", + actual); + + udpa::type::v1::TypedStruct expected = actual; + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Messages packed into `TypedStruct` with unknown type URLs are skipped. +TEST_F(ProtobufUtilityTest, RedactTypedStructWithUnknownTypeUrl) { + udpa::type::v1::TypedStruct actual; + TestUtility::loadFromYaml(R"EOF( +type_url: type.googleapis.com/envoy.unknown.Message +value: + sensitive_string: This field is sensitive, but we have no way of knowing. +)EOF", + actual); + + udpa::type::v1::TypedStruct expected = actual; + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + +// Deeply-nested opaque protos (`Any` and `TypedStruct`), which are reified using the +// `DynamicMessageFactory`, should be redacted correctly. +TEST_F(ProtobufUtilityTest, RedactDeeplyNestedOpaqueProtos) { + envoy::test::Sensitive actual, expected; + TestUtility::loadFromYaml(R"EOF( +insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: This field should be redacted (1 of 4). + insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: This field should be redacted (2 of 4). +insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: This field should be redacted (3 of 4). + insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: This field should be redacted (4 of 4). +)EOF", + actual); + TestUtility::loadFromYaml(R"EOF( +insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: '[redacted]' + insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: '[redacted]' +insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + insensitive_any: + '@type': type.googleapis.com/envoy.test.Sensitive + sensitive_string: '[redacted]' + insensitive_typed_struct: + type_url: type.googleapis.com/envoy.test.Sensitive + value: + sensitive_string: '[redacted]' +)EOF", + expected); + MessageUtil::redact(actual); + EXPECT_TRUE(TestUtility::protoEqual(expected, actual)); +} + TEST_F(ProtobufUtilityTest, KeyValueStruct) { const ProtobufWkt::Struct obj = MessageUtil::keyValueStruct("test_key", "test_value"); EXPECT_EQ(obj.fields_size(), 1); diff --git a/test/common/secret/secret_manager_impl_test.cc b/test/common/secret/secret_manager_impl_test.cc index d11d93319a808..c31909a7fd880 100644 --- a/test/common/secret/secret_manager_impl_test.cc +++ b/test/common/secret/secret_manager_impl_test.cc @@ -515,9 +515,9 @@ name: "abc.com.stek" name: "abc.com.stek" session_ticket_keys: keys: - - filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ticket_key_a" - - inline_string: "[redacted]" + - filename: "[redacted]" - inline_string: "[redacted]" + - inline_bytes: "W3JlZGFjdGVkXQ==" )EOF"; checkConfigDump(TestEnvironment::substitute(updated_once_more_config_dump)); } @@ -691,58 +691,6 @@ name: "abc.com.nopassword" checkConfigDump(expected_config_dump); } -TEST_F(SecretManagerImplTest, ConfigDumpNotRedactFilenamePrivateKey) { - Server::MockInstance server; - auto secret_manager = std::make_unique(config_tracker_); - time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); - NiceMock secret_context; - envoy::config::core::v3alpha::ConfigSource config_source; - NiceMock local_info; - NiceMock dispatcher; - NiceMock random; - Stats::IsolatedStoreImpl stats; - NiceMock init_manager; - NiceMock init_watcher; - Init::TargetHandlePtr init_target_handle; - EXPECT_CALL(init_manager, add(_)) - .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { - init_target_handle = target.createHandle("test"); - })); - EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); - EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); - EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); - EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); - - const std::string tls_certificate = R"EOF( -name: "abc.com" -tls_certificate: - certificate_chain: - inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" - private_key: - inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" - password: - filename: "/etc/certs/password" -)EOF"; - envoy::extensions::transport_sockets::tls::v3alpha::Secret tls_cert_secret; - TestUtility::loadFromYaml(TestEnvironment::substitute(tls_certificate), tls_cert_secret); - secret_manager->addStaticSecret(tls_cert_secret); - const std::string expected_config_dump = R"EOF( -static_secrets: -- name: "abc.com" - secret: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3alpha.Secret - name: "abc.com" - tls_certificate: - certificate_chain: - inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" - private_key: - inline_string: "[redacted]" - password: - filename: "/etc/certs/password" -)EOF"; - checkConfigDump(expected_config_dump); -} - TEST_F(SecretManagerImplTest, ConfigDumpHandlerStaticValidationContext) { Server::MockInstance server; auto secret_manager = std::make_unique(config_tracker_); @@ -830,9 +778,9 @@ name: "abc.com.stek" name: "abc.com.stek" session_ticket_keys: keys: - - filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ticket_key_a" - - inline_string: "[redacted]" + - filename: "[redacted]" - inline_string: "[redacted]" + - inline_bytes: "W3JlZGFjdGVkXQ==" )EOF"; checkConfigDump(TestEnvironment::substitute(expected_config_dump)); } diff --git a/test/proto/BUILD b/test/proto/BUILD index 7af0abc86c222..3e058be5ec2c5 100644 --- a/test/proto/BUILD +++ b/test/proto/BUILD @@ -43,3 +43,12 @@ envoy_proto_descriptor( "well_known_protos", ], ) + +envoy_proto_library( + name = "sensitive_proto", + srcs = [":sensitive.proto"], + deps = [ + "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//udpa/type/v1:pkg", + ], +) diff --git a/test/proto/sensitive.proto b/test/proto/sensitive.proto new file mode 100644 index 0000000000000..aefa73973f8e2 --- /dev/null +++ b/test/proto/sensitive.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package envoy.test; + +option java_package = "io.envoyproxy.envoy.test"; +option java_outer_classname = "SensitiveProto"; +option java_multiple_files = true; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + +import "udpa/annotations/sensitive.proto"; +import "udpa/type/v1/typed_struct.proto"; + +message Sensitive { + string sensitive_string = 1 [(udpa.annotations.sensitive) = true]; + repeated string sensitive_repeated_string = 2 [(udpa.annotations.sensitive) = true]; + bytes sensitive_bytes = 3 [(udpa.annotations.sensitive) = true]; + repeated bytes sensitive_repeated_bytes = 4 [(udpa.annotations.sensitive) = true]; + int64 sensitive_int = 5 [(udpa.annotations.sensitive) = true]; + repeated int64 sensitive_repeated_int = 6 [(udpa.annotations.sensitive) = true]; + Sensitive sensitive_message = 7 [(udpa.annotations.sensitive) = true]; + repeated Sensitive sensitive_repeated_message = 8 [(udpa.annotations.sensitive) = true]; + google.protobuf.Any sensitive_any = 9 [(udpa.annotations.sensitive) = true]; + repeated google.protobuf.Any sensitive_repeated_any = 10 [(udpa.annotations.sensitive) = true]; + udpa.type.v1.TypedStruct sensitive_typed_struct = 11 [(udpa.annotations.sensitive) = true]; + repeated udpa.type.v1.TypedStruct sensitive_repeated_typed_struct = 12 + [(udpa.annotations.sensitive) = true]; + + string insensitive_string = 101; + repeated string insensitive_repeated_string = 102; + bytes insensitive_bytes = 103; + repeated bytes insensitive_repeated_bytes = 104; + int64 insensitive_int = 105; + repeated int64 insensitive_repeated_int = 106; + Sensitive insensitive_message = 107; + repeated Sensitive insensitive_repeated_message = 108; + google.protobuf.Any insensitive_any = 109; + repeated google.protobuf.Any insensitive_repeated_any = 110; + udpa.type.v1.TypedStruct insensitive_typed_struct = 111; + repeated udpa.type.v1.TypedStruct insensitive_repeated_typed_struct = 112; +} diff --git a/tools/check_format.py b/tools/check_format.py index 41ae732148e84..45e93aeb78a5c 100755 --- a/tools/check_format.py +++ b/tools/check_format.py @@ -46,6 +46,7 @@ # Files in these paths can use MessageLite::SerializeAsString SERIALIZE_AS_STRING_WHITELIST = ( "./source/common/config/version_converter.cc", + "./source/common/protobuf/utility.cc", "./source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc", "./test/common/protobuf/utility_test.cc", "./test/common/config/version_converter_test.cc", diff --git a/tools/protoxform/protoxform.py b/tools/protoxform/protoxform.py index 289110e88cdce..a1b79858dfa18 100755 --- a/tools/protoxform/protoxform.py +++ b/tools/protoxform/protoxform.py @@ -32,6 +32,7 @@ # Note: we have to include those proto definitions to make FormatOptions work, # this also serves as whitelist of extended options. from google.api import annotations_pb2 as _ +from udpa.annotations import sensitive_pb2 as _ from validate import validate_pb2 as _ from envoy.annotations import deprecation_pb2 as _ from envoy.annotations import resource_pb2 diff --git a/tools/spelling_dictionary.txt b/tools/spelling_dictionary.txt index 2ac972e539f64..47e48717a0bcc 100644 --- a/tools/spelling_dictionary.txt +++ b/tools/spelling_dictionary.txt @@ -510,6 +510,7 @@ dir dirname djb downcasted +downcasting downstreams dtor dubbo @@ -882,6 +883,8 @@ referer refetch regex regexes +reified +reify reimplements rele releasor @@ -893,6 +896,7 @@ repicked repo requirepass reselecting +reserialize reservable resize resized