31 stable releases
| 2.4.17 | Sep 11, 2025 |
|---|---|
| 2.4.13 | Aug 25, 2025 |
| 2.4.5 | Jul 30, 2025 |
| 2.0.0 | Dec 5, 2024 |
| 1.2.0 | Oct 13, 2024 |
#60 in HTTP server
135KB
1.5K
SLoC
AKAS: API Key Authorization Server
A simple and higth performance server to authorized HTTP requests by API key checks.
- A hight performance server written in Rust,
- In-memory keys storage,
- Control authorization bearer with pre-checks,
- Perform a hot reload of the key file.
Authorization: Bearer <key>
The file of the list of the keys to be used for authorization should contain one key per line in plain or SHA-256 format:
- sha256 (default)
8b89600015b273c28f966f368456e45e01df239a36bf939ff72a16881f775679
fb22be500af1ef0479745bbbce847854da33f5e910361ad278e0282995b95f4d
...
- plain
mykey-3532dceb-f38a-491b-814d-9607bc9a947a
mykey-c2d79a40-388e-4709-9e4b-903035b0e71e
...
Usage
$ ./akas --help
A HTTP API key-Based Authorization Server
Usage: akas <COMMAND>
Commands:
serve Start the server
load Load keys from file (Not yet implemented)
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
$./akas serve --help
Start the server
Usage: akas serve [OPTIONS]
Options:
--admin-key <ADMIN_KEY>
Admin key for /load and /status URI [env: AKAS_ADMIN_KEY=] [default: ]
--no-admin-key
No admin key flag
--local
Bind local adress only [env: AKAS_LOCAL=]
--enable-metrics
Enable Prometheus metrics endpoint [env: AKAS_ENABLE_METRICS=]
-p, --port <PORT>
Port of the server [env: AKAS_PORT=] [default: 5001]
--log-level <LOG_LEVEL>
Log level <error|warn|info|debug|trace> [env: AKAS_LOG_LEVEL=] [default: info]
--original-length <ORIGINAL_LENGTH>
Length of the x-forwarded-for, x-original header fields [env: AKAS_ORIGINAL_LENGTH=] [default: 100]
--metadata-length <METADATA_LENGTH>
Length of the metadata header field [env: AKAS_METADATA_LENGTH=] [default: 0]
--key-length <KEY_LENGTH>
Length of the key [optional] [env: AKAS_KEY_LENGTH=] [default: 0]
--key-prefix <KEY_PREFIX>
Prefix of the key [optional] [env: AKAS_KEY_PREFIX=] [default: ]
-h, --help
Print help
Start akas server with the default port 5001
./akas serve --admin-key my-admin-key
Example of configuration of a Nginx server
server {
listen 80;
server_name _;
location / {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
root /usr/share/nginx/html;
index index.html index.htm;
}
location = /auth {
internal;
proxy_pass http://localhost:5001/auth;
proxy_pass_request_body off;
proxy_set_header content-length "";
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_set_header x-original-host $host;
proxy_set_header x-original-uri $request_uri;
proxy_set_header x-akas-metadata "my-metadata";
}
}
More details of Nginx configuration can be found in the configuring subrequest authentication documentation
- Authorized request:
curl -H "Authorization: Bearer <key>" http://<host>/
Endpoints URIs
/auth: Authorization endpoint
If the API key is present in the hashset
return 200 OK,
otherwise return 401 Unauthorized.
/load
Load new plain/hash keys file and replace the current keys in HashSet. The access is protected by an optional admin key.
Example of a curl request:
curl -v \
-H "Authorization: Bearer my-admin-key" \
--url http://localhost:5001/load \
-F 'json={"format": "sha256", "hash_input_file": "43fcba0b3a ..."};type=application/json' \
-F file=@./tests/files/sha256_key.txt
| Field | Description | Required | Default |
|---|---|---|---|
file |
File path of the keys file to upload | Yes | - |
format |
Format of the keys <sha256|plain> | No | sha256 |
hash_input_file |
sha-256 of the uploaded file | No | - |
If the server is started without an admin key (--no-admin-key), the header Authorization: Bearer is still required with a fake key.
/status
Return the application state in JSON format. The access is protected by an optional admin key. Example:
{
"log_level": "INFO",
"original_length": 100,
"metadata_length": 0,
"file_hash": "43fcba0b3a5ab1b302f9d13617ae4eec6ae623a7fd52437dd992d5dca115e68d",
"file_date": "2024-11-09T14:07:23.416999558+00:00",
"file_key_count": 150,
"key_length": 42,
"key_prefix": "mykey-"
}
Example of request:
curl -v \
-H "Authorization: Bearer my-admin-key" \
http://localhost:5001/status
If the server is started without an admin key (--no-admin-key), the header Authorization: Bearer is still required with a fake key.
/metrics
Enabling the --enable-metrics flag exposes Prometheus metrics via the /metrics endpoint:
# HELP akas_http_requests_duration_seconds HTTP request duration in seconds for all requests
# TYPE akas_http_requests_duration_seconds histogram
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.005"} 1
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.01"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.025"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.05"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.1"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.25"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="0.5"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="1"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="2.5"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="5"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="10"} 2
akas_http_requests_duration_seconds_bucket{endpoint="/auth",method="GET",status="401",le="+Inf"} 2
akas_http_requests_duration_seconds_sum{endpoint="/auth",method="GET",status="401"} 0.005529125
akas_http_requests_duration_seconds_count{endpoint="/auth",method="GET",status="401"} 2
# HELP akas_http_requests_total Total number of HTTP requests
# TYPE akas_http_requests_total counter
akas_http_requests_total{endpoint="/auth",method="GET",status="401"} 2
# HELP auth_akas_requests_total Total number of requests for auth with custom labels
# TYPE auth_akas_requests_total counter
auth_akas_requests_total{endpoint="/auth",metadata="-",method="GET",status="401",x_original_host="-"} 2
/health
Returns 200 OK to indicate the service is healthy and operational.
/auth-unauthorized
Always return 401 Unauthorized without checking the key (for testing purposes or disable access).
Features & Limitations
- Authorization by HTTP Bearer key.
- Configuration:
- via command line arguments.
- via environment variables.
- Subcommand
serve: Start server - Subcommand
load: Load file - Subcommand
status: Get Hash of input file, datetime of load, number of valid keys. - load plain keys file (plain text) by curl.
- load hash keys file (hashed - sha256) by curl.
- Plain or hashed keys loaded and saved in a Rust HashSet for a fast authorization check.
- Check of the key format during the loading process of the file based keys storage:
- prefix and length for plain keys file.
- SHA-256 for hashed keys file.
- Initial check of the input key format in the header (length and prefix) [optional].
- Endpoints:
-
/auth: default endpoint. -
/load: Load new plain/hash keys file. -
/status: Get Hash of input file, datetime of load, number of valid keys. -
/health: indicate the service is healthy and operational. -
/auth-unauthorized: always return401 Unauthorizedwithout checking the key.
-
- Admin key in header bearer for
/loadand/status. - Binaries compatibility for Linux with no dependencies:
- x86-64 and arm64.
- glibc (debian, ubuntu, fedora...) and musl libc (alpine ...).
- Tests:
- Unit tests (Rust).
- Functional tests (Robot Framework).
- Gitlab CI/CD Pipeline to auto-publish new versions.
- Renovate Bot auto-update dependencies.
- AKAS packaged in a distroless Docker image.
- Log implemenations with
https://crates.io/crates/tracing-actix-web - Log requests:
- All requests: Level Info
- Only unauthorized requests (401): Level Warn
- Json log format
- Length truncation of header fields
- Metadata field
- Prometheus metrics
-
/load-diffLoad diff file - Cache implementation for faster access to key authorization without SHA-256 operation (LRU Cache).
Installation
-
Binary file installation on Linux via the GitLab package registry of the project:
- 2 architectures:
- akas-x86_64-linux-<gnu|musl>.tar.gz : x86_64 (Intel, AMD).
- akas-aarch64-linux-<gnu|musl>.tar.gz : arm64
- 2 C standard library with no dependencies:
- akas-<x86_64|aarch64>-linux-gnu.tar.gz : glibc for Debian, Ubuntu, Fedora...
- akas-<x86_64|aarch64>-linux-musl.tar.gz : musl libc for Alpine
- 2 architectures:
-
With a Rust environment, running this command will globally install the akas binary:
cargo install akas
Log
The level of log is set with the RUST_LOG environment variable:
- error - Requests are not logged.
- warn - Only unauthorized requests (401) are logged.
- info (default) - all requests are logged.
- debug
- trace
- off
Access log in jsonl format
{
"timestamp": "2025-05-29T22:25:56.133350Z",
"level": "INFO",
"fields": {
"message": "access authorized",
"key_hash": "92c55f4d88b1",
"forwarded_for": "203.0.113.195",
"original_host": "my-host.com",
"original_uri": "/some/path",
"metadata": "my-metadata",
"access": "authorized"
},
"target": "akas"
}
{
"timestamp": "2025-05-29T22:25:56.135564Z",
"level": "WARN",
"fields": {
"message": "access unauthorized",
"key_hash": "24328022c7341148e4d84fab687dff6bd1f7c836a73a307ceb3357a3b9bb2d9d",
"forwarded_for": "203.0.113.195",
"original_host": "my-host.com",
"original_uri": "/some/path",
"metadata": "my-metadata",
"access": "unauthorized"
},
"target": "akas"
}
| Value | Description | Max field length |
|---|---|---|
timestamp |
Date and time in ISO 8601 format | |
level |
Log level | |
fields.message |
Message | |
fields.key_hash |
sha256 key of the user, limited to 12 characters when authorized | |
fields.forwarded_for |
Extract of x-forwarded-for header field set by nginx, if not set: - |
--original-length option or AKAS_ORIGINAL_LENGTH env. variable [default: 100] |
fields.original_host |
Extract of x-original-host header field set by nginx, if not set: - |
--original-length option or AKAS_ORIGINAL_LENGTH env. variable [default: 100] |
fields.original_uri |
Extract of x-original-uri header field set by nginx, if not set: - |
--original-length option or AKAS_ORIGINAL_LENGTH env. variable [default: 100] |
fields.metadata |
Extract of x-akas-metadata header field set by nginx, if not set: - |
--metadata-length option or AKAS_METADATA_LENGTH env. variable [default: 0] |
fields.access |
authorized, unauthorized |
|
target |
Component |
More details:
Tests
AKAS employs two types of tests to ensure its quality:
- Unit tests are written in Rust.
- Functional tests are managed via Robot Framework and reside in a dedicated repository: AKAS Functional Tests.
Development
-
Clone the source repository:
git clone https://gitlab.com/op_so/projects/akas.git -
To format and lint:
cargo fmt # cargo fmt -- --check
cargo clippy # Rust linter
- To test:
cargo test # Unit and integration tests
cargo tarpaulin --ignore-tests # Code coverage
cargo audit # Security audit
-
To run:
cargo run -
To build:
cargo build # Debug binary target/debug/akas
cargo build --release # Release binary target/release/akas
Authors
- FX Soubirou - Initial work - GitLab repositories
License
This program is free software: you can redistribute it and/or modify it under the terms of the MIT License (MIT). See the LICENSE for details.
Dependencies
~24–42MB
~694K SLoC