Image of Georg Kalus
Georg Kalus
/

How to use the STACKIT Secrets Manager with Terraform

Vault

This guide describes how to work with the STACKIT Secrets Manager in Terraform. We are going to look at

  1. how to provision a STACKIT Secrets Manager,
  2. how to create user credentials to access secrets in the Secrets Manager and
  3. how to put a secret into it.

Introduction

The STACKIT Secrets Manager is a managed HashiCorp Vault, compatible with the HashiCorp Vault KV2 API.

Here is a list of the most important resources for working with the STACKIT Secrets Manager (and HashiCorp Vault for that matter):

How to provision a STACKIT Secrets Manager?

Provisioning a Secrets Manager instance is done with the stackit_secretsmanager_instance resource. In In a real-world case, the ACL should not be set to 0.0.0.0/0 but limited to the IP range of the CI runners, for example.

Multiple Secret Manager instances can be created inside a project.

secretsmanager_instance.tf
terraform {
  required_providers {
    stackit = {
      source = "stackitcloud/stackit"
      version = "0.68.0"
    }
  }
  backend "s3" {
    bucket = "terraform-state"
    key    = "the/key"
    endpoints = {
      s3 = "https://object.storage.eu01.onstackit.cloud"
    }
    region                      = "eu01"
    skip_credentials_validation = true
    skip_region_validation      = true
    skip_s3_checksum            = true
    skip_requesting_account_id  = true
  }
}

provider "stackit" {
  default_region      = "eu01"
  service_account_key_path = var.service_account_key
}

resource "stackit_secretsmanager_instance" "example" {
  project_id = var.project_id
  name       = "example-secrets"
  acls       = ["0.0.0.0/0"]
}

If it worked, we can see our shiny Secrets Manager instance in the STACKIT Console.

How to create user credentials?

Creating credentials for the STACKIT Secrets Manager is straightforward. As the user name and password properties are generated automatically, the only two properties we can set are a credential description and a flag whether the credentials can be used for writing secrets or only for reading.

In the example below we are creating two users: one for adding the secrets to the Secrets Manager and another one with read only permissions to be used by the application for accessing the secrets.

secretsmanager_user.tf
resource "stackit_secretsmanager_user" "example_secrets_writer" {
  project_id    = var.project_id
  instance_id   = stackit_secretsmanager_instance.example.instance_id
  description   = "Terraform User"
  write_enabled = true
}

resource "stackit_secretsmanager_user" "example_secrets_reader" {
  project_id    = var.project_id
  instance_id   = stackit_secretsmanager_instance.example.instance_id
  description   = "Application User"
  write_enabled = false
}

How to put a secret into the STACKIT Secrets Manager?

Putting a secret in the STACKIT Secrets Manager requires the HashiCorp Vault Terraform provider. After it is added to the list of required providers, we must initialize the provider with the Vault base address and authentication credentials. This is where the previously created example_secrets_writer user comes into play.

The Vault base address for the STACKIT Secrets Manager is https://prod.sm.eu01.stackit.cloud.

By default, the HashiCorp Vault Terraform provider tries to create a temporary token for making API calls against the Vault. This does not work with the STACKIT Secrets Manager, as our user does not have the permission to create tokens. Creation of Vault resources would always fail with 404 or similar errors, like this:

...
vault_kv_secret_v2.example: Refreshing state... [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/data/example-credentials]
Planning failed. Terraform encountered an error while generating this plan.

 Error: failed to create limited child token: Error making API request.
 
 URL: POST https://prod.sm.eu01.stackit.cloud/v1/auth/token/create
 Code: 404. Errors:
 
 
 
   with vault_kv_secret_v2.example,
   on main.tf line 84, in resource "vault_kv_secret_v2" "example":
   84: resource "vault_kv_secret_v2" "example" {
 

The solution to the limited child token error is to configure the Vault provider to not use a temporary child token by setting the flag skip_child_token = true.

A second non-obvious point when working with the Vault Terraform provider for the STACKIT Secrets Manager is the value of the Vault mount path: the mount path must be set to the instance ID of the Secrets Manager instance.

vault_secret.tf
terraform {
  required_providers {
    stackit = {
      source = "stackitcloud/stackit"
      version = "0.68.0"
    }
    vault = {
      source = "hashicorp/vault"
      version = "5.3.0"
    }
  }
}

provider "vault" {
  address = "https://prod.sm.eu01.stackit.cloud"
  skip_child_token = true
  auth_login_userpass {
    username = stackit_secretsmanager_user.example_secrets_writer.username
    password = stackit_secretsmanager_user.example_secrets_writer.password
  }
}

resource "vault_kv_secret_v2" "example" {
  mount        = stackit_secretsmanager_instance.example.instance_id
  name         = "example-credentials"
  data_json = jsonencode({
    name       = stackit_mariadb_credential.example_database_credential.name,
    host       = stackit_mariadb_credential.example_database_credential.host,
    port       = stackit_mariadb_credential.example_database_credential.port,
    username   = stackit_mariadb_credential.example_database_credential.username,
    password   = stackit_mariadb_credential.example_database_credential.password
  })
}

If it worked, the secret should appear in the portal, like so

We can also check the secret payload in the Secret data section:

Conclusion

Working with the STACKIT Secrets Manager in Terraform is relatively straightforward after two non-obvious hurdles are taken:

  1. for authentication with the Vault, the skip_child_token flag must be set to true when initializing the Vault Terraform provider.
  2. the Vault mount path in secret resources must be set to the ID of the Secrets Manager instance.
To top