Cloud-Infrastruktur mit Lyx
Dieser Guide erklärt den praktischen Einsatz der std.cloud-Units für AWS, DigitalOcean, Cloudflare und Google Cloud Platform: Credential-Setup, Response-Handling, typische Workflows und die Auswahl des richtigen Dienstes.
→ std.cloud (Unit-Referenz) · AWS-Units · DigitalOcean-Units · Cloudflare-Units · GCP-Units · Welche Unit?
Credentials einrichten
AWS
AWS verwendet AWSCreds als zentralen Credential-Typ. Die empfohlene Methode ist die Credential Chain via AWSCredentialsDefault(): Sie prüft automatisch Umgebungsvariablen, dann ~/.aws/credentials.
import std.cloud.aws.core;
// Empfohlen: Chain (Env → ~/.aws/credentials → leer)
var creds: AWSCreds := AWSCredentialsDefault();
// Explizit aus Umgebungsvariablen (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY):
var creds2: AWSCreds := AWSCredentialsFromEnv();
// Explizit aus ~/.aws/credentials (Profil "production"):
var creds3: AWSCreds := AWSCredentialsProfile("production"c);
// Hardcodiert (nur für Tests):
var creds4: AWSCreds := AWSCredentialsStatic("AKIAIOSFODNN7EXAMPLE"c,
"wJalrXUtnFEMI/K7MDENG/bPxRfi..."c);
// Am Ende immer freigeben:
AWSCredentialsFree(creds);
Umgebungsvariablen für AWS:
| Variable | Bedeutung |
|---|---|
AWS_ACCESS_KEY_ID | Access Key ID |
AWS_SECRET_ACCESS_KEY | Secret Access Key |
AWS_SESSION_TOKEN | Session Token (nur bei STS/temporären Creds) |
AWS_DEFAULT_REGION | Ziel-Region (z.B. eu-central-1) |
AWS_REGION | Alternativ zu AWS_DEFAULT_REGION |
DigitalOcean
DigitalOcean verwendet einen einfachen Bearer-Token:
import std.cloud.do.credentials;
// Aus Umgebungsvariable DIGITALOCEAN_TOKEN (empfohlen):
var creds: DOCredentials := DOCredentialsFromEnv();
// Direkt (nur für Tests):
var creds2: DOCredentials := DOCredentialsFromToken("dop_v1_xxxxxxxxxxxx"c);
// Aus doctl-Konfigurationsdatei (~/.config/doctl/config.yaml):
var creds3: DOCredentials := DOCredentialsDefault();
// Am Ende immer freigeben:
DOCredentialsFree(creds);
Response-Handling-Muster
Die meisten Lese-Funktionen in std.cloud geben ein int64 zurück, das auf einen allokierten Puffer mit der rohen API-Antwort zeigt (XML bei AWS S3/EC2/SQS, JSON bei AWS DynamoDB/Lambda/DO). Bei Fehler oder leerem Ergebnis ist der Rückgabewert 0.
Schreib- und Lösch-Funktionen geben int64 zurück: 1 = Erfolg, 0 = Fehler.
import std.cloud.aws.core;
import std.cloud.s3;
import std.alloc;
fn main(): int64 {
var creds: AWSCreds := AWSCredentialsDefault();
var s3: S3Client := S3Connect(creds, "eu-central-1"c);
// Lese-Funktion: gibt allokierten Puffer zurück (0 bei Fehler)
var result: int64 := S3ListBuckets(s3);
if (result == 0) {
PrintLn("Fehler oder keine Buckets"c);
S3Close(s3);
return 1;
}
Print(result as pchar);
PrintLn(""c);
free(result, StrLen(result as pchar) + 1); // Puffer freigeben!
// Schreib-Funktion: gibt 1 bei Erfolg zurück
var ok: int64 := S3PutObjectFile(s3, "mein-bucket"c,
"logs/2026-06-12.log"c,
"/var/log/app.log"c,
"text/plain"c);
if (ok == 0) {
PrintLn("Upload fehlgeschlagen"c);
}
S3Close(s3);
return 0;
}
alloc() — der Aufrufer trägt die Ownership. free(result, StrLen(result as pchar) + 1) ist das Standardmuster.
Cloudflare
Cloudflare verwendet CFCredentials mit API-Token. Der wichtigste Unterschied zu AWS und DO: Cloudflare gibt immer HTTP 200 zurück — der Erfolg steckt im success-Feld der CFResponse. Die High-Level-Funktionen (DNSRecordUpsert, KVGet, …) abstrahieren das weg und geben direkt int64 (Puffer oder 0) bzw. Struct zurück.
import std.cloud.cf.credentials;
import std.cloud.cf.transport;
// Aus Umgebungsvariablen CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID:
var creds: CFCredentials := CFCredentialsFromEnv();
var c: CFClient := CFClientNew(creds);
// Cleanup:
CFClientFree(c);
CFCredentialsFree(creds);
Umgebungsvariablen für Cloudflare:
| Variable | Bedeutung |
|---|---|
CLOUDFLARE_API_TOKEN | API-Token (empfohlen) |
CLOUDFLARE_ACCOUNT_ID | Account-ID |
CLOUDFLARE_API_KEY | Legacy API-Key |
CLOUDFLARE_API_EMAIL | Legacy E-Mail (nur zusammen mit API-Key) |
Google Cloud Platform
GCP verwendet GCPCredentials mit Application Default Credentials (ADC). Die Credential Chain prüft drei Quellen automatisch: Umgebungsvariable → ADC-Datei → GCE-Metadata-Server.
import std.cloud.gcp.credentials;
// Empfohlen: Credential Chain
// 1. GOOGLE_APPLICATION_CREDENTIALS → JSON-Datei
// 2. ~/.config/gcloud/application_default_credentials.json
// 3. GCE-Metadata-Server (automatisch auf Compute Engine)
var creds: GCPCredentials := GCPCredentialsDefault(
"https://www.googleapis.com/auth/cloud-platform"c);
// Explizit aus Service-Account-JSON-Datei:
// var creds2: GCPCredentials := GCPCredentialsFromFile("/pfad/sa.json"c, scope);
GCPCredentialsFree(creds);
Umgebungsvariablen für GCP:
| Variable | Bedeutung |
|---|---|
GOOGLE_APPLICATION_CREDENTIALS | Pfad zur Service-Account- oder Authorized-User-JSON-Datei |
Der Token wird intern gecacht und automatisch erneuert, sobald er weniger als 60 Sekunden gültig ist.
Typische Workflows
Workflow 1: Datei nach S3 hochladen und Presigned URL erzeugen
import std.cloud.aws.core;
import std.cloud.s3;
import std.alloc;
fn main(): int64 {
var creds: AWSCreds := AWSCredentialsDefault();
var s3: S3Client := S3Connect(creds, "eu-central-1"c);
// Kleine Datei hochladen
S3PutObjectFile(s3, "mein-bucket"c, "report.pdf"c,
"/tmp/report.pdf"c, "application/pdf"c);
// Presigned GET-URL (gültig 3600 Sekunden = 1 Stunde)
var url: int64 := S3PresignGet(s3, "mein-bucket"c, "report.pdf"c, 3600);
if (url != 0) {
Print("Download-Link: "c); Print(url as pchar); PrintLn(""c);
free(url, StrLen(url as pchar) + 1);
}
// Presigned PUT-URL (damit Clients direkt uploaden können, ohne Credentials)
var putUrl: int64 := S3PresignPut(s3, "mein-bucket"c, "uploads/foto.jpg"c, 900);
if (putUrl != 0) {
Print("Upload-Link: "c); Print(putUrl as pchar); PrintLn(""c);
free(putUrl, StrLen(putUrl as pchar) + 1);
}
// Fehler prüfen
if (S3LastStatus(s3) != 200 && S3LastStatus(s3) != 0) {
Print("Fehler: "c); Print(S3LastError(s3)); PrintLn(""c);
}
S3Close(s3);
return 0;
}
S3-kompatible Dienste — dieselbe API, anderer Connect:
// Cloudflare R2 (kein Egress-Preis):
var r2: S3Client := S3ConnectR2("mein-account-id"c,
"r2-access-key"c, "r2-secret-key"c);
// MinIO (lokale Entwicklung / Self-Hosted):
var minio: S3Client := S3ConnectMinio("localhost"c, 9000,
"minioadmin"c, "minioadmin"c);
// Nach dem Connect identische API wie AWS S3:
S3PutObjectFile(r2, "mein-bucket"c, "datei.pdf"c, "/tmp/datei.pdf"c, "application/pdf"c);
S3Close(r2);
Workflow 2: Secret aus Secrets Manager lesen
Das häufigste Muster für Produktions-Deployments: Credentials nie in den Code einbetten, immer aus Secrets Manager lesen.
import std.cloud.aws.core;
import std.cloud.secrets;
import std.alloc;
fn main(): int64 {
var creds: AWSCreds := AWSCredentialsDefault();
var sm: SecretsClient := SecretsConnect(creds, "eu-central-1"c);
// Direkt als String (häufigster Fall)
var dbPassword: int64 := SecretsGetString(sm, "prod/db/password"c);
if (dbPassword == 0) {
PrintLn("Secret nicht gefunden"c);
SecretsClose(sm);
return 1;
}
// ... Secret verwenden ...
// Sofort nach Verwendung aus dem Speicher löschen:
var n: int64 := StrLen(dbPassword as pchar);
var i: int64 := 0;
while (i < n) { poke8(dbPassword + i, 0); i := i + 1; }
free(dbPassword, n + 1);
SecretsClose(sm);
return 0;
}
Workflow 3: Nachrichten über SQS verarbeiten
import std.cloud.aws.core;
import std.cloud.sqs;
import std.alloc;
fn main(): int64 {
var creds: AWSCreds := AWSCredentialsDefault();
var sqs: SQSClient := SQSConnect(creds, "eu-central-1"c);
var queueUrl: pchar := "https://sqs.eu-central-1.amazonaws.com/123456789/meine-queue"c;
// Long Polling: bis zu 5 Nachrichten, 20 Sekunden warten
var xml: int64 := SQSReceiveMessages(sqs, queueUrl, 5, 20);
if (xml != 0) {
// Erste Nachricht parsen
var msg: SQSMessage := SQSParseFirstMessage(xml, StrLen(xml as pchar));
// Nachricht verarbeiten
Print("Body: "c); Print(msg.body as pchar); PrintLn(""c);
// Quittieren (sonst wird sie nach VisibilityTimeout erneut zugestellt)
SQSDeleteMessage(sqs, queueUrl, msg.receiptHandle as pchar);
SQSMessageFree(msg);
free(xml, StrLen(xml as pchar) + 1);
}
SQSClose(sqs);
return 0;
}
Workflow 4: Lambda-Funktion aufrufen
import std.cloud.aws.core;
import std.cloud.lambda;
import std.alloc;
fn main(): int64 {
var creds: AWSCreds := AWSCredentialsDefault();
var lc: LambdaClient := LambdaConnect(creds, "eu-central-1"c);
var payload: pchar := "{\"action\":\"process\",\"id\":42}"c;
var payloadLen: int64 := StrLen(payload);
// Synchroner Aufruf (RequestResponse) — gibt Response-Body zurück
var resp: int64 := LambdaInvoke(lc, "meine-funktion"c,
payload as int64, payloadLen);
if (resp != 0) {
Print("Response: "c); Print(resp as pchar); PrintLn(""c);
free(resp, StrLen(resp as pchar) + 1);
}
LambdaClose(lc);
return 0;
}
Workflow 5: DigitalOcean Droplet erstellen und warten
import std.cloud.do.credentials;
import std.cloud.do.droplets;
import std.alloc;
fn main(): int64 {
var creds: DOCredentials := DOCredentialsFromEnv();
// SSH-Key-ID muss vorher im DO-Account hinterlegt sein
var keyIds: array<int64> := [12345678];
var d: DODroplet := DropletCreateSimple(
creds,
"web-01"c, // Name
"fra1"c, // Region: Frankfurt
"s-2vcpu-4gb"c, // Größe
"ubuntu-22-04-x64"c, // Image-Slug
keyIds as int64,
1 // Anzahl
);
if (d.id == 0) {
PrintLn("Droplet-Erstellung fehlgeschlagen"c);
DOCredentialsFree(creds);
return 1;
}
// Polling bis Droplet "active" ist (blockiert bis zu ~60 s)
d = DropletWait(creds, d.id, "active"c);
var ip: int64 := DropletGetIP(creds, d.id);
if (ip != 0) {
Print("Droplet bereit unter: "c);
Print(ip as pchar);
PrintLn(""c);
free(ip, StrLen(ip as pchar) + 1);
}
DODropletFree(d);
DOCredentialsFree(creds);
return 0;
}
Workflow 6: Cloudflare DNS-Record setzen
import std.cloud.cf.credentials;
import std.cloud.cf.transport;
import std.cloud.cf.dns;
fn main(): int64 {
var creds: CFCredentials := CFCredentialsFromEnv();
var c: CFClient := CFClientNew(creds);
// Upsert: legt den Record an oder aktualisiert ihn falls vorhanden
var r: CFDNSRecord := DNSRecordUpsert(c,
"abc123def456"c, // Zone-ID (aus Cloudflare-Dashboard)
"A"c, // Typ
"api"c, // Name → api.meine-domain.de
"1.2.3.4"c, // Content
1, // TTL (1 = auto)
1 // proxied (1 = oranges Wolkensymbol)
);
CFDNSRecordFree(r);
CFClientFree(c);
CFCredentialsFree(creds);
return 0;
}
Workflow 7: Cloudflare Worker deployen
import std.cloud.cf.credentials;
import std.cloud.cf.transport;
import std.cloud.cf.workers;
import std.fs;
import std.alloc;
fn main(): int64 {
var creds: CFCredentials := CFCredentialsFromEnv();
var c: CFClient := CFClientNew(creds);
// Worker-Script aus Datei laden
var sz: int64 := FileSize("worker.js"c);
var script: int64 := alloc(sz + 1);
ReadFile("worker.js"c, script as pchar, sz);
poke8(script + sz, 0);
// Deployen
var ok: int64 := WorkerDeploy(c, creds.accountId as pchar,
"mein-worker"c, script, sz);
free(script, sz + 1);
if (ok == 1) {
PrintLn("Worker deployed"c);
}
// Route anlegen: meine-domain.de/api/* → Worker
var route: CFWorkerRoute := WorkerRouteCreate(c,
"abc123def456"c, // Zone-ID
"meine-domain.de/api/*"c,
"mein-worker"c
);
CFWorkerRouteFree(route);
CFClientFree(c);
CFCredentialsFree(creds);
return 0;
}
Workflow 8: R2-Objekt hochladen
import std.cloud.cf.credentials;
import std.cloud.cf.r2;
import std.fs;
import std.alloc;
fn main(): int64 {
var creds: CFCredentials := CFCredentialsFromEnv();
var r2: R2Conn := R2Connect(creds, creds.accountId as pchar);
// Datei hochladen
var sz: int64 := FileSize("/tmp/export.csv"c);
var data: int64 := alloc(sz);
ReadFile("/tmp/export.csv"c, data as pchar, sz);
R2Upload(r2, "mein-bucket"c, "exports/2026-06-12.csv"c, data, sz);
free(data, sz);
// Presigned URL für 1 Stunde
var url: int64 := R2PresignedURL(r2, "mein-bucket"c,
"exports/2026-06-12.csv"c, "GET"c, 3600);
if (url != 0) {
Print("Download: "c); Print(url as pchar); PrintLn(""c);
free(url, StrLen(url as pchar) + 1);
}
R2Disconnect(r2);
CFCredentialsFree(creds);
return 0;
}
Workflow 9: Cache nach Deployment leeren
import std.cloud.cf.credentials;
import std.cloud.cf.transport;
import std.cloud.cf.cache;
fn purgeAfterDeploy(zoneId: pchar): void {
var creds: CFCredentials := CFCredentialsFromEnv();
var c: CFClient := CFClientNew(creds);
// Gesamten Zone-Cache leeren
CachePurgeAll(c, zoneId);
CFClientFree(c);
CFCredentialsFree(creds);
}
Workflow 10: CloudWatch-Metrik schreiben
import std.cloud.aws.core;
import std.cloud.cloudwatch;
import std.alloc;
fn reportMetric(value: int64): void {
var creds: AWSCreds := AWSCredentialsDefault();
var cw: CWClient := CWConnect(creds, "eu-central-1"c);
// datum als JSON-String mit einem einzelnen Datenpunkt
var datum: pchar := "[{\"MetricName\":\"RequestCount\",\"Value\":1,\"Unit\":\"Count\"}]"c;
CWPutMetricData(cw, "MeineApp"c, datum as int64, 1);
CWClose(cw);
AWSCredentialsFree(creds);
}
Workflow 11: GCS-Datei hochladen und herunterladen
import std.cloud.gcp.credentials;
import std.cloud.gcp.storage;
import std.alloc;
fn main(): int64 {
var creds: GCPCredentials := GCPCredentialsDefault(
"https://www.googleapis.com/auth/devstorage.read_write"c);
var gcs: GCSConn := GCSConnect(addr creds, "mein-projekt"c);
// Datei hochladen
var data: pchar := "Reporting-Daten 2026"c;
GCSUpload(gcs, "mein-bucket"c, "reports/2026-06.txt"c,
data as int64, 20, "text/plain"c);
// Datei herunterladen — Body liegt im GCPResponse
var r: GCPResponse := GCSDownload(gcs, "mein-bucket"c, "reports/2026-06.txt"c);
if (r.statusCode == 200) {
Print(r.body as pchar); PrintLn(""c);
}
GCPResponseFree(r); // gibt r.body und r.contentType frei
GCSDisconnect(gcs);
GCPCredentialsFree(creds);
return 0;
}
GCP-spezifisch: Alle Lese-Funktionen geben GCPResponse zurück (nicht int64). Immer GCPResponseFree® statt free(r.body, …) verwenden — das gibt Body und Content-Type gemeinsam frei.
Workflow 12: GCP-Secret auslesen
import std.cloud.gcp.credentials;
import std.cloud.gcp.secrets;
import std.alloc;
fn main(): int64 {
var creds: GCPCredentials := GCPCredentialsDefault(
"https://www.googleapis.com/auth/cloud-platform"c);
var sc: SecretConn := SecretConnect(addr creds, "mein-projekt"c);
// Secret anlegen (base64url-kodiert gespeichert)
var payload: pchar := "geheimes-passwort-42"c;
SecretCreate(sc, "db-password"c, payload as int64, 20);
// Neueste Version auslesen — wird automatisch dekodiert
var val: int64 := SecretGet(sc, "db-password"c);
if (val != 0) {
// ... verwenden ...
// Sofort überschreiben und freigeben
var n: int64 := StrLen(val as pchar);
var i: int64 := 0;
while (i < n) { poke8(val + i, 0); i := i + 1; }
free(val, n + 1);
}
SecretDisconnect(sc);
GCPCredentialsFree(creds);
return 0;
}
Welchen AWS-Dienst wählen?
Speicher
| Anforderung | Dienst | Begründung |
|---|---|---|
| Dateien, Backups, statische Assets | std.cloud.s3 | Objekt-Speicher; unbegrenzte Kapazität; Presigned URLs |
| Strukturierte Daten mit schnellem Lookup | std.cloud.dynamodb | Schemalos; millisekunden-Latenz bei gezieltem Key-Zugriff |
| Relationale Daten | Managed DB (extern) | Kein RDS in std.cloud — eigene Instanz via EC2 + std.db |
| Temporäre Konfiguration / Feature Flags | std.cloud.secrets SSM | SSM Parameter Store für nicht-sensitive Konfiguration |
| Geheimnisse (Passwörter, API-Keys) | std.cloud.secrets Secrets Manager | Automatische Rotation, Audit-Log in CloudTrail |
Messaging & Events
| Anforderung | Dienst | Begründung |
|---|---|---|
| Aufgaben-Queue (Worker verarbeiten Jobs) | std.cloud.sqs | Pull-basiert; Retry via VisibilityTimeout; Dead-Letter-Queue |
| Benachrichtigungen an mehrere Empfänger | std.cloud.sns | Push-basiert; Fan-out an SQS, E-Mail, SMS, HTTPS gleichzeitig |
| Bestimmte Reihenfolge garantieren | std.cloud.sqs FIFO | FIFO-Queue mit MessageGroupId |
| E-Mail versenden | std.cloud.sns (PublishToPhone) | Nur SMS; für E-Mail: SNS + E-Mail-Subscription |
Typisches Muster: SNS → SQS → Lambda (Fan-out mit Entkopplung):
Publisher → SNS-Topic → SQS-Queue → Lambda-Funktion
→ SQS-Queue (2. Subscriber)
→ E-Mail-Subscription
Compute
| Anforderung | Dienst | Begründung |
|---|---|---|
| Kurzläufer (< 15 min), event-getrieben | std.cloud.lambda | Kein Server-Management; pay-per-invocation |
| Dauerhafter Server, volle Kontrolle | std.cloud.ec2 | Flexible Konfiguration; persistentes Dateisystem |
| Lambda aus SQS oder DynamoDB triggern | std.cloud.lambda + LambdaCreateEventSourceMapping | Automatisches Polling |
| Batch-Verarbeitung großer Datenmengen | EC2 Spot-Instanzen | Günstig; für kurze Burst-Workloads |
Monitoring
| Anforderung | Dienst | Begründung |
|---|---|---|
| Metriken aus dem Programm senden | std.cloud.cloudwatch CWPutMetricData | Standard-AWS-Monitoring |
| Alarm wenn Metrik Schwellwert überschreitet | std.cloud.cloudwatch CWPutMetricAlarm | Benachrichtigung via SNS |
| Strukturierte Logs schreiben | std.cloud.cloudwatch CWLogsClient | Zentrale Log-Aggregation; filterbar via Log Insights |
AWS vs. DigitalOcean
| Aufgabe | AWS | DigitalOcean |
|---|---|---|
| Datei-Speicher | std.cloud.s3 | std.cloud.do.spaces (S3-kompatibel) |
| VM starten | std.cloud.ec2 | std.cloud.do.droplets |
| Managed Datenbank | (EC2 + std.db) | std.cloud.do.databases (PostgreSQL/MySQL/Redis) |
| Kubernetes | (EC2 + extern) | std.cloud.do.kubernetes (DOKS) |
| Container Registry | (ECR, extern) | std.cloud.do.registry |
| Serverless | std.cloud.lambda | std.cloud.do.functions |
| App deployen (PaaS) | (Elastic Beanstalk, extern) | std.cloud.do.apps |
| DNS / Load Balancer | std.cloud.ec2 (Route53 via Query-API) | std.cloud.do.networking |
| Monitoring / Alerts | std.cloud.cloudwatch | std.cloud.do.monitoring |
| Secrets / Konfiguration | std.cloud.secrets | Umgebungsvariablen in App-Spec |
| Queue / Messaging | std.cloud.sqs / std.cloud.sns | (kein nativer Queue-Dienst — SQS oder externe Lösung) |
Wann AWS wählen: Compliance-Anforderungen (SOC 2, HIPAA, FedRAMP), globale Verfügbarkeit in > 30 Regionen, komplexe Event-Architektur (SNS/SQS/Lambda-Ketten), IAM-Feingranularität.
Wann DigitalOcean wählen: Einfacheres Preismodell, schnelles Setup ohne IAM-Konfiguration, Managed Databases und Kubernetes out-of-the-box, kleinere Teams ohne AWS-Kenntnisse.
Lokal testen mit LocalStack
AWS-Dienste können lokal mit LocalStack simuliert werden — ohne echten AWS-Account und ohne Kosten.
# LocalStack starten (Docker):
docker run --rm -p 4566:4566 localstack/localstack
import std.cloud.aws.core;
import std.cloud.s3;
fn main(): int64 {
// AWSServiceConfigLocalStack() setzt endpoint auf http://localhost:4566
var cfg: AWSServiceConfig := AWSServiceConfigLocalStack();
// Dummy-Credentials (LocalStack prüft sie nicht)
var creds: AWSCreds := AWSCredentialsStatic("test"c, "test"c);
// S3ConnectConfig statt S3Connect — nutzt cfg.endpoint
var s3: S3Client := S3ConnectConfig(creds, cfg);
S3CreateBucket(s3, "test-bucket"c);
S3PutObjectFile(s3, "test-bucket"c, "hello.txt"c, "/tmp/hello.txt"c, "text/plain"c);
var data: int64 := S3GetObject(s3, "test-bucket"c, "hello.txt"c);
if (data != 0) {
Print(data as pchar); PrintLn(""c);
free(data, StrLen(data as pchar) + 1);
}
S3Close(s3);
return 0;
}
LocalStack unterstützt S3, DynamoDB, SQS, SNS, Lambda, IAM, Secrets Manager und die meisten weiteren AWS-Dienste.
Sicherheitsregeln
1. Credentials nie im Code einbetten
// Falsch:
var creds: AWSCreds := AWSCredentialsStatic("AKIA..."c, "wJalr..."c);
// Richtig:
var creds: AWSCreds := AWSCredentialsDefault(); // Env → Datei
2. IAM Least Privilege — nur notwendige Rechte vergeben
Für eine Anwendung die nur S3 liest: nur s3:GetObject und s3:ListBucket erlauben — kein s3:DeleteObject, kein EC2-Zugriff. Über std.cloud.iam Rollen mit minimalen Policies anlegen.
3. Secrets über Secrets Manager, nicht über Umgebungsvariablen
Umgebungsvariablen sind im Prozess-Speicher sichtbar und landen in Logs. Secrets Manager hat Audit-Log, Rotation und Versionierung.
4. Temporäre Credentials bevorzugen (STS AssumeRole)
import std.cloud.iam;
var sts: STSClient := STSConnect(baseCreds);
var tempCreds: STSCredentials := STSAssumeRole(sts,
"arn:aws:iam::123456789:role/DeployRole"c,
"deploy-session"c);
// tempCreds.accessKey, .secretKey, .sessionToken
// Automatisch ablaufend nach max. 12 Stunden
5. Response-Puffer nach sensiblen Daten sofort überschreiben
Passwörter und Secrets nicht länger im Speicher halten als nötig:
var secret: int64 := SecretsGetString(sm, "prod/db/password"c);
// ... verwenden ...
var n: int64 := StrLen(secret as pchar);
var i: int64 := 0;
while (i < n) { poke8(secret + i, 0); i := i + 1; }
free(secret, n + 1);
6. S3-Buckets nicht öffentlich exponieren
Presigned URLs statt öffentlicher Bucket-Policy für zeitlich begrenzte Downloads:
// Statt: öffentlicher Bucket
// Besser: Presigned URL mit kurzer Laufzeit
var url: int64 := S3PresignURL(s3, "bucket"c, "datei.pdf"c, 900); // 15 Minuten
7. Retry-Logik für transiente Fehler
AWS-APIs können bei kurzer Überlastung HTTP 503 oder 429 zurückgeben. AWSSendWithRetry behandelt das automatisch:
// Direkt: AWSSendWithRetry(req, 3) — intern genutzt von allen High-Level-Funktionen
// Für eigene Low-Level-Requests: maxRetries als dritten Parameter nutzen
Entscheidungsguide
| Ich will … | Empfehlung |
|---|---|
| Datei speichern und abrufbar machen | std.cloud.s3 + S3PresignURL |
| Zeitlich begrenzten Download-Link | std.cloud.s3 → S3PresignURL(s3, bucket, key, 900) |
| Passwort / API-Key sicher speichern | std.cloud.secrets → SecretsGetString |
| Hintergrundaufgaben verteilen | std.cloud.sqs (Worker) |
| Push-Benachrichtigung an viele Systeme | std.cloud.sns |
| Code event-getrieben ausführen | std.cloud.lambda + LambdaInvoke |
| VM starten (AWS) | std.cloud.ec2 + EC2RunInstances / EC2DescribeInstanceById |
| VM starten (DigitalOcean) | std.cloud.do.droplets + DropletCreateSimple / DropletWait |
| Managed PostgreSQL / MySQL (DO) | std.cloud.do.databases + DatabaseCreate |
| Kubernetes-Cluster anlegen (DO) | std.cloud.do.kubernetes + K8sClusterCreate / K8sKubeconfig |
| DNS-Eintrag setzen (DO) | std.cloud.do.networking + DomainRecordCreate |
| Container-Image speichern (DO) | std.cloud.do.registry + RegistryCreate |
| Metriken überwachen (AWS) | std.cloud.cloudwatch + CWPutMetricData / CWPutMetricAlarm |
| Lokal testen ohne AWS-Account | AWSServiceConfigLocalStack() + LocalStack via Docker |
| Temporäre Credentials für Deployment | std.cloud.iam + STSAssumeRole |
| DNS-Record anlegen / aktualisieren (CF) | std.cloud.cf.dns + DNSRecordUpsert |
| Cloudflare Zone pausieren / reaktivieren | std.cloud.cf.zones + ZonePause / ZoneUnpause |
| Worker-Script deployen | std.cloud.cf.workers + WorkerDeploy |
| Worker-Route anlegen (URL-Muster → Worker) | std.cloud.cf.workers + WorkerRouteCreate |
| Worker-Secret (Env-Variable) setzen | std.cloud.cf.workers + WorkerSecretSet |
| KV-Wert lesen / schreiben (mit TTL) | std.cloud.cf.kv + KVGet / KVPutWithTTL |
| R2-Objekt hochladen / herunterladen | std.cloud.cf.r2 + R2Upload / R2Download |
| R2 Presigned URL erzeugen | std.cloud.cf.r2 + R2PresignedURL |
| D1-Datenbank abfragen | std.cloud.cf.d1 + D1Query |
| Cache nach Deployment leeren | std.cloud.cf.cache + CachePurgeAll |
| IP-Adresse sperren (WAF) | std.cloud.cf.waf + FirewallBlockIP |
| Rate-Limiting für Endpunkt | std.cloud.cf.waf + RateLimitCreate |
| Cloudflare Pages deployen | std.cloud.cf.pages + PagesDeployDir |
| Tunnel ohne offenen Port | std.cloud.cf.tunnel + TunnelCreate / TunnelToken |
| E-Mail-Weiterleitung an Worker | std.cloud.cf.email + EmailRuleCreateWorker |
| Zone-Analytics abfragen | std.cloud.cf.analytics + AnalyticsDashboard |
| Datei in Google Cloud Storage speichern | std.cloud.gcp.storage + GCSUpload |
| GCS-Datei herunterladen | std.cloud.gcp.storage + GCSDownload |
| GCP-Secret auslesen / anlegen | std.cloud.gcp.secrets + SecretGet / SecretCreate |
| Firestore-Dokument schreiben / lesen | std.cloud.gcp.firestore + FSCreate / FSGet |
| GCE-VM anlegen und warten | std.cloud.gcp.compute + GCEInstanceCreate + GCEOperationWait |
| Pub/Sub-Nachricht publishen | std.cloud.gcp.pubsub + PubSubPublish |
| Cloud Function aufrufen | std.cloud.gcp.functions + GCFInvoke |
| Log-Eintrag in Cloud Logging schreiben | std.cloud.gcp.logging + LogWrite |
| Custom Metric in Cloud Monitoring schreiben | std.cloud.gcp.logging + MonWriteMetric |
| GCP Credentials laden (Service Account / ADC) | std.cloud.gcp.credentials + GCPCredentialsDefault / GCPCredentialsFromFile |
Letzte Aktualisierung: 2026-06-13
