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.
cargoship upload ./data s3://bucket/prefix \
--kms-key-id alias/cargoship-encryption \
--encrypt-manifestDownloads 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):
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_IDGrant 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-manifestin production — metadata is sensitive. - Follow least privilege: uploaders get
GenerateDataKey, downloaders getDecrypt. - 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:PutObjecton its ownwriters/<id>/prefix, scopeds3:ListBucket, read-onlys3:GetObjecton its config prefix, andkms:GenerateDataKey— nos3:DeleteObject, nokms: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-onlyemits it andghostship init --mintprovisions 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 signedallow_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 =
GenerateDataKeyonly; 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 withcargoship 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.
