Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EXPORTER] OTLP GRPC mTLS support #2120

Merged
merged 9 commits into from
Jun 29, 2023

Conversation

kylepl
Copy link
Contributor

@kylepl kylepl commented Apr 25, 2023

Fixes #1785

Changes

Please provide a brief description of the changes here.

For significant contributions please make sure you have completed the following items:

  • CHANGELOG.md updated for non-trivial changes
  • Unit tests have been added
  • Changes in public API reviewed

@kylepl kylepl requested a review from a team April 25, 2023 17:59
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Apr 25, 2023

CLA Signed

The committers listed above are authorized under a signed CLA.

@@ -6,13 +6,44 @@
#include "opentelemetry/exporters/otlp/otlp_environment.h"

#include <memory>
// TODO: These requires C++17, is that OK? It seems like we need to support C++0x?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need support c++11. You can use absl::variant and absl::optional for alternative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


// TODO: Check if this strong-typing is ok. It seems nice, and allows variant typing.
struct FilePath {
std::string value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd better use nostd::string_view here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just note that the existing options in OtlpGrpcExporterOptions all use std::string, hence why I used that. If this should be different, so be it - just checking before changing it.

@owent
Copy link
Member

owent commented Apr 26, 2023

The trace is already stable. I think we need discuss this approch because it break the API and also we need it to support environment variables in specification.

@lalitb
Copy link
Member

lalitb commented Apr 26, 2023

@kylepl Thanks for working on this. You can also go through #1793, as this provides support for client-side cert/key for OTLP HTTP exporter.

@kylepl
Copy link
Contributor Author

kylepl commented Apr 26, 2023

Thanks for the comments!

Based on my understanding of Stable, compilation breakages are not allowed except for major version changes (reasonable). Is it reasonable to still make things compatible, but mark ssl_credentials_cacert_path and ssl_credentials_cacert_as_string as deprecated? It's not quite obvious to me what needs to ABI compatible (i.e. I don't know what gets shipped by itself).

Supporting the environment variables sounds good to me, can do so.

Also, a related thing related to what I'm interested in - is gRPC actually has experimental support refreshing certificates every X seconds from disk. If that seems reasonable, while it could be a separate PR, given it may effect the API, it may be worth discussing now.

And of course feel free to give me your opinions on style and such, once we agree on the high-level, I'll take another pass on the code:

  • If it is reasonable to have the ssl credentials held in a sub-struct (to group them together), and thus somehow mark ssl_credentials_cacert_path and ssl_credentials_cacert_as_string - while still supporting them.
  • If supporting auto-refresh of certificates seems reasonable (it is an experimental gRPC feature, we could add a field called "experimental_enable_auto_refresh" to signify that.

@codecov
Copy link

codecov bot commented May 3, 2023

Codecov Report

Merging #2120 (1eec89b) into main (d0452f8) will decrease coverage by 0.02%.
The diff coverage is n/a.

❗ Current head 1eec89b differs from pull request most recent head ab7c455. Consider uploading reports for the commit ab7c455 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2120      +/-   ##
==========================================
- Coverage   87.53%   87.50%   -0.02%     
==========================================
  Files         169      169              
  Lines        4889     4888       -1     
==========================================
- Hits         4279     4277       -2     
- Misses        610      611       +1     

see 2 files with indirect coverage changes

@lalitb
Copy link
Member

lalitb commented May 3, 2023

@kylepl Why do we want to deprecate the existing members - ssl_credentials_cacert_path and ssl_credentials_cacert_as_string. These are for server-side auth, and can remain there. Can't we just add the new members to OtlpGrpcExporterOptions for client-side auth ? Sorry if I am missing something here.

@kylepl
Copy link
Contributor Author

kylepl commented May 3, 2023

@lalitb Just to be precise, and is likely what you mean, ssl_credentials_cacert_{path|as_string} are specified by the client as the root certificates to validate the server.

There are few pieces to the change:

  • I think it is useful to group related options together into sub-structs to show what is related, and to avoid an unwieldy top-level struct. Thus the thinking was to group client-side cert, key and root certs (for authenticating the server). This is what gRPC does too.
  • I personally like more type-safe objects - hence using a single field as either a file or string contents. This avoids the need to just have a comment that only one is respected - there is no way to specify both.

But, there is a cost of changing what is already there even if we did agree on what to do if this was entirely new code. Thus my proposal is to support the new format and the old format, with a deprecation warning - but this is where I defer to everyone on what makes sense.

So if you want the two existing options to remain where they are, and potentially just have SSLOptions but without the root certs, that's also fine, just not quite as ideal IMO long-term - but everything is trade-offs. :)

@kylepl
Copy link
Contributor Author

kylepl commented May 3, 2023

I've switched to using absl::variant/optional, thus the compilation should be fixed for earlier versions.

@@ -17,7 +16,7 @@ namespace otlp
{

// This type allows the variants to be default-constructed to neither type.
// This avoids needing deeper template if std::optional<std::variant<>>.
// This avoids needing deeper template if absl::optional<absl::variant<>>.
struct Unset {};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: This is what nostd::monostate is for, remove this,

@marcalff
Copy link
Member

@kylepl

First, thanks for picking this up, support for mTLS in the gRPC exporter is
long overdue.

Please find here some comments and guidance.

struct OtlpGrpcExporterOptions

The ca_cert is already implemented with ssl_credentials_cacert_path and
ssl_credentials_cacert_as_string, so these should not change unfortunately.

For the client cert and key, please use a flat structure, with different
members for the path or string options.

Using a std::variant is technically correct, and more type safe, but it
causes additional complexity to use the interface itself, and the pattern is
different from the HTTP exporter.

Please follow the pattern from struct OtlpHttpExporterOptions, for
consistency.

In the long term, configurations using environment variables is going to be
replaced by configuration using a yaml file, with a different structure, per
OTEP 225:

When this change is implemented for all opentelemetry repositories, the
options struct in opentelemetry-cpp will probably be revisited then.

For now, consistency with the existing HTTP pattern will avoid too many intermediate changes.

Environment variables

struct OtlpGrpcExporterOptions should by default read environment variables,
so that configuration options are honored.

Please call:

  • GetOtlpDefaultTracesSslClientKeyPath();
  • GetOtlpDefaultTracesSslClientKeyString();
  • GetOtlpDefaultTracesSslClientCertificatePath();
  • GetOtlpDefaultTracesSslClientCertificateString();

Likewise, see struct OtlpHttpExporterOptions.

CMake

This is a new feature, so it needs a CMake option, for optional adoption.

Something like:

  • CMake option WITH_OTLP_GRPC_SSL_MTLS_PREVIEW
  • define ENABLE_OTLP_GRPC_SSL_MTLS_PREVIEW

See existing options for the OTLP HTTP exporter.

In the implementation:

  • it is ok to require a recent gRPC version if mTLS support is required
  • it is not ok to require a recent gRPC version if mTLS support is not
    required.

In other words, the code should still build with old gRPC libraries,
with the understanding that mTLS will not be available then.

See build failures in CI related to gcc 4.8 with a very old gRPC library, it
should still build.

C++11 support, and support for old libraries, will go away over time, but for
now these old builds should still be functional for existing features.

Unit tests

For unit tests for the option struct itself, see file
otlp_grpc_exporter_test.cc.

Examples of units tests for the HTTP exporter can be found in file
otlp_http_exporter_test.cc.

Functional tests

See functional/otlp for existing OTLP HTTP functional tests.

Either in the same PR, or in subsequent work, functional tests talking to an
opentelemetry collector using the OTLP GRPC exporter can be implemented the
same way.

@marcalff marcalff changed the title Add support for client-side cert/key to gRPC exports. [EXPORTER] Add support for client-side cert/key to gRPC exports. May 26, 2023
@marcalff
Copy link
Member

@kylepl

Please confirm if you are still working on this.

The following link contains comments and guidance about how to implement this change, in case you missed it.

Thanks.

TODO: Add tests.

I have not run or written any tests, other than verifying it worked once
in my production system.
@kylepl
Copy link
Contributor Author

kylepl commented Jun 21, 2023

Apologies for the long delay. I've taken another pass - doing everything except for the tests - which I can do once this LGTY.

@kylepl
Copy link
Contributor Author

kylepl commented Jun 21, 2023

There were a number of failures - I think because of the unnecessary variant/optional include. I've removed them, so hopefully the bazel versions pass now.

For formatting, is there a script I should run to do the auto-formatting?

Also, I wasn't sure if the thumbs-up meant review seemed reasonable, but I'll wait for an explicit comment before doing the tests. :)

"SSL" to the mTLS macros since evenetually there will be something named
TLS on the gRPC side.
@kylepl
Copy link
Contributor Author

kylepl commented Jun 22, 2023

And I've put in one more fix for Windows not liking initializer lists for structs.

Should just be the formatting errors to resolve (once I know what to run for it).

Copy link
Member

@marcalff marcalff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylepl

Thanks for the PR, this is looking much better already.

Right now, the build fails (to fix), and does not use the new MTLS_PREVIEW option anyway.

Please look for:

        -DWITH_OTLP_HTTP_SSL_PREVIEW=ON \
        -DWITH_OTLP_HTTP_SSL_TLS_PREVIEW=ON \

in file ci/do_ci.sh,

and add both WITH_OTLP_GRPC and WITH_OTLP_GRPC_SSL_MTLS_PREVIEW at the same places, to have some CI coverage of the new code.

@marcalff
Copy link
Member

To fix format errors, run clang-format version 10.

See docs/using-clang-format.md

@kylepl
Copy link
Contributor Author

kylepl commented Jun 23, 2023

I've done clang-format on the .cc/.h files, and enabled this path in the CI.

@kylepl
Copy link
Contributor Author

kylepl commented Jun 23, 2023

I've done another pass of fixing format errors.

There are also now failures about gRPC inputs not being included, I think because more options must be specified - but I'm not sure what exactly needs to be copied over (seems like a lot?). e.g.

  grpc_cpp_plugin=`which grpc_cpp_plugin`
  proto_make_file="CMakeFiles/opentelemetry_proto.dir/build.make"
  sed -i "s~gRPC_CPP_PLUGIN_EXECUTABLE-NOTFOUND~$grpc_cpp_plugin~" ${proto_make_file} #fixme

@marcalff
Copy link
Member

@kylepl

I've done another pass of fixing format errors.

There are also now failures about gRPC inputs not being included, I think because more options must be specified - but I'm not sure what exactly needs to be copied over (seems like a lot?). e.g.

Indeed, a lot more setup is needed beside just adding WITH_OTLP_GRPC.

This was bad guidance from me, sorry about that.

Let's revert this changes to do_ci.sh, and instead, add WITH_OTLP_GRPC_SSL_MTLS_PREVIEW to only cmake.exporter.otprotocol.test then.

This should be simpler as the GRPC setup is already done for this build.

@kylepl
Copy link
Contributor Author

kylepl commented Jun 26, 2023

No worries, done.

Copy link
Member

@owent owent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and thanks.

Copy link
Member

@lalitb lalitb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks for the contribution.
Perhaps as separate PR, we can add the functional tests for validating OTLP gRPC with client certificate chain + Server ca certificate.
Ref- https://github.com/open-telemetry/opentelemetry-cpp/tree/main/functional/otlp

Copy link
Member

@marcalff marcalff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, thanks for the contribution.

@kylepl

If you want to continue working in this area, feel free to pick

@marcalff marcalff changed the title [EXPORTER] Add support for client-side cert/key to gRPC exports. [EXPORTER] OTLP GRPC mTLS support Jun 29, 2023
@marcalff marcalff merged commit 049ab63 into open-telemetry:main Jun 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[EXPORTER] OTLP GRPC mTLS support
4 participants