Make Tyk Gateway Support TLS Certificate for Two Ports?

Hey there! We’re setting up tyk Gateway on kubernetes but it seems we got some problems on the TLS certificate.

The background of us is at first we planned to use HTTP and gRPC for one port, but it seems the current tyk doesn’t support two different protocols for one port. So we decided to use two ports for different kinds of requests, in our case, 8080 is for HTTPS and 8081 is for RPC calls. For port 8080 it’s working well now. But for port 8081, we’re using a self-signed cert, and part of the configuration file is as below (as instructed by here):

    "http_server_options": {
        "enable_http2": true,
        "enable_websockets": true,
        "use_ssl": true,
        "ssl_insecure_skip_verify": true,
        "server_name": "*",
        "min_version": 771,
        "certificates": [{
            "domain_name": "*",
            "cert_file": "/etc/ssl/certs/cert.pem",
            "key_file": "/etc/ssl/certs/key.pem"
        }]
    },

And part of the API config is:

{
  "name": "storage-service-grpc",
  "slug": "storage-service-grpc",
  "listen_port": 8081,
  "protocol": "https",
  "enable_proxy_protocol": false,
  "api_id": "storage-service-grpc",
  "org_id": "1",
  ...
  "proxy": {
    "preserve_host_header": true,
    "listen_path": "/",
    "target_url": "h2c://10.1.0.81",
    "disable_strip_slash": false,
    "strip_listen_path": true,
    "enable_load_balancing": false,
    "target_list": null,
    "check_host_against_uptime_tests": false,
    "service_discovery": {
      "use_discovery_service": false,
      "query_endpoint": "",
      "use_nested_query": false,
      "parent_data_path": "",
      "data_path": "",
      "port_data_path": "",
      "target_path": "",
      "use_target_list": false,
      "cache_timeout": 0,
      "endpoint_returns_list": false
    },
    "transport": {
      "ssl_insecure_skip_verify": false,
      "ssl_ciphers": null,
      "ssl_min_version": 0,
      "ssl_max_version": 0,
      "ssl_force_common_name_check": false,
      "proxy_url": ""
    }
  },
...
}

If I port-forward the port 8080, and access https://localhost:8080/, it will show “Your connection is not private”, which is fine since we’re using a self-signed cert. But when port-forwarding 8081 and access https://localhost:8081/, the browser just simply says “This site can’t provide a secure connection” with ERR_SSL_PROTOCOL_ERROR, which means tyk is not using TLS cert correctly.

update:
We found a PR from 2 years ago here https://github.com/TykTechnologies/tyk/pull/3372. Guess it might be the reason why h2c:// not works in our API definition. My colleague left a comment there.

Do anyone have any thoughts on how to use certificate for two or more ports? Thanks!

Best,
B.

Hi @byu and welcome to the community.

I don’t think I see anything wrong your configuration, however, I am just checking to confirm if have you enabled port whitelisting or disabled port whitelisting in your gateway config file?

Hi @Olu thank you for the help! We have disabled the env variable TYK_GW_DISABLEPORTWHITELIST by setting it to true

Thanks for the information.

I can confirm that Tyk does work when using HTTP and gRPC for one port. I have shared a snippet of my API definitions at the bottom of this reply and outlined the main differences needed for it to work below:

  1. Both API definition protocols have to be set as http
  2. Each respective target URL should use their intended protocol. For example HTTP API definition would use http:// and the gRPC API definition would use h2c://
  3. The gRPC listen path must be set as the root (/), while the HTTP can have a sub path like /http/.

I will try to reproduce the issue with HTTPs and RPC on two different ports and give you the feedback.

HTTP API Definition

...
	"listen_port": 6067,
	"protocol": "http",
	"proxy": {
		"check_host_against_uptime_tests": false,
		"disable_strip_slash": false,
		"enable_load_balancing": false,
		"listen_path": "/http/",
		"preserve_host_header": false,
		"service_discovery": {
			"_sd_show_port_path": false,
			"cache_timeout": 0,
			"data_path": "",
			"endpoint_returns_list": false,
			"parent_data_path": "",
			"port_data_path": "",
			"query_endpoint": "",
			"target_path": "",
			"use_discovery_service": false,
			"use_nested_query": false,
			"use_target_list": false
		},
		"strip_listen_path": true,
		"target_list": [],
		"target_url": "http://host.docker.internal:80/anything",
	}
...

gRPC API Definition

...
	"listen_port": 6067,
	"protocol": "http",
	"proxy": {
		"check_host_against_uptime_tests": false,
		"disable_strip_slash": false,
		"enable_load_balancing": false,
		"listen_path": "/",
		"preserve_host_header": false,
		"service_discovery": {
			"_sd_show_port_path": false,
			"cache_timeout": 0,
			"data_path": "",
			"endpoint_returns_list": false,
			"parent_data_path": "",
			"port_data_path": "",
			"query_endpoint": "",
			"target_path": "",
			"use_discovery_service": false,
			"use_nested_query": false,
			"use_target_list": false
		},
		"strip_listen_path": true,
		"target_list": [],
		"target_url": "h2c://host.docker.internal:50052"
	}
...

Hey Olu! Sorry for not replying to you!

We finally tried another strategy by setting two ports for HTTP and gRPC, for example 8080 for web browsing and 8081 for gRPC. To solve the certificate issue, I added an envoy instance between external loadbalancer and tyk gateway instances. So it’s like LB => envoy => gateway:8081 => PSC to the backend service. envoy helps terminate SSL so gateway can handle the request properly.

This method is kinda “silly”, but it works and meet out requirements

1 Like