Skip to content

Commit

Permalink
feat(authz): Authorino for Service Mesh (#784)
Browse files Browse the repository at this point in the history
* feat(authz): Authorino for Service Mesh

This first iteration is to cover authentication needs for KServe

* Add templates to install Authorino
* Add templates to configure Service Mesh to use Authorino to delegate Authorization
* Add KServe-specific templates add ability to secure KServe Inference Services
* Add relevant fields to DSCInitialization resource
* Code for proper cleanup, in case of uninstalling

Most (if not all) of this code comes from pull request opendatahub-io#605. Attribution to original authors: @bartoszmajsak, @aslakknutsen, @cam-garrison, et. al.

Related opendatahub-io/kserve#128

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Fix linter issues

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Resolve feedback: Bartosz

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* fix: Remove port from the authorization policy

Also, add `/metrics` to the ignored paths for auth.

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Fix feedback: Bartosz

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* More feedback: Bartosz

Co-authored-by: Bartosz Majsak <bartosz.majsak@gmail.com>

* Fix feedback: Reto - Adjust AuthorizationPolicy

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Fix more feedback: Bartosz

- Remove Authorino namespace field from DSCI.
- Move around some code in kserve.go to servicemesh_setup.go

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* chore: adds sec. prefix to authorino label selector

* fix: adds base dir to manifest sources

* chore: uses security instead of sec as a prefix in authorino label

* fix: /healthz is called by _something_, skipp

* fix: adopt ODH-ADR-0006 for clean up label

* fix: uses correct CRD name for authconfigs

Co-authored-by: Cameron Garrison <cgarriso@redhat.com>

* Remove left-over file

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: remove auth-refs ConfigMap

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Add missing role.yaml changes

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Go back to installing Authorino on its own namespace

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: Add clean-up for KServe/OSSM-auth

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: Simplify namings

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* fix: add auth-refs cm

* Feedback: adjust labels and a log message

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Bugfix: Extension provider terminating with error when SMCP is gone

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Fix: add missing RBAC for ConfigMaps func

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Fix: Run `make bundle` and commit resulting changes

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: Wen - Better feature namings

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: Bartosz

* Use feature logger
* Don't trim -applications suffix on ResolveAuthNamespace

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

* Feedback: Wen - revert image placeholder was replaced

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>

---------

Signed-off-by: Edgar Hernández <23639005+israel-hdez@users.noreply.github.com>
Co-authored-by: Bartosz Majsak <bartosz.majsak@gmail.com>
Co-authored-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Cameron Garrison <cgarriso@redhat.com>
  • Loading branch information
4 people authored Feb 19, 2024
1 parent e7e3982 commit e32a7c2
Show file tree
Hide file tree
Showing 29 changed files with 655 additions and 48 deletions.
2 changes: 1 addition & 1 deletion apis/dscinitialization/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,28 @@ spec:
user experience; e.g. it provides unified authentication giving
a Single Sign On experience.
properties:
auth:
description: Auth holds configuration of authentication and authorization
services used by Service Mesh in Opendatahub.
properties:
audiences:
default:
- https://kubernetes.default.svc
description: Audiences is a list of the identifiers that the
resource server presented with the token identifies as.
Audience-aware token authenticators will verify that the
token was intended for at least one of the audiences in
this list. If no audiences are provided, the audience will
default to the audience of the Kubernetes apiserver (kubernetes.default.svc).
items:
type: string
type: array
namespace:
description: Namespace where it is deployed. If not provided,
the default is to use '-auth-provider' suffix on the ApplicationsNamespace
of the DSCI.
type: string
type: object
controlPlane:
description: ControlPlane holds configuration of Service Mesh
used by Opendatahub.
Expand Down
25 changes: 25 additions & 0 deletions bundle/manifests/opendatahub-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,12 @@ spec:
- tokenreviews
verbs:
- create
- apiGroups:
- authorino.kuadrant.io
resources:
- authconfigs
verbs:
- '*'
- apiGroups:
- authorization.k8s.io
resources:
Expand Down Expand Up @@ -548,6 +554,7 @@ spec:
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
Expand Down Expand Up @@ -1180,6 +1187,12 @@ spec:
- deletecollection
- get
- patch
- apiGroups:
- networking.istio.io
resources:
- envoyfilters
verbs:
- '*'
- apiGroups:
- networking.istio.io
resources:
Expand Down Expand Up @@ -1260,6 +1273,12 @@ spec:
- patch
- update
- watch
- apiGroups:
- operator.authorino.kuadrant.io
resources:
- authorinos
verbs:
- '*'
- apiGroups:
- operator.knative.dev
resources:
Expand Down Expand Up @@ -1401,6 +1420,12 @@ spec:
- patch
- update
- watch
- apiGroups:
- security.istio.io
resources:
- authorizationpolicies
verbs:
- '*'
- apiGroups:
- security.openshift.io
resources:
Expand Down
9 changes: 7 additions & 2 deletions components/kserve/kserve.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,16 @@ func (k *Kserve) ReconcileComponent(ctx context.Context, cli client.Client, resC
return err
}
}
return nil

return k.configureServiceMesh(dscispec)
}

func (k *Kserve) Cleanup(_ client.Client, instance *dsciv1.DSCInitializationSpec) error {
return k.removeServerlessFeatures(instance)
if removeServerlessErr := k.removeServerlessFeatures(instance); removeServerlessErr != nil {
return removeServerlessErr
}

return k.removeServiceMeshConfigurations(instance)
}

func (k *Kserve) configureServerless(instance *dsciv1.DSCInitializationSpec) error {
Expand Down
46 changes: 46 additions & 0 deletions components/kserve/servicemesh_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package kserve

import (
"path"

operatorv1 "github.com/openshift/api/operator/v1"

dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1"
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/feature"
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/feature/servicemesh"
)

func (k *Kserve) configureServiceMesh(dscispec *dsciv1.DSCInitializationSpec) error {
if dscispec.ServiceMesh.ManagementState == operatorv1.Managed && k.GetManagementState() == operatorv1.Managed {
serviceMeshInitializer := feature.ComponentFeaturesHandler(k, dscispec, k.defineServiceMeshFeatures())
return serviceMeshInitializer.Apply()
}
if dscispec.ServiceMesh.ManagementState == operatorv1.Unmanaged && k.GetManagementState() == operatorv1.Managed {
return nil
}

return k.removeServiceMeshConfigurations(dscispec)
}

func (k *Kserve) removeServiceMeshConfigurations(dscispec *dsciv1.DSCInitializationSpec) error {
serviceMeshInitializer := feature.ComponentFeaturesHandler(k, dscispec, k.defineServiceMeshFeatures())
return serviceMeshInitializer.Delete()
}

func (k *Kserve) defineServiceMeshFeatures() feature.FeaturesProvider {
return func(handler *feature.FeaturesHandler) error {
kserveExtAuthzErr := feature.CreateFeature("kserve-external-authz").
For(handler).
Manifests(
path.Join(feature.KServeDir),
).
WithData(servicemesh.ClusterDetails).
Load()

if kserveExtAuthzErr != nil {
return kserveExtAuthzErr
}

return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ spec:
user experience; e.g. it provides unified authentication giving
a Single Sign On experience.
properties:
auth:
description: Auth holds configuration of authentication and authorization
services used by Service Mesh in Opendatahub.
properties:
audiences:
default:
- https://kubernetes.default.svc
description: Audiences is a list of the identifiers that the
resource server presented with the token identifies as.
Audience-aware token authenticators will verify that the
token was intended for at least one of the audiences in
this list. If no audiences are provided, the audience will
default to the audience of the Kubernetes apiserver (kubernetes.default.svc).
items:
type: string
type: array
namespace:
description: Namespace where it is deployed. If not provided,
the default is to use '-auth-provider' suffix on the ApplicationsNamespace
of the DSCI.
type: string
type: object
controlPlane:
description: ControlPlane holds configuration of Service Mesh
used by Opendatahub.
Expand Down
25 changes: 25 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ rules:
- tokenreviews
verbs:
- create
- apiGroups:
- authorino.kuadrant.io
resources:
- authconfigs
verbs:
- '*'
- apiGroups:
- authorization.k8s.io
resources:
Expand Down Expand Up @@ -352,6 +358,7 @@ rules:
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
Expand Down Expand Up @@ -984,6 +991,12 @@ rules:
- deletecollection
- get
- patch
- apiGroups:
- networking.istio.io
resources:
- envoyfilters
verbs:
- '*'
- apiGroups:
- networking.istio.io
resources:
Expand Down Expand Up @@ -1064,6 +1077,12 @@ rules:
- patch
- update
- watch
- apiGroups:
- operator.authorino.kuadrant.io
resources:
- authorinos
verbs:
- '*'
- apiGroups:
- operator.knative.dev
resources:
Expand Down Expand Up @@ -1205,6 +1224,12 @@ rules:
- patch
- update
- watch
- apiGroups:
- security.istio.io
resources:
- authorizationpolicies
verbs:
- '*'
- apiGroups:
- security.openshift.io
resources:
Expand Down
28 changes: 15 additions & 13 deletions controllers/datasciencecluster/kubebuilder_rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@ package datasciencecluster
//+kubebuilder:rbac:groups="datasciencecluster.opendatahub.io",resources=datascienceclusters/finalizers,verbs=update;patch
//+kubebuilder:rbac:groups="datasciencecluster.opendatahub.io",resources=datascienceclusters,verbs=get;list;watch;create;update;patch;delete

/* Service Mesh prerequisite */
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshcontrolplanes,verbs=create;get;list;patch;update;use;watch

/* Serverless prerequisite */
// +kubebuilder:rbac:groups="networking.istio.io",resources=gateways,verbs=*
// +kubebuilder:rbac:groups="operator.knative.dev",resources=knativeservings,verbs=*
// +kubebuilder:rbac:groups="config.openshift.io",resources=ingresses,verbs=get

/* Service Mesh Integration */
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshcontrolplanes,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmemberrolls,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmembers,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmembers/finalizers,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices/status,verbs=update;patch;delete
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices/finalizers,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices,verbs=*
// +kubebuilder:rbac:groups="networking.istio.io",resources=gateways,verbs=*
// +kubebuilder:rbac:groups="networking.istio.io",resources=envoyfilters,verbs=*
// +kubebuilder:rbac:groups="security.istio.io",resources=authorizationpolicies,verbs=*
// +kubebuilder:rbac:groups="authorino.kuadrant.io",resources=authconfigs,verbs=*
// +kubebuilder:rbac:groups="operator.authorino.kuadrant.io",resources=authorinos,verbs=*

/* This is for DSP */
//+kubebuilder:rbac:groups="datasciencepipelinesapplications.opendatahub.io",resources=datasciencepipelinesapplications/status,verbs=update;patch;get
//+kubebuilder:rbac:groups="datasciencepipelinesapplications.opendatahub.io",resources=datasciencepipelinesapplications/finalizers,verbs=update;patch
Expand Down Expand Up @@ -93,10 +104,6 @@ package datasciencecluster
// +kubebuilder:rbac:groups="networking.k8s.io",resources=networkpolicies,verbs=get;create;list;watch;delete;update;patch
// +kubebuilder:rbac:groups="networking.k8s.io",resources=ingresses,verbs=create;delete;list;update;watch;patch;get

// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices/status,verbs=update;patch;delete
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices/finalizers,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices,verbs=*

// +kubebuilder:rbac:groups="monitoring.coreos.com",resources=servicemonitors,verbs=get;create;delete;update;watch;list;patch;deletecollection
// +kubebuilder:rbac:groups="monitoring.coreos.com",resources=podmonitors,verbs=get;create;delete;update;watch;list;patch
// +kubebuilder:rbac:groups="monitoring.coreos.com",resources=prometheusrules,verbs=get;create;patch;delete;deletecollection
Expand Down Expand Up @@ -189,7 +196,7 @@ package datasciencecluster
// +kubebuilder:rbac:groups="core",resources=endpoints,verbs=watch;list;get;create;update;delete

// +kubebuilder:rbac:groups="core",resources=configmaps/status,verbs=get;update;patch;delete
// +kubebuilder:rbac:groups="core",resources=configmaps,verbs=get;create;watch;patch;delete;list
// +kubebuilder:rbac:groups="core",resources=configmaps,verbs=get;create;update;watch;patch;delete;list

// +kubebuilder:rbac:groups="core",resources=clusterversions,verbs=watch;list
// +kubebuilder:rbac:groups="config.openshift.io",resources=clusterversions,verbs=watch;list
Expand Down Expand Up @@ -248,11 +255,6 @@ package datasciencecluster

// +kubebuilder:rbac:groups="*",resources=customresourcedefinitions,verbs=get;list;watch

// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshcontrolplanes,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmemberrolls,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmembers,verbs=create;get;list;patch;update;use;watch
// +kubebuilder:rbac:groups="maistra.io",resources=servicemeshmembers/finalizers,verbs=create;get;list;patch;update;use;watch

/* Only for RHODS */
// +kubebuilder:rbac:groups="user.openshift.io",resources=groups,verbs=get;create;list;watch;patch;delete
// +kubebuilder:rbac:groups="console.openshift.io",resources=consolelinks,verbs=create;get;patch;delete
41 changes: 41 additions & 0 deletions controllers/dscinitialization/servicemesh_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,47 @@ func configureServiceMeshFeatures() feature.FeaturesProvider {
}
}

cfgMapErr := feature.CreateFeature("mesh-shared-configmap").
For(handler).
WithResources(servicemesh.ConfigMaps).
Load()
if cfgMapErr != nil {
return cfgMapErr
}

extAuthzErr := feature.CreateFeature("mesh-control-plane-external-authz").
For(handler).
Manifests(
path.Join(feature.AuthDir, "auth-smm.tmpl"),
path.Join(feature.AuthDir, "base"),
path.Join(feature.AuthDir, "mesh-authz-ext-provider.patch.tmpl"),
).
WithData(servicemesh.ClusterDetails).
PreConditions(
feature.EnsureCRDIsInstalled("authconfigs.authorino.kuadrant.io"),
servicemesh.EnsureServiceMeshInstalled,
servicemesh.EnsureAuthNamespaceExists,
).
PostConditions(
feature.WaitForPodsToBeReady(serviceMeshSpec.ControlPlane.Namespace),
func(f *feature.Feature) error {
return feature.WaitForPodsToBeReady(f.Spec.Auth.Namespace)(f)
},
func(f *feature.Feature) error {
// We do not have the control over deployment resource creation.
// It is created by Authorino operator using Authorino CR
//
// To make it part of Service Mesh we have to patch it with injection
// enabled instead, otherwise it will not have proxy pod injected.
return f.ApplyManifest(path.Join(feature.AuthDir, "deployment.injection.patch.tmpl"))
},
).
OnDelete(servicemesh.RemoveExtensionProvider).
Load()
if extAuthzErr != nil {
return extAuthzErr
}

return nil
}
}
16 changes: 16 additions & 0 deletions infrastructure/v1/servicemesh_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ type ServiceMeshSpec struct {
ManagementState operatorv1.ManagementState `json:"managementState,omitempty"`
// ControlPlane holds configuration of Service Mesh used by Opendatahub.
ControlPlane ControlPlaneSpec `json:"controlPlane,omitempty"`
// Auth holds configuration of authentication and authorization services
// used by Service Mesh in Opendatahub.
Auth AuthSpec `json:"auth,omitempty"`
}

type ControlPlaneSpec struct {
Expand Down Expand Up @@ -38,3 +41,16 @@ type IngressGatewaySpec struct {
// the for Ingress Gateway.
Certificate CertificateSpec `json:"certificate,omitempty"`
}

type AuthSpec struct {
// Namespace where it is deployed. If not provided, the default is to
// use '-auth-provider' suffix on the ApplicationsNamespace of the DSCI.
Namespace string `json:"namespace,omitempty"`
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will verify
// that the token was intended for at least one of the audiences in this list.
// If no audiences are provided, the audience will default to the audience of the
// Kubernetes apiserver (kubernetes.default.svc).
// +kubebuilder:default={"https://kubernetes.default.svc"}
Audiences *[]string `json:"audiences,omitempty"`
}
Loading

0 comments on commit e32a7c2

Please sign in to comment.