Kubernetes Ingress
Kubernetes Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.
An Ingress can be configured to give Kubernetes services externally reachable URLs, load balance traffic, terminate SSL/TLS, and offer name-based virtual hosting.
FortiADC Ingress Controller is responsible for fulfilling the Ingress specified with the IngressClass "fadc-ingress-controller" with FortiADC.
Here is a simple example where an Ingress sends all its traffic to one Service:
In the above example, the Kubernetes service is an abstract method to expose an application running on a set of Pods as a network service. There are multiple types of Kubernetes services, among them, service with NodePort type exposes the service on each Kubernetes cluster Node's IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>:<NodePort>.
It is important to note that to satisfy an Ingress, you must have an Ingress controller (in the example above, FortiADC Ingress Controller is used). Only creating an Ingress resource would have no effect.
FortiADC Ingress Controller version 1.0 only supports services of type NodePort. |
Ingress class
Ingresses can be implemented by different controllers, often with different configurations. Each Ingress should specify an IngressClass name, which is a reference to an IngressClass resource that contains additional configuration including the name of the controller that should implement the class.
For an Ingress that would be implemented by FortiADC Ingress Controller, please specify the ingressClassName
to fadc-ingress-controller
in the ingress specification. Upon installation, FortiADC Ingress Controller is set as the default Ingress controller in the Helm chart value.yaml.
controller: ingressClassResource: name: "fadc-ingress-controller" enabled: true default: true controllerValue: "fortinet.com/fadc-ingress-controller"
Mapping of the Ingress related resources with the FortiADC objects
Kubernetes Objects |
FortiADC Objects |
---|---|
Ingress |
Virtual server Content Routing Scripting |
Service |
Real Server Pool Real Server |
Node | Real Server |
Secret |
Local Certificate Local Certificate Group Client-SSL |
Naming rule
For FortiADC objects created by FortiADC Ingress Controller, the name of the object is composed of the namespace and the name of the Kubernetes objects. The naming rule is shown below:
FortiADC Objects |
Naming Rule |
---|---|
Virtual server Real Server Pool Scripting Local Certificate Local Certificate Group Client-SSL |
[namespace of Kubernetes objects]_[name of Kubernetes objects] |
Content Routing | [namespace of Kubernetes objects]_[name of Kubernetes ingress]_[name of Kubernetes service] |
Real Server | Name of the Kubernetes node |
Ingress types
FortiADC supports all 5 types of Ingress:
For details on each Ingress type, see https://kubernetes.io/docs/concepts/services-networking/ingress/.
For an example Ingress file, see https://github.com/fortinet/fortiadc-ingress/tree/main/ingress_examples.
Ensure the service used in the Ingress is already deployed with NodePort type. Kubernetes does not verify whether the service defined in the Ingress exists or not when deploying an Ingress. So, if you remove the service used in the deployed Ingress, you will not be warned or blocked from this action. |
Default backend
An Ingress with no rules sends all traffic to a single default backend. If none of the hosts or paths match the HTTP request in the Ingress objects, the traffic is routed to your default backend. Therefore, if Rules are not specified, defaultBackend
must be specified in the Ingress.
Note: FortiADC Ingress Controller only supports Service
backend. A Resource
backend is not supported.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: default-backend annotations: { "fortiadc-ip" : "10.0.100.133", "fortiadc-login" : "fad-login", "fortiadc-ctrl-log" : "enable", "fortiadc-vdom" : "root", "virtual-server-ip" : "172.23.133.125", "virtual-server-interface" : "port1", "virtual-server-port" : "443", "virtual-server-addr-type" : "ipv4", "virtual-server-waf-profile" : "High-Level-Security", "virtual-server-av-profile" : "Antivirus-Profile", "virtual-server-dos-profile" : "", "virtual-server-captcha-profile" : "LB_CAPTCHA_PROFILE_DEFAULT", "virtual-server-nat-src-pool" : "", "virtual-server-traffic-group" : "default", "virtual-server-fortiview" : "enable", "virtual-server-traffic-log" : "enable", "virtual-server-wccp" : "enable", "load-balance-method" : "LB_METHOD_LEAST_CONNECTION", "load-balance-profile" : "LB_PROF_HTTPS" } spec: ingressClassName: fadc-ingress-controller defaultBackend: service: name: default-http-backend port: number: 80
You can add defaultBackend in any particular Ingress. You can check the example here:
Minimal-Ingress
A minimal-Ingress has at least one rule defined in the Ingress with no specified default backend. The following is an example of a minimal-Ingress.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: minimal-ingress annotations: { "fortiadc-ip" : "10.0.100.133", "fortiadc-login" : "fad-login", "fortiadc-ctrl-log" : "enable", "fortiadc-vdom" : "root", "virtual-server-ip" : "172.23.133.8", "virtual-server-interface" : "port1", "virtual-server-port" : "443", "virtual-server-addr-type" : "ipv4", "virtual-server-waf-profile" : "High-Level-Security", "virtual-server-av-profile" : "Antivirus-Profile", "virtual-server-dos-profile" : "", "virtual-server-captcha-profile" : "LB_CAPTCHA_PROFILE_DEFAULT", "virtual-server-nat-src-pool" : "", "virtual-server-traffic-group" : "default", "virtual-server-fortiview" : "enable", "virtual-server-traffic-log" : "enable", "virtual-server-wccp" : "enable", "load-balance-method" : "LB_METHOD_LEAST_CONNECTION", "load-balance-profile" : "LB_PROF_HTTPS" } spec: ingressClassName: fadc-ingress-controller rules: - http: paths: - path: /info pathType: Prefix backend: service: name: service1 port: number: 1241
Name-based virtual hosting
Name-based virtual hosts support the routing of HTTP/HTTPS traffic to multiple host names at the same IP address.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: name-virtual-host-ingress annotations: { "fortiadc-ip" : "10.0.100.133", "fortiadc-login" : "fad-login", "fortiadc-vdom" : "root", "virtual-server-ip" : "2001:db8::68", "virtual-server-interface" : "port1", "virtual-server-addr-type" : "ipv6" } spec: ingressClassName: fadc-ingress-controller rules: - host: foo.bar.com http: paths: - pathType: Prefix path: "/" backend: service: name: service3 port: number: 1245 - host: bar.foo.com http: paths: - pathType: Prefix path: "/" backend: service: name: service2 port: number: 1242
Hostname wildcards
The hostname can be a precise match or a wildcard. Precise matches require the HTTP host header to match the host field (e.g., foo.bar.com
). Wildcard matches require the HTTP host header to be equal to the suffix of the wildcard rule (e.g., *.foo.com
).
Refer to the examples below to determine whether an HTTP host header is a wildcard match or not.
Host |
Host header |
Does it match? |
---|---|---|
*.foo.com
|
bar.foo.com
|
Yes, it matches based on shared suffix. |
*.foo.com
|
baz.bar.foo.com
|
No, it does not match. Wildcard only covers a single DNS label. |
*.foo.com
|
foo.com
|
No, it does not match. Wildcard only covers a single DNS label. |
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-wildcard-host annotations: { "virtual-server-ip" : "172.23.133.10", "virtual-server-interface" : "port1", "fortiadc-ip" : "10.0.100.133", "fortiadc-login" : "fad-login", "fortiadc-vdom" : "root" } spec: ingressClassName: fadc-ingress-controller rules: - host: "foo.bar.com" http: paths: - pathType: Prefix path: "/info" backend: service: name: service1 port: number: 1241 - host: "*.foo.com" http: paths: - pathType: Prefix path: "/hello" backend: service: name: service2 port: number: 80
TLS
You can secure an Ingress by specifying a Secret that contains a TLS private key and certificate. The Ingress resource only supports a single TLS port, 443, and assumes TLS termination at the Ingress point (traffic to the Service and its Pods is in plain text). If the TLS configuration section in an Ingress specifies different hosts, they are multiplexed on the same port according to the hostname specified through the SNI TLS extension (provided the Ingress controller supports SNI). The TLS secret must contain keys named tls.crt
and tls.key
that contain the certificate and private key to use for TLS.
For example:
apiVersion: v1 kind: Secret metadata: name: testsecret-tls namespace: default data: tls.crt: base64 encoded cert tls.key: base64 encoded key type: kubernetes.io/tls
You can create the TLS secret by using the kubectl command, for example:
kubectl create secret tls testsecret-tls --cert=/etc/ssl/tls.crt --key=/etc/ssl/tls.key
Referencing this secret in an Ingress tells the Ingress controller to secure the channel from the client to the load balancer using TLS. You need to ensure the TLS secret you created came from a certificate that contains a Common Name (CN), also known as a Fully Qualified Domain Name (FQDN) for https-example.foo.com
.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tls-example-ingress annotations: { "virtual-server-ip" : "172.23.133.11", "virtual-server-interface" : "port1", "fortiadc-ip" : "10.0.100.133", "fortiadc-login" : "fad-login", "fortiadc-vdom" : "root" } spec: ingressClassName: fadc-ingress-controller tls: - hosts: - https-example.foo.com secretName: testsecret-tls rules: - host: https-example.foo.com http: paths: - path: / pathType: Prefix backend: service: name: service2 port: number: 80