Skip to content

Security model ​

CargoShip encrypts data at rest using AWS Key Management Service (KMS). It offers two independent, composable layers — encrypt data chunks, encrypt the manifest, or both for complete at-rest protection of your data and its metadata. This page covers the model and setup; for the day-to-day flags see Encryption (KMS & GPG).

Not end-to-end encryption

Data chunks use SSE-KMS, so S3 sees plaintext at write time and encrypts it server-side — this is at-rest encryption, not end-to-end. The manifest layer (--encrypt-manifest) is client-side (S3 never sees the plaintext manifest).

Two encryption layers ​

Data chunk encryption (SSE-KMS) ​

Chunks (tar.zst objects) are encrypted server-side with SSE-KMS. It's enabled automatically when you pass --kms-key-id, has no client-side performance overhead (AWS handles it), and is logged to CloudTrail.

Manifest encryption (envelope encryption) ​

The manifest holds file metadata (paths, sizes, timestamps). With --encrypt-manifest, CargoShip encrypts it client-side with AES-256-GCM before upload, using a data key wrapped by your KMS CMK — so the manifest is never stored unencrypted and integrity is authenticated.

bash
cargoship upload ./data s3://bucket/prefix \
  --kms-key-id alias/cargoship-encryption \
  --encrypt-manifest

Downloads and inspection (download, list, info) detect and decrypt encrypted manifests automatically, given the right KMS permissions.

KMS setup ​

Create a symmetric encrypt/decrypt key (an alias is recommended so you can rotate without changing commands):

bash
aws kms create-key --description "CargoShip data encryption key" --key-usage ENCRYPT_DECRYPT
aws kms create-alias --alias-name alias/cargoship-encryption --target-key-id KEY_ID

Grant least-privilege IAM permissions:

  • Upload: kms:GenerateDataKey, kms:DescribeKey
  • Download: kms:Decrypt, kms:DescribeKey

You can additionally enforce encryption on the bucket with an S3 bucket policy that denies s3:PutObject unless s3:x-amz-server-side-encryption is aws:kms.

Best practices ​

TIP

  • Use key aliases and separate keys per environment (prod / staging).
  • Enable automatic key rotation: aws kms enable-key-rotation --key-id KEY_ID.
  • Always --encrypt-manifest in production — metadata is sensitive.
  • Follow least privilege: uploaders get GenerateDataKey, downloaders get Decrypt.
  • Enable CloudTrail for a KMS audit trail.

Fleet (ghostship) trust model ​

Running a ghostship fleet adds a distinct security posture for unattended agents:

  • Write-only, delete-free per-writer IAM. Each agent gets s3:PutObject on its own writers/<id>/ prefix, scoped s3:ListBucket, read-only s3:GetObject on its config prefix, and kms:GenerateDataKey — no s3:DeleteObject, no kms:Decrypt, no access to other writers. A compromised agent can only append to its own subtree; it can't read back, decrypt, or delete. cargoship ghostship iam-policy --write-only emits it and ghostship init --mint provisions it.
  • Signed config over S3. Agents pull their config from a fleet/<id>/ control prefix and verify an ed25519 signature against a baked public key (the operator holds the private key). Unsigned/tampered/wrong-key configs are refused; on a bad refresh the agent keeps the last-good config; widening what a writer reads or deletes requires an explicit signed allow_scope_expansion.
  • Break-glass restore is separate. Recovery uses a distinct role with bucket read + kms:Decrypt, never the write-only agent identity — so decryption capability isn't sitting on the backup boxes.
  • CMK-custody is the long-term SPOF. Use a dedicated fleet CMK (agent = GenerateDataKey only; break-glass role = Decrypt). With no scheduled deletion and immutable history, losing the CMK means losing the data — enable key rotation and back up / multi-Region the key material. Verify the bucket's immutability posture with cargoship fleet lock-status.

Compliance ​

AWS KMS uses FIPS 140-2 validated HSMs and is HIPAA-eligible, PCI DSS, and SOC 2 compliant; all KMS operations are logged to CloudTrail. KMS keys are regional — SSE-KMS requires the bucket and key in the same region, while client-side manifest envelope encryption allows cross-region uploads.

Rotating GPG keys made before v0.23.0 ​

Private keys generated by cargoship create keys before v0.23.0 are unencrypted, and were written to $TMPDIR by default. If you hold such a key, see Rotating a key generated before v0.23.0. Because archives are encrypted to the public key, rotating protects future uploads but does not protect data already uploaded to the old key.

Reporting a vulnerability ​

Report security issues privately via GitHub Security Advisories.

See also ​