AWS- und gcloud-CLI-Skriptmuster für Bash
AI generated
$_
#!/
Bash · AWS CLI · gcloud CLI · Multi-Cloud
AWS- und gcloud-CLI-Skriptmuster für Bash
Multi-Cloud-Automatisierung ohne doppelten Code

Wer sowohl AWS als auch Google Cloud betreibt, schreibt schnell zwei parallele Skript-Welten mit unterschiedlicher Paginierung, Fehlerbehandlung und Ausgabeformaten. Bash-Muster für die aws- und gcloud-CLI vereinheitlichen Authentifizierung, Retry-Logik und JSON-Verarbeitung hinter einer gemeinsamen Schnittstelle, statt jede Cloud einzeln neu zu erfinden.

17 Min. Lesezeit aws sts · gcloud auth · jq · Retry-Logik AWS CLI v2 · gcloud SDK · Bash 5.x

1. Warum Multi-Cloud-Skripte eigene Muster brauchen

AWS CLI und gcloud CLI lösen ähnliche Aufgaben, unterscheiden sich aber in Authentifizierung, Ausgabeformaten und Paginierung so deutlich, dass naive Skripte für beide Clouds schnell zu doppeltem, schwer wartbarem Code führen. Ein Team, das sowohl S3 als auch Cloud Storage verwaltet, tippt für dieselbe logische Aufgabe zwei völlig unterschiedliche Befehlssequenzen, wenn es keine gemeinsamen AWS- und gcloud-CLI-Muster etabliert.

Der Wert konsistenter AWS- und gcloud-CLI-Skriptmuster zeigt sich vor allem in gemischten Infrastrukturen, in denen ein Deployment-Skript beide Clouds ansprechen muss, etwa weil Disaster-Recovery-Kopien in einer zweiten Cloud liegen oder weil unterschiedliche Teams unterschiedliche Provider gewählt haben. Ein Bash-Skript, das eine einheitliche Funktion wie cloud_list_buckets anbietet und intern zwischen aws s3api list-buckets und gcloud storage buckets list umschaltet, reduziert die kognitive Last für alle, die das Skript später warten.

Die folgenden Abschnitte bauen praxisnahe AWS- und gcloud-CLI-Muster auf: von einheitlicher Authentifizierung über konsistente Paginierung bis zu Retry-Logik, die mit den unterschiedlichen Rate-Limit-Verhalten beider Clouds umgeht.

2. Authentifizierung fuer AWS und gcloud sauber abstrahieren

AWS nutzt Profile und temporäre Zugangsdaten über aws sts assume-role, gcloud arbeitet mit Service-Account-Schlüsseln und gcloud auth activate-service-account oder Workload Identity Federation. Ein Skript, das beide Clouds ansprechen soll, braucht eine Abstraktion, die je nach Zielumgebung die passende Authentifizierungsmethode wählt, ohne dass der aufrufende Code diese Details kennen muss.

Wichtig bei AWS- und gcloud-CLI-Authentifizierung ist, dass temporäre Zugangsdaten explizit ein Verfallsdatum haben und ein Skript, das lange läuft, die Anmeldedaten rechtzeitig erneuern muss, bevor ein API-Aufruf mit einem Authentifizierungsfehler abbricht.


#!/usr/bin/env bash
# cloud-auth.sh — unified authentication for AWS and gcloud
set -euo pipefail

readonly PROVIDER="${1:?Usage: cloud-auth.sh <aws|gcp> <role-or-account>}"
readonly TARGET="${2:?Missing role ARN or service account}"

cloud_authenticate() {
  case "$PROVIDER" in
    aws)
      echo "[INFO] Assuming AWS role: ${TARGET}"
      local creds
      creds="$(aws sts assume-role --role-arn "$TARGET" \
        --role-session-name "bash-automation-$(date +%s)" \
        --duration-seconds 3600 --output json)"
      export AWS_ACCESS_KEY_ID
      export AWS_SECRET_ACCESS_KEY
      export AWS_SESSION_TOKEN
      AWS_ACCESS_KEY_ID="$(jq -r '.Credentials.AccessKeyId' <<< "$creds")"
      AWS_SECRET_ACCESS_KEY="$(jq -r '.Credentials.SecretAccessKey' <<< "$creds")"
      AWS_SESSION_TOKEN="$(jq -r '.Credentials.SessionToken' <<< "$creds")"
      ;;
    gcp)
      echo "[INFO] Activating GCP service account: ${TARGET}"
      gcloud auth activate-service-account --key-file="$TARGET"
      ;;
    *)
      echo "[ERROR] Unknown provider: ${PROVIDER} (expected aws or gcp)" >&2
      exit 1
      ;;
  esac
  echo "[OK] Authenticated against ${PROVIDER}"
}

cloud_authenticate

3. Einheitliche Wrapper-Funktionen fuer beide CLIs

Der zentrale Baustein von AWS- und gcloud-CLI-Skriptmustern ist eine dünne Abstraktionsschicht, die logisch gleiche Operationen unter einem gemeinsamen Funktionsnamen anbietet. Ein Skript ruft cloud_list_storage_buckets auf, die Funktion entscheidet intern anhand einer Umgebungsvariable oder eines Parameters, ob aws s3api list-buckets oder gcloud storage buckets list tatsächlich ausgeführt wird, und normalisiert die Ausgabe beider CLIs auf ein gemeinsames JSON-Format.

Diese Normalisierung ist der eigentliche Mehrwert: AWS liefert Bucket-Namen unter .Buckets[].Name, gcloud unter einem anderen JSON-Pfad. Ein AWS- und gcloud-CLI-Wrapper übersetzt beide Strukturen in ein einheitliches Schema, sodass der restliche Code der Anwendung nicht wissen muss, welche Cloud gerade angesprochen wird.


#!/usr/bin/env bash
# cloud-wrapper.sh — unified interface over aws and gcloud CLI
set -euo pipefail

# cloud_list_storage_buckets <aws|gcp> — normalized bucket listing
cloud_list_storage_buckets() {
  local provider="${1:?Usage: cloud_list_storage_buckets <aws|gcp>}"
  case "$provider" in
    aws)
      aws s3api list-buckets --output json \
        | jq '[.Buckets[] | {name: .Name, created: .CreationDate, provider: "aws"}]'
      ;;
    gcp)
      gcloud storage buckets list --format=json \
        | jq '[.[] | {name: .name, created: .timeCreated, provider: "gcp"}]'
      ;;
    *)
      echo "[ERROR] Unknown provider: ${provider}" >&2
      return 1
      ;;
  esac
}

# cloud_create_instance <aws|gcp> <name> <size> — normalized instance creation
cloud_create_instance() {
  local provider="$1" name="$2" size="$3"
  case "$provider" in
    aws)
      aws ec2 run-instances --image-id ami-0abcdef1234567890 \
        --instance-type "$size" --tag-specifications \
        "ResourceType=instance,Tags=[{Key=Name,Value=${name}}]" \
        --output json | jq '.Instances[0] | {id: .InstanceId, provider: "aws"}'
      ;;
    gcp)
      gcloud compute instances create "$name" --machine-type="$size" \
        --format=json | jq '.[0] | {id: .id, provider: "gcp"}'
      ;;
  esac
}

4. Paginierung und JSON-Verarbeitung konsistent mit jq

AWS-APIs liefern bei großen Ergebnismengen einen NextToken, gcloud nutzt stattdessen --page-token und liefert das nächste Token in einem eigenen Feld. Wer AWS- und gcloud-CLI-Skripte schreibt, ohne Paginierung zu berücksichtigen, verliert bei größeren Konten stillschweigend Daten, weil beide CLIs standardmäßig nur eine begrenzte Seitengröße zurückgeben.

Eine robuste Paginierungsfunktion sammelt alle Seiten in einer Schleife, bis kein weiteres Token mehr zurückkommt, und gibt am Ende ein vollständiges JSON-Array zurück, unabhängig davon, wie viele API-Aufrufe intern nötig waren.


#!/usr/bin/env bash
# cloud-paginate.sh — consistent pagination handling for both CLIs
set -euo pipefail

# aws_paginate_all <command...> — follow NextToken until exhausted
aws_paginate_all() {
  local next_token="" results="[]"
  while true; do
    local page
    if [[ -n "$next_token" ]]; then
      page="$("$@" --starting-token "$next_token" --output json)"
    else
      page="$("$@" --output json)"
    fi
    results="$(jq -s '.[0] + .[1]' <(echo "$results") <(jq '.Reservations // .Buckets // []' <<< "$page"))"
    next_token="$(jq -r '.NextToken // empty' <<< "$page")"
    [[ -z "$next_token" ]] && break
  done
  echo "$results"
}

# gcp_paginate_all <command...> — follow --page-token until exhausted
gcp_paginate_all() {
  local page_token="" results="[]"
  while true; do
    local page
    if [[ -n "$page_token" ]]; then
      page="$("$@" --page-token="$page_token" --format=json)"
    else
      page="$("$@" --format=json)"
    fi
    results="$(jq -s '.[0] + .[1]' <(echo "$results") <(echo "$page"))"
    page_token="$(jq -r '.nextPageToken // empty' <<< "$page" 2>/dev/null || echo "")"
    [[ -z "$page_token" ]] && break
  done
  echo "$results"
}

5. Ressourcen-Tagging und Multi-Cloud-Inventar

Ein häufiger Anwendungsfall für AWS- und gcloud-CLI-Skriptmuster ist ein Inventar-Report über alle laufenden Ressourcen beider Clouds, etwa für Kostenkontrolle oder Security-Audits. AWS nutzt Tags im Format Key-Value-Paare, gcloud nutzt Labels mit ähnlicher, aber nicht identischer Syntax und striktereren Zeichenbeschränkungen, etwa nur Kleinbuchstaben und Bindestriche.

Ein Inventar-Skript, das beide Clouds abfragt, sollte Tags und Labels in ein gemeinsames Format normalisieren und fehlende oder inkonsistente Tags als eigene Kategorie im Report ausweisen, damit Teams gezielt nachbessern können, statt Tag-Lücken erst bei der nächsten Rechnung zu bemerken.


#!/usr/bin/env bash
# multi-cloud-inventory.sh — combined resource inventory with tag/label check
set -euo pipefail

readonly REQUIRED_TAGS=("owner" "environment" "cost-center")

check_aws_tags() {
  aws resourcegroupstaggingapi get-resources --output json \
    | jq --argjson required "$(printf '%s\n' "${REQUIRED_TAGS[@]}" | jq -R . | jq -s .)" '
      .ResourceTagMappingList[] | {
        arn: .ResourceARN,
        tags: (.Tags | map(.Key) ),
        missing: ($required - (.Tags | map(.Key | ascii_downcase)))
      } | select(.missing | length > 0)
    '
}

check_gcp_labels() {
  gcloud asset search-all-resources --format=json \
    | jq --argjson required "$(printf '%s\n' "${REQUIRED_TAGS[@]}" | jq -R . | jq -s .)" '
      .[] | {
        name: .name,
        labels: (.labels // {} | keys),
        missing: ($required - (.labels // {} | keys))
      } | select(.missing | length > 0)
    '
}

echo "--- AWS resources missing required tags ---"
check_aws_tags
echo "--- GCP resources missing required labels ---"
check_gcp_labels

6. Rate Limits, Retries und Backoff bei Cloud-APIs

Beide Cloud-APIs drosseln bei zu vielen Anfragen, aber mit unterschiedlichen Fehlercodes und Wartezeiten. AWS antwortet meist mit Throttling oder RequestLimitExceeded, gcloud mit HTTP-429-Antworten und einem RESOURCE_EXHAUSTED-Status. Ein universeller Retry-Wrapper für AWS- und gcloud-CLI-Aufrufe erkennt beide Muster und wartet mit exponentiellem Backoff, statt beim ersten Rate-Limit-Fehler sofort abzubrechen.

Ohne diese Retry-Logik brechen Massenoperationen, etwa das Taggen hunderter Ressourcen in einer Schleife, regelmäßig mitten im Lauf ab, sobald die API-Drosselung einsetzt, was zu inkonsistenten Zwischenzuständen führt.


#!/usr/bin/env bash
# cloud-retry.sh — exponential backoff for AWS and gcloud rate limits
set -uo pipefail

cloud_retry() {
  local max_attempts=5 attempt=1 delay=2
  local output exit_code

  while (( attempt <= max_attempts )); do
    output="$("$@" 2>&1)"
    exit_code=$?

    if [[ $exit_code -eq 0 ]]; then
      echo "$output"
      return 0
    fi

    if grep -qiE "Throttling|RequestLimitExceeded|RESOURCE_EXHAUSTED|429" <<< "$output"; then
      echo "[WARN] Rate limited (attempt ${attempt}/${max_attempts}), waiting ${delay}s" >&2
      sleep "$delay"
      delay=$(( delay * 2 ))
      ((attempt++))
      continue
    fi

    echo "$output" >&2
    return "$exit_code"
  done

  echo "[ERROR] Command still rate-limited after ${max_attempts} attempts" >&2
  return 1
}

# Usage: cloud_retry aws s3api list-buckets
# Usage: cloud_retry gcloud storage buckets list

7. Kosten- und Ressourcen-Reports automatisieren

AWS Cost Explorer und die GCP Billing API liefern beide programmatischen Zugriff auf Kostendaten, aber mit unterschiedlichen Gruppierungsoptionen und Zeiträumen. Ein AWS- und gcloud-CLI-Skript für regelmäßige Kosten-Reports fragt beide APIs mit vergleichbaren Parametern ab, etwa Kosten der letzten 30 Tage gruppiert nach Service, und kombiniert die Ergebnisse in einem gemeinsamen Report.

Diese Reports laufen typischerweise als geplanter Job, der die kombinierten Zahlen an Slack oder in eine interne Dashboard-Anwendung schickt. Der Wert liegt darin, Kostenentwicklung über beide Clouds hinweg auf einen Blick zu sehen, statt zwei getrennte Konsolen manuell zu prüfen.


#!/usr/bin/env bash
# cost-report.sh — combined 30-day cost summary across AWS and GCP
set -euo pipefail

readonly START=$(date -u -d '30 days ago' +%Y-%m-%d)
readonly END=$(date -u +%Y-%m-%d)

aws_cost=$(aws ce get-cost-and-usage \
  --time-period "Start=${START},End=${END}" \
  --granularity MONTHLY --metrics "UnblendedCost" \
  --output json | jq -r '.ResultsByTime[0].Total.UnblendedCost.Amount')

gcp_cost=$(gcloud billing accounts list --format="value(name)" | head -1 | \
  xargs -I{} gcloud alpha billing accounts get-spend-summary {} \
  --format="value(cost)" 2>/dev/null || echo "n/a")

echo "=== Cost Report: ${START} to ${END} ==="
printf "AWS:  \$%s\n" "$aws_cost"
printf "GCP:  %s\n" "$gcp_cost"

8. Sicherheits-Fallstricke: Profile, Projekte und Cross-Account-Risiken

Der größte Sicherheitsfallstrick bei AWS- und gcloud-CLI-Skripten ist das versehentliche Ausführen eines Befehls im falschen Konto oder Projekt. AWS-Profile werden über --profile oder die Umgebungsvariable AWS_PROFILE ausgewählt, gcloud über gcloud config set project oder --project. Wird eine dieser Einstellungen vergessen oder von einer vorherigen Shell-Sitzung übernommen, landet ein destruktiver Befehl im falschen Kontext.

Ein defensives Skript prüft vor kritischen Operationen explizit, welches Konto oder Projekt aktuell aktiv ist, etwa mit aws sts get-caller-identity oder gcloud config get-value project, und vergleicht das Ergebnis mit dem erwarteten Wert, bevor die eigentliche Operation ausgeführt wird. Dieses Muster ist analog zu den Produktions-Guards, die auch bei kubectl-Wrappern sinnvoll sind, nur eben auf Cloud-Konto-Ebene statt auf Kubernetes-Namespace-Ebene.

9. aws CLI und gcloud CLI im direkten Vergleich

Die folgende Tabelle zeigt die wichtigsten Unterschiede, die AWS- und gcloud-CLI-Skriptmuster berücksichtigen müssen.

Aspekt AWS CLI gcloud CLI Bash-Anpassung
Authentifizierung Profile, sts assume-role Service-Account-Key, Workload Identity gemeinsame cloud_authenticate-Funktion
Paginierung NextToken --page-token / nextPageToken separate Paginierungsfunktion pro CLI
Rate-Limit-Fehler Throttling, RequestLimitExceeded HTTP 429, RESOURCE_EXHAUSTED gemeinsamer Retry-Wrapper mit Pattern-Matching
Metadaten Tags (Key/Value, case-sensitive) Labels (nur Kleinbuchstaben, Bindestrich) normalisierte Prüfung auf fehlende Pflichtfelder
Ausgabeformat --output json --format=json jq-Filter zur Vereinheitlichung des Schemas

Der Vergleich zeigt: Beide CLIs sind für sich genommen gut dokumentiert und funktional, aber erst durchdachte AWS- und gcloud-CLI-Skriptmuster machen ein Multi-Cloud-Setup wartbar, statt zwei parallele Codebasen ohne gemeinsame Struktur zu pflegen.

Mironsoft

Multi-Cloud-Automatisierung, DevOps-Tooling und Bash-Skripte

AWS und Google Cloud sollen sich nicht wie zwei Baustellen anfuehlen?

Wir bauen einheitliche Bash-Wrapper fuer eure AWS- und gcloud-CLI-Workflows, mit konsistenter Authentifizierung, Paginierung und Retry-Logik.

Wrapper-Bibliothek

Einheitliche Funktionen fuer AWS und gcloud mit normalisierter JSON-Ausgabe

Inventar & Kosten

Multi-Cloud-Reports fuer Tagging-Luecken und Kostenentwicklung

Sicherheits-Guards

Konto- und Projekt-Pruefung vor kritischen Cloud-Operationen

10. Zusammenfassung

Konsistente AWS- und gcloud-CLI-Skriptmuster verhindern, dass ein Multi-Cloud-Setup zu zwei parallelen, unverbundenen Codebasen wird. Eine einheitliche Authentifizierungsfunktion abstrahiert die unterschiedlichen Anmeldemechanismen, gemeinsame Wrapper-Funktionen normalisieren Ausgabeformate auf ein Schema, separate Paginierungslogik pro CLI sammelt vollständige Ergebnismengen, und ein universeller Retry-Wrapper erkennt Rate-Limit-Fehler beider Clouds anhand ihrer jeweiligen Fehlermuster.

Inventar- und Kosten-Reports profitieren besonders von dieser Vereinheitlichung, weil sie beide Clouds in einem einzigen Report zusammenführen, statt zwei getrennte Dashboards manuell zu vergleichen. Wer diese AWS- und gcloud-CLI-Muster einmal sauber implementiert, kann neue Cloud-Operationen deutlich schneller hinzufügen, weil die Grundstruktur für Authentifizierung, Fehlerbehandlung und Paginierung bereits steht.

AWS- und gcloud-CLI-Skriptmuster für Bash — Das Wichtigste auf einen Blick

Einheitliche Authentifizierung

Eine Funktion abstrahiert aws sts assume-role und gcloud auth activate-service-account.

Normalisierte Ausgaben

jq-Filter übersetzen beide JSON-Strukturen auf ein gemeinsames Schema für den restlichen Code.

Rate-Limit-Erkennung

Ein Retry-Wrapper erkennt Throttling und HTTP 429 gleichermaßen und wartet mit Backoff.

Konto-Guards

get-caller-identity und config get-value project vor kritischen Operationen prüfen.

11. FAQ: AWS- und gcloud-CLI-Skriptmuster für Bash

1Warum eigene Muster fuer beide CLIs?
Unterschiede in Auth, Paginierung und Fehlercodes fuehren sonst zu doppeltem Code.
2Authentifizierung gegen beide Clouds?
Wrapper-Funktion waehlt aws sts assume-role oder gcloud auth activate-service-account.
3JSON-Ausgaben normalisieren?
jq-Filter uebersetzen beide Strukturen in ein gemeinsames Schema.
4Paginierung behandeln?
Schleife pro CLI sammelt Seiten via NextToken beziehungsweise page-token.
5Rate-Limits erkennen?
Retry-Wrapper prueft auf Throttling und HTTP 429, wartet mit exponentiellem Backoff.
6Fehlende Tags pruefen?
Resource Groups Tagging API und Cloud Asset Inventory gegen Pflichtliste abgleichen.
7Kostenreports automatisieren?
get-cost-and-usage und Billing API kombiniert in einem Report.
8Falsches Konto vermeiden?
get-caller-identity beziehungsweise config get-value project vor kritischen Befehlen prüfen.
9Tags vs Labels?
AWS case-sensitive Key-Value, GCP nur Kleinbuchstaben und Bindestriche.
10Testen ohne echte Ressourcen?
--dry-run bei AWS und gemockte CLI-Binaries in BATS-Tests verwenden.