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

allow configuration of upstream TLS connection settings #5828

Merged
merged 35 commits into from
Dec 20, 2023

Conversation

KauzClay
Copy link
Contributor

@KauzClay KauzClay commented Oct 11, 2023

Just as you can configure TLS settings for downstream connections, like setting min/max TLS versions and cipher suites, you should be able to do that for upstream connections too.

For upstream connections, I would like the default Max TLS version to be 1.3, instead of the current Envoy default of 1.2

release-note/minor

Fixes #5501
Fixes #3574

@KauzClay KauzClay requested a review from a team as a code owner October 11, 2023 21:16
@KauzClay KauzClay requested review from skriss and sunjayBhatia and removed request for a team October 11, 2023 21:16
@tsaarni
Copy link
Member

tsaarni commented Oct 12, 2023

Hi @KauzClay 👋 Linking some previous discussions related to upstream TLS just for reference info: #5501, #5666

@KauzClay
Copy link
Contributor Author

KauzClay commented Oct 12, 2023

@sunjayBhatia , it is still pretty rough, but I've attempted to wire everything up for this new configuartion.

One question though: how do I enforce defaults for min and max TLS version in CRD and the ConfigMap? I would like the Contour default for max version to be different than Envoy's default.

EDIT: I ended up just sticking the default max in the code where the creation of UpstreamTLSContext happens

@KauzClay KauzClay force-pushed the ck-upstream-tls-config branch 2 times, most recently from 069fd5f to 1fc65cd Compare October 13, 2023 14:24
@sunjayBhatia sunjayBhatia added the release-note/minor A minor change that needs about a paragraph of explanation in the release notes. label Oct 13, 2023
@KauzClay
Copy link
Contributor Author

/test test-linux

@codecov
Copy link

codecov bot commented Oct 13, 2023

Codecov Report

Attention: 5 lines in your changes are missing coverage. Please review.

Comparison is base (eece587) 78.69% compared to head (c7dddae) 78.70%.
Report is 15 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #5828   +/-   ##
=======================================
  Coverage   78.69%   78.70%           
=======================================
  Files         138      138           
  Lines       19687    19717   +30     
=======================================
+ Hits        15493    15518   +25     
- Misses       3890     3895    +5     
  Partials      304      304           
Files Coverage Δ
cmd/contour/servecontext.go 83.84% <100.00%> (+0.18%) ⬆️
internal/contourconfig/contourconfiguration.go 98.18% <100.00%> (+0.05%) ⬆️
internal/dag/dag.go 98.70% <ø> (ø)
internal/dag/extension_processor.go 95.90% <100.00%> (+0.03%) ⬆️
internal/dag/httpproxy_processor.go 91.92% <100.00%> (+0.01%) ⬆️
internal/dag/ingress_processor.go 97.60% <100.00%> (+<0.01%) ⬆️
internal/envoy/v3/auth.go 100.00% <100.00%> (ø)
internal/envoy/v3/cluster.go 96.36% <100.00%> (+0.04%) ⬆️
internal/featuretests/v3/envoy.go 99.08% <100.00%> (+<0.01%) ⬆️
pkg/config/parameters.go 86.39% <100.00%> (+0.32%) ⬆️
... and 1 more

... and 2 files with indirect coverage changes

@KauzClay KauzClay changed the title [wip] allow configuration of upstream TLS connection settings allow configuration of upstream TLS connection settings Oct 13, 2023
Copy link
Member

@tsaarni tsaarni left a comment

Choose a reason for hiding this comment

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

Added some comments inline, but looks good to me in general!

I think it would be good to have some reasoning here about the corner cases that have led Envoy not to enable TLSv1.3 for upstream, and why it is OK for Contour to do so - something that answers to #5666 (review)

One more thought: It would be nice to have e2e test for the protocol version. The echoserver used for e2e suite returns a JSON response that includes the negotiated TLS version (see here). We could check that TLSv1.3 gets returned. Check test/e2e/httpproxy/backend_tls_test.go on similar assertion checks done for the response. In responseTLSDetails the client certificate was parsed from response document and compared to what we had configured.

cmd/contour/serve.go Outdated Show resolved Hide resolved
pkg/config/parameters.go Outdated Show resolved Hide resolved
internal/envoy/v3/cluster.go Outdated Show resolved Hide resolved
changelogs/unreleased/5828-KauzClay-minor.md Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Nov 7, 2023

The Contour project currently lacks enough contributors to adequately respond to all PRs.

This bot triages PRs according to the following rules:

  • After 14d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, the PR is closed

You can:

  • Mark this PR as fresh by commenting or pushing a commit
  • Close this PR
  • Offer to help out with triage

Please send feedback to the #contour channel in the Kubernetes Slack

@github-actions github-actions bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Nov 7, 2023
@skriss skriss removed the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Nov 7, 2023
@KauzClay
Copy link
Contributor Author

@sunjayBhatia @tsaarni looks like the tests are passing now, thanks for your feedback so far.

I tried linking the upstream tls config into extension services and dnsservices as well, but I'm not so sure I got it correct. I'd appreciate if you all took a closer look in that area next time you look through this 🙇

@@ -1026,6 +1030,7 @@ func (p *HTTPProxyProcessor) computeRoutes(
SlowStartConfig: slowStart,
MaxRequestsPerConnection: p.MaxRequestsPerConnection,
PerConnectionBufferLimitBytes: p.PerConnectionBufferLimitBytes,
UpstreamTLS: determineUpstreamTLS(p.UpstreamTLS),
Copy link
Member

Choose a reason for hiding this comment

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

Just an observation about small inconsistency:

It seems we have previously in some cases avoided setting TLS parameters if TLS is not used by upstream in the first place: Cluster.UpstreamValidation is set to nil. We also have set TLS parameters unconditionally: Cluster.SNI will be set even if TLS is not used. Now Cluster.UpstreamTLS will also be set even if cluster.Protocol is not implying TLS.

Just setting the values unconditionally can be seen as simplification of the logic here. In reality the TLS parameters are ignored later in internal/envoy/v3/cluster.go when constructing envoy.Cluster when Cluster.protocol does not indicate TLS. So at the end, it does not matter if Cluster is filled in with TLS settings, even when TLS is not used.

internal/envoy/v3/cluster.go Show resolved Hide resolved
internal/envoy/v3/cluster.go Show resolved Hide resolved
@@ -429,6 +429,9 @@ type ClusterParameters struct {
//
// +optional
PerConnectionBufferLimitBytes *uint32 `yaml:"per-connection-buffer-limit-bytes,omitempty"`

// UpstreamTLS contains the TLS policy parameters for upstream connections
UpstreamTLS TLSParameters `yaml:"upstream-tls,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Should we avoid reusing the TLSParameters struct here since it contains some parameters that can be meaningful only for downstream or upstream TSL?

For example field TLSParameters.FallbackCertificate is used as server certificate, which appears as configuration file field tls.fallback-certificate. When reusing the struct for upstream, it could be also defined as cluster.upstream-tls.fallback-certificate according purely to syntax, but if defined there, it would be ignored.

Similarly, config file field tls.envoy-client-certificate is used as optional client cert in upstream TLS. Reusing the struct would mean field cluster.upstream-tls.envoy-client-certificate is syntactically correct, but actually it will not get used.

Copy link
Contributor Author

@KauzClay KauzClay Dec 8, 2023

Choose a reason for hiding this comment

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

hmmm I see. I went with TLSParameters originally because it had what I needed and I didn't want to create a similar-but-not-quite-the-same struct.

What would you say to creating a new struct that just contains {MinimumProtocolVersion,MaximumProtocolVersion,CipherSuites}, and then making that struct a part of TLSParameters?

Then cluster.upstream-tls would only contain options that can actually be used.

Copy link
Member

Choose a reason for hiding this comment

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

👍 that sounds good to me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I ended up creating a new smaller struct called ProtocolParameters. I can always change it if you think a different name is better

// UpstreamTLS contains the TLS policy parameters for upstream connections
//
// +optional
UpstreamTLS *EnvoyTLS `json:"upstream-tls,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Question: What do people prefer: nesting TLS config in ContourConfiguration.spec.envoy.cluster.upstream-tls (like suggested here) or bumping it one level ContourConfiguration.spec.envoy.upstream-tls?

Maybe bit unfortunate but there is existing upstream TLS parameter directly under ContourConfiguration.spec.envoy, which is clientCertificate. It's bit unfortunate that the upstream TLS settings will be split in two places, but hopefully not too far from each other.

The corresponding downstream TLS setting is ContourConfiguration.spec.envoy.listener.tls. I guess perfect symmetry across TLS settings is not achievable anymore, not even in CRD config which was the fresh start :)

Copy link
Member

Choose a reason for hiding this comment

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

Given dowstream TLS settings are nested under envoy.listener, I think putting upstream settings under envoy.cluster is logical.

Re: clientCertificate -- the CRD is still v1alpha1, so we could make a breaking change if we wanted to reorganize. Seems like moving clientCertificate into UpstreamTLS might make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could move clientCertificate into UpstreamTLS. OR would you prefer that be in a separate MR?

Copy link
Member

Choose a reason for hiding this comment

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

Let's hold off for now to see what others think about that change, we can do it in a separate PR if we decide to proceed.

Copy link
Member

Choose a reason for hiding this comment

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

+1 for keeping it under cluster

apis/projectcontour/v1alpha1/contourconfig.go Outdated Show resolved Hide resolved
// UpstreamTLS contains the TLS policy parameters for upstream connections
//
// +optional
UpstreamTLS *EnvoyTLS `json:"upstream-tls,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Given dowstream TLS settings are nested under envoy.listener, I think putting upstream settings under envoy.cluster is logical.

Re: clientCertificate -- the CRD is still v1alpha1, so we could make a breaking change if we wanted to reorganize. Seems like moving clientCertificate into UpstreamTLS might make sense?

KauzClay and others added 2 commits December 8, 2023 13:27
* change json key style
* re-run make generate

Co-authored-by: Steve Kriss <[email protected]>

Signed-off-by: Clay Kauzlaric <[email protected]>
Namespace: namespace,
}
})
Context("with backend tls version configured via Contour ConfigMap", func() {
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 can combine these two contexts (configmap and contourconfig-specific wrappers) and just set the same options in the BeforeEach just as we do here:

BeforeEach(func() {
contourConfig.EnableExternalNameService = true
contourConfiguration.Spec.EnableExternalNameService = ref.To(true)
})

we have different test runs for using each type of config so we should only need one instance of the test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay I combined them into 1 before each. Does it look how you're imagining now?

Copy link
Member

@sunjayBhatia sunjayBhatia left a comment

Choose a reason for hiding this comment

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

Functionality looks good and change overall looks good modulo whatever existing nits there are and questions about API types

Once those are resolved I'm good to go with this change 👍🏽

changelogs/unreleased/5828-KauzClay-minor.md Outdated Show resolved Hide resolved
internal/dag/extension_processor.go Outdated Show resolved Hide resolved
internal/dag/httpproxy_processor.go Outdated Show resolved Hide resolved
@@ -429,6 +429,9 @@ type ClusterParameters struct {
//
// +optional
PerConnectionBufferLimitBytes *uint32 `yaml:"per-connection-buffer-limit-bytes,omitempty"`

// UpstreamTLS contains the TLS policy parameters for upstream connections
UpstreamTLS TLSParameters `yaml:"upstream-tls,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

👍 that sounds good to me

Signed-off-by: Clay Kauzlaric <[email protected]>
* because the two structs are identical, we can cast between them apparently

Signed-off-by: Clay Kauzlaric <[email protected]>
pkg/config/parameters.go Outdated Show resolved Hide resolved
@skriss
Copy link
Member

skriss commented Dec 15, 2023

I'll take another pass today but I think this is looking pretty good

Copy link
Member

@skriss skriss left a comment

Choose a reason for hiding this comment

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

Sorry, a couple last things, but I think that's it from me.

cmd/contour/serve.go Show resolved Hide resolved
internal/featuretests/v3/upstreamprotocol_test.go Outdated Show resolved Hide resolved
Copy link
Member

@skriss skriss left a comment

Choose a reason for hiding this comment

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

This LGTM, will leave for another maintainer to take another pass, thanks @KauzClay!

Copy link
Member

@tsaarni tsaarni 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 to me too! Just one more small request. If I'm not mistaken, I think we can avoid the typecasts to dag.UpstreamTLS

cmd/contour/serve.go Outdated Show resolved Hide resolved
* gets rid of need to typecast

Signed-off-by: Clay Kauzlaric <[email protected]>
@skriss
Copy link
Member

skriss commented Dec 20, 2023

Looks like we're good to merge here, thanks @KauzClay! Will merge later today.

@skriss skriss merged commit b57fa06 into projectcontour:main Dec 20, 2023
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note/minor A minor change that needs about a paragraph of explanation in the release notes.
Projects
None yet
4 participants