The awsappstream provider allows Terraform to manage AWS AppStream resources.
Authentication and region configuration follow the standard AWS SDK behavior, with optional customization of retry behavior.
Support for AWS AppStream in the official
hashicorp/terraform-provider-aws provider is currently
incomplete and, in some cases, does not reflect the latest AWS AppStream features or expected resource behavior.
This provider was created to offer more complete and reliable AppStream support. For context, see the open AppStream-related issues in the AWS provider.
| Name | Resource | Data Source |
|---|---|---|
| awsappstream_stack | ✅ | ✅ |
| awsappstream_stack_theme | ✅ | ✅ |
| awsappstream_fleet | ✅ | ✅ |
| awsappstream_associate_fleet_stack | ✅ | ❌ |
| awsappstream_user | ✅ | ✅ |
| awsappstream_associate_user_stack | ✅ | ❌ |
| awsappstream_sessions | ❌ | ✅ |
| awsappstream_application | ✅ | ✅ |
| awsappstream_associate_application_fleet | ✅ | ❌ |
| awsappstream_entitlement | ✅ | ✅ |
| awsappstream_associate_application_entitlement | ✅ | ❌ |
| awsappstream_app_block | ✅ | ✅ |
| awsappstream_app_block_builder | ✅ | ✅ |
| awsappstream_associate_app_block_builder_app_block | ✅ | ❌ |
| awsappstream_directory_config | ✅ | ❌ |
| awsappstream_image | ❌ | ✅ |
| awsappstream_copied_image | ✅ | ❌ |
| awsappstream_imported_image | ✅ | ❌ |
| awsappstream_updated_image | ✅ | ❌ |
| awsappstream_image_permission | ✅ | ❌ |
| awsappstream_image_permissions | ❌ | ✅ |
| awsappstream_image_builder | ✅ | ✅ |
| awsappstream_associate_image_builder_software | ✅ | ❌ |
| awsappstream_software_associations | ❌ | ✅ |
| awsappstream_usage_report_subscription | ✅ | ✅ |
| awsappstream_export_image_task | ❌ | ✅ |
| awsappstream_export_image_tasks | ❌ | ✅ |
This provider follows a read-after-write model to ensure Terraform state accurately reflects the authoritative state in AWS.
In practice, this means:
-
Create and Update operations are always followed by a Read
- After a successful
CreateorUpdate, the provider performs a fresh read from AWS and uses that response as the source of truth for state. - This avoids relying on partial or inconsistent API responses.
- After a successful
-
Read is authoritative
- If a resource cannot be found during
Read, it is removed from state. - This applies to external deletions and drift detection.
- If a resource cannot be found during
-
Idempotent behavior
- Create operations tolerate existing resources where possible and converge state instead of failing when safe to do so.
- Association-style resources model relationships only and verify existence rather than storing mutable state.
-
Tag management is declarative
- Tags are reconciled using a diff-based approach.
- Default tags and resource-level tags are merged and applied consistently during Create and Update.
- Changes to default tags are automatically propagated on the next apply.
-
Context-aware cancellation
- All operations respect context cancellation and deadlines to avoid corrupting state during interrupted applies.
Overall, the provider prioritizes correctness, consistency, and drift resilience over minimizing API calls.
This provider intentionally follows an attribute ownership model that differs from the official Terraform AWS provider.
Only attributes that are explicitly set by the user in Terraform configuration are considered managed by Terraform. Attributes that are not configured by the user are treated as AWS-managed defaults and are not enforced or reconciled by Terraform.
In practical terms:
- If an attribute is not set in the Terraform configuration, the provider:
- Does not attempt to normalize it
- Does not enforce AWS default values
- Does not generate diffs when AWS populates or changes default values
- If an attribute is set by the user, Terraform fully owns it:
- The value is sent to AWS
- The value is read back from AWS
- Drift is detected and corrected if the value changes
This behavior avoids perpetual diffs caused by AWS-side defaults, implicit behavior, or service-specific normalization.
Fleet resources:
- If
image_nameis set andimage_arnis not, onlyimage_nameis tracked. - If
image_arnis set, onlyimage_arnis tracked. - If AWS returns both values, the provider preserves ownership of only the attribute configured by the user.
Stack resources:
- Optional nested blocks (for example, user settings, application settings, streaming experience settings) are only tracked if explicitly defined.
- AWS-generated defaults or inferred values are ignored unless the user opts in by defining them.
AWS AppStream frequently:
- Applies implicit defaults
- Normalizes values
- Returns additional fields that were never explicitly configured
Tracking all returned fields would lead to:
- Constant, non-actionable diffs
- Forced configuration of values users did not intend to manage
- Reduced clarity around which settings Terraform truly controls
By limiting state ownership to user-defined attributes, this provider:
- Produces stable plans
- Avoids perpetual drift
- Makes ownership boundaries explicit and predictable
- You are not required to configure every available attribute.
- AWS defaults are respected unless you choose to override them.
- If you want Terraform to manage a value, you must explicitly define it.
- Importing existing resources will populate only user-managed attributes.
This behavior is intentional and applies consistently across resources such as fleets and stacks, and may be extended to additional resources in the future.
This provider intentionally does not implement action-style Terraform resources for imperative operations such as:
- Starting or stopping fleets
- Starting or stopping image builders
- Starting or stopping app block builders
- Triggering one-shot operational actions
AWS AppStream APIs exhibit eventual consistency and transient errors, especially when creating or associating dependent resources (for example, fleets, stacks, and entitlements).
This provider uses a layered retry approach:
-
AWS SDK retries
- Configurable via provider settings (
retry_mode,retry_max_attempts,retry_max_backoff) - Handles throttling, networking issues, and standard AWS retryable errors
- Configurable via provider settings (
-
Provider-level retries
- Applied selectively to operations known to fail temporarily due to
AppStream lifecycle constraints (for example
OperationNotPermittedExceptionorResourceNotFoundExceptionduring creation or association) - Uses bounded exponential backoff and respects Terraform cancellation
- Applied selectively to operations known to fail temporarily due to
AppStream lifecycle constraints (for example
This ensures Terraform operations converge reliably without requiring manual sleeps or explicit dependencies in configuration.
Some acceptance tests for this provider require manual AWS AppStream prerequisites and are not run automatically.
Before running the acceptance tests, you must set up the required AWS resources.
This repository includes a helper script that prepares all necessary prerequisites:
./setup-acceptance-tests.shThis repository uses Conventional Commits for commit messages.
Examples:
feat: add retry for invalid role errorsfix: handle write-only password on updatechore: pin workflow action shas
For local validation, this repository includes a dedicated commitlint CLI tool:
- Install:
make install-tool-commitlint - Run (default PR-style range):
commitlint - Full usage and output formats:
tools/commitlint/README.md
Before running local development targets, ensure these tools are available:
- Go (version from
go.mod) golangci-lint- Terraform CLI (used by
make generateforterraform fmt)
Some targets execute go run ... tools and may download modules on first run
(for example govulncheck, tfplugindocs, and copywrite).
| Target | Description | Requires |
|---|---|---|
make fmt |
Format Go code (provider + tools) with configured formatters | Go, golangci-lint |
make lint |
Run linters (provider + tools) | Go, golangci-lint |
make commitlint |
Validate commit messages with local commitlint tool | Go, git repository with commit history |
make test |
Run unit tests (provider + tools); supports TESTFLAGS |
Go |
make govulncheck |
Run vulnerability checks (provider + tools) | Go, network access on first run |
make generate |
Generate provider artifacts/docs and format examples | Go, Terraform CLI, network access on first run |
make build |
Build provider binary into ./bin |
Go |
make build-debug |
Build non-optimized debug binary | Go |
make install |
Install provider binary with go install |
Go |
make install-tool-commitlint |
Install commitlint CLI tool with go install |
Go |
make testacc |
Run acceptance tests; supports TESTFLAGS |
Go, Terraform CLI, AWS credentials + test prerequisites |
Module-specific targets are also available for fmt, lint, test, and
govulncheck:
*-provider*-tool-provider-codegen*-tool-commitlint
Examples:
make test TESTFLAGS='-p=8 -parallel=8'make testacc TESTFLAGS='-p=4 -parallel=4'make commitlint COMMITLINTFLAGS='--format json --fail-level none'
To test a local provider binary with Terraform:
- Build the provider binary:
make build-debug- Create or update
~/.terraformrc(or useTF_CLI_CONFIG_FILE) with a development override. The source address must match your Terraformrequired_providersentry.
provider_installation {
dev_overrides {
"st3ffn/aws-appstream" = "<PATH_TO_REPOSITORY>/terraform-provider-aws-appstream/bin"
}
direct {}
}- In the Terraform project that uses the provider, run:
terraform init -upgrade
terraform plan- Adjust the local path to your checkout location.
- Keep
direct {}so non-overridden providers still resolve normally. - For debugger setup and attaching Terraform to a local provider process, see: https://developer.hashicorp.com/terraform/plugin/debugging