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

Console fix up with mutual TLS #1402

Merged
merged 3 commits into from
Jul 12, 2024
Merged

Conversation

RafalKorepta
Copy link
Contributor

This PR is based on #1386 to solve early return problem in go template.

Client certificates does not relay on secret reference, that's why checks are removed.

Add integration test that setup mTLS for all listeners (Kafka, Admin API, HTTP Proxy, Schema Registry, RPC).

Verification in rpk client is not always done using rpk. curl should be replaced with port-forward and simple go based http client Get/Post/Delete implementation.

Fix ClientAuthRequired check as Dig function should start from listeners object.

Expose, in Redpanda values, Console config and chunk of Connectors values.

Mount all client certificates (ca, certificate and key) in Console deployment.

Move Admin API configuration from env vars to ConfigMap.

Reference

https://docs.redpanda.com/current/develop/http-proxy/

https://docs.redpanda.com/current/manage/schema-reg/schema-reg-api/

@RafalKorepta RafalKorepta requested a review from jan-g June 27, 2024 16:36
Copy link
Contributor

@chrisseto chrisseto left a comment

Choose a reason for hiding this comment

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

Not a full review will follow up on the test. Seems like we'll want to solve the subcharting problem soon.

@@ -89,7 +89,7 @@ func ClientCerts(dot *helmette.Dot) []certmanagerv1.Certificate {
panic(fmt.Sprintf("Certificate %q referenced but not defined", name))
}

if helmette.Empty(data.SecretRef) || !ClientAuthRequired(dot) {
if !ClientAuthRequired(dot) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I was a bit worried about this. We'll need to ask Azure (cc @c4milo or @ncole ) how they'd like to handle this.
For mTLS to work, the chart needs to be able to get a client certificate for either console or RPK (@RafalKorepta which is it?). This currently works through the cert manager integration but there's not really a fallback. If y'all can mint a cert we can find a field to add a secretRef to or we can talk through relying on the cert-manger integration either partially or fully.

Copy link

Choose a reason for hiding this comment

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

I'm not sure the context on this, but I think you're saying for mTLS we need a client cert. We are already creating a self-signed CA AND a client cert, so we can provide that ref somehow for Console (or RPK, whichever it is @RafalKorepta)?

In fact, in the other providers, if mTLS is enabled, we add a self-signed CA and a cert for kminion to use so we have an existing precedent for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For mTLS to work, the chart needs to be able to get a client certificate for either console or RPK (@RafalKorepta which is it?).

In this particular case, client certificate is used for both RPK and console. They will reference and mount the same certificate.

This currently works through the cert manager integration but there's not really a fallback. If y'all can mint a cert we can find a field to add a secretRef to or we can talk through relying on the cert-manger integration either partially or fully.

I agree, that this check needs to accommodate a use case when certificate is provided. I will change that check.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, that this check needs to accommodate a use case when certificate is provided. I will change that check.

Let's handle that in a follow up PR/commit?

return event, nil
}

func (c *Client) GetClusterHealth(ctx context.Context, dot *helmette.Dot) (map[string]any, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't love the idea of using *helmette.Dot here. If there's a bug in some of the Values functions that would surface here and potentially obscure issues from our tests, specifically in the case of TLS configurations.

I think it would be a more robust testing strategy to instead have the Client accept the TLS certificates (extracted from the cluster if using the cert-manger integration) and then use those to actually dial into the various listeners of the Pod, piggy backing on kubectl port-forward to actually make the connection. Then we can rely on client libraries instead of having to template out CLI commands.

For an initial implementation thought, let's roll with it!

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 will add certificate to the Client.

}

if values.Connectors.Enabled {
// TODO Do not cal Dig with dot.Values as restPort that is defined in connectors helm chart is not
Copy link
Contributor

Choose a reason for hiding this comment

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

I can think of ~2 ways we could handle this.

  1. Have a helmette function that runs a "raw" template command (Though it'll be quite difficult to get that to work reliably in go but perhaps that's okay. helmette.Raw("(include connectors.serviceName $var)")
  2. Teach gotohelm how to handle subcharts by resolving the name to the appropriate call but not actually transpile the underlying call.

Given that we'll need to convert the connectors and console chart, I'm leaning towards 2 but 1 would certainly be faster.

charts/redpanda/console.tpl.go Show resolved Hide resolved
charts/redpanda/helpers.go Show resolved Hide resolved
@@ -654,23 +661,14 @@ spec:
- name: kafka-default-cert
secret:
defaultMode: 272
items:
Copy link
Contributor

Choose a reason for hiding this comment

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

huh. Do you know where these diffs are stemming from? It seems incorrect for these to be removed. Could they just be out of date?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

urls:
- https://redpanda-0.redpanda.default.svc.cluster.local.:8081
- https://redpanda-1.redpanda.default.svc.cluster.local.:8081
- https://redpanda-2.redpanda.default.svc.cluster.local.:8081
tls:
caFilepath: /mnt/cert/kafka/default/ca.crt
certFilepath: ""
Copy link
Contributor

Choose a reason for hiding this comment

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

Are empty strings valid values of certFilepath and keyFilepath?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Console didn't complain and does not use cert nor key if it has empty string in the kafka, schema registry and admin API clinets.

@RafalKorepta RafalKorepta force-pushed the rk/K8S-261/mTLS-test-suite branch 3 times, most recently from 16a8c2d to 38b69a1 Compare July 9, 2024 21:45
@RafalKorepta
Copy link
Contributor Author

@RafalKorepta RafalKorepta marked this pull request as ready for review July 9, 2024 22:16
@RafalKorepta RafalKorepta force-pushed the rk/K8S-261/mTLS-test-suite branch 10 times, most recently from 942a159 to 9891e67 Compare July 11, 2024 15:20
Copy link
Contributor

@chrisseto chrisseto left a comment

Choose a reason for hiding this comment

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

This is quite a large PR again 😅 Let's try to get the for loop fix merged externally so we can cut down on the diff a bit.

I'm seeing some concerning looking diffs in the golden files. Do you think they're expected?

charts/redpanda/chart_test.go Outdated Show resolved Hide resolved

record, err := rpk.RetrieveEventFromTopic(ctx, httpTestTopic, 0)
require.NoError(t, err)
require.Equal(t, fmt.Sprintf("[{\"topic\":\"%s\",\"key\":null,\"value\":\"Redpanda\",\"partition\":0,\"offset\":0}]", httpTestTopic), record)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe use JSONEq here unless the key ordering form the proxy is guaranteed?
nit: Using backticks makes for much more readable JSON.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ordering form the proxy is guaranteed

Yes, it's guaranteed.

Using backticks makes for much more readable JSON.

I will use JSONEq here, so the object will be created as map[string]any

charts/redpanda/chart_test.go Outdated Show resolved Hide resolved
charts/redpanda/chart_test.go Outdated Show resolved Hide resolved
charts/redpanda/chart_test.go Outdated Show resolved Hide resolved
@@ -154,3 +158,80 @@ func (c *Ctl) Exec(ctx context.Context, pod *corev1.Pod, opts ExecOptions) error
Stdin: opts.Stdin,
})
}

func (c *Ctl) PortForward(ctx context.Context, pod *corev1.Pod, out, errOut io.Writer) ([]portforward.ForwardedPort, func(), error) {
// Apparently, nothing in the k8s SDK, except exec'ing, uses RESTClientFor.
Copy link
Contributor

Choose a reason for hiding this comment

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

Ugh, I remember hitting this issue way back. Most frequently I've seen people make an instance of the type client set which internally does something like this though it's split across 3 different packages if IIRC.


dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", req.URL())

var ports []string
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a huge fan of relying on the "portforwarding" abstraction because it binds to local ports for no reason which adds a bunch of extra goroutines and indirection but it's much easier to get started.

We can rip the guts out of https://github.com/kubernetes/client-go/blob/592d891671b2a09e5f81781b28ebe078d8115e41/tools/portforward/portforward.go#L335 to wrap this up into a Dialer interface that'll place nice with go's networking constructs which is a lot easier to utilize with other client libraries (http.RoundTripper for example).

That's a bigger change for later. Just leaving so notes for ourselves.

pkg/helm/helmtest/helmtest.go Outdated Show resolved Hide resolved
pkg/helm/helm.go Outdated Show resolved Hide resolved
@RafalKorepta RafalKorepta force-pushed the rk/K8S-261/mTLS-test-suite branch 5 times, most recently from b192503 to 65b0f78 Compare July 12, 2024 12:49
jan-g and others added 2 commits July 12, 2024 18:23
Console TLS configuration needs to have client certificates for mutual
TLS communication. With this commit Console go package is imported to
have strongly typed Console configuration. As Console configuration has
yaml annotation, not json transpiler is trying to parse yaml annotation
as a fallback.
@RafalKorepta RafalKorepta enabled auto-merge (rebase) July 12, 2024 17:31
@RafalKorepta RafalKorepta merged commit 62f8ec2 into main Jul 12, 2024
42 checks passed
@RafalKorepta RafalKorepta deleted the rk/K8S-261/mTLS-test-suite branch July 12, 2024 17:43
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.

None yet

4 participants