Repository: linkerd/linkerd2
Pull request #4160 (2020-03-10 09:37:51)

Set auth override
The changes here use the change in proxy-api to set the AuthorityOverride when that is present on the endpoints annotation. Additionally, it enables the cluster watcher to set the gateway identity data on the endpoints that it creates. This enalbes authority rewrite in the proxy as well as end to end identitiy. 



zaharidichev: This.. depends on https://github.com/linkerd/linkerd2-proxy-api/pull/38 which should come with a new release for the proxy api

Patch:
diff --git a/Dockerfile-proxy b/Dockerfile-proxy
index fd1a9a508..b758d67db 100644
--- a/Dockerfile-proxy
+++ b/Dockerfile-proxy
@@ -9,7 +9,7 @@ RUN (proxy=$(bin/fetch-proxy $(cat proxy-version)) && \
     mv "$proxy" linkerd2-proxy)
 
 ## compile proxy-identity agent
-FROM gcr.io/linkerd-io/go-deps:6b9a8ea4 as golang
+FROM gcr.io/linkerd-io/go-deps:1b3f62c3 as golang
 WORKDIR /linkerd-build
 COPY pkg/flags pkg/flags
 COPY pkg/tls pkg/tls
diff --git a/cli/Dockerfile-bin b/cli/Dockerfile-bin
index fe5542c4c..32957f83e 100644
--- a/cli/Dockerfile-bin
+++ b/cli/Dockerfile-bin
@@ -1,5 +1,5 @@
 ## compile binaries
-FROM gcr.io/linkerd-io/go-deps:6b9a8ea4 as golang
+FROM gcr.io/linkerd-io/go-deps:1b3f62c3 as golang
 WORKDIR /linkerd-build
 COPY cli cli
 COPY charts charts
diff --git a/cni-plugin/Dockerfile b/cni-plugin/Dockerfile
index 69e39fbfa..c812258ea 100644
--- a/cni-plugin/Dockerfile
+++ b/cni-plugin/Dockerfile
@@ -1,5 +1,5 @@
 ## compile cni-plugin utility
-FROM gcr.io/linkerd-io/go-deps:6b9a8ea4 as golang
+FROM gcr.io/linkerd-io/go-deps:1b3f62c3 as golang
 WORKDIR /linkerd-build
 COPY pkg pkg
 COPY controller controller
diff --git a/controller/Dockerfile b/controller/Dockerfile
index 21dcac40d..2c6684e4c 100644
--- a/controller/Dockerfile
+++ b/controller/Dockerfile
@@ -1,5 +1,5 @@
 ## compile controller service
-FROM gcr.io/linkerd-io/go-deps:6b9a8ea4 as golang
+FROM gcr.io/linkerd-io/go-deps:1b3f62c3 as golang
 WORKDIR /linkerd-build
 COPY controller/gen controller/gen
 COPY pkg pkg
diff --git a/controller/api/destination/endpoint_translator.go b/controller/api/destination/endpoint_translator.go
index c4acdbc7c..7a1811699 100644
--- a/controller/api/destination/endpoint_translator.go
+++ b/controller/api/destination/endpoint_translator.go
@@ -49,12 +49,20 @@ func (et *endpointTranslator) Add(set watcher.AddressSet) {
 		if address.Pod != nil {
 			wa, err = et.toWeightedAddr(address)
 		} else {
+			var authOverride *pb.AuthorityOverride
+			if address.AuthorityOverride != "" {
+				authOverride = &pb.AuthorityOverride{
+					AuthorityOverride: address.AuthorityOverride,
+				}
+			}
+
 			// handling address with no associated pod
 			var addr *net.TcpAddress
 			addr, err = et.toAddr(address)
 			wa = &pb.WeightedAddr{
-				Addr:   addr,
-				Weight: defaultWeight,
+				Addr:              addr,
+				Weight:            defaultWeight,
+				AuthorityOverride: authOverride,
 			}
 
 			if address.Identity != "" {
@@ -65,7 +73,7 @@ func (et *endpointTranslator) Add(set watcher.AddressSet) {
 						},
 					},
 				}
-				// in this case we most likely have a proxy on the side, so set protocol hint as well.
+				// in this case we most likely have a proxy on the other side, so set protocol hint as well.
 				if et.enableH2Upgrade {
 					wa.ProtocolHint = &pb.ProtocolHint{
 						Protocol: &pb.ProtocolHint_H2_{
diff --git a/controller/api/destination/watcher/endpoints_watcher.go b/controller/api/destination/watcher/endpoints_watcher.go
index fd2f6b450..6dfb400e2 100644
--- a/controller/api/destination/watcher/endpoints_watcher.go
+++ b/controller/api/destination/watcher/endpoints_watcher.go
@@ -31,12 +31,13 @@ type (
 	// case that this endpoint is not associated with a pod and maps
 	// to some other IP (i.e. a remote service gateway)
 	Address struct {
-		IP        string
-		Port      Port
-		Pod       *corev1.Pod
-		OwnerName string
-		OwnerKind string
-		Identity  string
+		IP                string
+		Port              Port
+		Pod               *corev1.Pod
+		OwnerName         string
+		OwnerKind         string
+		Identity          string
+		AuthorityOverride string
 	}
 
 	// AddressSet is a set of Address, indexed by ID.
@@ -90,6 +91,7 @@ type (
 	portPublisher struct {
 		id         ServiceID
 		targetPort namedPort
+		srcPort    Port
 		hostname   string
 		log        *logging.Entry
 		k8sAPI     *k8s.API
@@ -392,6 +394,7 @@ func (sp *servicePublisher) newPortPublisher(srcPort Port, hostname string) *por
 	port := &portPublisher{
 		listeners:  []EndpointUpdateListener{},
 		targetPort: targetPort,
+		srcPort:    srcPort,
 		hostname:   hostname,
 		exists:     exists,
 		k8sAPI:     sp.k8sAPI,
@@ -465,10 +468,16 @@ func (pp *portPublisher) endpointsToAddresses(endpoints *corev1.Endpoints) Addre
 					Namespace: endpoints.ObjectMeta.Namespace,
 				}
 
+				var authorityOverride string
+				if fqName, ok := endpoints.Annotations[consts.RemoteServiceFqName]; ok {
+					authorityOverride = fmt.Sprintf("%s:%d", fqName, pp.srcPort)
+				}
+
 				addresses[id] = Address{
-					IP:       endpoint.IP,
-					Port:     resolvedPort,
-					Identity: endpoints.Annotations[consts.RemoteGatewayIdentity],
+					IP:                endpoint.IP,
+					Port:              resolvedPort,
+					Identity:          endpoints.Annotations[consts.RemoteGatewayIdentity],
+					AuthorityOverride: authorityOverride,
 				}
 				continue
 			}
diff --git a/controller/cmd/service-mirror/cluster_watcher.go b/controller/cmd/service-mirror/cluster_watcher.go
index 782be2b0f..ffedf91c1 100644
--- a/controller/cmd/service-mirror/cluster_watcher.go
+++ b/controller/cmd/service-mirror/cluster_watcher.go
@@ -76,6 +76,7 @@ type (
 		gatewayData          *gatewayMetadata
 		newResourceVersion   string
 		affectedServices     []*corev1.Service
+		identity             string
 	}
 
 	// ConsiderGatewayUpdateDispatch is issued when we are receiving an update for a
@@ -142,9 +143,9 @@ func (re RetryableError) Error() string {
 	return fmt.Sprintf("Inner errors:\n\t%s", strings.Join(errorStrings, "\n\t"))
 }
 
-func (rcsw *RemoteClusterServiceWatcher) extractGatewayInfo(gateway *corev1.Service) ([]corev1.EndpointAddress, int32, string, error) {
+func (rcsw *RemoteClusterServiceWatcher) extractGatewayInfo(gateway *corev1.Service) ([]corev1.EndpointAddress, int32, string, string, error) {
 	if len(gateway.Status.LoadBalancer.Ingress) == 0 {
-		return nil, 0, "", errors.New("expected gateway to have at lest 1 external Ip address but it has none")
+		return nil, 0, "", "", errors.New("expected gateway to have at lest 1 external Ip address but it has none")
 	}
 
 	var foundPort = false
@@ -158,7 +159,7 @@ func (rcsw *RemoteClusterServiceWatcher) extractGatewayInfo(gateway *corev1.Serv
 	}
 
 	if !foundPort {
-		return nil, 0, "", fmt.Errorf("cannot find  port named %s on gateway", consts.GatewayPortName)
+		return nil, 0, "", "", fmt.Errorf("cannot find  port named %s on gateway", consts.GatewayPortName)
 	}
 
 	var gatewayEndpoints []corev1.EndpointAddress
@@ -168,16 +169,19 @@ func (rcsw *RemoteClusterServiceWatcher) extractGatewayInfo(gateway *corev1.Serv
 			Hostname: ingress.Hostname,
 		})
 	}
-	return gatewayEndpoints, port, gateway.ResourceVersion, nil
+
+	gatewayIdentity := gateway.Annotations[consts.GatewayIdentity]
+
+	return gatewayEndpoints, port, gateway.ResourceVersion, gatewayIdentity, nil
 }
 
 // When the gateway is resolved we need to produce a set of endpoint addresses that that
 // contain the external IPs that this gateway exposes. Therefore we return the IP addresses
 // as well as a single port on which the gateway is accessible.
-func (rcsw *RemoteClusterServiceWatcher) resolveGateway(metadata *gatewayMetadata) ([]corev1.EndpointAddress, int32, string, error) {
+func (rcsw *RemoteClusterServiceWatcher) resolveGateway(metadata *gatewayMetadata) ([]corev1.EndpointAddress, int32, string, string, error) {
 	gateway, err := rcsw.remoteAPIClient.Svc().Lister().Services(metadata.Namespace).Get(metadata.Name)
 	if err != nil {
-		return nil, 0, "", err
+		return nil, 0, "", "", err
 	}
 	return rcsw.extractGatewayInfo(gateway)
 }
@@ -401,7 +405,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceUpdated(ev *RemoteSe
 	serviceInfo := fmt.Sprintf("%s/%s", ev.remoteUpdate.Namespace, ev.remoteUpdate.Name)
 	rcsw.log.Debugf("Updating remote mirrored service %s/%s", ev.localService.Namespace, ev.localService.Name)
 
-	gatewayEndpoints, gatewayPort, resVersion, err := rcsw.resolveGateway(ev.gatewayData)
+	gatewayEndpoints, gatewayPort, resVersion, gatewayIdentity, err := rcsw.resolveGateway(ev.gatewayData)
 	if err == nil {
 		ev.localEndpoints.Subsets = []corev1.EndpointSubset{
 			{
@@ -413,6 +417,12 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceUpdated(ev *RemoteSe
 		ev.localEndpoints.Labels[consts.RemoteGatewayNameLabel] = ev.gatewayData.Name
 		ev.localEndpoints.Labels[consts.RemoteGatewayNsLabel] = ev.gatewayData.Namespace
 
+		if gatewayIdentity != "" {
+			ev.localEndpoints.Annotations[consts.RemoteGatewayIdentity] = gatewayIdentity
+		} else {
+			delete(ev.localEndpoints.Annotations, consts.RemoteGatewayIdentity)
+		}
+
 	} else {
 		rcsw.log.Warnf("Could not resolve gateway for %s: %s, nulling endpoints", serviceInfo, err)
 		ev.localEndpoints.Subsets = nil
@@ -479,11 +489,14 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceCreated(ev *RemoteSe
 				consts.RemoteGatewayNameLabel: ev.gatewayData.Name,
 				consts.RemoteGatewayNsLabel:   ev.gatewayData.Namespace,
 			},
+			Annotations: map[string]string{
+				consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.%s", remoteService.Name, remoteService.Namespace, rcsw.clusterDomain),
+			},
 		},
 	}
 
 	// Now we try to resolve the remote gateway
-	gatewayEndpoints, gatewayPort, resVersion, err := rcsw.resolveGateway(ev.gatewayData)
+	gatewayEndpoints, gatewayPort, resVersion, gatewayIdentity, err := rcsw.resolveGateway(ev.gatewayData)
 	if err == nil {
 		// only if we resolve it, we are updating the endpoints addresses and ports
 		rcsw.log.Debugf("Resolved remote gateway [%v:%d] for %s", gatewayEndpoints, gatewayPort, serviceInfo)
@@ -493,9 +506,10 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteServiceCreated(ev *RemoteSe
 				Ports:     rcsw.getEndpointsPorts(ev.service, gatewayPort),
 			},
 		}
-
 		serviceToCreate.Annotations[consts.RemoteGatewayResourceVersionAnnotation] = resVersion
-
+		if gatewayIdentity != "" {
+			endpointsToCreate.Annotations[consts.RemoteGatewayIdentity] = gatewayIdentity
+		}
 	} else {
 		rcsw.log.Warnf("Could not resolve gateway for %s: %s, skipping subsets", serviceInfo, err)
 		endpointsToCreate.Subsets = nil
@@ -570,6 +584,13 @@ func (rcsw *RemoteClusterServiceWatcher) handleRemoteGatewayUpdated(ev *RemoteGa
 				Ports:     rcsw.getEndpointsPorts(updatedService, ev.newPort),
 			},
 		}
+
+		if ev.identity != "" {
+			updatedEndpoints.Annotations[consts.RemoteGatewayIdentity] = ev.identity
+		} else {
+			delete(updatedEndpoints.Annotations, consts.RemoteGatewayIdentity)
+		}
+
 		_, err = rcsw.localAPIClient.Client.CoreV1().Services(updatedService.Namespace).Update(updatedService)
 		if err != nil {
 			errors = append(errors, err)
@@ -624,7 +645,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleConsiderGatewayUpdateDispatch(eve
 			Name:      event.maybeGateway.Name,
 			Namespace: event.maybeGateway.Namespace,
 		}
-		if endpoints, port, resVersion, err := rcsw.extractGatewayInfo(event.maybeGateway); err != nil {
+		if endpoints, port, resVersion, identity, err := rcsw.extractGatewayInfo(event.maybeGateway); err != nil {
 			rcsw.log.Warnf("Gateway [%s/%s] is not a compliant gateway anymore, dispatching GatewayDeleted event: %s", event.maybeGateway.Namespace, event.maybeGateway.Name, err)
 			// in case something changed about this gateway and it is not really a gateway anymore,
 			// simply dispatch deletion event so all endpoints are nulled
@@ -646,6 +667,7 @@ func (rcsw *RemoteClusterServiceWatcher) handleConsiderGatewayUpdateDispatch(eve
 					gatewayData:          gatewayMeta,
 					newResourceVersion:   resVersion,
 					affectedServices:     affectedServices,
+					identity:             identity,
 				})
 			}
 
diff --git a/go.mod b/go.mod
index 230c5509b..4d1761920 100644
--- a/go.mod
+++ b/go.mod
@@ -31,7 +31,7 @@ require (
 	github.com/huandu/xstrings v1.2.0 // indirect
 	github.com/imdario/mergo v0.3.7
 	github.com/julienschmidt/httprouter v1.2.0
-	github.com/linkerd/linkerd2-proxy-api v0.1.10
+	github.com/linkerd/linkerd2-proxy-api v0.1.12
 	github.com/linkerd/linkerd2-proxy-init v1.3.2
 	github.com/mattn/go-isatty v0.0.9
 	github.com/mattn/go-runewidth v0.0.2
diff --git a/go.sum b/go.sum
index 57e1e409a..f13c3cfc2 100644
--- a/go.sum
+++ b/go.sum
@@ -211,6 +211,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/linkerd/linkerd2-proxy-api v0.1.10 h1:zGwz2Fek7fdfCxyZW7jq8IE6sexeVFW5UFBQFL6MrP4=
 github.com/linkerd/linkerd2-proxy-api v0.1.10/go.mod h1:2WJHEYXoww5ALM6c1QspRFiROGZg08tGxCO1js0tTVA=
+github.com/linkerd/linkerd2-proxy-api v0.1.12-0.20200309112816-75a7b3b20597 h1:HIzyna4iqxvaBgLVicTvoiBJjWlgqe28iBDygTG14lA=
+github.com/linkerd/linkerd2-proxy-api v0.1.12-0.20200309112816-75a7b3b20597/go.mod h1:2WJHEYXoww5ALM6c1QspRFiROGZg08tGxCO1js0tTVA=
+github.com/linkerd/linkerd2-proxy-api v0.1.12 h1:mP0UYjmemLI6Ru7m1HW3d9up5Bt9VRB9FsxRA8jy2IM=
+github.com/linkerd/linkerd2-proxy-api v0.1.12/go.mod h1:2WJHEYXoww5ALM6c1QspRFiROGZg08tGxCO1js0tTVA=
 github.com/linkerd/linkerd2-proxy-init v1.3.1 h1:KTvUvPlSKUkpzZM0L/EIk+EJaKk7dwygu0CP95fOyGI=
 github.com/linkerd/linkerd2-proxy-init v1.3.1/go.mod h1:lK/sORPZDP6aFhPZps+AHMKphX5v9bKVDNESllz18C0=
 github.com/linkerd/linkerd2-proxy-init v1.3.2 h1:bl+gwdBtHI0cki/urTyicxxb/ekQtVWJ6NDWzMXAgVs=
diff --git a/pkg/k8s/labels.go b/pkg/k8s/labels.go
index ac8ebeba9..92ad276d9 100644
--- a/pkg/k8s/labels.go
+++ b/pkg/k8s/labels.go
@@ -377,6 +377,9 @@ const (
 	// RemoteGatewayIdentity follows the same kind of logic as RemoteGatewayNameLabel
 	RemoteGatewayIdentity = SvcMirrorPrefix + "/remote-gateway-identity"
 
+	// GatewayIdentity can be found on the remote gateway service
+	GatewayIdentity = SvcMirrorPrefix + "/gateway-identity"
+
 	// ConfigKeyName is the key in the secret that stores the kubeconfig needed to connect
 	// to a remote cluster
 	ConfigKeyName = "kubeconfig"
diff --git a/web/Dockerfile b/web/Dockerfile
index c06e9eb4d..d123ba527 100644
--- a/web/Dockerfile
+++ b/web/Dockerfile
@@ -21,7 +21,7 @@ COPY web/app ./web/app
 RUN ./bin/web build
 
 ## compile go server
-FROM gcr.io/linkerd-io/go-deps:6b9a8ea4 as golang
+FROM gcr.io/linkerd-io/go-deps:1b3f62c3 as golang
 WORKDIR /linkerd-build
 RUN mkdir -p web
 COPY web/main.go web


Test patch:
diff --git a/controller/api/destination/endpoint_translator_test.go b/controller/api/destination/endpoint_translator_test.go
index 3f5e22b38..9a07fe75c 100644
--- a/controller/api/destination/endpoint_translator_test.go
+++ b/controller/api/destination/endpoint_translator_test.go
@@ -105,6 +105,13 @@ var (
 		Port:     2,
 		Identity: "some-identity",
 	}
+
+	remoteGatewayWithTLSAndAuthOverride = watcher.Address{
+		IP:                "1.1.1.2",
+		Port:              2,
+		Identity:          "some-identity",
+		AuthorityOverride: "some-auth.com:2",
+	}
 )
 
 func makeEndpointTranslator(t *testing.T) (*mockDestinationGetServer, *endpointTranslator) {
@@ -165,6 +172,46 @@ func TestEndpointTranslatorForRemoteGateways(t *testing.T) {
 		}
 	})
 
+	t.Run("Sends TlsIdentity and Auth override when present", func(t *testing.T) {
+		expectedTLSIdentity := &pb.TlsIdentity_DnsLikeIdentity{
+			Name: "some-identity",
+		}
+
+		expectedProtocolHint := &pb.ProtocolHint{
+			Protocol: &pb.ProtocolHint_H2_{
+				H2: &pb.ProtocolHint_H2{},
+			},
+		}
+
+		expectedAuthOverride := &pb.AuthorityOverride{
+			AuthorityOverride: "some-auth.com:2",
+		}
+
+		mockGetServer, translator := makeEndpointTranslator(t)
+
+		translator.Add(mkAddressSetForServices(remoteGatewayWithTLSAndAuthOverride))
+
+		addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
+		if len(addrs) != 1 {
+			t.Fatalf("Expected [1] address returned, got %v", addrs)
+		}
+
+		actualTLSIdentity := addrs[0].GetTlsIdentity().GetDnsLikeIdentity()
+		if !reflect.DeepEqual(actualTLSIdentity, expectedTLSIdentity) {
+			t.Fatalf("Expected TlsIdentity to be [%v] but was [%v]", expectedTLSIdentity, actualTLSIdentity)
+		}
+
+		actualProtocolHint := addrs[0].GetProtocolHint()
+		if !reflect.DeepEqual(actualProtocolHint, expectedProtocolHint) {
+			t.Fatalf("Expected ProtoclHint to be [%v] but was [%v]", expectedProtocolHint, actualProtocolHint)
+		}
+
+		actualAuthOverride := addrs[0].GetAuthorityOverride()
+		if !reflect.DeepEqual(actualProtocolHint, expectedProtocolHint) {
+			t.Fatalf("Expected AuthOverride to be [%v] but was [%v]", expectedAuthOverride, actualAuthOverride)
+		}
+	})
+
 	t.Run("Does not send TlsIdentity when not present", func(t *testing.T) {
 		mockGetServer, translator := makeEndpointTranslator(t)
 
diff --git a/controller/api/destination/watcher/endpoints_watcher_test.go b/controller/api/destination/watcher/endpoints_watcher_test.go
index 9e0e09b73..bd4178a89 100644
--- a/controller/api/destination/watcher/endpoints_watcher_test.go
+++ b/controller/api/destination/watcher/endpoints_watcher_test.go
@@ -31,6 +31,9 @@ func addressString(address Address) string {
 	if address.Identity != "" {
 		addressString = fmt.Sprintf("%s/%s", addressString, address.Identity)
 	}
+	if address.AuthorityOverride != "" {
+		addressString = fmt.Sprintf("%s/%s", addressString, address.AuthorityOverride)
+	}
 	return addressString
 }
 
@@ -664,7 +667,7 @@ subsets:
 			id:          ServiceID{Name: "name1-remote", Namespace: "ns"},
 			port:        8989,
 			expectedAddresses: []string{
-				"172.17.0.12:8989/gateway-identity-1",
+				"172.17.0.12:8989/gateway-identity-1/name1-remote-fq:8989",
 			},
 			expectedNoEndpoints:              false,
 			expectedNoEndpointsServiceExists: false,
@@ -700,7 +703,7 @@ subsets:
 			id:          ServiceID{Name: "name1-remote", Namespace: "ns"},
 			port:        8989,
 			expectedAddresses: []string{
-				"172.17.0.12:8989",
+				"172.17.0.12:8989/name1-remote-fq:8989",
 			},
 			expectedNoEndpoints:              false,
 			expectedNoEndpointsServiceExists: false,
@@ -738,7 +741,44 @@ subsets:
 			id:          ServiceID{Name: "name1-remote", Namespace: "ns"},
 			port:        8989,
 			expectedAddresses: []string{
-				"172.17.0.12:9999/gateway-identity-1",
+				"172.17.0.12:9999/gateway-identity-1/name1-remote-fq:8989",
+			},
+			expectedNoEndpoints:              false,
+			expectedNoEndpointsServiceExists: false,
+		},
+		{
+			k8sConfigs: []string{`
+apiVersion: v1
+kind: Service
+metadata:
+  name: name1-remote
+  namespace: ns
+spec:
+  type: LoadBalancer
+  ports:
+  - port: 8989`,
+				`
+apiVersion: v1
+kind: Endpoints
+metadata:
+  name: name1-remote
+  namespace: ns
+  annotations:
+    mirror.linkerd.io/remote-gateway-identity: ""
+    mirror.linkerd.io/remote-svc-fq-name: "name1-remote-fq"
+  labels:
+    mirror.linkerd.io/mirrored-service: "true"
+subsets:
+- addresses:
+  - ip: 172.17.0.12
+  ports:
+  - port: 9999`,
+			},
+			serviceType: "mirrored service with empty identity and remapped port in endpoints",
+			id:          ServiceID{Name: "name1-remote", Namespace: "ns"},
+			port:        8989,
+			expectedAddresses: []string{
+				"172.17.0.12:9999/name1-remote-fq:8989",
 			},
 			expectedNoEndpoints:              false,
 			expectedNoEndpointsServiceExists: false,
diff --git a/controller/cmd/service-mirror/cluster_watcher_test.go b/controller/cmd/service-mirror/cluster_watcher_test.go
index eb8980aa1..e2189ed27 100644
--- a/controller/cmd/service-mirror/cluster_watcher_test.go
+++ b/controller/cmd/service-mirror/cluster_watcher_test.go
@@ -145,7 +145,7 @@ func TestRemoteServiceCreated(t *testing.T) {
 				mirroredService("service-one-remote", "ns1", "missing-gateway", "missing-namespace", "111", "", nil),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("service-one-remote", "ns1", "missing-gateway", "missing-namespace", "", nil),
+				endpoints("service-one-remote", "ns1", "missing-gateway", "missing-namespace", "", "", nil),
 			},
 		},
 		{
@@ -188,10 +188,10 @@ func TestRemoteServiceCreated(t *testing.T) {
 					}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "", nil),
+				endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "", "", nil),
 			},
 			remoteResources: []string{
-				gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "incoming-port-wrong", 888, t),
+				gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "incoming-port-wrong", 888, "", t),
 			},
 		},
 		{
@@ -239,7 +239,7 @@ func TestRemoteServiceCreated(t *testing.T) {
 					}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "192.0.2.127", []corev1.EndpointPort{
+				endpoints("service-one-remote", "ns1", "existing-gateway", "existing-namespace", "192.0.2.127", "gateway-identity", []corev1.EndpointPort{
 					{
 						Name:     "port1",
 						Port:     888,
@@ -253,7 +253,7 @@ func TestRemoteServiceCreated(t *testing.T) {
 				}),
 			},
 			remoteResources: []string{
-				gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "incoming-port", 888, t),
+				gatewayAsYaml("existing-gateway", "existing-namespace", "222", "192.0.2.127", "incoming-port", 888, "gateway-identity", t),
 			},
 		},
 	} {
@@ -275,7 +275,7 @@ func TestRemoteServiceDeleted(t *testing.T) {
 
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "", "", "", nil, t),
-				endpointsAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "", "", nil, t),
+				endpointsAsYaml("test-service-remote-to-delete-remote", "test-namespace-to-delete", "", "", "", "gateway-identity", nil, t),
 			},
 		},
 	} {
@@ -314,7 +314,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 							Port:     222,
 						},
 					}),
-					localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", []corev1.EndpointPort{
+					localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{
 						{
 							Name:     "port1",
 							Port:     888,
@@ -333,7 +333,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 				},
 			},
 			remoteResources: []string{
-				gatewayAsYaml("gateway-new", "gateway-ns", "currentGatewayResVersion", "0.0.0.0", "incoming-port", 999, t),
+				gatewayAsYaml("gateway-new", "gateway-ns", "currentGatewayResVersion", "0.0.0.0", "incoming-port", 999, "", t),
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "past", "pastGatewayResVersion", []corev1.ServicePort{
@@ -348,7 +348,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 						Port:     222,
 					},
 				}, t),
-				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", []corev1.EndpointPort{
+				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{
 					{
 						Name:     "port1",
 						Port:     888,
@@ -383,7 +383,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 					}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-remote", "test-namespace", "gateway-new", "gateway-ns", "0.0.0.0", []corev1.EndpointPort{
+				endpoints("test-service-remote", "test-namespace", "gateway-new", "gateway-ns", "0.0.0.0", "", []corev1.EndpointPort{
 					{
 						Name:     "port1",
 						Port:     999,
@@ -425,7 +425,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 							Port:     222,
 						},
 					}),
-					localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", []corev1.EndpointPort{
+					localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{
 						{
 							Name:     "port1",
 							Port:     888,
@@ -444,7 +444,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 				},
 			},
 			remoteResources: []string{
-				gatewayAsYaml("gateway", "gateway-ns", "currentGatewayResVersion", "192.0.2.127", "incoming-port", 888, t),
+				gatewayAsYaml("gateway", "gateway-ns", "currentGatewayResVersion", "192.0.2.127", "incoming-port", 888, "", t),
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "past", "pastGatewayResVersion", []corev1.ServicePort{
@@ -464,7 +464,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 						Port:     333,
 					},
 				}, t),
-				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", []corev1.EndpointPort{
+				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{
 					{
 						Name:     "port1",
 						Port:     888,
@@ -499,7 +499,7 @@ func TestRemoteServiceUpdated(t *testing.T) {
 			},
 
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", []corev1.EndpointPort{
+				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "192.0.2.127", "", []corev1.EndpointPort{
 					{
 						Name:     "port1",
 						Port:     888,
@@ -572,14 +572,14 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 				}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-1-port",
 							Port:     999,
 							Protocol: "TCP",
 						}}),
-				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-2-port",
@@ -596,7 +596,7 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 							Port:     8081,
 						},
 					}, t),
-				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-1-port",
@@ -610,7 +610,7 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 						Port:     8082,
 					},
 				}, t),
-				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-2-port",
@@ -668,14 +668,14 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 				}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1",
+				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-1-port",
 							Port:     888,
 							Protocol: "TCP",
 						}}),
-				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1",
+				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.1", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-2-port",
@@ -693,7 +693,7 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 							Port:     8081,
 						},
 					}, t),
-				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-1-port",
@@ -707,7 +707,105 @@ func TestRemoteGatewayUpdated(t *testing.T) {
 						Port:     8082,
 					},
 				}, t),
-				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
+					[]corev1.EndpointPort{
+						{
+							Name:     "svc-2-port",
+							Port:     888,
+							Protocol: "TCP",
+						}}, t),
+			},
+		},
+
+		{
+			testDescription: "identity is updated on gateway change",
+			events: []interface{}{
+				&RemoteGatewayUpdated{
+					identity:             "new-identity",
+					newPort:              888,
+					newEndpointAddresses: []corev1.EndpointAddress{{IP: "0.0.0.0"}},
+					gatewayData: &gatewayMetadata{
+						Name:      "gateway",
+						Namespace: "gateway-ns",
+					},
+					newResourceVersion: "currentGatewayResVersion",
+					affectedServices: []*corev1.Service{
+						mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion",
+							[]corev1.ServicePort{
+								{
+									Name:     "svc-1-port",
+									Protocol: "TCP",
+									Port:     8081,
+								},
+							}),
+						mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{
+							{
+								Name:     "svc-2-port",
+								Protocol: "TCP",
+								Port:     8082,
+							},
+						}),
+					},
+				},
+			},
+			expectedLocalServices: []*corev1.Service{
+				mirroredService("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion",
+					[]corev1.ServicePort{
+						{
+							Name:     "svc-1-port",
+							Protocol: "TCP",
+							Port:     8081,
+						},
+					}),
+				mirroredService("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "currentGatewayResVersion", []corev1.ServicePort{
+					{
+						Name:     "svc-2-port",
+						Protocol: "TCP",
+						Port:     8082,
+					},
+				}),
+			},
+			expectedLocalEndpoints: []*corev1.Endpoints{
+				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "new-identity",
+					[]corev1.EndpointPort{
+						{
+							Name:     "svc-1-port",
+							Port:     888,
+							Protocol: "TCP",
+						}}),
+				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "new-identity",
+					[]corev1.EndpointPort{
+						{
+							Name:     "svc-2-port",
+							Port:     888,
+							Protocol: "TCP",
+						}}),
+			},
+
+			localResources: []string{
+				mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion",
+					[]corev1.ServicePort{
+						{
+							Name:     "svc-1-port",
+							Protocol: "TCP",
+							Port:     8081,
+						},
+					}, t),
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
+					[]corev1.EndpointPort{
+						{
+							Name:     "svc-1-port",
+							Port:     888,
+							Protocol: "TCP",
+						}}, t),
+				mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion", []corev1.ServicePort{
+					{
+						Name:     "svc-2-port",
+						Protocol: "TCP",
+						Port:     8082,
+					},
+				}, t),
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-2-port",
@@ -752,8 +850,8 @@ func TestRemoteGatewayDeleted(t *testing.T) {
 				}),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", nil),
-				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", nil),
+				endpoints("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil),
+				endpoints("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil),
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "pastGatewayResVersion",
@@ -764,7 +862,7 @@ func TestRemoteGatewayDeleted(t *testing.T) {
 							Port:     8081,
 						},
 					}, t),
-				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-1-port",
@@ -778,7 +876,7 @@ func TestRemoteGatewayDeleted(t *testing.T) {
 						Port:     8082,
 					},
 				}, t),
-				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0",
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "",
 					[]corev1.EndpointPort{
 						{
 							Name:     "svc-2-port",
@@ -802,9 +900,9 @@ func TestClusterUnregistered(t *testing.T) {
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil, t),
-				endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", nil, t),
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil, t),
 				mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil, t),
-				endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", nil, t),
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil, t),
 			},
 		},
 	} {
@@ -822,9 +920,9 @@ func TestGcOrphanedServices(t *testing.T) {
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-1-remote", "test-namespace", "gateway", "gateway-ns", "", "", nil, t),
-				endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", nil, t),
+				endpointsAsYaml("test-service-1-remote", "test-namespace", "", "", "", "", nil, t),
 				mirroredServiceAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil, t),
-				endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", nil, t),
+				endpointsAsYaml("test-service-2-remote", "test-namespace", "", "", "", "", nil, t),
 			},
 			remoteResources: []string{
 				remoteServiceAsYaml("test-service-1", "test-namespace", "gateway", "gateway-ns", "", nil, t),
@@ -835,7 +933,7 @@ func TestGcOrphanedServices(t *testing.T) {
 			},
 
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-1-remote", "test-namespace", "", "", "", nil),
+				endpoints("test-service-1-remote", "test-namespace", "", "", "", "", nil),
 			},
 		},
 	} {
@@ -891,11 +989,11 @@ func onAddOrUpdateTestCases(t *testing.T, isAdd bool) []testCase {
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil, t),
-				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil, t),
+				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil, t),
 			},
 			expectedEventsInQueue: []interface{}{&RemoteServiceUpdated{
 				localService:   mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil),
-				localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil),
+				localEndpoints: endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil),
 				remoteUpdate:   remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil),
 				gatewayData: &gatewayMetadata{
 					Name:      "gateway",
@@ -906,23 +1004,23 @@ func onAddOrUpdateTestCases(t *testing.T, isAdd bool) []testCase {
 				mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "pastResourceVersion", "gatewayResVersion", nil),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil),
+				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil),
 			},
 		},
 		{
-			testDescription: fmt.Sprintf("not not enqueue any events as this update does not really tell us anything new (res version is the same...) (%s)", testType),
+			testDescription: fmt.Sprintf("not enqueue any events as this update does not really tell us anything new (res version is the same...) (%s)", testType),
 			events: []interface{}{
 				onAddOrUpdateEvent(isAdd, remoteService("test-service", "test-namespace", "gateway", "gateway-ns", "currentResVersion", nil)),
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil, t),
-				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil, t),
+				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil, t),
 			},
 			expectedLocalServices: []*corev1.Service{
 				mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil),
+				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil),
 			},
 		},
 		{
@@ -932,7 +1030,7 @@ func onAddOrUpdateTestCases(t *testing.T, isAdd bool) []testCase {
 			},
 			localResources: []string{
 				mirroredServiceAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil, t),
-				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil, t),
+				endpointsAsYaml("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil, t),
 			},
 			expectedEventsInQueue: []interface{}{&RemoteServiceDeleted{
 				Name:      "test-service",
@@ -943,7 +1041,7 @@ func onAddOrUpdateTestCases(t *testing.T, isAdd bool) []testCase {
 				mirroredService("test-service-remote", "test-namespace", "gateway", "gateway-ns", "currentResVersion", "gatewayResVersion", nil),
 			},
 			expectedLocalEndpoints: []*corev1.Endpoints{
-				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", nil),
+				endpoints("test-service-remote", "test-namespace", "gateway", "gateway-ns", "0.0.0.0", "", nil),
 			},
 		},
 	}
diff --git a/controller/cmd/service-mirror/cluster_watcher_test_util.go b/controller/cmd/service-mirror/cluster_watcher_test_util.go
index 05d73a4a5..17869dbcb 100644
--- a/controller/cmd/service-mirror/cluster_watcher_test_util.go
+++ b/controller/cmd/service-mirror/cluster_watcher_test_util.go
@@ -131,7 +131,7 @@ func mirroredServiceAsYaml(name, namespace, gtwName, gtwNs, resourceVersion, gat
 	return string(bytes)
 }
 
-func gateway(name, namespace, resourceVersion, ip, portName string, port int32) *corev1.Service {
+func gateway(name, namespace, resourceVersion, ip, portName string, port int32, identity string) *corev1.Service {
 	svc := corev1.Service{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Service",
@@ -141,6 +141,9 @@ func gateway(name, namespace, resourceVersion, ip, portName string, port int32)
 			Name:            name,
 			Namespace:       namespace,
 			ResourceVersion: resourceVersion,
+			Annotations: map[string]string{
+				consts.GatewayIdentity: identity,
+			},
 		},
 		Spec: corev1.ServiceSpec{
 			Ports: []corev1.ServicePort{
@@ -159,8 +162,8 @@ func gateway(name, namespace, resourceVersion, ip, portName string, port int32)
 	return &svc
 }
 
-func gatewayAsYaml(name, namespace, resourceVersion, ip, portName string, port int32, t *testing.T) string {
-	gtw := gateway(name, namespace, resourceVersion, ip, portName, port)
+func gatewayAsYaml(name, namespace, resourceVersion, ip, portName string, port int32, identity string, t *testing.T) string {
+	gtw := gateway(name, namespace, resourceVersion, ip, portName, port, identity)
 
 	bytes, err := yaml.Marshal(gtw)
 	if err != nil {
@@ -169,7 +172,7 @@ func gatewayAsYaml(name, namespace, resourceVersion, ip, portName string, port i
 	return string(bytes)
 }
 
-func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, ports []corev1.EndpointPort) *corev1.Endpoints {
+func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, gatewayIdentity string, ports []corev1.EndpointPort) *corev1.Endpoints {
 	var subsets []corev1.EndpointSubset
 	if gatewayIP != "" {
 		subsets = []corev1.EndpointSubset{
@@ -184,7 +187,7 @@ func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, ports []corev1
 		}
 	}
 
-	return &corev1.Endpoints{
+	endpoints := &corev1.Endpoints{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Endpoints",
 			APIVersion: "v1",
@@ -198,13 +201,22 @@ func endpoints(name, namespace, gtwName, gtwNs, gatewayIP string, ports []corev1
 				consts.RemoteGatewayNameLabel: gtwName,
 				consts.RemoteGatewayNsLabel:   gtwNs,
 			},
+			Annotations: map[string]string{
+				consts.RemoteServiceFqName: fmt.Sprintf("%s.%s.svc.cluster.local", strings.Replace(name, "-remote", "", 1), namespace),
+			},
 		},
 		Subsets: subsets,
 	}
+
+	if gatewayIdentity != "" {
+		endpoints.Annotations[consts.RemoteGatewayIdentity] = gatewayIdentity
+	}
+
+	return endpoints
 }
 
-func endpointsAsYaml(name, namespace, gtwName, gtwNs, gatewayIP string, ports []corev1.EndpointPort, t *testing.T) string {
-	ep := endpoints(name, namespace, gtwName, gtwNs, gatewayIP, ports)
+func endpointsAsYaml(name, namespace, gtwName, gtwNs, gatewayIP, gatewayIdentity string, ports []corev1.EndpointPort, t *testing.T) string {
+	ep := endpoints(name, namespace, gtwName, gtwNs, gatewayIP, gatewayIdentity, ports)
 
 	bytes, err := yaml.Marshal(ep)
 	if err != nil {