Skip to content

Full Feature Parity in STACKIT Terraform Provider (Eliminate AWS and Hashicorp Vault Provider Dependency for Resource Configuration) #1098

Open

Description

@kdambiec

Problem description

I'm frustrated that the stackit Terraform provider does not cover the full lifecycle of resources on STACKIT Cloud. In practice, this leads to situations where we have to mix providers—primarily the stackit provider to create resources and then the aws/hashicorp vault provider to configure essential features that should be first-class on STACKIT. Also for creating and managing secrets we then have to use the Hashicorp Vault provider and can not do this using the stackit terraform provider.

Concrete example:
We can create an Object Storage bucket with the stackit provider, but to enable bucket versioning we must switch to the aws Terraform provider. This is an architectural anti-pattern for several reasons:

Provider split-brain & drift risk: Managing the same resource across two providers introduces state drift risk (e.g., one provider’s schema or lifecycle ignores changes made by the other). It becomes harder to reason about desired vs. actual state, especially during plan/apply and import/export operations.

Undocumented coupling: The dependency and mapping between stackit resources and AWS APIs is implicit and fragile. Changes on either side (API behavior, auth, endpoints, regional mappings) can break deployments without clear contracts in the stackit provider.

Security & compliance concerns: Credentials, endpoints, and policy models differ. Using AWS provider to control a STACKIT resource complicates IAM boundaries, audit trails, and compliance posture (e.g., who granted what, via which control plane).

Operational complexity: Module composition, provider configuration, and lifecycle hooks get more complex (e.g., depends_on across providers). Rollbacks, imports, and refactors are significantly harder.

User experience & portability: Terraform users expect a single provider to encapsulate the cloud’s capabilities. Requiring another provider erodes trust, increases onboarding friction, and blocks clean, portable modules targeting STACKIT.

Proposed solution

Expand the stackit Terraform provider to fully support core operations and configurations for STACKIT Cloud services—specifically, Object Storage bucket versioning (enable/disable, MFA delete where applicable, status queries), lifecycle rules, server-side encryption, access control methods, and relevant metadata/features, without requiring the AWS provider or Hashicorp Vault provider.

This implies:

  1. Add a versioning block (and related attributes) to the stackit_object_storage_bucket resource (or introduce a dedicated stackit_object_storage_bucket_versioning resource if modeling separation is preferred).
  2. Ensure read-modify consistency: terraform plan should detect and reconcile versioning state; importing existing buckets should bring their versioning state under stackit control.
  3. Provide parity with commonly expected Object Storage features (lifecycle, SSE/KMS, public access blocks, policies) within the stackit provider, or document exact coverage and roadmap.
  4. Align error handling and diagnostics with Terraform UX (clear diffs, actionable messages).
terraform {
  required_version = ">= 1.6.0"
  required_providers {
    stackit = {
      source  = "stackitcloud/stackit"
      version = ">= 0.XX.0"
    }
    # NOTE: No aws provider required in the proposed solution.
  }
}

provider "stackit" {
  # Authentication via STACKIT mechanisms (token/credentials)
  # Example:
  # token = var.stackit_token
  # endpoint = var.stackit_api_endpoint
}

# Proposed: versioning supported directly in bucket resource
resource "stackit_object_storage_bucket" "logs" {
  name     = "my-logs-bucket"
  project  = var.project_id
  region   = var.region

  versioning {
    enabled     = true
    # If applicable in STACKIT’s model:
    # mfa_delete  = false
  }

  # Optional future-parity blocks:
  # encryption { kms_key_id = var.kms_key_id }
  # lifecycle_rule {
  #   id      = "expire-old-versions"
  #   status  = "Enabled"
  #   noncurrent_version_expiration {
  #     days = 90
  #   }
  # }
  # public_access_block {
  #   block_public_acls       = true
  #   block_public_policy     = true
  #   ignore_public_acls      = true
  #   restrict_public_buckets = true
  # }
}

output "bucket_name" {
  value = stackit_object_storage_bucket.logs.name
}

Activity

  1. changed the title [-]Full Feature Parity in STACKIT Terraform Provider (Eliminate AWS Provider Dependency for Resource Configuration)[/-] [+]Full Feature Parity in STACKIT Terraform Provider (Eliminate AWS and Hashicorp Vault Provider Dependency for Resource Configuration)[/+] on Dec 17, 2025
  2. Fyusel commented on Jan 8, 2026

    @Fyusel
    Contributor

    Hi @kdambiec,
    thank you for reporting this issue and providing such detailed information.

    We are limited to the API of the service teams therefore we cannot change this at the moment.
    However, we will keep this on our radar should the situation change.

  3. albgus commented on Jan 23, 2026

    @albgus

    I would like to reference some additional context from the Terraform documentation, that further highlights practical problems with this approach caused by the need to configure additional providers: https://developer.hashicorp.com/terraform/language/modules/develop/providers#legacy-shared-modules-with-provider-configurations . I feel like this better highlights the actual problems than the AI,..

    Basically as soon as you dynamically configure a provider, you're going to end up having a bunch of caveats with Terraform execution due having a provider being dependent on a dynamic resource. We are very specifically seeing issues trying to use modules and suddenly having to take extra steps to remove a model from the state.

    I realize that you cannot change the upstream services, but I would hope that you are able to raise this feedback internally? Or perhaps this needs to be raised through a feature request support ticket as well?

  4. kdambiec commented on Jan 23, 2026

    @kdambiec
    Author

    Additionally, a number of basic, required features, most notably VM backup configuration, are currently only available in beta in the STACKIT Terraform provider, making it difficult to rely on it for production environments.

  5. HartmannVolker commented on Feb 19, 2026

    @HartmannVolker

    Hey I know this is a limitation by the STACKIT by the STACKIT API, but I would still like to highlight that this is quite annoying for more advanced setups.
    As an example: This nicely written guideline on how to use the AWS provider with a stackit object storage bucket only works if each step is applied individually.
    If you want to run everything with a single terraform apply you get the following error from the aws provider:

    │ Error: No valid credential sources found
    │ 
    │   with provider["registry.terraform.io/hashicorp/aws"],
    │   on main.tf line 24, in provider "aws":
    │   24: provider "aws" {
    │ 
    │ Please see https://registry.terraform.io/providers/hashicorp/aws
    │ for more information about providing credentials.
    │ 
    │ Error: failed to refresh cached credentials, no EC2 IMDS role found,
    │ operation error ec2imds: GetMetadata, request canceled, context deadline
    │ exceeded
    │ 
    

    As far as I understand, this is because the provider is evaluated during planning, which happens before any resources are created. Therefore, it cannot access the not-yet-existing credentials and fails because it is missing credentials for authentication.

    In our case, we provide Terraform modules for our teams to abstract some of the complexity away. Unfortunately, this makes it impossible to create a module that sets up a bucket with credentials and a default bucket policy. The only solution could be to create the credentials in that module first with a -target apply and then apply the rest of the module. Which results in a very cumbersome developer experience.

  6. mardonner commented on Jun 2, 2026

    @mardonner

    Hi @HartmannVolker,
    I had a similar issue with s3 in #922
    The workaround for me was to create a dummy credential file for the aws provider. See my comment here

    Can't tell if this will also work for you though.

  7. albgus commented on Jun 10, 2026

    @albgus

    I just want to add that this limitation has been a pain point at several points when developing Terraform code for StackIT.

    I created an internal module for S3 buckets from StackIT, that does several operations such as enabling versioning and making sure theres a policy to remove old versions by default, and also setting up Bucket policies so that we have unique credential groups per Bucket.

    However, as soon as this module is referenced we start having problems with the legacy provider setup. Namely that a bunch of features become unavailable, such as count/for_each loops, and lifecycle { enabled = var... }.

    Would a workaround in the terraform provider be to create a short lived credential to directly interface with the S3 API?

    Perhaps something like this pseudo-code-ish

    resource "stackit_objectstorage_bucket" "example" {
      project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      name       = "example"
    }
    
    resource "stackit_objectstorage_credentials_group" "example" {
      project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      name       = "example-credentials-group"
    }
    
    # Nice to have: Create credentials without storing in the state.
    ephemeral "stackit_objectstorage_credential" "example" {
      credentials_group_id = stackit_objectstorage_credentials_group.example.credentials_group_id
      ttl = 300
    }
    
    resource "stackit_objectstorage_bucket_config" "example" {
      bucket = stackit_objectstorage_bucket.example.name
    
      access_key        = ephemeral.stackit_objectstorage_credential.example.access_key
      secret_access_key = ephemeral.stackit_objectstorage_credential.example.secret_access_key
      
      versioning {
        enabled = true
      }
    
      lifecycle_rule {
        id      = "expire-old-versions"
        status  = "Enabled"
        noncurrent_version_expiration {
          days = 90
        }
      }
    
      # Optional future-parity blocks:
      # encryption { kms_key_id = var.kms_key_id }
    }
    
    resource "stackit_objectstorage_bucket_policy" "allow_public_read_access" {
      bucket = stackit_objectstorage_bucket.example.name
    
      access_key        = ephemeral.stackit_objectstorage_credential.example.access_key
      secret_access_key = ephemeral.stackit_objectstorage_credential.example.secret_access_key
    
      policy = <<EOF
       {
         "Statement": [
           {
             "Sid": "Public GET",
             "Effect": "Allow",
             "Principal": "*",
             "Action": "s3:GetObject",
             "Resource": "urn:sgws:s3:::example/*"
           }
         ]
       }
      EOF
    }
    
    

    I realize passing credentials like this is likely an anti pattern, but perhaps not less of an anti-pattern than dynamically configuring a provider with credentials created during the run..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions