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
||||
)
)
Start akas server with the default port 5001
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:
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:
Example of request:
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 Unauthorized
without checking the key.
-
- Admin key in header bearer for
/load
and/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-diff
Load 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
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.