Repository: kumahq/kuma
Pull request #2271 (2021-07-02 02:28:30)

chore(*) make the authentication interface type oblivious
### Summary

There are two proxy types that can be authenticated and in the future there may be more. Rather than adding a new method for authenticating each proxy type, switch to authenticating a generic model Resource and allow each authenticator implentation to type switch internally.
    
This allows the xDS authentication callbacks to be insensitive to the DP proxy type, except when fetching an existing resource, which needs to allocate an instance of the concrete type.

The other approach I considered was making each `Authenticator` implementation responsible for a authenticating a single type, then using a factory interface to choose the right instance. I didn't go with that, since there was more scaffolding and the benefits over the internal type switch weren't very clear.

### Full changelog

N/A

### Issues resolved

N/A

### Documentation

N/A
### Testing

- [x] Unit tests
- [x] E2E tests
- [ ] Manual testing on Universal
- [ ] Manual testing on Kubernetes 


codecov-commenter: # [Codecov](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq) Report
> Merging [#2271](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq) (1dd0d59) into [master](https://codecov.io/gh/kumahq/kuma/commit/17666e496c07fba35c62d779dce56624b01cc43d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq) (17666e4) will **increase** coverage by `0.31%`.
> The diff coverage is `51.35%`.

[![Impacted file tree graph](https://codecov.io/gh/kumahq/kuma/pull/2271/graphs/tree.svg?width=650&height=150&src=pr&token=D7Yvqs6rwV&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq)](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq)

```diff
@@            Coverage Diff             @@
##           master    #2271      +/-   ##
==========================================
+ Coverage   51.61%   51.92%   +0.31%     
==========================================
  Files         910      914       +4     
  Lines       41206    41241      +35     
==========================================
+ Hits        21268    21416     +148     
+ Misses      17901    17765     -136     
- Partials     2037     2060      +23     
```


| [Impacted Files](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq) | Coverage Δ | |
|---|---|---|
| [pkg/xds/auth/k8s/authenticator.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3hkcy9hdXRoL2s4cy9hdXRoZW50aWNhdG9yLmdv) | `0.00% <0.00%> (ø)` | |
| [pkg/xds/auth/universal/authenticator.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3hkcy9hdXRoL3VuaXZlcnNhbC9hdXRoZW50aWNhdG9yLmdv) | `76.19% <42.85%> (-6.67%)` | :arrow_down: |
| [pkg/xds/auth/universal/noop\_authenticator.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3hkcy9hdXRoL3VuaXZlcnNhbC9ub29wX2F1dGhlbnRpY2F0b3IuZ28=) | `50.00% <42.85%> (-16.67%)` | :arrow_down: |
| [pkg/xds/auth/callbacks.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3hkcy9hdXRoL2NhbGxiYWNrcy5nbw==) | `81.81% <81.25%> (+5.52%)` | :arrow_up: |
| [pkg/core/xds/metadata.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL2NvcmUveGRzL21ldGFkYXRhLmdv) | `62.16% <0.00%> (-2.71%)` | :arrow_down: |
| [api/internal/util/proto/types.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-YXBpL2ludGVybmFsL3V0aWwvcHJvdG8vdHlwZXMuZ28=) | `50.00% <0.00%> (ø)` | |
| [...k8s/native/controllers/proxytemplate\_controller.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3BsdWdpbnMvcmVzb3VyY2VzL2s4cy9uYXRpdmUvY29udHJvbGxlcnMvcHJveHl0ZW1wbGF0ZV9jb250cm9sbGVyLmdv) | `0.00% <0.00%> (ø)` | |
| [...kg/plugins/resources/k8s/native/pkg/test/within.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3BsdWdpbnMvcmVzb3VyY2VzL2s4cy9uYXRpdmUvcGtnL3Rlc3Qvd2l0aGluLmdv) | `100.00% <0.00%> (ø)` | |
| [api/internal/util/proto/proto.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-YXBpL2ludGVybmFsL3V0aWwvcHJvdG8vcHJvdG8uZ28=) | `62.50% <0.00%> (ø)` | |
| [pkg/xds/generator/direct\_access\_proxy\_generator.go](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq#diff-cGtnL3hkcy9nZW5lcmF0b3IvZGlyZWN0X2FjY2Vzc19wcm94eV9nZW5lcmF0b3IuZ28=) | `81.57% <0.00%> (+1.31%)` | :arrow_up: |
| ... and [17 more](https://codecov.io/gh/kumahq/kuma/pull/2271/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq). Last update [17666e4...1dd0d59](https://codecov.io/gh/kumahq/kuma/pull/2271?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kumahq).


Patch:
diff --git a/pkg/xds/auth/callbacks.go b/pkg/xds/auth/callbacks.go
index 9a9232229..0ccc935fc 100644
--- a/pkg/xds/auth/callbacks.go
+++ b/pkg/xds/auth/callbacks.go
@@ -119,60 +119,34 @@ func (a *authCallbacks) credential(streamID core_xds.StreamID) (Credential, erro
 
 func (a *authCallbacks) authenticate(credential Credential, req util_xds.DiscoveryRequest) error {
 	md := core_xds.DataplaneMetadataFromXdsMetadata(req.Metadata())
-	switch md.GetProxyType() {
-	case mesh_proto.IngressProxyType:
-		return a.authenticateZoneIngress(credential, req)
-	default:
-		return a.authenticateDataplane(credential, req)
-	}
-}
 
-func (a *authCallbacks) authenticateZoneIngress(credential Credential, req util_xds.DiscoveryRequest) error {
-	zoneIngress := core_mesh.NewZoneIngressResource()
-	md := core_xds.DataplaneMetadataFromXdsMetadata(req.Metadata())
-	if md.GetZoneIngressResource() != nil {
-		zoneIngress = md.GetZoneIngressResource()
-	} else {
+	// If we already have a resource from the xDS bootstrap, we can use that.
+	resource := md.Resource
+
+	// Otherwise, search for the pre-created resource.
+	if resource == nil {
 		proxyId, err := core_xds.ParseProxyIdFromString(req.NodeId())
 		if err != nil {
-			return errors.Wrap(err, "request must have a valid Proxy Id")
+			return errors.Wrap(err, "request must have a valid Proxy ID")
 		}
-		backoff, _ := retry.NewConstant(a.dpNotFoundRetry.Backoff)
-		backoff = retry.WithMaxRetries(uint64(a.dpNotFoundRetry.MaxTimes), backoff)
-		err = retry.Do(context.Background(), backoff, func(ctx context.Context) error {
-			err := a.resManager.Get(ctx, zoneIngress, core_store.GetBy(proxyId.ToResourceKey()))
-			if core_store.IsResourceNotFound(err) {
-				return retry.RetryableError(errors.New("zoneIngress not found. Create ZoneIngress in Kuma CP first or pass it as an argument to kuma-dp"))
-			}
-			return err
-		})
-		if err != nil {
-			return err
-		}
-	}
-
-	if err := a.authenticator.AuthenticateZoneIngress(context.Background(), zoneIngress, credential); err != nil {
-		return errors.Wrap(err, "authentication failed")
-	}
-	return nil
-}
 
-func (a *authCallbacks) authenticateDataplane(credential Credential, req util_xds.DiscoveryRequest) error {
-	dataplane := core_mesh.NewDataplaneResource()
-	md := core_xds.DataplaneMetadataFromXdsMetadata(req.Metadata())
-	if md.GetDataplaneResource() != nil {
-		dataplane = md.GetDataplaneResource()
-	} else {
-		proxyId, err := core_xds.ParseProxyIdFromString(req.NodeId())
-		if err != nil {
-			return errors.Wrap(err, "request must have a valid Proxy Id")
+		switch md.GetProxyType() {
+		case mesh_proto.IngressProxyType:
+			resource = core_mesh.NewZoneIngressResource()
+		case mesh_proto.DataplaneProxyType:
+			resource = core_mesh.NewDataplaneResource()
+		default:
+			return errors.Errorf("unsupported proxy type %q", md.GetProxyType())
 		}
+
 		backoff, _ := retry.NewConstant(a.dpNotFoundRetry.Backoff)
 		backoff = retry.WithMaxRetries(uint64(a.dpNotFoundRetry.MaxTimes), backoff)
 		err = retry.Do(context.Background(), backoff, func(ctx context.Context) error {
-			err := a.resManager.Get(ctx, dataplane, core_store.GetBy(proxyId.ToResourceKey()))
+			err := a.resManager.Get(ctx, resource, core_store.GetBy(proxyId.ToResourceKey()))
 			if core_store.IsResourceNotFound(err) {
-				return retry.RetryableError(errors.New("dataplane not found. Create Dataplane in Kuma CP first or pass it as an argument to kuma-dp"))
+				return retry.RetryableError(errors.Errorf(
+					"resource %q not found; create a %s in Kuma CP first or pass it as an argument to kuma-dp",
+					proxyId, resource.GetType()))
 			}
 			return err
 		})
@@ -181,10 +155,8 @@ func (a *authCallbacks) authenticateDataplane(credential Credential, req util_xd
 		}
 	}
 
-	if err := a.authenticator.Authenticate(context.Background(), dataplane, credential); err != nil {
-		return errors.Wrap(err, "authentication failed")
-	}
-	return nil
+	return errors.Wrap(a.authenticator.Authenticate(context.Background(), resource, credential),
+		"authentication failed")
 }
 
 func extractCredential(ctx context.Context) (Credential, error) {
diff --git a/pkg/xds/auth/interfaces.go b/pkg/xds/auth/interfaces.go
index c5f364994..eea036a0c 100644
--- a/pkg/xds/auth/interfaces.go
+++ b/pkg/xds/auth/interfaces.go
@@ -3,12 +3,11 @@ package auth
 import (
 	"context"
 
-	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 )
 
 type Credential = string
 
 type Authenticator interface {
-	Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential Credential) error
-	AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential Credential) error
+	Authenticate(ctx context.Context, resource model.Resource, credential Credential) error
 }
diff --git a/pkg/xds/auth/k8s/authenticator.go b/pkg/xds/auth/k8s/authenticator.go
index 16a4ee12f..bcbc3c26c 100644
--- a/pkg/xds/auth/k8s/authenticator.go
+++ b/pkg/xds/auth/k8s/authenticator.go
@@ -10,6 +10,7 @@ import (
 	kube_client "sigs.k8s.io/controller-runtime/pkg/client"
 
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 	util_k8s "github.com/kumahq/kuma/pkg/util/k8s"
 	"github.com/kumahq/kuma/pkg/xds/auth"
 )
@@ -24,7 +25,20 @@ type kubeAuthenticator struct {
 	client kube_client.Client
 }
 
-func (k *kubeAuthenticator) Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
+var _ auth.Authenticator = &kubeAuthenticator{}
+
+func (k *kubeAuthenticator) Authenticate(ctx context.Context, resource model.Resource, credential auth.Credential) error {
+	switch resource := resource.(type) {
+	case *core_mesh.DataplaneResource:
+		return k.authDataplane(ctx, resource, credential)
+	case *core_mesh.ZoneIngressResource:
+		return k.authZoneIngress(ctx, resource, credential)
+	default:
+		return errors.Errorf("no matching authenticator for %s resource", resource.GetType())
+	}
+}
+
+func (k *kubeAuthenticator) authDataplane(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
 	if credential == "" {
 		return errors.New("authentication failed: k8s token is missing")
 	}
@@ -57,7 +71,7 @@ func (k *kubeAuthenticator) Authenticate(ctx context.Context, dataplane *core_me
 	return nil
 }
 
-func (k *kubeAuthenticator) AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
+func (k *kubeAuthenticator) authZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
 	if credential == "" {
 		return errors.New("authentication failed: k8s token is missing")
 	}
diff --git a/pkg/xds/auth/universal/authenticator.go b/pkg/xds/auth/universal/authenticator.go
index 25891a654..b5ddd2220 100644
--- a/pkg/xds/auth/universal/authenticator.go
+++ b/pkg/xds/auth/universal/authenticator.go
@@ -3,6 +3,8 @@ package universal
 import (
 	"context"
 
+	"github.com/kumahq/kuma/pkg/core/resources/model"
+
 	"github.com/pkg/errors"
 
 	"github.com/kumahq/kuma/pkg/tokens/builtin/zoneingress"
@@ -36,7 +38,20 @@ type universalAuthenticator struct {
 	zone              string
 }
 
-func (u *universalAuthenticator) Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
+var _ auth.Authenticator = &universalAuthenticator{}
+
+func (u *universalAuthenticator) Authenticate(ctx context.Context, resource model.Resource, credential auth.Credential) error {
+	switch resource := resource.(type) {
+	case *core_mesh.DataplaneResource:
+		return u.authDataplane(ctx, resource, credential)
+	case *core_mesh.ZoneIngressResource:
+		return u.authZoneIngress(ctx, resource, credential)
+	default:
+		return errors.Errorf("no matching authenticator for %s resource", resource.GetType())
+	}
+}
+
+func (u *universalAuthenticator) authDataplane(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
 	dpIdentity, err := u.issuer.Validate(credential, dataplane.Meta.GetMesh())
 	if err != nil {
 		return err
@@ -57,7 +72,7 @@ func (u *universalAuthenticator) Authenticate(ctx context.Context, dataplane *co
 	return nil
 }
 
-func (u *universalAuthenticator) AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
+func (u *universalAuthenticator) authZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
 	identity, err := u.zoneIngressIssuer.Validate(credential)
 	if err != nil {
 		return err
diff --git a/pkg/xds/auth/universal/noop_authenticator.go b/pkg/xds/auth/universal/noop_authenticator.go
index 59ac21ee3..83f5f557f 100644
--- a/pkg/xds/auth/universal/noop_authenticator.go
+++ b/pkg/xds/auth/universal/noop_authenticator.go
@@ -3,7 +3,10 @@ package universal
 import (
 	"context"
 
+	"github.com/pkg/errors"
+
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/xds/auth"
 )
 
@@ -14,10 +17,15 @@ func NewNoopAuthenticator() auth.Authenticator {
 type noopAuthenticator struct {
 }
 
-func (u *noopAuthenticator) Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, _ auth.Credential) error {
-	return nil
-}
+var _ auth.Authenticator = &noopAuthenticator{}
 
-func (u *noopAuthenticator) AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, _ auth.Credential) error {
-	return nil
+func (u *noopAuthenticator) Authenticate(ctx context.Context, resource model.Resource, _ auth.Credential) error {
+	switch resource := resource.(type) {
+	case *core_mesh.DataplaneResource:
+		return nil
+	case *core_mesh.ZoneIngressResource:
+		return nil
+	default:
+		return errors.Errorf("no matching authenticator for %s resource", resource.GetType())
+	}
 }
diff --git a/pkg/xds/bootstrap/generator.go b/pkg/xds/bootstrap/generator.go
index 7e0508649..6e4ecea53 100644
--- a/pkg/xds/bootstrap/generator.go
+++ b/pkg/xds/bootstrap/generator.go
@@ -94,7 +94,6 @@ func (b *bootstrapGenerator) Generate(ctx context.Context, request types.Bootstr
 		if err != nil {
 			return nil, "", err
 		}
-		b.hdsEnabled = false
 		return b.generateFor(*proxyId, request, "ingress", adminPort)
 	case mesh_proto.DataplaneProxyType, mesh_proto.GatewayProxyType:
 		proxyId := core_xds.BuildProxyId(request.Mesh, request.Name)
@@ -264,6 +263,11 @@ func (b *bootstrapGenerator) generateFor(proxyId core_xds.ProxyId, request types
 		return nil, "", err
 	}
 
+	proxyType := mesh_proto.ProxyType(request.ProxyType)
+	if request.ProxyType == "" {
+		proxyType = mesh_proto.DataplaneProxyType
+	}
+
 	accessLogSocket := envoy_common.AccessLogSocketName(request.Name, request.Mesh)
 	xdsHost := b.xdsHost(request)
 	xdsUri := net.JoinHostPort(xdsHost, strconv.FormatUint(uint64(b.config.Params.XdsPort), 10))
@@ -290,7 +294,7 @@ func (b *bootstrapGenerator) generateFor(proxyId core_xds.ProxyId, request types
 		KumaDpBuildDate:    request.Version.KumaDp.BuildDate,
 		EnvoyVersion:       request.Version.Envoy.Version,
 		EnvoyBuild:         request.Version.Envoy.Build,
-		HdsEnabled:         b.hdsEnabled,
+		HdsEnabled:         proxyType == mesh_proto.DataplaneProxyType && b.hdsEnabled,
 		DynamicMetadata:    request.DynamicMetadata,
 		DNSPort:            request.DNSPort,
 		EmptyDNSPort:       request.EmptyDNSPort,


Test patch:
diff --git a/pkg/hds/authn/callbacks_test.go b/pkg/hds/authn/callbacks_test.go
index b54b31175..3eb2ee512 100644
--- a/pkg/hds/authn/callbacks_test.go
+++ b/pkg/hds/authn/callbacks_test.go
@@ -2,10 +2,10 @@ package authn_test
 
 import (
 	"context"
-	"errors"
 
 	envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
 	envoy_service_health_v3 "github.com/envoyproxy/go-control-plane/envoy/service/health/v3"
+	"github.com/pkg/errors"
 	"google.golang.org/grpc/metadata"
 
 	"github.com/kumahq/kuma/pkg/hds/authn"
@@ -30,20 +30,21 @@ type testAuthenticator struct {
 
 var _ auth.Authenticator = &testAuthenticator{}
 
-func (t *testAuthenticator) Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
-	t.callCounter++
-	if credential == "pass" {
-		return nil
+func (t *testAuthenticator) Authenticate(_ context.Context, resource model.Resource, credential auth.Credential) error {
+	switch resource := resource.(type) {
+	case *core_mesh.DataplaneResource:
+		t.callCounter++
+		if credential == "pass" {
+			return nil
+		}
+	default:
+		return errors.Errorf("no matching authenticator for %s resource", resource.GetType())
 	}
-	return errors.New("invalid credential")
-}
 
-func (t *testAuthenticator) AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
-	return nil
+	return errors.New("invalid credential")
 }
 
 var _ = Describe("Authn Callbacks", func() {
-
 	var testAuth *testAuthenticator
 	var resManager core_manager.ResourceManager
 	var callbacks hds_callbacks.Callbacks
diff --git a/pkg/xds/auth/callbacks_test.go b/pkg/xds/auth/callbacks_test.go
index a50d4fa79..0e66f10c6 100644
--- a/pkg/xds/auth/callbacks_test.go
+++ b/pkg/xds/auth/callbacks_test.go
@@ -2,17 +2,18 @@ package auth_test
 
 import (
 	"context"
-	"errors"
 
 	envoy_api "github.com/envoyproxy/go-control-plane/envoy/api/v2"
 	envoy_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
 	envoy_server "github.com/envoyproxy/go-control-plane/pkg/server/v2"
 	pstruct "github.com/golang/protobuf/ptypes/struct"
+	"github.com/pkg/errors"
 	"google.golang.org/grpc/metadata"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_manager "github.com/kumahq/kuma/pkg/core/resources/manager"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/core/resources/model/rest"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
@@ -32,19 +33,22 @@ type testAuthenticator struct {
 
 var _ auth.Authenticator = &testAuthenticator{}
 
-func (t *testAuthenticator) Authenticate(ctx context.Context, dataplane *core_mesh.DataplaneResource, credential auth.Credential) error {
-	t.callCounter++
-	if credential == "pass" {
-		return nil
+func (t *testAuthenticator) Authenticate(_ context.Context, resource model.Resource, credential auth.Credential) error {
+	switch resource := resource.(type) {
+	case *core_mesh.DataplaneResource:
+		t.callCounter++
+		if credential == "pass" {
+			return nil
+		}
+	case *core_mesh.ZoneIngressResource:
+		t.zoneCallCounter++
+		if credential == "zone pass" {
+			return nil
+		}
+	default:
+		return errors.Errorf("no matching authenticator for %s resource", resource.GetType())
 	}
-	return errors.New("invalid credential")
-}
 
-func (t *testAuthenticator) AuthenticateZoneIngress(ctx context.Context, zoneIngress *core_mesh.ZoneIngressResource, credential auth.Credential) error {
-	t.zoneCallCounter++
-	if credential == "zone pass" {
-		return nil
-	}
 	return errors.New("invalid credential")
 }
 
@@ -219,7 +223,7 @@ var _ = Describe("Auth Callbacks", func() {
 		})
 
 		// then
-		Expect(err).To(MatchError("retryable: dataplane not found. Create Dataplane in Kuma CP first or pass it as an argument to kuma-dp"))
+		Expect(err.Error()).To(ContainSubstring("not found"))
 	})
 
 	It("should throw an error on authentication fail", func() {