Server-Side Encryption (SSE-C)

Relution can encrypt the objects it stores in an S3-compatible bucket using Server-Side Encryption with a Customer-Provided Key (SSE-C). With SSE-C, Relution sends the encryption key with every request, and the storage backend uses it to encrypt objects on write and decrypt them on read. The backend never stores the key itself - keeping it safe is solely the administrator’s responsibility.

Read before enabling: SSE-C takes effect immediately on startup and Relution does not encrypt objects that already exist in the bucket. Only enable it on a clean instance with an empty bucket, or encrypt all existing objects first. If the key is lost, all encrypted data is permanently lost. See Important Notes below for details.
SSE-C vs. KMS encryption: SSE-C is not the same as client-side encryption via AWS KMS. With KMS, a customer managed key (CMK) is held and managed by AWS KMS. With SSE-C, the key is provided by Relution on each request and stored only by the administrator. These two mechanisms are mutually exclusive - only SSE-C or KMS or neither can be enabled, but never both at the same time.

Prerequisites

  • A working S3-compatible object storage setup - see Connect object storage →.
  • An object storage backend that supports SSE-C. Support has been verified with SeaweedFS and Hetzner Object Storage. Other S3-compatible backends may work but have not been tested.
  • A 256-bit encryption key (see below).

Generating the Key

SSE-C requires a 256-bit (32-byte) key, provided as a Base64-encoded string. A key can be generated with openssl:

openssl rand -base64 32

The resulting value must be stored securely. If this key is lost, all encrypted objects in the S3 bucket can no longer be decrypted and are permanently lost.


Configuration

SSE-C is activated as soon as a key is configured. The key can either be provided inline via the relution.storage.s3.serverSideEncryption.key property (options A and B) or supplied as a file via relution.storage.s3.serverSideEncryption.keyFile (option C). If both are set, the key file takes precedence.

Option A: Using application.yml

The serverSideEncryption block is added to the application.yml:

relution:
  storage:
    resourceStorageType: S3
    s3:
      customEndpoint: http://seaweedfs:8333
      accessKey: %YOUR-ACCESS-KEY%
      secretKey: %YOUR-SECRET-KEY%
      bucketName: relution
      serverSideEncryption:
        key: %YOUR-BASE64-KEY%

Option B: Using Environment Variables

The following environment variable is added to the relution service in the compose.yaml:

services:
  relution:
    environment:
      - RELUTION_STORAGE_S3_SERVERSIDEENCRYPTION_KEY=%YOUR-BASE64-KEY%

Option C: Key as a file

Instead of providing the key inline, it can be read from a file. This is particularly useful when the key is mounted into the container as a Docker or Kubernetes secret. The path to the key file is configured via relution.storage.s3.serverSideEncryption.keyFile:

relution:
  storage:
    s3:
      serverSideEncryption:
        keyFile: /path/to/ssec.key

Or via the corresponding environment variable:

services:
  relution:
    environment:
      - RELUTION_STORAGE_S3_SERVERSIDEENCRYPTION_KEYFILE=/path/to/ssec.key

The file must contain the same Base64-encoded 256-bit key as the inline value (for example, generated with openssl rand -base64 32). A trailing newline is harmless because the value is trimmed; binary or hexadecimal keys are rejected.

On startup, Relution logs the read with Reading SSE-C key from file <path>. If the file is missing or does not contain a 32-byte key, startup aborts with a corresponding error message.

Verifying Activation

On startup, Relution logs the active encryption, for SSE-C with S3 storage encryption: SSE-C (server-side). An inline key (options A and B) is also validated on startup: if the value is not valid Base64 or does not yield a 32-byte key, startup aborts, with SSE-C key must be 32 bytes (AES-256) if the length is wrong.


Important Notes

No migration of existing files: SSE-C takes effect immediately when Relution starts with the key configured. Relution does not encrypt objects that already exist in the bucket. SSE-C should only be used on a clean instance with an empty bucket, or all existing S3 objects must be encrypted before Relution is started with the key. Otherwise, previously stored objects will remain unencrypted and may become inaccessible.
Losing the key means losing all data: The storage backend does not store the key - keeping it safe is solely the administrator’s responsibility. If the key is lost, all encrypted objects in the bucket become permanently unrecoverable, and Relution can no longer serve apps or resources from object storage. The key must be kept in a secure, backed-up location.
Key rotation requires re-encryption: Rotating the key is the administrator’s responsibility. Relution does not re-encrypt objects when the key changes. To rotate the key, all existing objects in the bucket must be re-encrypted with the new key (for example, by copying them with the new key) before starting Relution with the updated configuration. Starting Relution with a new key while objects are still encrypted with the old one will make those objects inaccessible.
Mutually exclusive with KMS: Server-side (SSE-C) and client-side (KMS) encryption cannot be active at the same time. If both are configured, startup aborts with Conflicting encryption configuration: client and server side encryption active.

How helpful was this article?