# SOCKS5

> Octelium documentation. Canonical page: <https://octelium.com/docs/octelium/latest/management/core/service/socks5>.

Setting the *Service* mode to `SOCKS5` enables it to operate in application-layer aware SOCKS5 proxy mode. This mode enables your *Users* to reach upstream destinations through a standard SOCKS5 proxy while the *Service* enforces identity-aware access control on a per-connection basis. This mode also provides you with clear application-layer aware visibility where the requested destinations of your SOCKS5 connections are logged and audited in real-time.

> **Note:**
>
> Read more about access to `SOCKS5` from a *User* perspective [here](https://octelium.com/docs/octelium/latest/user/cli/access.md#socks5).

## Secretless Access

Secretless access enables you to provide secretless access for authorized *Users* to `SOCKS5`-based *Service* by automatically injecting passwords to authenticate to the upstream SOCKS5 server, and force the *User* to connect to the upstream as a specific user. The password value is stored in a *Secret* (read more [here](https://octelium.com/docs/octelium/latest/management/core/secret.md#creating-a-secret)) instead of being set in plaintext in the *Service* configuration.

First, you need to create the *Secret* as follows:

```bash
octeliumctl create secret socks5-password
# OR via a --value flag
octeliumctl create secret --value <PASSWORD> socks5-password
# OR via a --file flag
octeliumctl create secret --file /PATH/TO/PASSWORD socks5-password
```

Now, you define your *Service* as follows:

```yaml
kind: Service
metadata:
  name: socks5
spec:
  mode: SOCKS5
  port: 1080
  config:
    upstream:
      url: tcp://address-to-host
    # !mark(1:5)
    socks5:
      auth:
        usernamePassword:
          username: usr1
          password:
            fromSecret: socks5-password
```

You can also explicitly instruct Vigil to use no authentication when connecting to the upstream server via the `noAuth` field as follows:

```yaml
kind: Service
metadata:
  name: socks5
spec:
  mode: SOCKS5
  port: 1080
  config:
    upstream:
      url: tcp://address-to-host
    socks5:
      auth:
        # !mark
        noAuth: true
```

> **Note:**
>
> For internal/private upstreams behind NAT, you need to remotely serve them via a connected `octelium` client or container as discussed [here](https://octelium.com/docs/octelium/latest/management/core/service/overview.md#remotely-via-a-connected-user).

## Embedded Mode

By default, the *Service* proxies SOCKS5 connections to the upstream set in the `upstream` field. You can, however, enable the "embedded" mode where the SOCKS5 proxy is served from within a connected `octelium` client rather than proxied to a separate upstream proxy server. In this mode, the connected client itself acts as the SOCKS5 egress point, which means the connections to the final destinations originate from the host running the `octelium` client. You can enable it via the `isEmbeddedMode` field as follows:

```yaml
kind: Service
metadata:
  name: socks5
spec:
  mode: SOCKS5
  port: 1080
  config:
    socks5:
      # !mark
      isEmbeddedMode: true
```

A *User* announces their intent to serve embedded SOCKS5 when connecting to the *Cluster* via the `--esocks5` flag in the `octelium connect` command (read more [here](https://octelium.com/docs/octelium/latest/user/cli/connect.md)). Authorized *Users* then reach the embedded SOCKS5 proxy of a certain *Session* by using the *Session*'s name as the SOCKS5 username. You can read more about accessing embedded SOCKS5 from a *User* perspective [here](https://octelium.com/docs/octelium/latest/user/cli/access.md#socks5).

> **Note:**
>
> The *Cluster* comes with a built-in `socks5.octelium` *Service* that operates in embedded mode, so you do not need to create your own embedded SOCKS5 *Service* in order to reach the embedded SOCKS5 proxies served by connected *Sessions*.

## Access Control

You can control access based on the SOCKS5 request information. Such information is stored in `ctx.request.socks5` where it contains the requested destination host, port and address type of the connection. Here is a detailed example of an inline *Policy* that controls access based on SOCKS5-specific information:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: SOCKS5
  port: 1080
  config:
    upstream:
      url: tcp://address-to-host
    # rest of the config
  authorization:
    inlinePolicies:
      - spec:
          rules:
            - effect: ALLOW
              condition:
                any:
                  of:
                  # !mark(1:2)
                    - match: ctx.request.socks5.connect.host.endsWith(".example.com")
                    - match: ctx.request.socks5.connect.port == 443
```

The address type of the requested destination is also available in `ctx.request.socks5.connect.addressType` which can be one of `IPV4`, `DOMAIN` or `IPV6`. Here is an example that only allows connections to domain-based destinations:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: SOCKS5
  port: 1080
  config:
    upstream:
      url: tcp://address-to-host
  authorization:
    inlinePolicies:
      - spec:
          rules:
            - effect: ALLOW
              condition:
                # !mark
                match: ctx.request.socks5.connect.addressType == "DOMAIN"
```

## Dynamic Configuration

You can use dynamic configuration in order to, for example, route to different upstreams or use different proxy credentials depending on the request's context (read more about dynamic configuration [here](https://octelium.com/docs/octelium/latest/management/core/service/dynamic-config.md)). Here is an example where *Users* belonging to the `ops` *Group* are proxied to one upstream while the rest are proxied to another:

```yaml
kind: Service
metadata:
  name: example-svc
spec:
  mode: SOCKS5
  port: 1080
  dynamicConfig:
    configs:
    - name: ops
      upstream:
        url: tcp://host-1:1080
      socks5:
        auth:
          usernamePassword:
            username: ops
            password:
              fromSecret: ops-password
    - name: dev
      upstream:
        url: tcp://host-2:1080
      socks5:
        auth:
          noAuth: true
    rules:
    - condition:
        match: '"ops" in ctx.user.spec.groups'
      configName: ops
    - condition:
        matchAny: true
      configName: dev
```

## Visibility

The *Service* emits access logs in real time to the audit collector. Each log provides SOCKS5 application-layer aware information about the connection such as the requested destination host, port and address type. Here is an example:

```json
{
  "apiVersion": "core/v1",
  "kind": "AccessLog",
  "metadata": {
    "id": "k3r8-2m1p-9wzt5xq7brhdmnkpttyabqsx-ai0l-7c2v",
    "createdAt": "2025-09-10T22:41:03.184524267Z",
    "actorRef": {
      "apiVersion": "core/v1",
      "kind": "Session",
      "uid": "b1bc6aaa-df51-456d-aa37-b77377ea26f0",
      "name": "usr1-3pt93j",
      "resourceVersion": "019935bf-8271-704d-b079-9af18e29037a"
    },
    "targetRef": {
      "apiVersion": "core/v1",
      "kind": "Service",
      "uid": "8ca3d118-a507-405f-8592-12a5fe1e16cb",
      "name": "socks5.default",
      "resourceVersion": "019934ca-9270-7480-8d96-230a538cb6a6"
    }
  },
  "entry": {
    "common": {
      "startedAt": "2025-09-10T22:41:03.182784369Z",
      "endedAt": "2025-09-10T22:41:03.184526057Z",
      "status": "ALLOWED",
      "mode": "SOCKS5",
      "sessionRef": {
        "apiVersion": "core/v1",
        "kind": "Session",
        "uid": "b1bc6aaa-df51-456d-aa37-b77377ea26f0",
        "name": "usr1-3pt93j",
        "resourceVersion": "019935bf-8271-704d-b079-9af18e29037a"
      },
      "userRef": {
        "apiVersion": "core/v1",
        "kind": "User",
        "uid": "d72a39da-6f1c-43f7-ad75-dbaf76111b10",
        "name": "usr1",
        "resourceVersion": "019934c7-3d99-7864-8ccf-abe9eadfe023"
      },
      "serviceRef": {
        "apiVersion": "core/v1",
        "kind": "Service",
        "uid": "8ca3d118-a507-405f-8592-12a5fe1e16cb",
        "name": "socks5.default",
        "resourceVersion": "019934ca-9270-7480-8d96-230a538cb6a6"
      },
      "namespaceRef": {
        "apiVersion": "core/v1",
        "kind": "Namespace",
        "uid": "659a016d-aa9b-45c5-aae7-4212e7d4da3d",
        "name": "default",
        "resourceVersion": "019934c7-6d7e-76d0-89c7-2966e41f2e5b"
      },
      "regionRef": {
        "apiVersion": "core/v1",
        "kind": "Region",
        "uid": "85477de2-67d3-48ed-bda7-6c914489badf",
        "name": "default"
      }
    },
    "info": {
      "socks5": {
        "type": "CONNECT",
        "host": "api.example.com",
        "port": 443,
        "addressType": "DOMAIN"
      }
    }
  }
}
```

As you can see in the above example, the type of this `SOCKS5` access *Log* is a `CONNECT`. The `SOCKS5` mode has currently 2 *Log* types: `CONNECT` and `SESSION_END`, where the `SESSION_END` type additionally includes the number of received and sent bytes as well as the resolved upstream host and port. You can read more in the API reference.
