Wrapping Cloud and Infrastructure CLIs
Cloud and infrastructure CLIs already implement complex remote APIs and state models. Bash adds value when it verifies targeting, standardizes preflight and output, and sequences well-defined operations without hiding provider semantics.
Learning objectives
By the end of this lesson
- Make account/project/region/workspace targeting explicit.
- Validate dependencies and supported versions.
- Use structured output and safe credential providers.
- Separate preview/plan from mutation.
- Keep wrappers thin and provider-aware.
1. Cloud CLIs are API clients with local defaults
AWS, Azure, Google Cloud, Terraform, Pulumi, and vendor-specific CLIs often read profiles, regions, projects, subscriptions, credentials, output formats, and environment variables. Scripts should make critical targeting parameters explicit rather than inheriting a developer's workstation defaults.
flowchart TD B["Bash wrapper"] --> C["cloud / infra CLI"] C --> A["remote API / state backend"] A --> R["structured response"] R --> V["validate + act"]
2. Check the exact executable and version contract
require_command() {
command -v "$1" >/dev/null 2>&1 || {
printf 'required command missing: %s\n' "$1" >&2
return 69
}
}
require_command terraform || exit $?
terraform version
If your wrapper depends on specific flags or output shapes, define and validate a supported version range instead of assuming every installed version behaves identically.
3. Make account, project, subscription, region, and workspace explicit
printf 'account=%s region=%s environment=%s\n' \
"$account" "$region" "$environment" >&2
[[ $environment != prod || $ALLOW_PROD == true ]] || {
printf 'production access not authorized\n' >&2
exit 65
}
The most dangerous automation bug is often not a bad command but a correct command against the wrong account, subscription, project, region, or workspace.
4. Request machine-readable output
# Example pattern:
cloud_cli resource list --output json |
jq -r '.items[] | [.name, .id] | @tsv'
Avoid parsing tables meant for humans. Most mature cloud CLIs offer JSON or other structured output.
5. Prefer CLI-native query filters when they are stable
Many cloud CLIs support built-in query languages. These can reduce transfer size and parsing complexity, but scripts should still validate the returned shape and avoid depending on undocumented human formatting.
6. Let supported credential providers handle secrets
Use workload identity, instance roles, service principals, managed identities, federated credentials, credential helpers, or CI secret integration according to the platform. Avoid placing long-lived credentials directly into shell source or command arguments.
Disable or carefully scope set -x around
authentication commands and secret-bearing environment variables.
7. Infrastructure plan and apply should be separate phases
terraform init -input=false
terraform plan \
-input=false \
-out=tfplan
terraform apply \
-input=false \
tfplan
Saving and applying the reviewed plan narrows the gap between what was evaluated and what is executed.
8. Disable prompts in automation
terraform plan -input=false
# Generic cloud CLI pattern:
cloud_cli operation \
--no-interactive \
--output json
Exact flags differ by tool, but the principle is universal: unattended automation must fail rather than wait for human input.
9. Do not add blind retries around infrastructure mutation
Cloud APIs often have eventual consistency and transient errors, but mutations can also have ambiguous outcomes. Prefer the CLI/provider's built-in retry semantics or reconcile remote state before repeating a side-effecting operation.
10. Use plan, what-if, preview, or dry-run capabilities
Preview is especially valuable for deletion, replacement, IAM, networking, and production changes.
11. Keep wrappers thin
main() {
preflight || return $?
verify_target || return $?
plan_change || return $?
apply_change || return $?
verify_result || return $?
}
The wrapper should coordinate stable CLI operations, not reimplement the provider's entire state model, dependency graph, or authentication system.
12. Hands-on lab: generic infrastructure wrapper skeleton
mkdir -p "$HOME/devops-academy/bash/chapter15/lesson05"
cd "$HOME/devops-academy/bash/chapter15/lesson05"
cat > infra-wrapper.sh <<'EOF'
#!/usr/bin/env bash
set -u
set -o pipefail
tool=${1:-}
target=${2:-}
[[ -n $tool && -n $target ]] || {
printf 'usage: %s TOOL TARGET\n' "$0" >&2
exit 64
}
command -v "$tool" >/dev/null 2>&1 || {
printf 'missing tool: %s\n' "$tool" >&2
exit 69
}
printf 'tool=%s target=%s phase=preflight\n' \
"$tool" "$target" >&2
if [[ $target == prod && ${ALLOW_PROD:-false} != true ]]; then
printf 'production target requires ALLOW_PROD=true\n' >&2
exit 65
fi
printf 'preflight=ok\n'
printf 'Next step: call a tool-specific read-only or plan command here.\n'
EOF
chmod u+x infra-wrapper.sh
./infra-wrapper.sh git staging
Verification checklist
13. Knowledge check
Question 1. What defaults should cloud automation avoid inheriting invisibly?
Question 2. Why prefer structured CLI output?
Question 3. Why separate infrastructure plan from apply?
Question 4. Why should wrappers stay thin?
14. Summary
Cloud and infrastructure CLI wrappers should make target identity explicit, validate versions and dependencies, use supported credential providers, request structured output, disable prompts, preview changes, and keep Bash focused on orchestration rather than reimplementing provider logic.
15. Further reading
- Terraform CLI documentation — init, plan, apply, non-interactive workflows.
- AWS CLI, Azure CLI, and Google Cloud CLI documentation for structured output and authentication.
- Cloud provider workload-identity documentation.
- Infrastructure-as-code guidance on plans, previews, and production safeguards.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.