LoadBalancer

Truefoundry by default provisions a single external load-balancer for one Kubernetes cluster. This is provisioned automatically by the tfy-istio-ingress helm chart installed by Truefoundry which creates a Kubernetes service of type LoadBalancer. You can find the configuration of this service in Deployments > Helm > tfy-istio-ingress (Make sure you are filtering for the desired cluster)

You can click on the three dots to understand the configuration.

If you want to modify any of your load-balancer settings, you will have to edit this configuration according to the guide mentioned below.

Modifying your load balancer configuration

The loadbalancer can be modified using annotations on the gateway object. Below is an example of possible modifications that you can do. To get a complete list of annoations - check here

AWS

gateway:
  annotations:
    # Denotes that this is a network load balancer. We use NLB so that TCP protocol can also be 
    # supported. Also, NLB has lower latency and costs than ALB (Application Load Balancer)
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    
    # This is the default setting - It makes the loadbalancer external. If you want to create an internal
    # load-balancer, you can remove this annotations
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

    # Use this only when you want to make the loadbalancer internal. Else remove this annotation
    service.beta.kubernetes.io/aws-load-balancer-internal: "true"

    # ACM cert arn to attach to the load balancer. If you have your own custom certificate, then you can remove this annotation. 
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-2:XXXXXXX:certificate/XXXXX-XXXXX-XXXXXX
    
    # You can let these settings as it is
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
    service.beta.kubernetes.io/aws-load-balancer-alpn-policy: HTTP2Preferred
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
    service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
tfyGateway:
  name: tfy-wildcard
  spec:
    servers:
      - tls:
          httpsRedirect: true
        port:
          name: http-tfy-wildcard
          number: 80
          protocol: HTTP
        hosts:
          - "*"
      - port:
          name: https-tfy-wildcard
          number: 443
          protocol: HTTP
        hosts:
          - "*"
    selector:
      istio: tfy-istio-ingress

As mentioned above, if you want the loadbalancer to be external, add the following annotation:

service.beta.kubernetes.io/aws-load-balancer-type: "external"  
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing

If you want it to be internal, the following annotation should be added:

service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"

If you convert the load balancer from internal to external or vice-versa, the loadbalancer will be recreated and you will have to remap your DNS.

GCP

The default configuration creates an external load-balancer:

gateway:
  tolerations:
  - key: "cloud.google.com/gke-spot"
    value: "true"
    effect: NoSchedule
    operator: Equal
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: cloud.google.com/gke-spot
            values:
            - "true"
            operator: In
tfyGateway:
  name: 'tfy-wildcard'
  spec:
    selector:
      istio: 'tfy-istio-ingress'
    servers:
    - hosts:
      - "*"
      port:
        name: http-tfy-wildcard
        number: 80
        protocol: HTTP
      tls:
        httpsRedirect: true
    - hosts:
      - "*"
      port:
        name: https-tfy-wildcard
        number: 443
        protocol: HTTP

To make the loadbalancer internal, add the annotation as follows:

gateway:
  annotations:
    networking.gke.io/load-balancer-type: "Internal"

Azure

The default configuration creates an external load balancer with the below configuration

gateway:
  tolerations:
  - key: CriticalAddonsOnly
    value: "true"
    effect: NoSchedule
    operator: Equal
tfyGateway:
  name: 'tfy-wildcard'
  spec:
    selector:
      istio: 'tfy-istio-ingress'
    servers:
    - hosts:
      - "*"
      port:
        name: http-tfy-wildcard
        number: 80
        protocol: HTTP
      tls:
        httpsRedirect: true
    - hosts:
      - "*"
      port:
        name: https-tfy-wildcard
        number: 443
        protocol: HTTP

To make the load balancer internal

gateway:
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"

Generic

  1. By default load balancer will be created without an external IP address in the case of generic cluster.
  2. Run metalLB to assign an IP address to the load balancer.
  3. Once the load balancer gets the IP address assign the certificates for it to terminate TLS traffic. For that you can use cert-manager or bring your own certificates.
    1. Cert-manager is present as an add-on in the cluster, so you can manage and edit the configurations for it vey seamlessly through the platform itself.
    2. cert-manager connects with your DNS providers and creates a secret in the k8s cluster.
    3. If you bring your own certificates, they need to be in the form of k8s secret. Check how you can create tls secret in k8s.
    4. Secret should be created in the istio-system namespace.
  4. Passing those secrets in the tfy-istio-ingress in tfyGateway.spec.servers[1].tls.credentialName
    tfyGateway:
      name: 'tfy-wildcard'
      spec:
        selector:
          istio: 'tfy-istio-ingress'
        servers:
        - hosts:
          - "*"
          port:
            name: http-tfy-wildcard
            number: 80
            protocol: HTTP
          tls:
            httpsRedirect: true
        - hosts:
          - "*"
          port:
            name: https-tfy-wildcard
            number: 443
            protocol: HTTP
          tls:
            mode: SIMPLE
            credentialName: <>
    

Deploy multiple load balancers

Each installation of tfy-istio-ingress creates a load balancer. If you want to deploy multiple multiple load-balancers, for e.g. one internal and one external, you can clone the current tfy-istio-ingress application in the same namespace istio-system, change the tfyGateway.Name to something else other then default tfy-wildcard and update the tfyGateway.spec.Selector with the new name of the application.

For e.g. if you clone the tfy-istio-ingress a new application with the name tfy-istio-ingress-1 will be created , update the tfyGateway.Name to a new name and the tfyGateway.spec.Selector to

tfyGateway:
  spec:
    selector:
      app: "tfy-istio-ingress-1"

Once the ingress is installed, it will automatically create another loadbalancer whose IP you can get using kubectl get svc -n istio-system.

Add authentication to all services behind a load balancer

We can configure Istio to apply authentication at a gateway level. This will work only if you are accessing the service using the DNS provided in Istio and not access the service directly from within the cluster. This process is a bit complicated, and you should only do this if you really want to enable authentication at an istio gateway level.

📘

Istio will validate if the JWT is valid. If not valid, it will return an Unauthorized Error.

  1. Create a RequestAuthentication resource to ensure that the JWT issuer and Audience are correct.
    1. Authentication will be only done if there is an Authorization header. This is pass-through if no Authorization header is present in the Request or it gets an empty string after removing the prefix.
    apiVersion: security.istio.io/v1beta1
    kind: RequestAuthentication
    metadata:
      name: tfy-oauth2
      namespace: istio-system
    spec:
      selector:
        matchLabels:
          istio: tfy-istio-ingress
      jwtRules:
      - issuer: "truefoundry.com"
        fromHeaders:
        - name: Authorization
          prefix: "Bearer "
        audiences:
          - <tenant_name_in_truefoundry>
        jwksUri: https://login.truefoundry.com/.well-known/jwks.json
        forwardOriginalToken: true
    
  2. Create an AuthorizationPolicy that will reject any requests with an empty JWT.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tfy-oauth2
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: tfy-istio-ingress
  action: DENY
  rules:
  - from:
    - source:
        notRequestPrincipals: ["*"]
    to:
      - operation:
          ports:
            - "443" 

You can read the Istio docs: https://istio.io/latest/docs/reference/config/security/request_authentication/ for further customization or making it work with your own IdP.