TCP
The TCP mode can be used for generic TCP-based applications. Here is an example:
kind: Service
metadata:
name: nats
spec:
port: 8080
mode: TCP
config:
upstream:
url: tcp://nats-server:8080Octelium 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, secretless 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:
kind: Service
metadata:
name: example-svc
spec:
port: 8080
mode: TCP
config:
upstream:
url: tcp://nats-server:8080
authorization:
inlinePolicies:
- spec:
rules:
- effect: ALLOW
condition:
match: '"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 secretless access via mTLS here) depending on the request's context (read more about dynamic configuration here). Here is an example:
kind: Service
metadata:
name: ssh1
spec:
mode: TCP
config:
upstream:
url: tcp://host-0:9000
dynamicConfig:
configs:
- name: host-1
upstream:
url: tcp://host-1:9001
- name: host-2
upstream:
url: tcp://host-2:9002
rules:
- condition:
match: '"ops" in ctx.user.spec.groups'
configName: host-1
- condition:
match: '"dev" in ctx.user.spec.groups'
configName: host-2TLS
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:
kind: Service
metadata:
name: my-nats
spec:
mode: TCP
port: 9000
isTLS: true
config:
upstream:
url: tcp://nats-server:8080If 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:
kind: Service
metadata:
name: my-api
spec:
mode: HTTP
config:
upstream:
url: https://my-upstream:6443
tls:
trustedCAs:
- |
-----BEGIN CERTIFICATE-----
CA
-----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:
kind: Service
metadata:
name: my-api
spec:
mode: HTTP
config:
upstream:
url: https://my-upstream:6443
tls:
insecureSkipVerify: trueIf 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:
kind: Service
metadata:
name: my-api
spec:
mode: HTTP
config:
upstream:
url: https://my-upstream:6443
tls:
trustedCAs:
- |
-----BEGIN CERTIFICATE-----
CA
-----END CERTIFICATE-----
clientCertificate:
fromSecret: client-private-keyVisibility
The Service emits access logs in real time to the audit collector. Here is an example of a TCP Log:
{
"apiVersion": "core/v1",
"entry": {
"common": {
"connectionID": "vldv-kx0n-jz20ix83wijy7p605o61puha-zpq6-2z7k",
"endedAt": "2025-03-21T22:28:53.184219118Z",
"isAuthenticated": true,
"isAuthorized": true,
"namespaceRef": {
"apiVersion": "core/v1",
"kind": "Namespace",
"name": "default",
"resourceVersion": "0195b81d-43ec-7ba7-81f7-9b77202b3612",
"uid": "bff0768e-eec8-4044-a972-9f7af81b79d8"
},
"regionRef": {
"apiVersion": "core/v1",
"kind": "Region",
"name": "default",
"uid": "6e233d12-2fd6-4670-a82d-8c712e1f7374"
},
"serviceRef": {
"apiVersion": "core/v1",
"kind": "Service",
"name": "pg2.default",
"resourceVersion": "0195bad1-6f83-7740-8db5-ca41ad514d3f",
"uid": "92e79dbb-5f69-419d-b41d-ca26cb892a4a"
},
"sessionRef": {
"apiVersion": "core/v1",
"kind": "Session",
"name": "usr1-3pt93j",
"resourceVersion": "0195bad0-8169-7c53-a2a4-eef7b5b23880",
"uid": "e8bea7be-b858-4457-a8ee-a0cb7f6c91da"
},
"startedAt": "2025-03-21T22:28:07.494538911Z",
"userRef": {
"apiVersion": "core/v1",
"kind": "User",
"name": "usr1",
"resourceVersion": "0195b821-228d-79b2-92f3-4bb458944f97",
"uid": "e0f251b2-6952-4a46-a771-2712a45c47f5"
}
},
"info": {
"tcp": {
"receivedBytes": "30253",
"sentBytes": "2876",
"type": "END"
}
}
},
"kind": "AccessLog",
"metadata": {
"actorRef": {
"apiVersion": "core/v1",
"kind": "Session",
"name": "usr1-3pt93j",
"resourceVersion": "0195bad0-8169-7c53-a2a4-eef7b5b23880",
"uid": "e8bea7be-b858-4457-a8ee-a0cb7f6c91da"
},
"createdAt": "2025-03-21T22:28:53.184211348Z",
"id": "q41j-e6m6-7wvk7mr90dy36kbbaxtpfmeh-ail9-8z34",
"targetRef": {
"apiVersion": "core/v1",
"kind": "Service",
"name": "pg2.default",
"resourceVersion": "0195bad1-6f83-7740-8db5-ca41ad514d3f",
"uid": "92e79dbb-5f69-419d-b41d-ca26cb892a4a"
}
}
}