Kong Hybrid Mode Deployment: GKE and On-Prem
Tags: kong, deployment, webdev
Published: 2024-05-14 07:09:12

Mastering Certificate Challenges with Ease

By _Amrutha Paladugu_
Author LinkedIn: https://www.linkedin.com/in/amrutha-paladugu/



**Introduction:**

Kong Hybrid mode represents a groundbreaking approach to API management, merging the control plane (CP) and data plane (DP) capabilities. This mode offers many benefits that empower organizations to achieve enhanced control, security, and performance in their API ecosystem. In this article, we’ll delve into a real-world scenario showcasing the capabilities of Kong Hybrid mode. Specifically, we’ll explore the deployment of Kong Hybrid across Google Kubernetes Engine (GKE) and an On-Premise Kubernetes cluster. We will focus on achieving secure communication, certificate management, workload deployment, and external access. Join us as we navigate this journey through a hybrid API management deployment.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qfme30umjn7z8qtfiwde.png)
 
Kong Hybrid architecture with one DP on the cloud and one DP on-premise.

**Understanding Certificates:**

Mutual Transport Layer Security (mTLS) plays a vital role in Kong’s security features by facilitating secure communication between services. When operating in hybrid mode, the authentication process relies on an mTLS handshake to ensure that communication between CP and DP nodes remains secure, requiring the presentation of certificates. Kong manages certificate key pairs in two distinct modes: Shared and PKI.

In the Shared mode (the default setting), Kong CLI generates a certificate/key pair, and copies of this pair are then distributed across nodes. CP and DP nodes share and utilize this certificate/key pair.

On the other hand, in the PKI mode, certificates signed by a central certificate authority (CA) are provided. Kong performs validation on both ends by verifying if they originate from the same CA. This approach effectively mitigates the risks associated with the transportation of private keys and provides increased security. If one of the DP nodes is compromised, an attacker won’t be able to affect other nodes in the Kong cluster.

In this article, we will use PKI mode and generate three different cert/key pairs for CP and the 2 DPs. All three pairs need to be signed by the same CA discussed above.
Additionally, we will provision a Let’s Encrypt certificate for DP1’s public-facing endpoint and verify encrypted traffic.

**Certificate generation:**

**Step1:** Generate CA cert using OpenSSL: 

```
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.crt
```

**Step2:** Generate private key and CSR(certificate signing request) for CP and DPs

```
openssl req -new -newkey rsa:2048 -nodes -keyout cp-tls.key -out cp-tls.csr -subj "/CN=*.kong.example.com"
openssl req -new -newkey rsa:2048 -nodes -keyout dp1-tls.key -out dp1-tls.csr -subj "/CN=*.kong.example.com"
openssl req -new -newkey rsa:2048 -nodes -keyout dp2-tls.key -out dp2-tls.csr -subj "/CN=*.127.0.0.1.nip.io"
```

The CN (Common Name) here would be your wildcard domain.

**Step3:** Use CA from Step1 to sign the generated CSRs from Step2

```
openssl x509 -req -in cp-tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out cp-tls.crt -days 365
openssl x509 -req -in dp1-tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dp1-tls.crt -days 365
openssl x509 -req -in dp2-tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dp2-tls.crt -days 365
```

**Step4:** Create bundle certs:

```
cat cp-tls.crt ca.crt > cp-tls-bundle.crt
cat dp1-tls.crt ca.crt > dp1-tls-bundle.crt
cat dp2-tls.crt ca.crt > dp2-tls-bundle.crt
```

**Note:** Save these certificates in an accessible directory (certs) for the CP and the DPs.

**Install CP and DP1 on GKE:**

Connect to a GKE cluster and use the next set of commands to install CP and DP1.

Create ns, Create secrets, update helm repo:

```
sudo snap install helm - classic
helm repo add kong https://charts.konghq.com
helm repo update
kubectl create namespace kong-cp
kubectl create namespace kong-dp1
```

**Create secrets for Kong Enterprise license, Session Config, Admin password, and Postgresql password:**

```
kubectl create secret generic kong-enterprise-license -n kong-cp \
 - from-file=license=license.json \
 - dry-run=client -o yaml | kubectl apply -f -

kubectl create secret generic kong-session-config -n kong-cp \
 - from-literal=portal_session_conf='{"storage":"kong","secret":"super_secret_salt_string","cookie_name":"portal_session","cookie_samesite":"off","cookie_secure":false, "cookie_domain": ".example.com"}' \
 - from-literal=admin_gui_session_conf='{"cookie_name":"admin_session","cookie_samesite":"off","secret":"super_secret_salt_string","cookie_secure":false,"storage":"kong", "cookie_domain": ".example.com"}'

kubectl create secret generic kong-manager-password -n kong-cp \
 - from-literal=password=password

kubectl create secret generic kong-cp-postgresql -n kong-cp \
 - from-literal=host="enterprise-postgresql.kong.svc.cluster.local" \
 - from-literal=password=password
```
**Note:** If you don’t have access to an Enterprise license, you can still go ahead and try the installation but will not be able to access the Admin GUI.

Now, create Kubernetes Secrets for the cluster cert and CA cert for ns kong-cp.

```
kubectl create secret tls kong-cluster-cert -n kong-cp \
 - cert=./certs/cp-tls-bundle.crt \
 - key=./certs/cp-tls.key

kubectl create secret generic kong-ca-cert -n kong-cp \
 - from-file=ca.crt=./certs/ca.crt
```
We use Helm to install the CP and DPs and use custom values.yaml files.

**Update the values-cp.yaml with the below values:**

```
image:
  repository: kong/kong-gateway
  tag: "3.4"

secretVolumes:
  - kong-cluster-cert
  - kong-ca-cert

env:
  role: control_plane
  cluster_mtls: pki
  cluster_ca_cert: /etc/secrets/kong-ca-cert/ca.crt
  cluster_cert: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  nginx_http_ssl_protocols: TLSv1.2
  admin_gui_ssl_cert: /etc/secrets/kong-cluster-cert/tls.crt
  admin_gui_ssl_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  admin_ssl_cert: /etc/secrets/kong-cluster-cert/tls.crt
  admin_ssl_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  portal_gui_ssl_cert: /etc/secrets/kong-cluster-cert/tls.crt
  portal_gui_ssl_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  portal_api_ssl_cert: /etc/secrets/kong-cluster-cert/tls.crt
  portal_api_ssl_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  lua_ssl_verify_depth: 3
  admin_api_uri: https://admin.kong.example.com
  admin_gui_url: https://manager.kong.example.com
  portal_auth: basic-auth
  portal_api_url: https://portal-api.kong.example.com
  portal_gui_url: https://portal-dev.kong.example.com
  portal_gui_host: portal-dev.kong.example.com
  portal_gui_protocol: https
  database: postgres
  pg_host: kong-cp-postgresql
  pg_database: kong
  pg_user: postgres
  pg_schema: kong
  pg_password:
    valueFrom:
      secretKeyRef:
        name: kong-cp-postgresql
        key: password
  portal_session_conf:
    valueFrom:
      secretKeyRef:
        name: kong-session-config
        key: portal_session_conf
  user: kong
  password:
    valueFrom:
      secretKeyRef:
        name: kong-manager-password
        key: password

admin:
  enabled: true
  type: ClusterIP
  annotations:
    konghq.com/protocol: https
  labels: {}
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8444
    parameters:
      - http2
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: admin.kong.example.com
    path: /
    tls: kong-cluster-cert

manager:
  enabled: true
  type: ClusterIP
  annotations:
    konghq.com/protocol: https
  labels: {}
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8445
    parameters:
      - http2
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: manager.kong.example.com
    path: /
    tls: kong-cluster-cert

cluster:
  enabled: true
  type: LoadBalancer
  annotations: {}
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8005
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: cp.kong.example.com
    path: /
    tls: kong-cluster-cert

clustertelemetry:
  enabled: true
  type: LoadBalancer
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8006
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: tel.kong.example.com
    path: /
    tls: kong-cluster-cert

proxy:
  enabled: false

ingressController:
  enabled: true
  ingressClass: kong-dev
  resources:
    limits:
      cpu: 200m
      memory: 256Mi
    requests:
      cpu: 100m
      memory: 128Mi
  installCRDs: false
  env:
    publish_service: kong-dp/kong-dp-kong-proxy
    kong_admin_token:
      valueFrom:
        secretKeyRef:
          name: kong-manager-password
          key: password

enterprise:
  enabled: true
  license_secret: kong-enterprise-license # CHANGEME
  vitals:
    enabled: false
  rbac:
    enabled: true
    session_conf_secret: kong-session-config
    admin_api_auth: basic-auth
  portal:
    enabled: true
  smtp:
    enabled: false

portal:
  enabled: true
  type: ClusterIP
  annotations: 
    konghq.com/protocol: https
  labels: {}
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8446
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: portal-dev.kong.example.com
    path: /
    tls: kong-cluster-cert

portalapi:
  enabled: true
  type: ClusterIP
  annotations: 
    konghq.com/protocol: https
  labels: {}
  http:
    enabled: false
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8447
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    enabled: true
    ingressClassName: kong-dev
    hostname: portal-api.kong.example.com
    path: /
    tls: kong-cluster-cert

postgresql:
  enabled: true
  auth:
    database: kong
    username: postgres
    existingSecret: kong-cp-postgresql
    secretKeys:
      adminPasswordKey: password
```

**Let’s try and understand the above values file:**

The secrets we created, kong-cluster-cert and kong-ca-cert are mounted as volumes for the SSL certificates and are accessed at the specified path, for example:

`cluster_ca_cert: /etc/secrets/kong-ca-cert/ca.crt`

The environment variables are for configuring Kong and its components. They control settings related to SSL/TLS, database connections, authentication, and more. Also, they specify the role as “control_plane” and enable cluster mutual TLS (mTLS) using the PKI method. The admin API and GUI URLs, authentication methods, and other configuration parameters are also defined using the env variables.

**Admin, Manager, Portal, Portal API, and PostgreSQL:**

- These sections configure various components of Kong. All these components are enabled for the CP and would be disabled in the DP values yaml. Their type ( ClusterIP), TLS, and Ingress settings are also defined, including annotations, hostnames, paths, and TLS certificates for these components.
- PostgreSQL settings specify authentication details for connecting to the PostgreSQL database used by Kong.
- Enterprise-related settings include the license secret, RBAC configuration, SMTP, and vitals.

**Proxy and Ingress Controller:**

- The proxy section specifies whether the Kong proxy is enabled. For CP values, this would be disabled as the DP does all the proxying.
- Ingress Controller settings define the resources and environment variables for the Kong Ingress Controller.

**Cluster and Cluster Telemetry:**

- Cluster and cluster telemetry are essential for Kong Gateway’s Control Plane (CP) and Data Plane (DP) connection. DP instances connect to the CP through the CP cluster, which provides redundancy, load balancing, and configuration synchronization.
- Cluster telemetry plays a crucial role in monitoring the health of both CP and DP components, ensuring they can work together effectively and respond to changes and issues in real time. This setup provides a reliable and resilient CP-DP connection in Kong Gateway deployments.

**Install the CP:**

`helm upgrade - install kong-cp kong/kong - namespace kong-cp -f values-cp.yaml`

Once the CP is installed, verify that all pods are running and the Cluster and Clusterterlemetry services’ external LoadBalancer IPs are ready.

To install DP in the same cluster, follow the steps below and create license and certificate secrets for DP1.

```
kubectl create secret generic kong-enterprise-license -n kong-dp1 \
  --from-file=license=license.json \
  --dry-run=client -o yaml | kubectl apply -f -

kubectl create secret tls kong-cluster-cert -n kong-dp1 \
 - cert=./certs/dp1-tls-bundle.crt \
 - key=./certs/dp1-tls.key

kubectl create secret generic kong-ca-cert -n kong-dp1 \
 - from-file=ca.crt=./certs/ca.crt
```

To encrypt the oneway traffic to the public-facing end point of DP1, we use Let’s Encrypt CA. Use the below link to generate one for the domain you use.

**SSL Certificate Generator: Free letsencrypt SSL in minutes:**

A free SSL Certificate Generator. No login is required. Secure your site with a letsencrypt certificate. Includes a…
punchsalad.com

**Create a secret for this cert in the kong-dp1 namespace:**

```
kubectl create secret tls kong-tls-cert -n kong-dp1 \
 - cert=./letsencrypt/ca.crt \
 - key=./letsencrypt/ca.key
Create a values-dp1.yaml file with the below values:
image:
  repository: kong/kong-gateway
  tag: "3.4"

secretVolumes:
  - kong-cluster-cert
  - kong-ca-cert
  - kong-tls-cert

env:
  role: data_plane
  database: "off"
  status_listen: 0.0.0.0:8100
  cluster_control_plane: cp.kong.example.com:443
  cluster_telemetry_endpoint: tel.kong.example.com:443
  cluster_mtls: pki
  cluster_server_name: cp.kong.example.com
  cluster_telemetry_server_name: tel.kong.example.com
  lua_ssl_verify_depth: 3
  cluster_ca_cert: /etc/secrets/kong-ca-cert/ca.crt
  lua_ssl_trusted_certificate: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_cert: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  ssl_cert: /etc/secrets/kong-tls-cert/tls.crt
  ssl_cert_key: /etc/secrets/kong-tls-cert/tls.key

ingressController:
  enabled: false

enterprise:
  enabled: true
  license_secret: kong-enterprise-license
  vitals:
    enabled: false
  portal:
    enabled: false
  rbac:
    enabled: false

admin:
  enabled: false

manager:
  enabled: false

portal:
  enabled: false

portalapi:
  enabled: false

proxy:
  enabled: true
  type: LoadBalancer
  annotations: {}
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8443
    parameters:
      - http2
  # stream: {}
  ingress:
    enabled: true
```
Please take note of the key differences here from the earlier values-cp yaml. All the Manager, Admin, Portal, Portalapi, and IngressController sections are disabled, while the Proxy section is enabled as type LoadBalancer. As explained earlier, ensuring the correct configuration of cluster and cluster telemetry endpoints is crucial.

Another point worth mentioning is the secret volume for the Let’s Encrypt certificate:kong-tls-cert. This is accessed through the below variables:

`ssl_cert: /etc/secrets/kong-tls-cert/tls.crt
ssl_cert_key: /etc/secrets/kong-tls-cert/tls.key`

**Install DP1:**

`helm upgrade --install kong-dp1 kong/kong --namespace kong-dp1 -f values-dp1.yaml`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0ant8a1rw2ap6ibwf20.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f1qhap0mufketts7ynxw.png)

Note the LoadBalancer IPs for the Cluster and Clustertelemetry service in the CP and the Proxy service in the DP. Map these values to the domain you intend to use. In our scenario, it would be as follows:

```
cp.kong.example.com - - - - - - - > 34.136.32.39

cp-tel.kong.example.com - - - - >34.68.58.255

*.kong.example.com - - - - - - - - >34.132.64.159
```

You should now be able to access Kong Manager (in case you are using an Enterprise license) at manager.kong.example.com, but the browser won’t recognize the OpenSSL CA, and hence it will appear as NotSecure as shown in the below image.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwq3vxy78r3unomd3ihf.png)Access Admi GUI and view certificate (Not Secure- openSSL)

**Deploy a sample application:**

Let’s deploy a sample nodeJS application in the same GKE cluster in the default namespace, try accessing it through the DP endpoint, and see if the Let’s Encrypt certificate is served.

```
kubectl create deploy --image debianmaster/nodejs-welcome welcome 
kubectl expose deployment welcome --type=LoadBalancer --name=welcome --port=8080 --target-port=8080
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27etp61294hnpacz9e3q.png)
Deploying a sample nodeJS ‘welcome’ application

Add a service and a route to this application through the Kong manager.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8pgjkbotkankljkckcb.png)

Now, the workload can be accessed through dp1.kong.example.com/welcome. Click on the lock icon🔒present right before the URL and view the certificate. You will notice that the Let’s Encrypt certificate is being served, as shown in the below image.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/baoebqz4aop5sunj4olu.png)

Access the workload through the DP endpoint and verify the Let’s Encrypt cert.

**Install DP2 on local K3s:**\

Connect to a local K3s (lightweight Kubernetes) cluster and install the following command set to install DP2.
Create namespace for DP2

`kubectl create ns kong-dp2`

Create secrets for enterprise licenses and certificates:

```
kubectl create secret generic kong-enterprise-license - from-file=license=./license.json -n kong-dp2 - dry-run=client -o yaml | kubectl apply -f -

kubectl create secret tls kong-cluster-cert -n kong-dp2 \
 - cert=./certs/dp2-tls-bundle.crt \
 - key=./certs/dp2-tls.key

kubectl create secret generic kong-ca-cert -n kong-dp2 \
 - from-file=ca.crt=./certs/ca.crt
```
**Create a values-dp2.yaml file with the below values:**

```
image:
  repository: kong/kong-gateway
  tag: "3.4"

secretVolumes:
  - kong-cluster-cert
  - kong-ca-cert

env:
  role: data_plane
  cluster_control_plane: cp.kong.example.com:443
  cluster_telemetry_endpoint: tel.kong.example.com:443
  lua_ssl_trusted_certificate: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_mtls: pki
  cluster_server_name: cp.kong.example.com
  cluster_telemetry_server_name: tel.kong.example.com
  cluster_ca_cert: /etc/secrets/kong-ca-cert/ca.crt
  cluster_cert: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  database: "off"
  audit_log: "on"
  headers: "off" 
  anonymous_reports: "off"
  untrusted_lua: "off"

enterprise:
  enabled: true
  license_secret: kong-enterprise-license
  vitals:
    enabled: false
  portal:
    enabled: false
  rbac:
    enabled: false
admin:
  enabled: false
manager:
  enabled: false
portal:
  enabled: false
portalapi:
  enabled: false
ingressController:
  enabled: false

proxy:
  enabled: true
  type: LoadBalancer
  annotations: {
    konghq.com/protocol: "https"
  }
  tls:
    enabled: true
    servicePort: 443
    containerPort: 8443
    parameters:
    - http2
  ingress:
    enabled: true
Install DP2
helm upgrade - install kong-dp2 kong/kong - namespace kong-dp2 -f values-dp2.yaml
```
**Deploy a sample application in the K3s cluster:**

Let’s deploy a sample nodeJS application in the same K3s cluster in the default namespace and try to access it through the DP2 endpoint and verify.

```
kubectl create deploy --image debianmaster/nodejs-welcome hello 
kubectl expose deployment hello --type=LoadBalancer --name=hello --port=8080 --target-port=8080
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/opkt4xexqjmqh4sjsxlg.png)
Verify deployment of nodeJS ‘hello’ application.

Add a service and a route to this application through the Kong manager.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfaczaq4spy4n2f4v358.png)

Now the workload can be accessed through dp2.127.0.0.1.nip.io/hello
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8m8uz4yn9pwrmf1kr8p.png)
**Conclusion:**

Throughout this article, we embarked on a journey to uncover the transformative power of Kong Hybrid mode within API management. By harmonizing the control plane (CP) and data plane (DP), Kong Hybrid empowers organizations to balance control, security, and performance seamlessly. Through a real-world scenario, we showcased the deployment of Kong Hybrid across Google Kubernetes Engine (GKE) and an On-Premise Kubernetes cluster.

We navigated the intricate landscape of certificate management, emphasizing the pivotal role of Mutual Transport Layer Security (mTLS) and certificates in fortifying Kong’s security architecture. By embracing PKI mode, we ensured secure communication and mitigated the risks inherent in key transportation.

By following our straightforward, step-by-step instructions, we achieved successful deployments of Kong CP and DP1 within the GKE cluster, followed by Kong DP2 in an On-Premise K3s cluster. We highlighted the deployment of sample applications, demonstrated access through DP endpoints, and verified Let’s Encrypt certificates, reinforcing the foundation of a robust and secure API ecosystem.

As we wrap up this journey, remember the importance of resource cleanup to prevent lingering costs. The world of Kong Hybrid mode introduces a revolutionary approach that bridges the gap between Cloud and On-Premise, enabling the creation of APIs that transcend traditional confines. With mastery of this approach, you’ll confidently and innovatively navigate the dynamic realm of modern API management.



**For more details visit:** [https://zelarsoft.com/kong-consulting-and-licensing/]