aegis proposes a minimal authentication protocol between the client service and the server it is going to proxy. It works based on headers containing signatures.
Every time the client makes a request to the server service, it must be add the following headers:
-
Auth-Headers: list of headers the client intends to sign. The list element seprator has to be ; For example: header1;....;header1
-
Auth-Kid: the name of client service which has to be used from server to verify identity
-
Auth-CorrelationId: it's the only mandatory header. It can be populated whit random value.
-
Signature: the signature of the following string
<list of indicated auth headers value>:Hash(payload)
π If the request does not expect a body or custom headers, payload or custom headers can be avoided. The signature must be composed by Auth-CorrelationId, at least.
As described in previous paragraph, payload has to be part of signature when exists. It is not intended as plain body but its computed hash. Aegis expects to parse the xxHash of request body. In particular, the XXH64 flavor is expected.
Signature of described information has to be computed usign classical HMAC algorithm based on SHA512 hash function. A symmetric key was shared betwwen system (proxy and client) and this is used as HMAC key.
In the end, the signature header (in a complete scenario) will be as follows;
HMAC-SHA512(Auth-CorrelationId;Auth-Headers...:XXH64(request body), symmetric key)
There is no dynamic trust mode between client and server. Keys trusting will be statically a priori.
Configuration is based on aconfig Go module. It has tobe in JSON form, example:
{
"ginmode": "debug", # release in production mode
"loglevel": "debug",
"server": {
"mode": "PLAIN", # can be PLAIN,TLS,MTLS
"tls": { # section needed just in TLS/MTLS case
"certpath": "test/server.crt", # file path of server certificate
"keypath": "test/server.key", # file path of key associated with server certificate
"cacert": "test/cacert.pem" # file path of CAs for certificate verification (MTLS)
},
"port": 8080, # proxy listen port
"probesport": 2112, # server port for probes endpoint (Kubernetes feat)
"upstream": "httpbin.org", # upstream host
"dropHeaders": ["Authorization"], # optional list of incoming headers to remove before forwarding upstream
"injectHeaders": [ # optional list of headers always added/overridden before forwarding upstream
{
"name": "X-Aegis-Proxy",
"value": "true"
},
{
"name": "Authorization",
"valueFromEnv": "UPSTREAM_AUTHORIZATION"
}
]
},
"kids": [ # list of strings representing all registered key id
"test"
]
}π
dropHeadersacts on request headers received by aegis before forwarding.injectHeadersis applied afterwards, so configured injected headers can override incoming values with the same name.
π Each
injectHeadersentry must explicitly definenameand exactly one ofvalueorvalueFromEnv. This makes the config shape unambiguous and allows sensitive upstream header values to stay in environment variables, typically populated from Kubernetes Secrets.
π Each kid MUST be associated to its value stored in specific env which has to be of the form ACCESSKEY_<UpperCase(kid)>. For example: if the kid is "test", the associated env will be ACCESSKEY_TEST="abcde1242352525gsgs"
π If an injected header uses
valueFromEnv, aegis validates the environment variable at startup and fails fast if it is missing.
- Build docker image locally or use official docker image
- Run docker image as follows:
docker run <imagename> -e CONFIG_PATH="<path to folder containing config.json>" -e ACCESSKEY_<KID1>="<secret value>" ... -e ACCESSKEY_<KIDn>="<secret value>" -p 8080:8080This is an example of POST request to target server containing Authentication headers:
curl --location --request POST 'http://localhost:8080/post' \
--header 'Auth-CorrelationId: jxW7faeiNP' \
--header 'Auth-Kid: test' \
--header 'Signature: sM4EOA3jh/F7X3PqKI52Cr3Sa9kvS9YwkSSqFKGy3hExBrfPKoro3w3eJSq26Yw7I7ydesiXgcjxkMGLMVfiNQ==' \
--header 'Content-Type: application/json' \
--data-raw '{
"min_position": 5,
"has_more_items": false,
"items_html": "Bus",
"new_latent_count": 8,
"data": {
"length": 25,
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
"numericalArray": [
29,
32,
33,
33,
28
],
"StringArray": [
"Oxygen",
"Oxygen",
"Oxygen",
"Oxygen"
],
"multipleTypesArray": true,
"objArray": [
{
"class": "lower",
"age": 0
},
{
"class": "upper",
"age": 9
},
{
"class": "middle",
"age": 0
},
{
"class": "lower",
"age": 2
},
{
"class": "lower",
"age": 5
}
]
}'Aegis has an official Helm Chart distribution which is available here and documented in this repository (helm docs).
