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

add TLS testing #150

Merged
merged 29 commits into from
Feb 21, 2023
Merged

add TLS testing #150

merged 29 commits into from
Feb 21, 2023

Conversation

tobert
Copy link
Collaborator

@tobert tobert commented Feb 3, 2023

Synopsis

This PR adds TLS testing capability to otel-cli's functional test harness, and to
make sure that functionality was complete enough to merge, I also added
client certificate authentication support. These are bundled because
I fixed some problems in otel-cli's TLS handling along the way. Hopefully this
will be the last big PR for a while. While on the large side of things, the bulk
of this code is the new TLS CA and tests.

Client Authentication

otel-cli can now directly authenticate to a server using a client certificate.
While this may have worked before via opentelemetry-go environment variables, we
could not call it a supported feature while not testing it, and not making it
work consistently with other otel-cli features (config & flags).

The new flags have been added with envvars and json keys. (note: I opened issue
#164 with a follow-up to fix the json keys): --tls-ca-cert,
--tls-client-cert, and --tls-client-key.

--no-tls-verify is now deprecated and renamed to --tls-no-verify so the
prefix usage is consistent.

TLS Testing Design

Building on the existing functional tests, tls_for_test.go has been added, and
implements an ephemeral self-signed certificate authority. It generates
everything needed for the client and server side to run tests with full TLS.
It's fast enough I barely notice the difference compared to exec'ing otel-cli a
bunch. New template variables are available for test fixtures to inject
certificate and key files. When the OTLP HTTP and gRPC servers start, they will
optionally enable TLS and client cert auth as configured on the fixture.

Amy Tobey added 3 commits February 2, 2023 18:19
Adds the first pass at TLS helpers and integration with tests.

https works now, grpc does not and needs more work
Amy Tobey added 4 commits February 3, 2023 10:22
There's still more work to do. --no-tls-verify does not seem to work as
expected and that needs figuring out and tested.

Also need to add tests for client cert authentication.

But this all works and the certs generated seem valid.

Added diagnistic for no-tls-verify.

Added setting a cacert in the root bundle in otel-cli. Need to
double-check this is the right behavior to ship.

Cacert config needs to be added to HTTPs as well if ^^ turns up as the
behavior being correct.
otelcli/root.go Outdated
@@ -67,6 +67,10 @@ func addClientParams(cmd *cobra.Command) {
cmd.Flags().StringToStringVar(&config.Headers, "otlp-headers", defaults.Headers, "a comma-sparated list of key=value headers to send on OTLP connection")
cmd.Flags().BoolVar(&config.Blocking, "otlp-blocking", defaults.Blocking, "block on connecting to the OTLP server before proceeding")

cmd.Flags().StringVar(&config.Certificate, "cacert", defaults.Certificate, "a file containing the server's CA certificate")
cmd.Flags().StringVar(&config.ClientCert, "client-cert", defaults.ClientCert, "a file containing the client certificate")
cmd.Flags().StringVar(&config.ClientKey, "client-key", defaults.ClientKey, "a file containing the client certificate key")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

^^ need feedback on these. Do they look ok? Should there be a set of --tls-* options?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's dealer's choice if these should have a tls- prefix. personally, I view adding a prefix now as more future-proof because over time we're likely to see more, not fewer, cli options, and we're probably not going to go back and change these, once committed, so we might as well make them explicit now. On the other hand, the flags that we add in future are unlikely to be cert related, so maybe the prefix is implied and we can skip it. Characters aren't too expensive (even in cli options) so i've talked myself into adding the prefix, but I don't see it as a major UX/comprehensibility issue either way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I made the change, it looks better this way:

      --tls-ca-cert string            a file containing the certificate authority bundle
      --tls-client-cert string        a file containing the client certificate
      --tls-client-key string         a file containing the client certificate key
      --tls-no-verify                 insecure! disables verification of the server certificate and name, mostly for self-signed CAs
      --no-tls-verify                 (deprecated) same as --tls-no-verify

otelcli/plumbing.go Outdated Show resolved Hide resolved
tls_for_test.go Show resolved Hide resolved
Amy Tobey added 16 commits February 14, 2023 18:28
On the first pass of this code I wasn't sure what all I would need,
so I put all the intermediate steps of the CA and certs in the
struct. Now that some tests are running, it's clear some things
don't need to be there and the code looks cleaner this way.
They were out of sync and it was silly to copy the code
in this case. 🤔 and now it can be tested independently.
SubjectKeyId shouldn't have been there in the first place, I
copied it and didn't trim it back. The IPAddresses doesn't seem
to have an impact on removal so removing it too.

The TLS config setups for server and client were both wrong.
They shouldn't have had RootCAs set. Setting ServerName seems to have
helped to get HTTP TLS working (but grpc still doesn't). Also setting
ClientCAs on the server for when we start testing client cert auth.
See comment for explanation of bewilderment.
The way the tests passed before wasn't ideal but was good enough
to call the approach to testing viable. Now that the TLS configs
are sorted out, the tests pass under --no-tls-verify and further
commits will add tests back for envvar and client auth.
Renamed config struct member to CACert.

Made config file names match the opentelemetry collector yaml,
for better or worse.

Added TLS settings to the example config.
In the first pass I built up the CA and certs according to my
outdated knowledge of building CAs with openssl and examples.
Since Go doesn't really care much about a lot of the cert metadata
I went through and stripped out as many superfluous fields as I
could and keep tests passing. Less code is good :)
@tobert tobert marked this pull request as ready for review February 15, 2023 20:18
@tobert tobert requested a review from edw-eqix February 15, 2023 20:18
// injectVars replaces all instances of {{endpoint}}, {{cacert}}, {{client_cert}}, and
// {{client_key}} with test values.
// This is needed because the otlpserver is configured to listen on :0 which has it
// grab a random port. Once that's generated we need to inject it into all the values
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: it would be slightly clearer to say:

Once generated, we need to inject the port into all the values so the test comparisons...

edw-eqix
edw-eqix previously approved these changes Feb 15, 2023
Copy link
Contributor

@edw-eqix edw-eqix left a comment

Choose a reason for hiding this comment

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

LGTM, discussion topics are non-blocking for commit

otelcli/root.go Outdated
@@ -67,6 +67,10 @@ func addClientParams(cmd *cobra.Command) {
cmd.Flags().StringToStringVar(&config.Headers, "otlp-headers", defaults.Headers, "a comma-sparated list of key=value headers to send on OTLP connection")
cmd.Flags().BoolVar(&config.Blocking, "otlp-blocking", defaults.Blocking, "block on connecting to the OTLP server before proceeding")

cmd.Flags().StringVar(&config.Certificate, "cacert", defaults.Certificate, "a file containing the server's CA certificate")
cmd.Flags().StringVar(&config.ClientCert, "client-cert", defaults.ClientCert, "a file containing the client certificate")
cmd.Flags().StringVar(&config.ClientKey, "client-key", defaults.ClientKey, "a file containing the client certificate key")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's dealer's choice if these should have a tls- prefix. personally, I view adding a prefix now as more future-proof because over time we're likely to see more, not fewer, cli options, and we're probably not going to go back and change these, once committed, so we might as well make them explicit now. On the other hand, the flags that we add in future are unlikely to be cert related, so maybe the prefix is implied and we can skip it. Characters aren't too expensive (even in cli options) so i've talked myself into adding the prefix, but I don't see it as a major UX/comprehensibility issue either way.

Comment on lines +7 to +9
* Do NOT copy this code for production systems. It makes a few compromises to
* optimize for testing and ephemeral certs that are totally inappropriate for
* use in settings where security matters.
Copy link
Contributor

Choose a reason for hiding this comment

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

is there any way to make this more forceful than a comment?
off the top of my head, perhaps some kind of output from the module that would flag the issue to an end user?
or maybe also add code comments that point out the specific compromises a cargo-cult-er needs to change?
and the last thought was adding some kind of friction here to make it hard to misuse, though I have no concrete ideas on how to go about that.

Copy link
Contributor

Choose a reason for hiding this comment

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

oh and one last thought was to add something akin to a comment in the output files so that anyone viewing their contents would investigate and find the comments in code

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since it's in the main_test package it can't be directly used as a dependency and doesn't ship with the otel-cli binary. Someone would have to copy the file and modify it, or copy/paste to reuse the code, so risk is pretty low. I mostly wanted to say something and leave it as an exercise to the reader to figure out those compromises.

Amy Tobey added 3 commits February 15, 2023 18:18
Per code review, I'm convinced that all the tls options should start
with --tls for clarity so they've been renamed.

--no-tls-verify has been renamed to --tls-no-verify. The old option is
still supported but will be removed before 1.0.
No idea how this was so very wrong. Fixed now :)
@tobert tobert mentioned this pull request Feb 21, 2023
@tobert tobert merged commit 9a7de86 into main Feb 21, 2023
@tobert tobert deleted the tls-testing branch February 21, 2023 23:45
This was referenced Feb 21, 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.

2 participants