Key takeaways
- Never ship long-lived cloud keys to runners: mint upload grants in your control plane; runners consume single-purpose URLs or minute-scale role sessions.
- Presigned URLs excel at blast-radius reduction: restrict bucket, prefix, HTTP verb, checksum headers, and expiry—then log the grant ID, not the secret.
- STS-shaped workflows add accounting: assume-role with external ID, session tags for
tenant_id/pipeline_id, and mandatory rotation tied to runner lease lifetime. - Integrity is a manifest, not a vibe: record digests, signing key IDs, and runner attestations in one structured row per artifact version.

1. Threat model: what attackers actually want
Compromised runners rarely exfiltrate through polished REST APIs—they scrape env vars, hijack CI secrets, or replay tokens scooped from logs. Your goal is to ensure that even with shell access, an attacker obtains at most a short window to write into a predetermined prefix and cannot mint new grants from inside the lease. That implies separating upload authorization (control plane) from upload mechanics (runner) and keeping IAM users off the guest entirely when possible.
For Apple-platform outputs, the integrity story does not stop at tarball bytes: codesigning identity and notarization receipts already force a disciplined secret boundary on the same hosts. The same operational muscle applies to generic artifact blobs—see Apple Silicon cloud Mac iOS/macOS CI: codesign, Notarization, stapler & keychain boundaries—reproducible pipelines and rejection-code troubleshooting for how credentials and artifact identity interact on runners.
2. Presigned URLs versus short-lived STS sessions
Presigned URLs push authorization decisions to the control plane: the runner receives an opaque URL that already embeds policy (verb, object key, optional SSE-KMS key, content-length ceiling). Because the secret never becomes an ambient environment variable, leak surfaces shrink—provided you reject broad wildcard keys and keep TTLs measured in minutes.
STS-like federation (cloud vendor assume-role, OIDC from your CI IdP, or a proprietary broker) helps when you need multi-part uploads, many objects per build, or dynamic key naming. Bind sessions to runner_lease_id, cap duration to the expected job runtime plus slack, and attach ABAC-style tags so CloudTrail-style logs remain queryable by tenant. Avoid recycling the same external ID across environments; that pattern quietly merges blast radius.
| Pattern | Best when | Watchouts |
|---|---|---|
| Presigned PUT/POST | Single or few objects; tight keys; minimal runner logic | Clock skew breaking expiry; logging full URLs; missing checksum enforcement |
| Short-lived role/session | Multipart uploads, dynamic manifests, many cached layers | Overpowered trust policies; sessions outliving runner leases |
| Hybrid | Large artifacts via multipart roles; metadata via presigned small JSON | Inconsistent audit fields across both paths |
Logging without leaking upload authority
Structured logs should carry grant_id, bucket, normalized object prefix, issuing principal, and TTL remaining at upload start—not the presigned query string. For STS sessions, log role_arn, session name, and tag set; rotate signing CA keys on a published schedule so incident response can answer “which trust chain was live at 14:03 UTC?” without opening ticket archaeology.
3. Runner integrity checks before “promote”
Treat every build output as untrusted until anchored by evidence collected before the upload completes: cryptographic digest (SHA-256 or stronger), optional Sigstore-style signatures, Git commit SHA, toolchain versions, and the OpenClaw job/workflow identifiers. Upload clients should send Content-SHA256 or equivalent where the object store verifies it, so tampering in transit surfaces as a hard failure rather than silent corruption.
Where GPU/RAM pressure causes flaky compiles, operators sometimes chase ghosts in networking while the real issue is memory contention; grounding runner sizing in telemetry keeps integrity checks trustworthy—Apple Silicon cloud Mac runner memory peaks & swap governance: compiling, Docker & Xcode together—metrics, degradation tactics & plan RAM boundaries outlines how swap signals intersect with CI stability on Apple Silicon hosts.
4. Ingestion pipeline & audit chain
Design three synchronized records: (1) grant issued—who approved upload scope; (2) runner attestation—digest manifest plus lease metadata; (3) storage acknowledgement—version ID or ETag from the bucket. Correlate them with a single artifact_id propagated through OpenClaw events so webhook consumers and SIEM queries share vocabulary.
Immutable logs beat screenshots: stream structured JSON to your existing retention tier, redact presigned query strings, and store only fingerprints of signing material. When auditors ask “could this binary have been swapped mid-pipeline?” your answer should cite aligned timestamps across control plane, runner agent, and object-store access logs—not narrative prose.
5. Closing
Least privilege for artifact egress is mostly boring plumbing—short TTLs, tight prefixes, and manifests—but it is what lets teams adopt aggressive automation without turning every cloud Mac runner into a roaming admin credential. Bake the controls into OpenClaw job templates early; retrofitting after incidents is slower and noisier than enforcing deny-by-default object ACLs on day one.
On cloud Mac, bounded egress pairs well with Apple Silicon throughput
Apple Silicon runners chew through Xcode archives quickly when RAM and disk are sized for peak overlap, while macOS integrates cleanly with modern OIDC and keychain workflows—useful when uploads must coexist with signing identities on the same lease. A dedicated cloud Mac mini tier keeps concurrency predictable so presigned TTLs and STS sessions can be tuned tightly without chronic overruns.
If you want OpenClaw-driven builds on hosts you can lock down and meter, kvmboot cloud Mac mini M4 is a practical starting point—see plans and pricing and align artifact egress policies with hardware you actually control.