Dynamic Configuration

A Service has its configuration which includes the information about its upstream as well as the application-layer specific configurations (e.g. HTTP-based configurations such as manipulating headers and injecting the upstream credentials) for various widely used L-7 protocols and supported by Octelium (read more about Service modes here). Here is an example:

1
kind: Service
2
metadata:
3
name: svc1
4
spec:
5
mode: HTTP
6
config:
7
upstream:
8
url: https://api.example.com
9
http:
10
auth:
11
bearer:
12
fromSecret: apikey1

The above configuration is the default configuration which is used globally for all the Service requests by default. However, in many cases, you might want to make this configuration dynamic depending on the request's context. For instance, you might want to route to a certain upstream depending on the identity of the User or the L-7 specific context (e.g. HTTP paths, headers, request body, etc...). For such cases, Octelium provides you a very flexible way to apply dynamic configuration where you can define multiple configurations and choose one of them on a per-request basis via rules that are defined exactly the same way as Policy rules (read more about Policies and access control here).

Here is an example where we can provide smart routing based on the User identity to route to additional upstreams. We now have 2 additional configs (i.e. config-1 and config-2) to the default configuration, each having a different credential representing maybe a different account and/or privileges for the upstream. If no rules match or if there are no rules, then the default config is used as a fallback config.

1
kind: Service
2
metadata:
3
name: svc1
4
spec:
5
mode: HTTP
6
# This is our typical static configuration used by default if no rules match
7
config:
8
upstream:
9
url: https://api.example.com
10
http:
11
auth:
12
bearer:
13
fromSecret: apikey0
14
dynamicConfig:
15
# we define a list of named configs that could override the global config
16
configs:
17
- name: config-1
18
upstream:
19
url: https://api-01.example.com
20
http:
21
auth:
22
bearer:
23
fromSecret: apikey1
24
- name: config-2
25
upstream:
26
url: https://api-02.example.com
27
http:
28
auth:
29
bearer:
30
fromSecret: apikey2
31
rules:
32
# Use the Config `config-1` for Users belonging to the Group `group-1`
33
- condition:
34
match: '"group-1" in ctx.user.spec.groups'
35
configName: config-1
36
# Use the Config `config-2` for Users belonging to the Group `group-2`
37
- condition:
38
match: '"group-2" in ctx.user.spec.groups'
39
configName: config-2

As shown in the example above, the dynamicConfig has 2 lists: one for the named dynamic configs represented by the configs list and another, rules, for the rules that are checked upon each request to choose one of these configs when matched. Each rule has a condition that can be defined in the exact same way as Policy rule conditions (read more here). A rule matches if its condition is met and in such case its corresponding named config, represented by the configName field, is chosen to be the configuration for that particular request overriding the default Service configuration.

Dynamic configuration is not restricted to a certain Service mode. The above example can be generalized to any other mode where you can override the default configuration based on whatever dynamic rules you wish to define. For example, you can use it for the POSTGRES and MYSQL modes to route to specific upstreams and/or use specific usernames and passwords as well as databases depending on the identity and/or context of the request. For the case of SSH, you can route to different usernames and passwords/private keys depending on the identity or the request's User. You can explore more mode-specific examples here:

Also, you are not really required to define a default configuration when you have one or more named configurations unless with working with certain situations (e.g. buffering request body in HTTP-based Services (read more here)). Here is an example of a Service that acts as an API gateway:

1
kind: Service
2
metadata:
3
name: my-api
4
spec:
5
mode: HTTP
6
dynamicConfig:
7
configs:
8
- name: v1
9
upstream:
10
url: https://apiv1.example.com
11
http:
12
auth:
13
bearer:
14
fromSecret: apikey1
15
path:
16
removePrefix: /v1
17
- name: v2
18
upstream:
19
url: https://apiv2.example.com
20
http:
21
auth:
22
bearer:
23
fromSecret: apikey2
24
path:
25
removePrefix: /v2
26
rules:
27
# Use the Config `config-1` for Users belonging to the Group `group-1`
28
- condition:
29
match: ctx.request.http.path.startsWith("/v1")
30
configName: v1
31
# Use the Config `config-2` for Users belonging to the Group `group-2`
32
- condition:
33
match: ctx.request.http.path.startsWith("/v2")
34
configName: v2
35
# Fallback to v1 when nothing matches
36
- condition:
37
matchAny: true
38
configName: v1

However, in such case, you need to be careful that your rules cover all the possible conditions.

© 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