TazPod: S3 Detail

Level 3 (Detail) — AWS S3 client for vault persistence.

Concept

The S3 client provides remote vault persistence to Amazon S3. It supports upload, download, and bucket creation. The default target is bucket tazlab-storage in eu-central-1.

Client Initialization

File: internal/utils/s3.goNewS3Client()

func NewS3Client(awsAccessKeyId, awsSsoProfile string) (*S3Client, error)
  • If awsAccessKeyId is set → uses static credentials directly
  • Otherwise → uses the AWS SSO profile from cfg.AwsSso.Profile
  • Falls back to AWS_ACCESS_KEY_ID env var if both are empty
  • Region is hardcoded to eu-central-1

Methods

UploadFile

func (s *S3Client) UploadFile(key, filePath string) error
  • key: S3 object key (e.g., tazpod/vault/vault.tar.aes)
  • filePath: local file path to upload
  • Uses s3manager.NewUploader

DownloadFile

func (s *S3Client) DownloadFile(key, filePath string) error
  • key: S3 object key
  • filePath: local destination path
  • Uses s3manager.NewDownloader

CreateBucket

func (s *S3Client) CreateBucket() error
  • Creates tazlab-storage bucket if it doesn’t exist
  • Called by setupStorage() command

Vault Object Contract

PropertyValue
Buckettazlab-storage
Regioneu-central-1
Latest keytazpod/vault/vault.tar.aes
History prefixtazpod/vault/history/vault-<TIMESTAMP>.tar.aes
Local path.tazpod/vault/vault.tar.aes

History Copies (v0.4+)

Every tazpod push vault creates a versioned history copy if the vault content has actually changed. Detection is via SHA256 of the plaintext (before encryption), stored as S3 metadata x-amz-meta-content-sha256 on both the latest and history objects.

tazpod/vault/vault.tar.aes                              ← Latest (overwrite, with content-sha256 metadata)
tazpod/vault/history/vault-20260520T210000.tar.aes       ← History copy (with content-sha256 metadata)
tazpod/vault/history/vault-20260520T200000.tar.aes       ← History copy
...

Retention: max N=50 history copies (configurable via vault.retention). Pruning is automatic on push.

Path Resolution (TD-022 — Fixed in v0.4+)

tazpod push vault and tazpod pull vault now try both paths and use the first that exists:

func vaultFilePath() string {
    paths := []string{
        "/workspace/.tazpod/vault/vault.tar.aes",  // inside container
        ".tazpod/vault/vault.tar.aes",              // on host (relative to cwd)
    }
    for _, p := range paths {
        if _, err := os.Stat(p); err == nil { return p }
    }
    return paths[0]
}

This works from both the container and the host regardless of current directory.

S3 Methods

MethodDescription
UploadFile(key, filePath)Upload file to S3 (plain, no metadata)
UploadFileWithMetadata(key, filePath, metadata)Upload with custom metadata map
DownloadFile(key, filePath)Download from S3 to local file
HeadObject(key)Get object metadata without downloading
ListObjects(prefix)List objects by prefix, returns []ObjectInfo{Key, LastModified, Size}
DeleteObjects(keys)Batch delete up to 1000 keys

Lineage Concept

The S3 integration supports a lineage-based versioning scheme (used by the Hetzner Vault runtime for deterministic restore):

  • tazpod/vault/vault.tar.aes — latest vault
  • Multiple slot-a / slot-b pointers for lineage tracking

See Also