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

RFC for mTLS #110

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

RFC for mTLS #110

wants to merge 1 commit into from

Conversation

david-martin
Copy link
Member

Follow on from investigation in Kuadrant/kuadrant-operator#1049 and a possible automated way to enable and manage mTLS for users instead of the manual documented way in Kuadrant/kuadrant-operator#1054

Signed-off-by: David Martin <[email protected]>

When enabled for a specific component, the following changes are performed by the kuadrant-operator and/or component operators. This may require trickling down configuration to other operator resources, like the Authorino or Limitador resources:

## Enabling the Istio sidecar proxy in that component
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably add a section for Envoy Gateway as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know what to add for that.
The Istio approach takes advantage of Istio sidecar capabilities to enable mTLS in the kuadrant pods.
If Istio isn't there, would that be some other solution outside of Envoy Gatway completely?

Comment on lines +30 to +32
mtls:
authorino: true
limitador: true
Copy link
Contributor

Choose a reason for hiding this comment

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

Although this could work for a first implementation, I wonder if it's clear to the user that the certs will be provisioned via Secret discovery service (SDS).

I can also see how non-mesh users could want this but by configuring certs by other means though. If we don't support such other means right away, should the API be more explicit about using SDS perhaps?

Copy link
Member Author

Choose a reason for hiding this comment

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

So the available options right now for mTLS seem quite limited (from reading this recent article https://blog.howardjohn.info/posts/mtls-kubernetes/)
There's either a sidecar approach (which this uses), ambient mode, a CNI approach (which doesn't exist yet), or DIY.
Is the abstraction too low if SDS is mentioned in the config?
What about an mTLS mode of 'mesh' being the initial option, with that meaning we'll integrate with the mesh if it's available i.e. if you're using Istio.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So what would be the minimum to allow configuring the certs. Would it just be to provide some paths to the CA for example? If so it would seem like a relatively simple adjustment to allow the needed paths to be provided under the mtls section. I haven't gone through that link in detail, but I can def see both use cases. One simple as possible just make mtls work. 2 the certs have to be specific certs from a the orgs CA etc

Copy link
Collaborator

Choose a reason for hiding this comment

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

One thing I am thinking here is we could go with an opinionated mTLS but ensure we allow users to still change values directly if needed. So when reconciling, we would assert that the section is there but not overwrite any new config for example.
So out of the box you get a working version that uses SDS if you want more than that you can configure it directly and we wont overwrite it


The corresponding EnvoyFilter for the component requires the following `transport_socket` configuration to be added:

```yaml
Copy link
Collaborator

Choose a reason for hiding this comment

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

@guicassolato I believe I am correct in saying we don't create these envoy filters until an Auth or RateLimit policy is created?
@david-martin I think we would need to make sure if mtls is enabled that part of marking the policy ready / accepted would mean ensuring this configuration was in place first.

authorino: true
limitador: true
```

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would be good to call out that if we don't support mTLS configuration for a gateway provider, it will be reflected in the status of the kuadrant resource. Also given how important this can be for users, kuadrant should probably not become ready until the specified mTLS can be handled or the mTLS section is removed.

Copy link
Collaborator

@maleck13 maleck13 left a comment

Choose a reason for hiding this comment

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

Some minor improvements suggest but, I like this as an initial pass at allowing configuration of mTLS when using Istio. Avoids users having to mess with resources owned by the kaudrant operator and also kuadrant users not needing to understand the innards of Envoy. It also seems relatively easy to extend with things like a specific CA etc.

Comment on lines +30 to +32
mtls:
authorino: true
limitador: true
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 there is a design issue here. More so when we think of the whole CR and just this feature. As this feature only has two components that is affected this will be harder to visualize, but I will try explain it from a generic features point of view.

spec:
  feature:
    activate: false # optional, boolean, defaults to false
    enabled: [] # optional, list of strings
    disabled: [] # optional, list of strings

Under the feature all fields are optional to ensure backwards compatibility. The feature will not be activated on less the activate field is set to true. This allows the feature to be enabled or disabled without changing the configuration for that feature. A feature would have a list of defaults components that would be affected by the feature being enabled. In this case that would be two, authorino & limitador, but this would not always be the case.

If the user wanted to disable the feature on a component lets say limitador they would add the following spec.

spec:
  feature:
    activate: true 
    disabled: ['limitador']

In this example only limitador will not have the feature enabled, but also if any new components are added to the defaults list that will be auto enabled. Being auto enabled by default may not be what the user wants. That is where the enabled list comes in. If the user wants to only have the feature enabled for authorino no matter what components are add in the future they could use the following spec.

spec:
  feature:
    activate: true 
    enable: ['authorino']

The enable list would be an explicit list. Only components listed would be affected. This ensures that behaviour would not change if a component is added to the support list later in the future. However, if there are a lot of components that is supported by default filling this list in could be tedious, but as it is a string list there is nothing stopping use from supporting keywords like 'defaults'. An example of this being used could be service monitors whereby default we only add them to the operands. A user many also add them to the operator that they care about. The below example shows that looks like.

spec:
  feature:
    activate: true
    enable: 
      - 'defaults'
      - 'authorino-operator'

So advantage that I see with doing this design are.

  • All features have the same basic interface.
  • New components don't require CRD updates to be supported. The change will only be required with the operator.
  • The common interface make documentation simpler

Copy link
Member Author

Choose a reason for hiding this comment

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

I like this approach.
Are the enabled & disabled lists mutually exclusive?

Copy link
Contributor

Choose a reason for hiding this comment

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

At first pass I think they should be exclusive, but I am not sure how we would enforce that. There might be something that could be done with CEL black magic and sets. If CEL doesn't work, a validating web hook is always an option. The bigger question around exclusive comes if we decide to allow keywords such as 'defaults'. There may be a component in the default list that the user wants to disable.

The example the comes to mind is a generic feature that works on both the operand and operator, but we decide that by default it only applies to the operand. The default list could be:

- authorino
- limitador

In this case the user may not be using authorino but also wants to use the feature with the limitador operator. The configuration they create would be something like:

spec:
  generic_feature:
    activate: true
    enable:
      - 'defaults'
      - 'limitador-operator'
    disable:
      - 'authorino'

For clarity this is the list that the feature would be applied to with the above configuration.

- limitador
- limitador-operator

In this scenario when building the list of component to apply the feature too, the disable list needs to read secondary. If the list were exclusive the order should not matter.

I think the behaviour around the keywords like 'defaults' needs a bit more refinement to explain what is regarded as expected behaviour.

I understood the question to mean one thing, but on second pass I can see it could be asking a different question to what I answer. The second way could be; are the enabled & disabled lists mutually exclusive within the Kuadrant Spec? As in, you can only have one or the other but not both at the same time. If this was want was meant by the question the answer would be no they are not mutually exclusive. If they were configuration like that give in the scenario above would not be possible, and I think that is where the real value of this interface is.

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.

4 participants