The TCP
mode can be used for generic TCP-based applications. Here is an example:
1kind: Service2metadata:3name: nats4spec:5port: 80806mode: TCP7config:8upstream:9url: tcp://nats-server:8080
Octelium supports a various of TCP-based application-layer protocols such as HTTP, SSH, PostgreSQL and MySQL. Using such modes instead of TCP
provides you with features such as L7 aware access control, secret-less access to upstreams, L7 aware dynamic configuration and L7 aware visibility. Read more here.
Access Control
Compared to application-layer aware modes such as HTTP
and KUBERNETES
where access control happens on every application-layer request where application-layer info are fed to the request context, access control in TCP
mode obviously happens only at the beginning of the TCP connection and there is no specific L7 information can be extracted. Here is an example:
1kind: Service2metadata:3name: example-svc4spec:5port: 80806mode: TCP7config:8upstream:9url: tcp://nats-server:808010authorization:11inlinePolicies:12- spec:13rules:14- effect: ALLOW15condition:16match: '"group-1" in ctx.user.spec.groups'
Secretless Access
You can provide secretless access to your Users (read more about secretless access here) to any TCP-based application layer protocol that is protected by mutual TLS (mTLS). Read more in detail here.
Dynamic Configuration
You can use dynamic configuration in order to, for example, route to different upstreams or use different mTLS certificates (read more about secret-less access via mTLS here) depending on the request's context (read more about dynamic configuration here). Here is an example:
1kind: Service2metadata:3name: ssh14spec:5mode: TCP6config:7upstream:8url: tcp://host-0:90009dynamicConfig:10configs:11- name: host-112upstream:13url: tcp://host-1:900114- name: host-215upstream:16url: tcp://host-2:900217rules:18- condition:19match: '"ops" in ctx.user.spec.groups'20configName: host-121- condition:22match: '"dev" in ctx.user.spec.groups'23configName: host-2
TLS
By default, the Service listens over plaintext TCP regardless of whether the upstream is listening over TCP or TLS. You can force the Service to listen over TLS, however, via the isTLS
flag as follows:
1kind: Service2metadata:3name: my-nats4spec:5mode: TCP6port: 90007isTLS: true8config:9upstream:10url: tcp://nats-server:8080
If the upstream is listening over TLS and using a certificate that is signed by private CA, you will have to manually add that root CA in a list of trustedCAs
. Here is an example:
1kind: Service2metadata:3name: my-api4spec:5mode: HTTP6config:7upstream:8url: https://my-upstream:64439tls:10trustedCAs:11- |12-----BEGIN CERTIFICATE-----13CA14-----END CERTIFICATE-----
You can also skip verifying the upstream's certificate altogether via the insecureSkipVerify
which is typically recommended only for troubleshooting/testing use cases. Here is an example:
1kind: Service2metadata:3name: my-api4spec:5mode: HTTP6config:7upstream:8url: https://my-upstream:64439tls:10insecureSkipVerify: true
If the upstream requires mutual TLS (mTLS), you will have to include your client certificate private key as a Secret (read more here), and then reference it as follows:
1kind: Service2metadata:3name: my-api4spec:5mode: HTTP6config:7upstream:8url: https://my-upstream:64439tls:10trustedCAs:11- |12-----BEGIN CERTIFICATE-----13CA14-----END CERTIFICATE-----15clientCertificate:16fromSecret: client-private-key
Visibility
The Service emits access logs in real time to the audit collector. Here is an example of a TCP
Log:
1{2"apiVersion": "core/v1",3"entry": {4"common": {5"connectionID": "vldv-kx0n-jz20ix83wijy7p605o61puha-zpq6-2z7k",6"endedAt": "2025-03-21T22:28:53.184219118Z",7"isAuthenticated": true,8"isAuthorized": true,9"namespaceRef": {10"apiVersion": "core/v1",11"kind": "Namespace",12"name": "default",13"resourceVersion": "0195b81d-43ec-7ba7-81f7-9b77202b3612",14"uid": "bff0768e-eec8-4044-a972-9f7af81b79d8"15},16"regionRef": {17"apiVersion": "core/v1",18"kind": "Region",19"name": "default",20"uid": "6e233d12-2fd6-4670-a82d-8c712e1f7374"21},22"serviceRef": {23"apiVersion": "core/v1",24"kind": "Service",25"name": "pg2.default",26"resourceVersion": "0195bad1-6f83-7740-8db5-ca41ad514d3f",27"uid": "92e79dbb-5f69-419d-b41d-ca26cb892a4a"28},29"sessionRef": {30"apiVersion": "core/v1",31"kind": "Session",32"name": "usr1-3pt93j",33"resourceVersion": "0195bad0-8169-7c53-a2a4-eef7b5b23880",34"uid": "e8bea7be-b858-4457-a8ee-a0cb7f6c91da"35},36"startedAt": "2025-03-21T22:28:07.494538911Z",37"userRef": {38"apiVersion": "core/v1",39"kind": "User",40"name": "usr1",41"resourceVersion": "0195b821-228d-79b2-92f3-4bb458944f97",42"uid": "e0f251b2-6952-4a46-a771-2712a45c47f5"43}44},45"info": {46"tcp": {47"receivedBytes": "30253",48"sentBytes": "2876",49"type": "END"50}51}52},53"kind": "AccessLog",54"metadata": {55"actorRef": {56"apiVersion": "core/v1",57"kind": "Session",58"name": "usr1-3pt93j",59"resourceVersion": "0195bad0-8169-7c53-a2a4-eef7b5b23880",60"uid": "e8bea7be-b858-4457-a8ee-a0cb7f6c91da"61},62"createdAt": "2025-03-21T22:28:53.184211348Z",63"id": "q41j-e6m6-7wvk7mr90dy36kbbaxtpfmeh-ail9-8z34",64"targetRef": {65"apiVersion": "core/v1",66"kind": "Service",67"name": "pg2.default",68"resourceVersion": "0195bad1-6f83-7740-8db5-ca41ad514d3f",69"uid": "92e79dbb-5f69-419d-b41d-ca26cb892a4a"70}71}72}