Using Istio ServiceEntry to configure external services
Learn how to use the Istio ServiceEntry resource to represent external services, be it as IP addresses or host names.
/debug/registryz
returns the information about all services Istio is aware of:ISTIOD=$(kubectl get -A pods --selector=app=istiod -o jsonpath='{.items[*].metadata.name}')
kubectl exec -it $ISTIOD -n istio-system -- curl localhost:8080/debug/registryz | jq '.[] | .hostname'
"httpbin.test-ns.svc.cluster.local"
"istio-egressgateway.istio-system.svc.cluster.local"
"istio-ingressgateway.istio-system.svc.cluster.local"
"istiod.istio-system.svc.cluster.local"
"kube-dns.kube-system.svc.cluster.local"
"kubernetes.default.svc.cluster.local"
"metrics-server.kube-system.svc.cluster.local"
"sleep.default.svc.cluster.local"
/debug/instancesz
is the one that shows the instance with the proxy injected - it shows the proxies that are connected to the Istios' control plane: kubectl exec -it $ISTIOD -n istio-system -- curl localhost:8080/debug/instancesz | jq 'keys'
[
"istio-egressgateway-7475c75b68-v87zj.istio-system",
"istio-ingressgateway-6688c7f65d-8rmw2.istio-system",
"sleep-75bbc86479-m8n6c.default"
]
https://httpbin.org/headers
from within any of the containers that are part of the mesh, we'll get the response back, even though the httpbin.org
host isn't part of the Istio's service registry.meshConfig.outboundTrafficPolicy.mode
settings, that's set to ALLOW_ANY
by default. If we change the outbound traffic policy to REGISTRY_ONLY
, Envoy proxies will block calls made to unknown services.Note
You can use the following command to change the outbound traffic policy mode:istioctl install --set profile=demo --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
https://httpbin.org/headers
using the mesh with the REGISTRY_ONLY
mode, we'll get back an HTTP 502 response because the Envoy proxy doesn't know anything about the httpbin.org
host. This is where we can use the ServiceEntry resource to add entries to the service registry manually.REGISTRY_ONLY
and blocking all external traffic by default is similar to configuring a deny-all authorization policy. We can be explicit about which external traffic we allow and include them in the mesh individually instead of using ALLOW_ALL
mode.REGISTRY_ONLY
mode in an existing mesh, as that might cause many problems and HTTP 502 responses. You might be better off continuing with ALLOW_ALL
mode while adding external services to the mesh. Once you've configured all services, switch to the REGISTRY_ONLY
.ServiceEntry for external services
httpbin.org
host:apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-httpbin
spec:
hosts:
- httpbin.org
location: MESH_EXTERNAL
ports:
- name: http
number: 80
protocol: HTTP
resolution: DNS
httpbin.org
host part of the Istio's service registry and tells Envoy proxies to pass through the requests.MESH_EXTERNAL
services, the mTLS authentication is disabled, and the policy enforcement is performed on the callers' side instead of the server side (as we don't know if there's a proxy running there or not).httpbin.org
host by querying the DNS. There are a couple of other options we have here that are related to different fields that can be set in the ServiceEntry resource, and we'll look at them through other scenarios.httpbin.org
) in VirtualService as in the ServiceEntry resource.apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin.org
http:
- fault:
abort:
httpStatus: 500
percentage:
value: 100
route:
- destination:
host: httpbin.org
What if I have an IP address?
STATIC
, and this tells Envoy to use the addresses specified in the endpoints
field:apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-ip
spec:
hosts:
- "thisdoesnt.matter"
addresses:
- 1.2.3.4
location: MESH_INTERNAL
ports:
- name: http
number: 80
protocol: HTTP
resolution: STATIC
endpoints:
- address: 1.2.3.4
addresses
field. These addresses are virtual IPs that are associated with the service. Practically, you can read the above ServiceEntry as "if I send a request to 1.2.3.4 (addresses field), the request will go to 1.2.3.4 (endpoints field)".apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ip-vs
spec:
hosts:
- thisdoesnt.matter
http:
- fault:
abort:
httpStatus: 500
percentage:
value: 100
route:
- destination:
host: thisdoesnt.matter
I have an IP address, but I want to use a DNS name
curl thisdoesnt.matter
instead of curl 1.2.3.4
, we can do that! To do that, we can create a headless Kubernetes service with an endpoint object. Then, in the ServiceEntry, we won't have any IP addresses, as the address would be part of the endpoint object, and we could use the DNS resolution and the hostname from the headless Kubernetes service.apiVersion: v1
kind: Service
metadata:
name: headless-svc
spec:
clusterIP: None
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Endpoints
metadata:
# Same as the Service name
name: headless-svc
namespace: default
subsets:
- addresses:
- hostname: headless-svc-0
ip: 1.2.3.4
ports:
- name: http
port: 80
protocol: TCP
headless-svc.default.svc.cluster.local
to access IP 1.2.3.4. Setting up the ServiceEntry for this is equivalent to the first scenario we explained:apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-httpbin
spec:
hosts:
- headless-svc
location: MESH_EXTERNAL
ports:
- name: http
number: 80
protocol: HTTP
resolution: DNS