Spacelift
PrivacyT&Cs
  • 👋Hello, Spacelift!
  • 🚀Getting Started
  • 🌠Main concepts
    • Stack
      • Creating a stack
      • Stack settings
      • Organizing stacks
      • Stack locking
      • Drift detection
    • Configuration
      • Environment
      • Context
      • Runtime configuration
        • YAML reference
    • Run
      • Task
      • Proposed run (preview)
      • Tracked run (deployment)
      • Module test case
      • User-Provided Metadata
      • Run Promotion
      • Pull Request Comments
    • Policy
      • Login policy
      • Access policy
      • Approval policy
      • Initialization policy
      • Plan policy
      • Push policy
      • Task policy
      • Trigger policy
    • Resources
    • Worker pools
    • VCS Agent Pools
  • 🛰️Platforms
    • Terraform
      • Module registry
      • External modules
      • Provider
      • State management
      • Terragrunt
      • Version management
      • Handling .tfvars
      • CLI Configuration
      • Cost Estimation
      • Resource Sanitization
      • Storing Complex Variables
      • Debugging Guide
    • Pulumi
      • Getting started
        • C#
        • Go
        • JavaScript
        • Python
      • State management
      • Version management
    • CloudFormation
      • Getting Started
      • Reference
      • Integrating with SAM
      • Integrating with the serverless framework
    • Kubernetes
      • Getting Started
      • Authenticating
      • Custom Resources
      • Helm
      • Kustomize
  • ⚙️Integrations
    • Audit trail
    • Cloud Integrations
      • Amazon Web Services (AWS)
      • Microsoft Azure
      • Google Cloud Platform (GCP)
    • Source Control
      • GitHub
      • GitLab
      • Azure DevOps
      • Bitbucket Cloud
      • Bitbucket Datacenter/Server
    • Docker
    • GraphQL API
    • Single sign-on
      • GitLab OIDC Setup Guide
      • Okta OIDC Setup Guide
      • OneLogin OIDC Setup Guide
      • Azure AD OIDC Setup Guide
      • AWS IAM Identity SAML 2.0 Setup Guide
    • Slack
    • Webhooks
  • 📖Product
    • Privacy
    • Security
    • Support
      • Statement of Support
    • Disaster Continuity
    • Billing
      • Stripe
      • AWS Marketplace
    • Terms and conditions
    • Refund Policy
  • Cookie Policy
Powered by GitBook
On this page
  • Taking it for a spin
  • How it works
  • Using inside Spacelift
  • Using outside of Spacelift
  • Proposed workflow
  • Boundaries of programmatic management

Was this helpful?

  1. Platforms
  2. Terraform

Provider

PreviousExternal modulesNextState management

Last updated 4 years ago

Was this helpful?

What would you say if you could manage Spacelift resources - that is , , , and - using Spacelift? We hate ClickOps as much as anyone, so we designed everything from the ground up to be easily managed using a Terraform provider. We hope that advanced users will define most of their resources programmatically.

Taking it for a spin

Our Terraform provider is open source and its always contains the latest available documentation. It's also distributed as part of our and available through our . The purpose of this article isn't as much to document the provider itself but to show how it can be used to incorporate Spacelift resources into your infra-as-code.

So, without further ado, let's define a stack:

stack.tf
resource "spacelift_stack" "managed-stack" {
  name = "Stack managed by Spacelift"

  # Source code.
  repository = "testing-spacelift"
  branch     = "master"
}

That's awesome. But can we put Terraform to good use and integrate it with resources from a completely different provider? Sure we can, and we have a good excuse, too. Stacks accessibility can be managed , so why don't we define some?

stack-and-teams.tf
resource "github_team" "stack-readers" {
  name = "managed-stack-readers"
}

resource "github_team" "stack-writers" {
  name = "managed-stack-writers"
}

resource "spacelift_stack" "managed-stack" {
  name = "Stack managed by Spacelift"

  # Source code.
  repository = "testing-spacelift"
  branch     = "master"

  # Access.
  readers_team = github_team.stack_readers.slug
  writers_team = github_team.stack_writers.slug
}
stack-teams-and-iam.tf
resource "github_team" "stack-readers" {
  name = "managed-stack-readers"
}

resource "github_team" "stack-writers" {
  name = "managed-stack-writers"
}

resource "spacelift_stack" "managed-stack" {
  name = "Stack managed by Spacelift"

  # Source code.
  repository = "testing-spacelift"
  branch     = "master"

  # Access.
  readers_team = github_team.stack_readers.slug
  writers_team = github_team.stack_writers.slug
}

# IAM role.
resource "aws_iam_role" "managed-stack" {
  name = "spacelift-managed-stack"

  assume_role_policy = jsonencode({
    Version   = "2012-10-17"
    Statement = [
      jsondecode(
        spacelift_stack.managed-stack.aws_assume_role_policy_statement
      )
    ]
  })
}

# Attaching a nice, powerful policy to it.
resource "aws_iam_role_policy_attachment" "managed-stack" {
  role       = aws_iam_role.managed-stack.name
  policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}

# Telling Spacelift stack to assume it.
resource "spacelift_stack_aws_role" "managed-stack" {
  stack_id = spacelift_stack.managed-stack.id
  role_arn = aws_iam_role.managed-stack.arn
}

How it works

provider "spacelift" {}

terraform {
  required_providers {
    spacelift = {
      source = "spacelift-io/spacelift"
    }
  }
}

Using inside Spacelift

Using outside of Spacelift

In order to set up the provider to use an API key, you will need the key ID, secret, and the API key endpoint:

variable "spacelift_key_id" {}
variable "spacelift_key_secret" {}

provider "spacelift" {
  api_key_endpoint = "https://your-account.app.spacelift.io"
  api_key_id       = var.spacelift_key_id
  api_key_secret   = var.spacelift_key_secret
}

These values can also be passed using environment variables, though this will only work to set up the provider for a single Spacelift account:

  • SPACELIFT_API_KEY_ENDPOINT for api_key_endpoint;

  • SPACELIFT_API_KEY_ID for api_key_id;

  • SPACELIFT_API_KEY_SECRET for api_key_secret;

variable "spacelift_first_key_id" {}
variable "spacelift_first_key_secret" {}

variable "spacelift_second_key_id" {}
variable "spacelift_second_key_secret" {}

provider "spacelift" {
  alias = "first"

  api_key_endpoint = "https://first.app.spacelift.io"
  api_key_id       = var.spacelift_first_key_id
  api_key_secret   = var.spacelift_first_key_secret
}

provider "spacelift" {
  alias = "second"

  api_key_endpoint = "https://second.app.spacelift.io"
  api_key_id       = var.spacelift_second_key_id
  api_key_secret   = var.spacelift_second_key_secret
}

If you're running from inside Spacelift, you can still use the default, zero-setup provider for the current account with providers for accounts set up through API keys:

variable "spacelift_that_key_id" {}
variable "spacelift_that_key_secret" {}

provider "spacelift" {
  alias = "this"
}

provider "spacelift" {
  alias = "that"

  api_key_endpoint = "https://that.app.spacelift.io"
  api_key_id       = var.spacelift_that_key_id
  api_key_secret   = var.spacelift_that_key_secret
}

Proposed workflow

We suggest to first manually create a single administrative stack, and then use it to programmatically define other stacks as necessary. If you're using an integration like AWS, you should probably give the role associated with this stack full IAM access too, allowing it to create separate roles and policies for individual stacks.

Programmatically generated stacks and contexts can still be manually augmented, for example by setting extra elements of the environment. Thanks to the magic of Terraform, these will simply be invisible to (and thus not disturbed by) your resource definitions.

Boundaries of programmatic management

In general, we believe that things like runs or tasks do not fit the (relatively static) Terraform resource lifecycle model and that hiding those parts of the API from Terraform helps us ensure the integrity of potentially sensitive data - just see the example above.

Now that we programmatically combine Spacelift and GitHub resources, let's add AWS to the mix and give our new stack a dedicated :

OK, so who wants to go back to clicking on things in the web GUI? Because you will likely need to do some clicking, too, .

Depending on whether you're using Terraform 0.12.x or higher, the Spacelift provider is distributed slightly differently. For 0.12.x users, the provider is distributed as a binary available in the in the same folder we put the Terraform binary. If you're using Terraform 0.13 and above, you can benefit from pulling our provider directly from our own provider registry. In order to do that, just point Terraform to the right location:

Within Spacelift, the provider is configured by an environment variable SPACELIFT_API_TOKEN injected into each run and task belonging to marked as . This value is a bearer token that contains all the details necessary for the provider to work, including the full address of the to talk to. It's technically valid for 3 hours but only when the responsible for generating it is in , or (for ) state and throughout that time it provides full administrative access to Spacelift entities within the same Spacelift account.

If you want to run the Spacelift provider outside of Spacelift, or you need to manage resources across multiple Spacelift accounts from the same Terraform project, the preferred method is to generate and use dedicated . Note that unless you're just accessing whitelisted data resources, the Terraform use case will normally require marking the API key as administrative.

If you want to talk to multiple Spacelift accounts, you just need to set up like this:

If you want to share data between stacks, please consider programmatically creating and attaching .

Spacelift administrative tokens are not like user tokens. Specifically, they allow access to a much smaller subset of the . They allow managing the lifecycles of , , , and , but they won't allow you to create or even access , or , or their associated logs.

Administrative tokens have no superpowers either. They can't read write-only configuration elements any more than you can as a user. Unlike human users with user tokens, administrative tokens won't allow you to run env in a and read back the logs.

🛰️
stacks
contexts
integrations
configuration
README
Docker runner image
own provider registry
by GitHub teams
IAM role
at least with your first stack
runner Docker image
stacks
administrative
API endpoint
run
Planning
Applying
Performing
tasks
that can be managed by Terraform
API keys
provider aliases
contexts
API
stacks
contexts
integrations
configuration
Terraform state
runs
tasks
task