ManagementCore APIServices
TCP

The TCP mode can be used for generic TCP-based applications. Here is an example:

1
kind: Service
2
metadata:
3
name: nats
4
spec:
5
port: 8080
6
mode: TCP
7
config:
8
upstream:
9
url: tcp://nats-server:8080
NOTE

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:

1
kind: Service
2
metadata:
3
name: example-svc
4
spec:
5
port: 8080
6
mode: TCP
7
config:
8
upstream:
9
url: tcp://nats-server:8080
10
authorization:
11
inlinePolicies:
12
- spec:
13
rules:
14
- effect: ALLOW
15
condition:
16
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 secret-less access via mTLS here) depending on the request's context (read more about dynamic configuration here). Here is an example:

1
kind: Service
2
metadata:
3
name: ssh1
4
spec:
5
mode: TCP
6
config:
7
upstream:
8
url: tcp://host-0:9000
9
dynamicConfig:
10
configs:
11
- name: host-1
12
upstream:
13
url: tcp://host-1:9001
14
- name: host-2
15
upstream:
16
url: tcp://host-2:9002
17
rules:
18
- condition:
19
match: '"ops" in ctx.user.spec.groups'
20
configName: host-1
21
- condition:
22
match: '"dev" in ctx.user.spec.groups'
23
configName: 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:

1
kind: Service
2
metadata:
3
name: my-nats
4
spec:
5
mode: TCP
6
port: 9000
7
isTLS: true
8
config:
9
upstream:
10
url: 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:

1
kind: Service
2
metadata:
3
name: my-api
4
spec:
5
mode: HTTP
6
config:
7
upstream:
8
url: https://my-upstream:6443
9
tls:
10
trustedCAs:
11
- |
12
-----BEGIN CERTIFICATE-----
13
CA
14
-----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:

1
kind: Service
2
metadata:
3
name: my-api
4
spec:
5
mode: HTTP
6
config:
7
upstream:
8
url: https://my-upstream:6443
9
tls:
10
insecureSkipVerify: 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:

1
kind: Service
2
metadata:
3
name: my-api
4
spec:
5
mode: HTTP
6
config:
7
upstream:
8
url: https://my-upstream:6443
9
tls:
10
trustedCAs:
11
- |
12
-----BEGIN CERTIFICATE-----
13
CA
14
-----END CERTIFICATE-----
15
clientCertificate:
16
fromSecret: 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
}
© 2025 octelium.comOctelium Labs, LLCAll rights reserved
Octelium and Octelium logo are trademarks of Octelium Labs, LLC.
WireGuard is a registered trademark of Jason A. Donenfeld