Kuberenetes ExternalName service forwarding request to service outside cluster - kubernetes

We have a requirement to forward the request to service outside of cluster.
/ -> some service outside cluster (someapi.com)
/api -> service inside cluster
When I try to hit the https://someapi.com/health it gives me proper response but not through ingress.
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: custom-ingress
annotations:
kubernetes.io/ingress.class: haproxy
status:
loadBalancer: {}
spec:
tls:
- hosts:
- mytenant.com
secretName: tenant-secret
rules:
- host: mytenant.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: external-service
port:
number: 80
Service
apiVersion: v1
kind: Service
metadata:
name: external-service
status:
loadBalancer: {}
spec:
type: ExternalName
sessionAffinity: None
externalName: someapi.com
curl -ikv https://mytenant.com/health is giving me
503 Service Unavailable
No server is available to handle this request.
Connection #0 to host mytenant.com left intact
I tried nslookup and it does evaluate to ip
/usr/src/app # nslookup external-service
Server: 901.63.1.11
Address: 901.63.1.11:53
external-service.default.svc.cluster.local canonical name = someapi.com
someapi.com canonical name = proxy-aws-can-55.elb.eu-central-1.amazonaws.com
Name: proxy-aws-can-55.elb.eu-central-1.amazonaws.com
Address: 92.220.220.137
Name: proxy-aws-can-55.elb.eu-central-1.amazonaws.com
Address: 33.43.161.163
Name: proxy-aws-can-55.elb.eu-central-1.amazonaws.com
Address: 98.200.178.250
external-service.default.svc.cluster.local canonical name = someapi.com
someapi.com canonical name = proxy-aws-can-55.elb.eu-central-1.amazonaws.com
When I changed the external-service port to 80 (also tried changing target port of service to 443)
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ExternalName
sessionAffinity: None
externalName: someapi.com
It keeps on looping with 301
< HTTP/2 301
< content-length: 0
< location: https://mytenant.com/health
< strict-transport-security: max-age=15768000
(With same setup if I just change the externalName to httpbin.org it works fine.)
When I changed ingress (port) and service (port and targetPort) to 443, I am getting
REFUSED_STREAM, retrying a fresh connect
Connection died, tried 5 times before giving up
Closing connection 5
curl: (56) Connection died, tried 5 times before giving up
I also tried setting host header mentioned here, https://www.haproxy.com/documentation/kubernetes/latest/configuration/ingress/#set-host but no luck still 301.
Please help me understand how I should make it work. many thanks!

I got the working configuration, I changed the ingress (port) and service (port/targetPort) to 443. Also, added annotation ingress.kubernetes.io/backend-protocol: h1-ssl on ingress.
I believe I was getting 301 because the upstream service was expecting https request and after adding the backend-protocol annotation, after ssl termination at HA Proxy controller, the new call that initiated was https and that fulfilled the request. Also, I think value for Service targetPort doesn't matter in case of ExternalName service.
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: custom-ingress
annotations:
ingress.kubernetes.io/backend-protocol: h1-ssl
kubernetes.io/ingress.class: haproxy
status:
loadBalancer: {}
spec:
tls:
- hosts:
- mytenant.com
secretName: tenant-secret
rules:
- host: mytenant.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: external-service
port:
number: 443
Service
apiVersion: v1
kind: Service
metadata:
name: external-service
status:
loadBalancer: {}
spec:
ports:
- protocol: TCP
port: 443
targetPort: 443
type: ExternalName
sessionAffinity: None
externalName: someapi.com

Related

im trying to set up a kubernetes service that points to an external api that is secured with tls so needs to keep the original host header

i'm trying to set up the following
external user calls https://service1.mycluster.com, my cluster calls https://service1.externalservice.com and then returns the response to the user
i'm doing this to leverage istio and kubernetes thats deployed in my cluster to provide centralised access to services but some of my legacy services can't be moved into the cluster
i believe i'm going to need a service with an externalName to represent the external service but unsure how to get it to resolve the tls and keep the hostname of service1.externalservice.com so the tls will pass
any ideas would be much appreciated thanks
Currently i have the following
service
apiVersion: v1
kind: Service
metadata:
annotations:
name: testservice1
spec:
externalName: https://service1.externalservice.com
internalTrafficPolicy: Cluster
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: None
type: ExternalName
ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: xxx
traefik.ingress.kubernetes.io/router.tls: "true"
name: test1
spec:
ingressClassName: xxx
rules:
- host: service1.mycluster.com
http:
paths:
- backend:
service:
name: testservice1
port:
number: 443
path: /
pathType: Prefix
tls:
- hosts:
- service1.mycluster.com
secretName: tls-test1-ingress

Using nginx-ingress http works but https is not on selfhost kubernetes

i use the nginx-ingress in my kubernetes cluster
i installed the nginx-ingress-controller successful.
here is my ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
spec:
ingressClassName: nginx
rules:
- host: demo.test.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-service
port:
number: 443
---
apiVersion: v1
kind: Service
metadata:
name: demo-service
spec:
selector:
app: hello-node
ports:
- port: 443 # service port
targetPort: 8080 # container port
protocol: TCP
# nodePort port exposed on the host machine
pupulate http url [http://demo.test.cn/] in browser, it works well
populate the https url [https://demo.test.cn/] in browser, it does't work
check the log in nginx-ingress-controller
access log

K8s ingress socket.io 503

I have a Nodejs with socket.io app running on EKS with a ELB. I have configured an ingress with the following yaml.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/websocket-services: ws-gateway
nginx.org/websocket-services: ws-gateway
name: web-socket
namespace: default
spec:
defaultBackend:
service:
name: ws-gateway
port:
number: 9090
rules:
- host: ws.example.com
http:
paths:
- backend:
service:
name: ws-gateway
port:
number: 9090
path: /
pathType: Prefix
tls:
- hosts:
- ws.example.com
secretName: ws-tls
However, when testing this I am receiving 503 Service Temporarily Unavailable. The domain name and service name and port are correct. The request is not reaching the app either.
Is there something that I am missing in the configuration?
The issue was on the service side. The containers were restarting unexpectedly because of connection lost to some other service, which cause a 503 every time I tried to access it.

Redirect everything with ingress-nginx

I have created a YAML file its only job is: It should immediately redirect to google.com
but it just doesn't work...
my localhost still returns 404-nginx
I'm on docker-desktop and my cluster version is v1.21.5
here is my redirect.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-google
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: doesntmatter
port:
number: 80
here is my kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
cheddar nginx cheddar.127.0.0.1.nip.io localhost 80 31m
my-google <none> * 80 26m
stilton nginx stilton.127.0.0.1.nip.io localhost 80 31m
wensleydale nginx wensleydale.127.0.0.1.nip.io localhost 80 31m
NOTE: the other ingress sevices e.g. cheddar.127.0.0.1.nip.io is working perfectly...
I guess you forgot the ingress class name.
spec:
ingressClassName: nginx
...
Apart from that, you can create an external service.
---
apiVersion: v1
kind: Service
metadata:
name: google
spec:
type: ExternalName
externalName: www.google.com
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: google
labels:
name: google
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/upstream-vhost: www.google.com
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: google
port:
name: https
Note, that the cert from your ingress controller is not the cert of google. So there can be some issues around that. One setting that may help with those kind of issues is the annotation nginx.ingress.kubernetes.io/upstream-vhost like shown above.

Istio Gateway/VirtualService does not work (local ip works)

I just set up istio for the first time on a service, and i cannot get the gateway/vs working.
Here is my configuration, it is according with the docs:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: dragon-gateway
spec:
selector:
# use Istio default gateway implementation
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: dragon
spec:
hosts:
- "vtest.westus.cloudapp.azure.com"
gateways:
- dragon-gateway
http:
- match:
- uri:
prefix: /
- uri:
prefix: /status
- uri:
prefix: /delay
- uri:
prefix: /api/values
route:
- destination:
host: dragon
port:
number: 80
The kubectl describe looks fine:
Name: dragon-gateway
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"networking.istio.io/v1alpha3","kind":"Gateway","metadata":{"annotations":{},"name":"dragon-gateway","namespace":"default"},...
API Version: networking.istio.io/v1alpha3
Kind: Gateway
Metadata:
Creation Timestamp: 2019-09-22T22:54:31Z
Generation: 1
Resource Version: 723889
Self Link: /apis/networking.istio.io/v1alpha3/namespaces/default/gateways/dragon-gateway
UID: f0738082-dd8b-11e9-b099-e259debf6109
Spec:
Selector:
Istio: ingressgateway
Servers:
Hosts:
*
Port:
Name: http
Number: 80
Protocol: HTTP
Name: dragon
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"networking.istio.io/v1alpha3","kind":"VirtualService","metadata":{"annotations":{},"name":"dragon","namespace":"default"},"...
API Version: networking.istio.io/v1alpha3
Kind: VirtualService
Metadata:
Creation Timestamp: 2019-09-22T22:54:31Z
Generation: 1
Resource Version: 723891
Self Link: /apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices/dragon
UID: f0988c3c-dd8b-11e9-b099-e259debf6109
Spec:
Gateways:
dragon-gateway
Hosts:
vtest.westus.cloudapp.azure.com
Http:
Match:
Uri:
Prefix: /
Uri:
Prefix: /status
Uri:
Prefix: /delay
Uri:
Prefix: /api/values
Route:
Destination:
Host: dragon
Port:
Number: 80
The service has the configuration as follow:
apiVersion: v1
kind: Service
metadata:
namespace: flight
name: dragon
labels:
app: dragon
release: r1
version: 1.0.0
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 80
selector:
app: dragon
release: r1
The docker file is quite simple:
FROM microsoft/dotnet:latest AS runtime
# ports
EXPOSE 80
EXPOSE 443
WORKDIR /
COPY /publish /app
RUN dir /app
WORKDIR /app
FROM runtime AS final
ENTRYPOINT ["dotnet", "dragon.dll"]
Please let me know if you have any idea. I tried to curl from another pod, and it works. The problem is using the external IP or using the internal IP that's assigned to the gateway. None of these work.
Thanks in advance for any clue.
Edit:
Adding more info about the curl
curl 40.118.228.111/api/values -v
* Trying 40.118.228.111...
* TCP_NODELAY set
* Connected to 40.118.228.111 (40.118.228.111) port 80 (#0)
> GET /api/values HTTP/1.1
> Host: 40.118.228.111
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< date: Sun, 22 Sep 2019 23:27:54 GMT
< server: istio-envoy
< content-length: 0
<
* Connection #0 to host 40.118.228.111 left intact
Adding proxy status as well:
NAME CDS LDS EDS RDS PILOT VERSION
dragon-dc789456b-g9fxb.flight SYNCED SYNCED SYNCED (50%) SYNCED istio-pilot-689d75bc8-j7j8m 1.1.3
istio-ingressgateway-5c4f9f859d-nj9sq.istio-system SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-689d75bc8-j7j8m 1.1.3
Looks like you put the dragon VirtualService and the dragon-gateway in the default namespace?
Because service names rely on dns and typically a pod's resolv.conf search paths only include the local namespace, the service name dragon will only resolve properly within the same namespace. Instead, use the fqdn for the dragon service:
...
route:
- destination:
host: dragon.flight.svc.cluster.local
port:
number: 80
You have configured istio to route based on hostname but your curl command is using the ip address. Either configure DNS with an A record like this - vtest.westus.cloudapp.azure.com -> 40.118.228.111, or force curl to send the correct host header:
curl http://vtest.westus.cloudapp.azure.com/api/values --resolve vtest.westus.cloudapp.azure.com:80:40.118.228.111
Hi I am not expert about istio but after invsetigation it looks like working with host and istio gateway, virtualnetworkservices you should use Host prefix in order to pass host HTTP Header,
like this:
curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/
This is needed because your ingress Gateway is configured to handle “httpbin.example.com”, but in your test environment you have no DNS binding for that host and are simply sending your request to the ingress IP.
From another point of view this setting must match Vitualservice:
A VirtualService must be bound to the gateway and must have one or more hosts that match the hosts specified in a server.
Specifying '*' bound all hostnames.
Also you can restrict Virtualservices or specify multiple rules for servers like hosts/hosts using this approach.
More advanced examples you can find here- Istio Server:
Hope this help.