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

adding mtls config #1170

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Conversation

laurafitzgerald
Copy link
Contributor

@laurafitzgerald laurafitzgerald commented Feb 20, 2025

Closes #1157

Changes

  • add a boolean to spec to turn on/off the config
  • add permissions on PeerAuthentication
  • new mtls reconciler
  • configure logic
  • uncofigure logic
  • state of the world new watch and reconcile
  • link peer authentication to gateway logic
  • is limitador installed logic
  • Deployment.spec.template.label mutator
  • LinkDeploymentToLimitador
  • LinkDeploymentToAuthorino
  • tests
  • Report a status to the cr?

Verification steps
Run the following on this branch.
make local-setup
kubectl apply -f config/samples/kuadrant_v1beta1_kuadrant.yaml
Follow steps in https://docs.kuadrant.io/dev/kuadrant-operator/doc/user-guides/full-walkthrough/secure-protect-connect/
Update the kuadrant cr to enable mts using
kubectl patch kuadrant kuadrant-sample --type='json' -p='[{"op": "replace", "path": "/spec/mtls/enable", "value": true}]'
Verify that a Peer Authentication exists
kubectl get peerauthentication default -n default -o yaml
which has the following details

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  labels:
    kuadrant.io/managed: "true"
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT

Verify that the two envoyfilters have a CLUSTER patch with a key "transport_socket" in spec.configPatches applyTo CLUSTER.patch.value
kubectl get envoyfilter -A -o yaml

Verify that the limitador and authorino deployments have the expected labels
kubectl get deployment limitador-limitador -o yaml | yq e '.spec.template.metadata.labels' kubectl get deployment authorino -o yaml | yq e '.spec.template.metadata.labels'
Both should output

authorino-resource: authorino
control-plane: controller-manager
sidecar.istio.io/inject: "true

@laurafitzgerald laurafitzgerald requested a review from a team as a code owner February 20, 2025 13:10
@laurafitzgerald laurafitzgerald marked this pull request as draft February 20, 2025 13:12
Copy link
Contributor

@Boomatang Boomatang left a comment

Choose a reason for hiding this comment

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

There is a few comments that I have. I didn't try running this locally.

I would like to point out with the state of the world and the topology any time you find your self request data from the cluster you are doing something wrong

Comment on lines 27 to 41
func MergeMapStringString(modified *bool, existing *map[string]string, desired map[string]string) {
if *existing == nil {
*existing = map[string]string{}
}

// for each desired key value set, e.g. labels
// check if it's present in existing. if not add it to existing.
// e.g. preserving existing labels while adding those that are in the desired set.
for desiredKey, desiredValue := range desired {
if existingValue, exists := (*existing)[desiredKey]; !exists || existingValue != desiredValue {
(*existing)[desiredKey] = desiredValue
*modified = true
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use labels.Set.Merge from the apimachinery to do this over defining our own.

Copy link
Contributor

Choose a reason for hiding this comment

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

it's not a map merge operation. It's doing what the comments say.

err = r.ReconcileResource(eventCtx, &v12.Deployment{}, deployment, reconcilers.DeploymentMutator(deploymentMutators...))
}

valueMap := map[string]interface{}{
Copy link
Contributor

Choose a reason for hiding this comment

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

Everything here being a map[sting]interface seems like a code smell.

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 believe this is the standard way that EnvoyFilter Config Object Patches arehandle. You can see an exmaple of this here https://github.com/Kuadrant/kuadrant-controller/blob/22535aa8e4f142bf07a69dc6391c84a59b232255/pkg/istio/envoy_filters.go#L14-L47


func IsLimitadorOperatorInstalled(restMapper meta.RESTMapper, logger logr.Logger) (bool, error) {
if ok, err := utils.IsCRDInstalled(restMapper, kuadrantv1beta1.LimitadorGroupKind.Group, kuadrantv1beta1.LimitadorGroupKind.Kind, limitadorv1alpha1.GroupVersion.Version); !ok || err != nil {
logger.V(1).Error(err, "Limitador Operator CRD was not installed", "group", kuadrantv1beta1.AuthorinoGroupKind.Group, "kind", kuadrantv1beta1.AuthorinoGroupKind.Kind, "version", authorinooperatorv1beta1.GroupVersion.Version)
Copy link
Contributor

Choose a reason for hiding this comment

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

Might want to fix the references to the authorino types here.

Copy link
Contributor

@Boomatang Boomatang left a comment

Choose a reason for hiding this comment

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

I think this is now at the stage where we need to be able to compile and run the operator to do a good review. It is getting close.

Comment on lines +65 to +68
type MTLS struct {
Enable bool `json:"enable,omitempty"`
}

Copy link
Contributor

Choose a reason for hiding this comment

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

At some point can you add a comment to what the mtls struct is for. The comment gets added to the CRD definition as a description. You will also need to run make manifest , bundle and helm at some point.

@laurafitzgerald laurafitzgerald force-pushed the mtls branch 3 times, most recently from da6de62 to e64e213 Compare March 12, 2025 12:45
@laurafitzgerald laurafitzgerald marked this pull request as ready for review March 12, 2025 12:45
if kObj == nil && kObj.Spec.MTLS == nil && (!kObj.Spec.MTLS.Enable || anyAttachedAuthorRateLimitPolicy == false) {
defer logger.V(1).Info("mtls not enabled or applicable", "status", "completed")
peerAuthentications := lo.FilterMap(topology.Objects().Items(), func(item machinery.Object, _ int) (machinery.Object, bool) {
if peerAuthentication, ok := item.(*PeerAuthentication); ok {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This isn't working yet. It's not picking up the exising PeerAuthentications.

Copy link
Contributor

@eguzki eguzki left a comment

Choose a reason for hiding this comment

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

Very good progress.

Few questions:

  • If the gateway provider is not Istio and a user enables mtls, should we report in kuadrant status?
  • When a user deletes a gateway, the peerAuthentications objects gets deleted? (not very important now and can be tackled in follow up PR's) (I learned that one peerAuthentications is created at the kuadrant namespace)

To: DeploymentGroupKind,
Func: func(child machinery.Object) []machinery.Object {
return lo.Filter(authorinos, func(k machinery.Object, _ int) bool {
return k.GetNamespace() == child.GetNamespace() && child.GetName() == "authorino"
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not very familiar with these linking functions. I still need to educate myself.

Question: child's type is Authorino, isn't it? Then, isn't this linking function linking all deployments in Authorino namespace to Authorino? even those that are not authorino deployment, like limitador deployment?

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'm also new to them, the idea here, which may not be implemented correctly yet is that we link the authorino deployment, I'm uisng the GetName to isolate it, although I'd rather not hardcode, that needs to be fixed so that it's only that one that get's picked up and not all in the authorino namespace. AIUI this is to add it as a child of the Authorino cr in the topology.

@@ -3,4 +3,6 @@ apiVersion: kuadrant.io/v1beta1
kind: Kuadrant
metadata:
name: kuadrant-sample
spec: {}
spec:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the sample being shown in operatorhub web console. Do we want to add (optional) mtls config to 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.

If we'd prefer not to i'm fine with that. My reasoning for adding it here is that in the verification steps i'm using kubectl patch kuadrant kuadrant-sample --type='json' -p='[{"op": "replace", "path": "/spec/mtls/enable", "value": false}]' as a quick way to switch it on and off for testing. But if this gets presented in the console where the description will show that it can be used optionally, i would agree it's best not to include it. I'll remove this before we merge.

"tls_certificate_sds_secret_configs": []interface{}{
map[string]interface{}{
"name": "default",
"sds_config": map[string]interface{}{
Copy link
Contributor

Choose a reason for hiding this comment

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

Am I correct assuming that the gateway will fetch the client certificate from XDS interface?

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'm actually not familiar with this configuration. I've taken it from https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/install/mtls-configuration.md#envoy-filter making the assumption that it will work as is and doesn't need any changes. @david-martin and @maleck13 are the original authors there so may be answer questions around that.

}
}
*/
func LinkDeploymentToAuthorino(objs controller.Store) machinery.LinkFunc {
Copy link
Contributor

Choose a reason for hiding this comment

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

"k8s.io/apimachinery/pkg/api/meta"
)

func IsLimitadorOperatorInstalled(restMapper meta.RESTMapper, logger logr.Logger) (bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is required to check the existence of the operator? Shouldn't it be Limitador itself?

Comment on lines 27 to 41
func MergeMapStringString(modified *bool, existing *map[string]string, desired map[string]string) {
if *existing == nil {
*existing = map[string]string{}
}

// for each desired key value set, e.g. labels
// check if it's present in existing. if not add it to existing.
// e.g. preserving existing labels while adding those that are in the desired set.
for desiredKey, desiredValue := range desired {
if existingValue, exists := (*existing)[desiredKey]; !exists || existingValue != desiredValue {
(*existing)[desiredKey] = desiredValue
*modified = true
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

it's not a map merge operation. It's doing what the comments say.

@@ -56,6 +56,10 @@ func (r *IstioRateLimitClusterReconciler) Reconcile(ctx context.Context, _ []con
if kuadrant == nil {
return nil
}
mtls := false
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
mtls := false
mtls := kuadrant != nil && kuadrant.Spec.MTLS != nil && kuadrant.Spec.MTLS.Enable

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, it could be mtls := kuadrant.IsMTLSEnabled() according to https://github.com/Kuadrant/kuadrant-operator/pull/1170/files#r1995757686

@eguzki
Copy link
Contributor

eguzki commented Mar 17, 2025

Trying to run the verification steps: it fails with

{"level":"info","ts":"2025-03-17T14:54:07Z","logger":"kuadrant-operator","msg":"pkg/mod/k8s.io/[email protected]/tools/cache/reflector.go:243: failed to list *v1.PeerAuthentication: peerauthentications.security.istio.io is forbidden: User \"system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager\" cannot list resource \"peerauthentications\" in API group \"security.istio.io\" at the cluster scope"}

Consider granting required permissions to the operator


logger.Info("creating peer authentication resource", "status", "processing")

err = r.CreateResource(eventCtx, peerAuth)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider calling ReconcileResource and passing a mutator. Feel free to pick CreateOnlyMutator

return nil, false
})
// add label to authorino deployment {"sidecar.istio.io/inject":"true"}}}}}
aDeployment := &v12.Deployment{
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if the kuadrant operator could add a label to Authorino CR, which is the API exposed from the authorino operator to external users of it. Instead, kuadrant operator needs to speculate and assume that the deployment name will be authorino because it has created a Authorino CR called authorino, which is ugly to the very least and easy to break.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eguzki i think we may do this in the future. or maybe the progression of this pr will result in us making the final decision around that. I think the con for that was around adding an additional api that we will have to maintain and we wanted to be sure about that first. @maleck13 given the progress of the implementation here does that change our deesire to add taht additional api via the spec of the cr?

lDeployment := &v12.Deployment{
ObjectMeta: metav1.ObjectMeta{
// TODO can't be hardcoded, this is just one example
Name: "limitador-limitador",
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as https://github.com/Kuadrant/kuadrant-operator/pull/1170/files#r1998972201

The alternative to hardcode the name is to filter by labels we expect to have. Still not perfect.

return fmt.Errorf("could not add label to limitador deployment %w", err)
}

peerAuth := &istiosecurity.PeerAuthentication{
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding ownerref to Kuadrant CR

@laurafitzgerald
Copy link
Contributor Author

@eguzki thanks for you reviews. I've been caught up with other work but starting to address those now. Need to rebase first. 🤕 😂

Signed-off-by: Laura Fitzgerald <[email protected]>
…ts to limitador and authorino crs

Signed-off-by: Laura Fitzgerald <[email protected]>
…e other cleanup and it's runnable now

Signed-off-by: Laura Fitzgerald <[email protected]>
Signed-off-by: Laura Fitzgerald <[email protected]>
Signed-off-by: Laura Fitzgerald <[email protected]>
Signed-off-by: Laura Fitzgerald <[email protected]>
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.

Expose configuration in the kuadrant cr that controls the mTLS configuration by component
4 participants