Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
6e53828
feat(weight-annotation): Annotation to add load-balancing weight
Lowaiz Sep 12, 2022
21a96c7
Set tls1.2 as minimum downstream proto
Aluxima Jun 20, 2022
fcc0193
feat(split-time): splits timeout annotation into 3 different ones
Lowaiz Sep 12, 2022
bc7f82a
feat(split-timeout): Docs
Lowaiz Sep 13, 2022
71a5eb3
feat(split-timeout): Default Timeouts flags and config
Lowaiz Sep 13, 2022
386e28a
feat(split-timeout): fix comment and default TO for cluster
Lowaiz Sep 15, 2022
c087705
Update README.md
Lowaiz Sep 19, 2022
1eff785
feat(split-timeout): Fix tests
Lowaiz Sep 20, 2022
98ea1b7
Use http2 for upstream proxy, add paramters
Aluxima Nov 17, 2022
40155dc
Add support for envoy 1.24
Aluxima Nov 23, 2022
3612b11
Raise default circuit breaker limits
Aluxima Dec 6, 2022
ec3c605
Add configurable listener ALPN protocols to enable downstream http2
Aluxima Dec 16, 2022
e1381f3
Allow matching <host>:*
Aluxima Jan 30, 2023
19a4967
Adds multiple envoy listener ipv4 adresses
MathildeLeroi Apr 5, 2023
13f2f78
replace deprecated ioutils with os.
SoulKyu May 13, 2024
94798ec
Correct deduplication and healthcheck for wildcard
SoulKyu May 13, 2024
e2efcb0
Add annotation on README
SoulKyu May 21, 2024
0f050b0
Ignoring launch.json
SoulKyu May 21, 2024
c63dc04
Add a validation on the subdomain to be sure healthcheck is no't on a…
SoulKyu May 21, 2024
c4efbea
Add yggdrasil.uswitch.com/upstream-http-version annotation
Aluxima Jun 12, 2023
821ce3a
remove healthcheck for bad configure ingress with wildcard (#8)
SoulKyu Jun 19, 2024
e7d67d6
Feat/custom log file (#9)
SoulKyu Jun 19, 2024
e74820f
test: correct address as a list
SoulKyu Jul 4, 2024
e26ab46
Fix tests
Aluxima Jul 4, 2024
65aa824
feat(mode-maintenance): handle mode maintenance for clusters
SoulKyu Jul 29, 2024
8e05749
fix(metrics): be aware when an ingress is deleted and remove it corre…
SoulKyu Sep 2, 2024
ed99fb7
fix(file): remove unwanted file
SoulKyu Sep 2, 2024
fb566e5
Merge pull request #10 from numberly/correctly-remove-prom-metrics
Aluxima Sep 2, 2024
d276186
Feat/support p384 p521 certs (#12)
Nicopfy Jun 19, 2025
906b21e
feat(aggregator.go): adding a warn log when err is not nil
Nicopfy Jun 3, 2025
42dbee0
Merge pull request #11 from numberly/fix/log-get-ingress-informer
Aluxima Jun 19, 2025
d954113
feat: update readme
Nicopfy Jun 19, 2025
98af4b7
Merge pull request #13 from numberly/feat/update-envoy-readme
Aluxima Jun 19, 2025
036f68f
feat: adding mTLS downstream configuration + some tests
Nicopfy Jul 3, 2025
f7d0b9e
feat: adding mTLS support on envoy upstream
Nicopfy Jul 23, 2025
14f5369
feat: update README
Nicopfy Jul 31, 2025
ed84c35
feat: add support for sticky sessions (#14)
jvlxz Mar 17, 2026
a59733f
feat: add annotation to allow configuration on http duration + fix de…
SoulKyu Mar 23, 2026
e15b47d
fix: pr
jvlxz Aug 6, 2026
3c49006
fix: fail closed for mTLS
jvlxz Aug 7, 2026
87648a6
Merge remote-tracking branch 'origin/staging' into feat/support-mTLS
jvlxz Aug 7, 2026
abefba9
Revert "fix: fail closed for mTLS"
jvlxz Aug 7, 2026
a3cbe9e
Revert "Merge remote-tracking branch 'origin/staging' into feat/suppo…
jvlxz Aug 7, 2026
5504c23
Reapply "Merge remote-tracking branch 'origin/staging' into feat/supp…
jvlxz Aug 7, 2026
4d6e0b9
chore: remove commented draft code
jvlxz Aug 7, 2026
a6a67d6
Merge pull request #23 from numberly/feat/support-mTLS
jvlxz Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
with:
go-version: "1.17"
- run: make build-linux
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: bin
path: bin/
Expand Down
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
bin/
command
testing
ca/
config/
envoy/

ca
config
envoy
launch.json
75 changes: 58 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Yggdrasil
Yggdrasil is an Envoy control plane that configures listeners and clusters based off Kubernetes ingresses from multiple Kube Clusters. This allows you to have an envoy cluster acting as a mutli-cluster loadbalancer for Kubernetes. This was something we needed as we wanted our apps to be highly available in the event of a cluster outage but did not want the solution to live inside of Kubernetes itself.

`Note:` Currently we support versions 1.20.x to 1.26.x of Envoy.</br>
`Note:` Currently we support versions 1.20.x to 1.34.x of Envoy.</br>
`Note:` Yggdrasil now uses [Go modules](https://github.com/golang/go/wiki/Modules) to handle dependencies.

## Usage
Expand Down Expand Up @@ -75,24 +75,49 @@ Yggdrasil allows for some customisation of the route and cluster config per Ingr
| Name | type |
|--------------------------------------------------------------|----------|
| [yggdrasil.uswitch.com/healthcheck-path](#health-check-path) | string |
| [yggdrasil.uswitch.com/timeout](#timeout) | duration |
| [yggdrasil.uswitch.com/healthcheck-host](#health-check-host) | string |
| [yggdrasil.uswitch.com/timeout](#timeouts) | duration |
| [yggdrasil.uswitch.com/cluster-timeout](#timeouts) | duration |
| [yggdrasil.uswitch.com/route-timeout](#timeouts) | duration |
| [yggdrasil.uswitch.com/per-try-timeout](#timeouts) | duration |
| [yggdrasil.uswitch.com/weight](#weight) | uint32 |
| [yggdrasil.uswitch.com/retry-on](#retries) | string |
| [yggdrasil.uswitch.com/auth-tls-verify-client](#mtls) | string |
| [yggdrasil.uswitch.com/auth-tls-secret](#mtls) | string |

### Health Check Path
Specifies a path to configure a [HTTP health check](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/core/v3/health_check.proto#config-core-v3-healthcheck-httphealthcheck) to. Envoy will not route to clusters that fail health checks.

### Health Check Host
Permit to change the host of the healthcheck when using wildcard. Example: healthcheck for `*.my-app.example.com` can't work natively, you can configure a specific path with `yggdrasil.uswitch.com/healthcheck-host: health.my-app.example.com`.

* [config.core.v3.HealthCheck.HttpHealthCheck.Path](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/core/v3/health_check.proto#envoy-v3-api-field-config-core-v3-healthcheck-httphealthcheck-path)

### Timeout
Allows for adjusting the timeout in envoy. Currently this will set the following timeouts to this value:
### Timeouts
Allows for adjusting the timeout in envoy.

The `yggdrasil.uswitch.com/cluster-timeout` annotation will set the [config.cluster.v3.Cluster.ConnectTimeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/cluster/v3/cluster.proto#envoy-v3-api-field-config-cluster-v3-cluster-connect-timeout)

The `yggdrasil.uswitch.com/route-timeout` annotation will set the [config.route.v3.RouteAction.Timeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-timeout)

the `yggdrasil.uswitch.com/per-try-timeout` annotation will set the [config.route.v3.RetryPolicy.PerTryTimeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-retrypolicy-per-try-timeout)

The `yggdrasil.uswitch.com/timeout` annotation will set all of the above with the same value. This annotation has the lowest priority, if set with one of the other TO annotations, the specific one will override the general annotation.


* [config.route.v3.RouteAction.Timeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-timeout)
* [config.route.v3.RetryPolicy.PerTryTimeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-retrypolicy-per-try-timeout)
* [config.cluster.v3.Cluster.ConnectTimeout](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/cluster/v3/cluster.proto#envoy-v3-api-field-config-cluster-v3-cluster-connect-timeout)
### Weight
Allows for adjusting the [load balancer weights](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/endpoint/v3/endpoint_components.proto#config-endpoint-v3-lbendpoint) in envoy.

### Retries
Allows overwriting the default retry policy's [config.route.v3.RetryPolicy.RetryOn](https://www.envoyproxy.io/docs/envoy/v1.19.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-retrypolicy-retry-on) set by the `--retry-on` flag (default 5xx). Accepts a comma-separated list of retry-on policies.

### mTLS
Used to enable mTLS between client and Envoy.

The `yggdrasil.uswitch.com/auth-tls-verify-client` annotation allow you enable or disable mTLS, can be either `true` or `false` (default).

The `yggdrasil.uswitch.com/auth-tls-secret` annotation allow you to specify the name of the Kubernetes TLS secret containing the CA certificate used to verify client certificates.

### Example
Below is an example of an ingress with some of the annotations specified

Expand All @@ -105,6 +130,7 @@ metadata:
annotations:
yggdrasil.uswitch.com/healthcheck-path: /healthz
yggdrasil.uswitch.com/timeout: 30s
yggdrasil.uswitch.com/weight: "12"
yggdrasil.uswitch.com/retry-on: gateway-error,connect-failure
spec:
rules:
Expand All @@ -122,14 +148,15 @@ Downstream TLS certificates can be dynamically fetched and updated from Kubernet

In this mode, only a single `certificate` may be specified in Yggdrasil configuration. It will be used for hosts with misconfigured or invalid secret.

**Note**: ECDSA >256 keys are not supported by envoy and will be discarded. See https://github.com/envoyproxy/envoy/issues/10855
**Note**: ECDSA P-256, P-384 and P-521 keys are now supported by envoy (see https://github.com/envoyproxy/envoy/issues/10855)

## Configuration
Yggdrasil can be configured using a config file e.g:
```json
{
"nodeName": "foo",
"ingressClasses": ["multi-cluster", "multi-cluster-staging"],
"accessLog": "/var/log/envoy/",
"syncSecrets": false,
"certificates": [
{
Expand All @@ -142,7 +169,9 @@ Yggdrasil can be configured using a config file e.g:
{
"token": "xxxxxxxxxxxxxxxx",
"apiServer": "https://cluster1.api.com",
"ca": "pathto/cluster1/ca"
"ca": "pathto/cluster1/ca",
"maintenance": false,
"kubernetesClusterName": "cluster1"
},
{
"tokenPath": "/path/to/a/token",
Expand All @@ -159,18 +188,29 @@ The list of certificates will be loaded by Yggdrasil and served to the Envoy nod
The `ingressClasses` is a list of ingress classes that yggdrasil will watch for.
Each cluster represents a different Kubernetes cluster with the token being a service account token for that cluster. `ca` is the Path to the ca certificate for that cluster.

Maintenance is a new mode that allow to set a cluster in maintenance mode :
- Upstream only in one cluster are keeped
- Upstream in at least 1 cluster that is not in maintenance is deleted for the cluster in maintenance mode
- Yggdrasil will Fatal if all clusters are in maintenance mode.

This is optional and equal to `false` by default.

kubernetesClusterName is the name of the cluster, it's only for information and will be used for metrics. Optional defaults to `""`

## Metrics
Yggdrasil has a number of Go, gRPC, Prometheus, and Yggdrasil-specific metrics built in which can be reached by cURLing the `/metrics` path at the health API address/port (default: 8081). See [Flags](#Flags) for more information on configuring the health API address/port.

The Yggdrasil-specific metrics which are available from the API are:

| Name | Description | Type |
|-----------------------------|------------------------------------------------|----------|
| yggdrasil_cluster_updates | Number of times the clusters have been updated | counter |
| yggdrasil_clusters | Total number of clusters generated | gauge |
| yggdrasil_ingresses | Total number of matching ingress objects | gauge |
| yggdrasil_listener_updates | Number of times the listener has been updated | counter |
| yggdrasil_virtual_hosts | Total number of virtual hosts generated | gauge |
| Name | Description | Type |
|----------------------------------------------|------------------------------------------------|----------|
| yggdrasil_cluster_updates | Number of times the clusters have been updated | counter |
| yggdrasil_clusters | Total number of clusters generated | gauge |
| yggdrasil_ingresses | Total number of matching ingress objects | gauge |
| yggdrasil_listener_updates | Number of times the listener has been updated | counter |
| yggdrasil_virtual_hosts | Total number of virtual hosts generated | gauge |
| yggdrasil_kubernetes_cluster_in_maintenance | Return 1 if cluster in maintenance or 0 | gauge |
| yggdrasil_upstream_info | Provide informations relate to upstream | gauge |

## Flags
```
Expand All @@ -180,7 +220,8 @@ The Yggdrasil-specific metrics which are available from the API are:
--config string config file
--config-dump Enable config dump endpoint at /configdump on the health-address HTTP server
--debug Log at debug level
--envoy-listener-ipv4-address string IPv4 address by the envoy proxy to accept incoming connections (default "0.0.0.0")
--access-log path for the file logs
--envoy-listener-ipv4-address strings IPv4 addresses by the envoy proxy to accept incoming connections (default "0.0.0.0")
--envoy-port uint32 port by the envoy proxy to accept incoming connections (default 10000)
--health-address string yggdrasil health API listen address (default "0.0.0.0:8081")
-h, --help help for yggdrasil
Expand Down
Loading
Loading