148 lines
4.0 KiB
Markdown
148 lines
4.0 KiB
Markdown
# Encrypted Config file API Service
|
||
|
||
This project implements a secure, encrypted API service using CherryPy and
|
||
Python. The API allows clients to securely interact with config files. It
|
||
supports reading, writing and modifying content. Complete files or sections /
|
||
topics from the files. The service supports creating backup copies before every
|
||
modifying action. The service employs JWE (JSON Web Encryption) tokens for
|
||
authentication, along with ECC (Elliptic Curve Cryptography) for key exchange
|
||
and AES for encrypting request and response bodies.
|
||
|
||
I strongly recomend running this behind reverse proxy (like nginx) that
|
||
provides TLS communication between the server and client.
|
||
|
||
## Features
|
||
|
||
* JWE Token Authentication:
|
||
The service uses encrypted JWE tokens for authentication and key exchange.
|
||
|
||
* ECC for Key Exchange:
|
||
The client encrypts a symmetric key using the server’s ECC public key,
|
||
which is used for AES encryption/decryption.
|
||
|
||
* AES Encryption:
|
||
Both request and response bodies are encrypted using AES with a single use
|
||
symmetric key, ensuring data confidentiality.
|
||
|
||
* Config File Handling:
|
||
Supports reading, writing, and updating config files. Initially designed
|
||
for WireGuard configs but easily extendable to any config format.
|
||
|
||
* POST-Only API:
|
||
The API only accepts POST requests for all interactions.
|
||
|
||
* Single API Endpoint:
|
||
The entire service operates through a single endpoint, keeping the API
|
||
interface minimal and clean.
|
||
|
||
## Requirements
|
||
|
||
Python 3.11+
|
||
CherryPy
|
||
cryptography
|
||
requests
|
||
|
||
Some controllers (file handlers) may have other dependencies.
|
||
|
||
## Config
|
||
|
||
config.toml
|
||
|
||
The config.toml file is used to configure the server, logging, and the paths to
|
||
the config files. Here’s a sample configuration:
|
||
|
||
[server]
|
||
host = "0.0.0.0"
|
||
port = 8000
|
||
base_url = '/'
|
||
|
||
[logging]
|
||
log_file = "service.log"
|
||
debug = true
|
||
|
||
[files]
|
||
wireguard_wg0 = ["/etc/wireguard/wg0.conf", backup=true]
|
||
|
||
[client_keys]
|
||
public_key = """
|
||
-----BEGIN PUBLIC KEY-----
|
||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA.....
|
||
-----END PUBLIC KEY-----
|
||
"""
|
||
|
||
- server: Defines the host, port and the url where the service will run.
|
||
- logging: Configures the log file location and debug mode.
|
||
- files: Key/[value] list of config files and their settings.
|
||
- client_keys.public_key: The client’s ECC public key (used for verifying
|
||
signatures and decrypting data).
|
||
|
||
Ensure the config.toml is in the same directory as your application.
|
||
|
||
## Sending Requests
|
||
|
||
All API requests must be sent as POST requests with an encrypted body. The
|
||
encryption key is exchanged using the ECC-based JWE token provided in the
|
||
Authorization header.
|
||
|
||
Headers:
|
||
|
||
Authorization: Must contain the JWE token in the format Bearer <token>.
|
||
|
||
Request Body:
|
||
|
||
The body of the request must be encrypted using AES, with the symmetric key
|
||
provided inside the JWE token.
|
||
|
||
|
||
Reading a config file:
|
||
|
||
{
|
||
"action": "read_file",
|
||
"file": "wireguard_wg0"
|
||
}
|
||
|
||
Writing to a config file:
|
||
|
||
|
||
{
|
||
"action": "write_file",
|
||
"file": "wireguard_wg0",
|
||
"data": {
|
||
[Interface]
|
||
PrivateKey = PrivateKey123=
|
||
Address = 10.10.200.1/32
|
||
ListenPort = 51820
|
||
|
||
[Peer]
|
||
PublicKey = PublicKey123=
|
||
AllowedIPs = 10.10.200.2/32
|
||
}
|
||
}
|
||
}
|
||
|
||
## Response Structure Details
|
||
|
||
Response is json document like:
|
||
|
||
{
|
||
"data": "<encrypted_data>",
|
||
"signature": "<base64-encoded signature>"
|
||
}
|
||
|
||
The decrypted data could look like this:
|
||
|
||
{
|
||
"status": 200,
|
||
"timestamp": "2024-10-22T10:30:00Z",
|
||
"message": "File written successfully"
|
||
}
|
||
|
||
|
||
|
||
## Error Handling
|
||
|
||
400 Bad Request: Returned if the request is malformed or the token is invalid.
|
||
401 Unauthorized: If the Authorization header or the JWE token is missing or invalid.
|
||
403 Forbidden: If the signature validation fails.
|
||
500 Internal Server Error: For unexpected errors in processing the request.
|