I'm running Istio in Google Kubenetes Engine. My application uses gRPC and has an Extensible Service Proxy container to link to the Google Enpoints Service.
Istio on GKE by default blocks all egress requests, bu that breaks the ESP container since it needs to request some data from outside the Istio mesh.
The logs from the ESP informed me it was trying to access IP 169.254.169.254 to get some metadata, so I opened up an egress channel from Istio to let that happen, and that's fine.
But the next thing the ESP attempts is to "fetch the service config ID from the rollouts service". Again this is blocked but this time the log error doesn't tell me the URL that it's trying to access, only the path. So I don't know what url to open up for egress.
This is the log entry:
WARNING:Retrying (Retry(total=2, connect=None, read=None, redirect=None,
status=None)) after connection broken by 'ProtocolError('Connection
aborted.', error(104, 'Connection reset by peer'))':
/v1/services/rev79.endpoints.rev79-232812.cloud.goog/rollouts?filter=status=SUCCESS
so can anyone tell me what URLs the ESP needs to access to be able to work?
For anyone else stuck with this problem.
The ESP needs access to two separate endpoints in order to run without crashing. They are
servicemanagement.googleapis.com (HTTPS)
169.254.269.254 (HTTP)
To function correctly, it also needs
servicecontrol.googleapis.com (HTTPS)
If you have strict egress filtering in your Istio mesh, you will need two ServiceEntry resource to make this happen.
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: endpoints-cert
spec:
hosts:
- metadata.google # this field does not matter
addresses:
- 169.254.169.254/32
ports:
- number: 80
name: http
protocol: HTTP
resolution: NONE
location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: endpoints-metadata
spec:
hosts:
- "servicemanagement.googleapis.com"
- "servicecontrol.googleapis.com"
ports:
- number: 80 # may not be necessary
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
If you are using an egress gateway, you will need additional configuration for both of
these endpoints.
I eventually stumbled across what I was looking for by googling parts of the path with some key words.
This looks like what the ESP is trying to access:
https://servicemanagement.googleapis.com/v1/services/{serviceName}/rollouts/{rolloutId}
Indeed opening up a route to that host gets the ESP up and running.
Related
I am running Azure AKS with Kubenet networking, in which I have deployed several services, exposed on several ports.
I have configured a URL based routing and it seems to work for the services I could test.
I found out the following:
sending URL and URL:80, returns the desired web page, but the URL displayed in the browser's address bar is removing the port, if I send it. Looks like http://URL/
When I try accessing other web pages or services, I get a strange phenomena: Calling the URL with the port number, is waiting until the browser says it's unreachable. Fiddler returns "time out".
When I access the service (1 of 3 I could check visibly) and not provide the port, the Ingress rules I applied answer the request and I get the resulting web page, which is exposed on the internal service port.
i'm using this YAML, for rabbit management page:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rabbit-admin-on-ingress
namespace: mynamespace
spec:
rules:
- host: rabbit.my.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rabbitmq
port:
number: 15672
ingressClassName: nginx
and also, apply this config (using kubectl apply -f config.file.yaml):
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
namespace: ingress-nginx
data:
15672: "mynamespace/rabbitmq:15672"
What happens is:
http://rabbit.my.local gets the rabbit admin page
http://rabbit.my.local:15672 get a time out and I get frustrated
It seems this is also happening on another service I have running on port 8085 and perhaps even the DB running on the usual SQL port (might be a TCP only connection)
Both are configured the same as the rabbitmq service in the yaml rules and config file, with their respected service names, namespaces and ports.
Please help me to figure out how I can make Ingress accept the URLs with the :PORT attached to it and answer them. Save me.
A quick reminder - :80 works fine. Perhaps because it's one of the defaults for Ingress
Thank you so much in advance.
Moshe
I want block outgoing traffic to the ip (eg-DB) in IP tables in K8s.
I know that in K8s ip tables exist only at node level.
and I'm not sure in which file changes should be made and what is the command or changes required.
Please help me with this query.
Thanks.
You could deploy istio and specifically the istio egress gateway.
This way you will be able to manage outgoing traffic within the istio manifest
You can directly run the IPtable command (ex. iptables -A OUTPUT -j REJECT) on top of a node if that's fine.
however file depends on the OS : /etc/sysconfig/iptables this is for ipv4
i would suggest checking out the Network policy in Kubernetes using that you can block the outgoing traffic.
https://kubernetes.io/docs/concepts/services-networking/network-policies/
No extra setup is required like Istio or anything.
Cluster security you can handle using the network policy in the backend it uses IP tables only.
For example to block traffic on specific CIDR or IP by applying the YAML only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
Was anyone able to integrate the three in the subject to achive end-2-end TLS? To clarify, I'm talking about TLS between Application Gateway and Istio ingress.
There are some threads on StackOverflow and there is an old issue on AGIC Github repo but i was not able to find any evidence it's really working. If someone have it working, can you share the setup?
• According to the Istio documentation, any request to the gateway will have two connections, viz., client downstream inbound connection to the gateway and client outbound connection to the destination as shown in the figure below: -
Thus, in the above scenario, consider the gateway as the Azure application gateway and the Istio ingress as the destination, as a result both these connections are independent TLS connections.
For TLS connections, there are a few more options:
a) What protocol is encapsulated? If the connection is HTTPS, the server protocol should be configured as HTTPS. Otherwise, for a raw TCP connection encapsulated with TLS, the protocol should be set to TLS.
b) Is the TLS connection terminated or passed through? For passthrough traffic, configure the TLS mode field to PASSTHROUGH : -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
...
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
In this mode, Istio will route based on SNI information and forward the connection as-is to the destination. Mutual TLS can be configured through the TLS mode MUTUAL. When this is configured, a client certificate will be requested and verified against the configured caCertificates or credentialName : -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
...
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: MUTUAL
caCertificates: ... ’
The only difference is that you should be careful to consider the Gateway settings when configuring this. For example, if the Gateway is configured with TLS PASSTHROUGH while the DestinationRule configures TLS origination, you will end up with double encryption. This works but is often not the desired behavior.
A VirtualService bound to the gateway needs care as well to ensure it is consistent with the Gateway definition. In this scenario, consider the gateway as an Azure application gateway in that sense the TLS settings are configured correctly. For more information, kindly refer to the Istio documentation below: -
https://istio.io/latest/docs/ops/configuration/traffic-management/tls-configuration/
https://istio.io/latest/docs/tasks/traffic-management/ingress/ingress-sni-passthrough/
I have the following situation:
I have a couple of microservices, only 2 are relevant right now.
- Web Socket Service API
- Dispatcher Service
We have 3 users that we'll call respectively 1, 2, and 3. These users connect themselves to the web socket endpoint of our backend. Our microservices are running on Kubernetes and each services can be replicated multiple times inside Pods. For this situation, we have 1 running container for the dispatcher, and 3 running containers for the web socket api. Each pod has its Load Balancer and this will be each time the entry point.
In our situation, we will then have the following "schema":
Now that we have a representation of our system (and a legend), our 3 users will want to use the app and connect.
As we can see, the load balancer of our pod forwarded the web socket connection of our users across the different containers. Each container, once it gets a new connection, will let to know the Dispatcher Service, and this one will save it in its own database.
Now, 3 users are connected to 2 different containers and the Dispatcher service knows it.
The user 1 wants to message user 2. The container A will then get a message and tell the Dispatcher Service: Please, send this to the user 2.
As the dispatcher knows to which container the user 2 is connected, I would like to send a request directly to my Container instead of sending it to the Pod. Sending it to the Pod is resulting in sending a request to a load balancer which actually dispatches the request to the most available container instance...
How could I manage to get the container IP? Can it be accessed by another container from another Pod?
To me, the best approach would be that, once the app start, it gets the current container's IP and then send it within the register request to the dispatcher, so the dispatcher would know that ContainerID=IP
Thanks!
edit 1
There is my web-socket-service-api.yaml
apiVersion: v1
kind: Service
metadata:
name: web-socket-service-api
spec:
ports:
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8080
targetPort: 8080
protocol: TCP
name: grpc
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8081
targetPort: 8081
protocol: TCP
name: rest
# Port that accepts WebSockets.
- port: 8082
targetPort: 8082
protocol: TCP
name: websocket
selector:
app: web-socket-service-api
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-socket-service-api
spec:
replicas: 3
template:
metadata:
labels:
app: web-socket-service-api
spec:
containers:
- name: web-socket-service-api
image: gcr.io/[PROJECT]/web-socket-service-api:latest
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 8082
Dispatcher ≈ Message broker
As how I understand your design, your Dispatcher is essentially a message broker for the pods of your Websocket Service. Let all Websocket pods connect to the broker and let the broker route messages. This is a stateful service and you should use a StatefulSet for this in Kubernetes. Depending on your requirements, a possible solution could be to use a MQTT-broker for this, e.g. mosquitto. Most MQTT brokers have support for websockets.
Scale out: Multiple replicas of pods
each services can be replicated multiple times inside Pods. For this situation, we have 1 running container for the dispatcher, and 3 running containers for the web socket api.
This is not how Kubernetes is intented to be used. Use multiple replicas of pods instead of multiple containers in the pod. I recommend that you create a Deployment for your Websocket Service with as many replicas you want.
Service as Load balancer
Each pod has its Load Balancer and this will be each time the entry point.
In Kubernetes you should create a Service that load balance traffic to a set of pods.
Your solution
To me, the best approach would be that, once the app start, it gets the current container's IP and then send it within the register request to the dispatcher, so the dispatcher would know that ContainerID=IP
Yes, I mostly agree. That is similar to what I have described here. But I would let the Websocket Service establish a connection to the Broker/Dispatcher.
Any pod, has some information about itself. And one of the info, is it own IP address. As an example:
apiVersion: v1
kind: Pod
metadata:
name: envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_POD_IP;
sleep 10;
done;
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
Within the container, MY_POD_IP would contain the IP address of the pod. You can let the dispatcher know about it.
$ kubectl logs envars-fieldref
10.52.0.3
$ kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
envars-fieldref 1/1 Running 0 31s 10.52.0.3 gke-klusta-lemmy-3ce02acd-djhm <none> <none>
Note that it is not a good idea to rely on pod IP address. But this should do the trick.
Also, it is exactly the same thing to send a request to the pod or to the container.
I am running a restfull service behind self signed cert thru NGINX in google cloud kubernetes infrastructure.
Kubernetes service loader exposes 443 and routes the traffic those containers. All is working just fine as expected other than asking internal clients to ignore the self sign cert warning!
It is time for to move to CA cert thus only option as far as I see is https loader but I couldnt figure out how we can reroute the traffic to service loader or directly to pods as service loader(http loader)
Any help apprecaited
Update Firewall Rules for:
IP: 130.211.0.0/22
tcp:30000-32767
Create NodePort type service:
apiVersion: v1
kind: Service
metadata:
name: yourservicenodeport
labels:
name: your-service-node-port
spec:
type: NodePort
ports:
- port: 80
nodePort: 30001
selector:
name: yourpods
Create health check.
For the nodeport which is in this case: 30001
Create an ingress service:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: youTheking-ingress-service
spec:
backend:
serviceName: yourservice
servicePort: 80
Wait for few minutes, be patient.
Change the health check on http load balancer.
a. Go to the Load Balancing on Networking Tab.
b. Click Advance menu.
c. Go Backend Services and Edit.
d. Update health check option and use the one created for nodeport service.
Repeat step 5 for instance group to be recognized health.
SSL is needed, go back to the load balancer, edit, click Frontend Configuration, then add https with cert.
You are ready to roll.
I'm not sure I fully understand you question but I'll try to answer it anyway.
You have two options for exposing your service using a cert signed by a trusted CA:
Do what you are doing today but with the real cert. You will probably want to put the cert into a secret and point your nginx configuration at it to load the cert.
Replace nginx with the google L7 load balancer. You would upload your certificate to google, configure the L7 balancer to terminate HTTPS and forward traffic to your backends.