Enabling HTTPS port in k8s - kubernetes-ingress

I am trying to add port 5665 into istio-ingressgatway and its been added but the traffic is not (I think) routed correctly since i am keep getting SSL error
curl -k https://api.loadbalancer.local.com:5665/v1/bla ; echo
curl: (35) error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number
where I am able to telnet the port on ingressgateway LB
❯ telnet api.loadbalancer.local.com 5665
Trying 10.239.49.9...
Connected to api.loadbalancer.local.com.
Escape character is '^]'.
and the service is responding fine if I call directly the POD IP as example
IP: 10.23.49.90
Controlled By: ReplicaSet/icinga2-84bd777b9
Containers:
icinga2:
Image: jordan/icinga2:latest
Ports: 80/TCP, 443/TCP, 5665/TCP
Host Ports: 0/TCP, 0/TCP, 0/TCP
State: Running
Ready: True
Restart Count: 0
Liveness: http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
❯ curl -k https://10.23.49.90:5665/
<h1>Unauthorized. Please check your user credentials.</h1>%
❯ curl -k https://10.23.49.90:5665/v1/bla
<h1>Unauthorized. Please check your user credentials.</h1>%
❯ curl -k http://10.23.49.90:5665/
curl: (52) Empty reply from server
Routing config
istio-ingress-gateway for opening the port
- name: api
nodePort: 30431
port: 5665
protocol: TCP
targetPort: 5665
Gateway configuration
apiVersion: v1
items:
- apiVersion: networking.istio.io/v1beta1
kind: Gateway
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: api
number: 5665
protocol: HTTPS
tls:
mode: SIMPLE
VirtualService
apiVersion: v1
items:
- apiVersion: networking.istio.io/v1beta1
kind: VirtualService
spec:
gateways:
- icinga2
hosts:
- '*'
http:
- match:
- port: 5665
route:
- destination:
host: icinga2.default.svc.cluster.local
port:
number: 5665
Question
What I am doing wrong to make this port working same as when I am calling the POD IP directly ?
and I presume that the reason that I am getting curl: (35) error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number is due to some misconfiguration.
Also I even don't know where to look to troubleshoot the issue so if someone could explain where to look would be helpful too.
Regards.

Just to add the answer for others how i fixed the issue.
Gateway
Change:
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: https
number: 5665
protocol: HTTPS
targetPort: 5665
tls:
mode: PASSTHROUGH
VirtualService
Change:
spec:
gateways:
- icinga2
hosts:
- '*'
tls:
- match:
- port: 5665
route:
- destination:
host: icinga2.default.svc.cluster.local
port:
number: 5665
Please note the TLS tag above the match rule, before somehow i put there http
And now i am able to make the call to the api via https
❯ curl -k https://api.loadbalancer.local.com:5665/v1/bla ; echo
<h1>Unauthorized. Please check your user credentials.</h1>

Related

How to expose MySQL database in kubernetes using Kong Gateway?

I installed kong using helm chart. In values.yaml I specified two TCP ports in Stream section:
stream:
- containerPort: 39019 #MongoDB
servicePort: 39019
protocol: TCP
parameters:
- ssl
- containerPort: 43576 #MySQL
servicePort: 43576
protocol: TCP
parameters:
- ssl
My intention is to expose one port for MongoDB and another for MySQL.
After that, I created a TCPIngress file for both databases:
one for MySQL
apiVersion: configuration.konghq.com/v1beta1
kind: TCPIngress
metadata:
name: tcp-mysql
annotations:
kubernetes.io/tls-acme: "true"
cert-manager.io/cluster-issuer: letsencrypt
kubernetes.io/ingress.class: kong
konghq.com/plugins: global-file-log
spec:
tls:
- hosts:
- s.mytest.domain
secretName: s.mytest.domain-certificate
rules:
- host: s.mytest.domain
port: 43576
backend:
serviceName: mysql
servicePort: 3306
and other for MongoDB
apiVersion: configuration.konghq.com/v1beta1
kind: TCPIngress
metadata:
name: tcp-mongodb
annotations:
kubernetes.io/tls-acme: "true"
cert-manager.io/cluster-issuer: letsencrypt
kubernetes.io/ingress.class: kong
konghq.com/plugins: global-file-log
spec:
tls:
- hosts:
- s.mytest.domain
secretName: s.mytest.domain-certificate
rules:
- host: s.mytest.domain
port: 39019
backend:
serviceName: mongodb
servicePort: 27017
with this configuration, MongoDB works perfect, but MySQL doesnt.
I couldn't find a way to connect to MySQL using my test domain.
If I do a port-forward to my MySQL pod, it works as expected.
I'm new to Kong and Kubernetes in general. How can I trace whats going wrong and how can I solve this?

ambassador edge stack mapping is not working

I am trying to set up the ambassador edge stack in my local Kubernetes (Docker Desktop cluster).
After all deployment, I checked the ambassador namespace and everything is working as expected. Moreover, I have my deployment (pod and services) working.I have changed the ambassador edge-stack service to nodeport so I can access and test locally. also, I have added the url in my HOST file.
Now, Here is the detail.
kubectl get svc -n ambassador
kubectl get svc -n sample-on-ambassador-edgestack
edgestack-listener yaml:
--------------------------
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: my-listener-80
namespace: sample-on-ambassador-edgestack
spec:
port: 80
protocol: HTTP
securityModel: XFP
hostBinding:
namespace:
from: ALL
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: my-listener-8080
namespace: sample-on-ambassador-edgestack
spec:
port: 8080
protocol: HTTP
securityModel: XFP
hostBinding:
namespace:
from: ALL
edgestack-binding yaml
-------------------------
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: my-mappingrules
namespace: sample-on-ambassador-edgestack
spec:
hostname: "local.edgestack.com"
prefix: /apple/
service: my-apple-service.sample-on-ambassador-edgestack
NOTE: I have used Service: pod.service form above.
With this, I am getting edgestack home page with http://local.edgestack.com
but If I type: local.edgestack.com/apple/ I am getting 404 error page.
same with curl comamnd:
curl -i http://local.edgestack.com:32510/apple/
HTTP/1.1 404 Not Found
date: Thu, 02 Dec 2021 01:51:48 GMT
server: envoy
content-length: 0
Your issue has nothing to do with namespacing but rather is that you are accessing the service on a NodePort and are therefore including the port in the host of your curl request but not configuring Emissary to account for that.
If you were to send a curl with the -v flag set, you would see that this request has > Host: local.edgestack.com:32510 which is not the same as local.edgestack.com which your Emissary Ingress is expecting. Since the hostname of the incoming request does not match the Mapping.spec.hostname you have configured, Emissary is not finding a matching route and returning a 404.
You can get around this by doing a glob in the Mapping.spec.hostname so that it matches local.edgestack.com and any ports that follow
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: my-mappingrules
namespace: sample-on-ambassador-edgestack
spec:
hostname: "local.edgestack.com*"
prefix: /apple/
service: my-apple-service

How to visualize my web application with browser using Kubernetes Nginx Ingress?

I am following this web site to develop an API with Nginx Ingress. When I use curl command it works !
curl -v -k -H "Host: myServiceA.foo.org" http:<IP_ADDRESS_INGRESS_NGINX>:80
Now I would like to use a browser like Chrome or Firefox but I don't find any way to do it knowing that http:<IP_ADDRESS_INGRESS_NGINX>:80 doesn't work without header.
Do you know how to do please ?
Regards
It's not working because you've configured the host field in ingress yaml.
Using the same yaml from Nginx docs you've posted:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org <== HERE
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
The ingress will only accept the connection and forwarding the request to your service if the request contains the host myServiceA.foo.org.
You could test it editing the /etc/hosts of your machine e pointing to the nginx ingress ip:
File /etc/hosts
<INGRESS_IP> myServiceA.foo.org
Or another option is remove the field host in this way the ingress will accept requests coming from the Nginx ingress ip, like this yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: echo-svc
servicePort: 80

Kubernetes ingress same path multiple ports

After much googling and searching (even here), I'm not able to find a definitive answer to my question. So I hope someone here might be able to point me in the right direction.
I have a Kube Service definition that's already working for me, but right now I've simply exposed it with just a LoadBalancer. Here's my current Service yaml:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: namespace1
labels:
app: my-service
spec:
type: LoadBalancer
selector:
app: my-service
tier: web
ports:
- name: proxy-port
port: 8080
targetPort: 8080
- name: metrics-port
port: 8082
targetPort: 8082
- name: admin-port
port: 8092
targetPort: 8092
- name: grpc-port
port: 50051
targetPort: 50051
This is obviously only TCP load-balanced. What I want to do is secure this with Mutual TLS, so that the server will only accept connections from my client with the authorized certificate.
From all I can tell in Kube land, what I need to do that is an Ingress definition. I've been researching all the docs I can find on kind:Ingress and I can't seem to find anything where it allows me to create a single Ingress with multiple ports on the same path!
Am I missing something here? Is there no way to create a K8s Ingress that simply has the same functionality as the above Service definition?
To my knowledge you cannot use custom ports (e.g 8080) for HTTPS LoadBalancer backed with Ingress Controller (e.g. NGINX HTTP(S) Proxy), as
currently the port of an Ingress is implicitly :80 for http and :443 for https, as official doc reference for IngressRule explains.
I think the workaround would be to use different host per service, like with this example of Ingress resource:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: proxy.foo.com
http:
paths:
- backend:
serviceName: proxy-svc
servicePort: 8080
- host: metrics.foo.com
http:
paths:
- backend:
serviceName: metrics-svc
servicePort: 8082
- host: admin.foo.com
http:
paths:
- backend:
serviceName: admin-svc
servicePort: 8092
- host: grpc.foo.com
http:
paths:
- backend:
serviceName: grpc-svc
servicePort: 50051
I faced the same situation where we had to expose port 80,443 and 50051 on the same host. Using traefik v2+ on K3S, this is how I solved it:
Apply this file to modify traefik config; this is with K3S. If you have installed traefik directly with the chart, add a values file with the same config as below.
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
grpc:
port: 50051
protocol: TCP
expose: true
exposedPort: 50051
After it is done, watch the traefik service be updated with the new config.
If its not working, make sure the port youve set are free and not used by another service.
When this is done, you can create IngressRoute object. Here I got one for grpc (50051) and one for web (80/443).
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: db
spec:
entryPoints:
- web
- websecure
routes:
- kind: Rule
match: Host(`lc1.nebula.global`)
services:
- name: db
port: 80
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: db-grpc
spec:
entryPoints:
- grpc
routes:
- kind: Rule
match: Host(`lc1.nebula.global`)
services:
- name: db-grpc
port: 50051
EDIT:::
if running with your own instance of k3s with the community helm chart (not the one provided by k3s). Here is the equivalent config I have:
traefik:
rbac:
enabled: true
ports:
web:
redirectTo: websecure
websecure:
tls:
enabled: true
grpc:
port: 50051
protocol: TCP
expose: true
exposedPort: 50051
podAnnotations:
prometheus.io/port: "8082"
prometheus.io/scrape: "true"
providers:
kubernetesIngress:
publishedService:
enabled: true
priorityClassName: "system-cluster-critical"
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
additionalArguments:
- "--entrypoints.grpc.http2.maxconcurrentstreams=10000"
ingress:
enabled: false
host: traefik.local
annotations: {}
In my case, I also increase the max number of concurrent http2 streams for grpc.

how to check if kubernetes services like mysql, rabbitmq are reachable by the deployed app

I am new to Kubernetes. I am trying to deploy a microservices architecture based springboot web application in Kubernetes. I have setup Kubernetes on OpenStack. All Kubernetes services are running fine.
I followed https://github.com/fabric8io/gitcontroller/tree/master/vendor/k8s.io/kubernetes/examples/javaweb-tomcat-sidecar
to deploy a sample springboot application at
https://www.mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/
and I could see the web app at localhost:8080 and <'node-ip'>:8080.
But the application which I am trying to deploy needs MySQL and rabbitmq, so I created MySQL and rabbitmq services using the yaml file(javaweb.yaml):
javaweb.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
type: NodePort
ports:
- protocol: TCP
port: 3306
targetPort: 3306
selector:
app: mysql
---
apiVersion: v1
kind: Service
metadata:
# Expose the management HTTP port on each node
name: rabbitmq-management
labels:
app: rabbitmq
spec:
type: NodePort # Or LoadBalancer in production w/ proper security
ports:
- port: 15672
name: http
selector:
app: rabbitmq
---
apiVersion: v1
kind: Service
metadata:
# The required headless service for StatefulSets
name: rabbitmq
labels:
app: rabbitmq
spec:
ports:
- port: 5672
name: amqp
- port: 4369
name: epmd
- port: 25672
name: rabbitmq-dist
clusterIP: None
selector:
app: rabbitmq
---
apiVersion: v1
kind: Pod
metadata:
name: javaweb
spec:
containers:
- image: chakravarthych/sample:v1
name: war
volumeMounts:
- mountPath: /app
name: app-volume
- image: mysql:5.7
name: mysql
ports:
- protocol: TCP
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: root123
command: ["sh","-c","service mysql start; tail -f /dev/null"]
- image: rabbitmq:3.7-management
name: rabbitmq
ports:
- name: http
protocol: TCP
containerPort: 15672
- name: amqp
protocol: TCP
containerPort: 5672
command: ["sh","-c","service rabbitmq-server start; tail -f /dev/null"]
- image: tomcat:8.5.33
name: tomcat
volumeMounts:
- mountPath: /usr/local/tomcat/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8080
command: ["sh","-c","/usr/local/tomcat/bin/startup.sh; tail -f /dev/null"]
volumes:
- name: app-volume
emptyDir: {}
When I try to access my application at localhost:8080 or <'node-ip'>:8080 I see a blank page.
command kubectl get all -o wide gave me below output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
pod/javaweb 4/4 Running 0 1h 192.168.9.123 kube-node1 <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d <none>
service/mysql NodePort 10.101.253.11 <none> 3306:30527/TCP 1h app=mysql
service/rabbitmq ClusterIP None <none> 5672/TCP,4369/TCP,25672/TCP 1h app=rabbitmq
service/rabbitmq-management NodePort 10.108.7.162 <none> 15672:30525/TCP 1h app=rabbitmq
which shows that MySQL and rabbitmq are running.
My question is how to check if my application has access to MySQL and rabbitmq services running in Kubernetes.
Note:
I could access rabbitmq at 192.168.9.123:15672 only.
I could also log in to MySQL inside of Docker container.
Did you try a "kubectl log" on the springboot pod? You may have some indication of what is going wrong.