Skip to main content

Authentication & Security

Lioran S3 provides two primary authentication schemes for client requests, plus temporary delegated access via cryptographically signed presigned URLs.


1. Authentication Models​

┌────────────────────────────────────────┐
│ Authentication Methods │
└──────────────────┬─────────────────────┘
│
┌─────────────────────────┴─────────────────────────┐
▼ ▼
┌────────────────────────┐ ┌────────────────────────┐
│ Basic HTTP Auth │ │ Programmatic Keys │
│ (Username + Password) │ │ (AccessKey + SecretKey)│
├────────────────────────┤ ├────────────────────────┤
│ • Interactive CLI │ │ • Microservices / Apps │
│ • Web Dashboard │ │ • CI/CD Pipelines │
│ • Argon2id Hashing │ │ • Independent Secrets │
│ • Roles: admin, rw, ro │ │ • Rotatable / Scoped │
└────────────────────────┘ └────────────────────────┘

A. Basic Authentication (Username & Password)​

  • Standard RFC 7617 HTTP Basic authentication header: Authorization: Basic <base64(username:password)>.
  • Passwords are encrypted on disk in RocksDB using Argon2id password hashing.
  • Role-based authorization levels:
    • admin: Full system control (create/delete buckets, manage users, rotate keys, inspect metrics).
    • readwrite: Read, upload, and delete objects in accessible buckets.
    • readonly: Read and list objects and buckets only; mutating writes rejected.

B. Programmatic Access Keys​

  • Authenticated via custom headers (x-bastion-access-key and x-bastion-secret-key) or via Basic authorization where username is Key ID and password is Key Secret.
  • Key secrets are displayed only once upon generation and hashed before storage.
  • Key IDs use the standard prefix bk_ (e.g. bk_live_0192a7b8...).
  • Secret keys use the standard prefix sk_ (e.g. sk_live_9f83a21b...).

2. Administrator Bootstrap & Forced Password Rotation​

When initializing a fresh Lioran S3 deployment:

  1. The server bootstraps an initial administrator account using BASTION_ADMIN_USERNAME (default: admin) and BASTION_ADMIN_PASSWORD.
  2. In production (BASTION_ENV=production), Bastion requires an explicit strong password (>= 8 characters) and rejects insecure defaults like admin, password, or 123456.
  3. The newly bootstrapped account is flagged with must_change_password = true.
  4. The first administrative or mutating call will return HTTP 403 Forbidden with the error code:
    {
    "code": "password_change_required",
    "message": "You must change the bootstrap password before performing administrative or storage operations"
    }

Changing the Bootstrap Password via CLI​

liorans3 user passwd --old admin --new "MyNewSecurePassword123!"

Changing the Bootstrap Password via SDK​

import { BastionClient } from "@liorans3/driver";

const client = new BastionClient("bastion://admin:admin@127.0.0.1:27118");

// Change bootstrap password
await client.users.changePassword("admin", "MyNewSecurePassword123!");

// Reconnect with new credentials
const authClient = new BastionClient("bastion://admin:MyNewSecurePassword123!@127.0.0.1:27118");

3. Creating & Managing Access Keys​

Via CLI​

# Create a new access key for the authenticated user
liorans3 key create "backend-worker" --expires-days 90

# Output:
# =============================================================
# NEW ACCESS KEY CREATED
# =============================================================
# Name: backend-worker
# Key ID: bk_live_0192a7b8c9d0
# Secret Key: sk_live_8f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c
# Owner: admin
# Expires: 2026-12-30T12:00:00.000Z
# =============================================================

To automatically save the newly generated access key to a named CLI profile:

liorans3 key create "ci-pipeline" --save-to-profile ci

Rotating an Access Key​

Rotating a key immediately revokes the old secret and generates a new active secret:

liorans3 key rotate bk_live_0192a7b8c9d0

4. Expiring Presigned URLs​

Presigned URLs grant temporary, time-bound access to a specific object without sharing credentials. The signature is computed using HMAC-SHA256 bound to:

  • HTTP Method (GET, PUT, or HEAD)
  • Bucket Name
  • Object Key
  • Expiration Unix timestamp (expires)
https://s3.example.com/api/v1/buckets/media/objects/sample.mp4?expires=1798765432&signature=a9f8e7d6...
const bucket = client.bucket("media");

// Generate link valid for 1 hour (3600 seconds)
const downloadUrl = await bucket.presignGet("videos/sample.mp4", {
expiresIn: 3600,
});
console.log("Presigned Download URL:", downloadUrl);
// Authorize a browser or third-party client to upload directly via PUT
const uploadUrl = await bucket.presignPut("uploads/user-avatar.png", {
expiresIn: 900, // 15 minutes
});
# GET presigned URL valid for 2 hours
liorans3 object presign media videos/sample.mp4 --method GET --expires 7200

5. Zero-Leak Credential Masking​

Lioran S3 enforces strict credential masking across all layers:

  • Server Logs: Connection URIs containing credentials are automatically redacted as bastion://***:***@host:port.
  • CLI Outputs: Command outputs and error messages sanitize passwords and secrets.
  • SDK Serialization: client.safeUri, client.toJSON(), and util.inspect automatically hide embedded credentials.