conveyor_service_account_token (Resource)
A credential token for a service account. This resource tracks only non-secret metadata: use the conveyor_service_account_token ephemeral resource to read the token's secret, which is never persisted to state.
Example Usage
# Example: fully automatic token rotation, writing the current token secret into an AWS SSM
# parameter without the secret ever touching Terraform state.
#
# Steady state has exactly one live token. A new one is minted every `rotation_days`; the previous
# one is retired `grace_period_days` after its own mint, giving consumers time to pick up the new
# value before the old one is revoked. Keep grace_period_days < rotation_days so a mint tick and a
# retire tick never land in the same apply under normal cadence. Apply at least once per grace window,
# or a sparse apply can land both in the same run (resulting in a brief, single-apply-duration gap).
terraform {
required_providers {
time = {
source = "hashicorp/time"
}
aws = {
source = "hashicorp/aws"
}
}
}
variable "rotation_days" {
default = 30
}
variable "grace_period_days" {
default = 3
}
resource "conveyor_service_account" "my_service_account" {
name = "my_service_account"
type = "scoped"
project_ids = [conveyor_project.my_project.id]
environment_ids = [conveyor_environment.my_environment.id]
}
resource "time_rotating" "mint" {
rotation_days = var.rotation_days
}
locals {
current_generation = time_rotating.mint.unix
# This reconstructs the previous generation from the current mint time, which assumes you apply
# at least once per rotation period. If you might skip an apply across an entire rotation
# boundary, persist mint history explicitly instead (for example with a `terraform_data`
# resource) rather than recomputing it here.
previous_mint_time = timeadd(time_rotating.mint.rfc3339, "-${var.rotation_days * 24}h")
previous_deadline = timeadd(local.previous_mint_time, "${var.grace_period_days * 24}h")
previous_generation = timecmp(timestamp(), local.previous_deadline) < 0 ? tostring(local.previous_mint_time) : null
generations = compact([tostring(local.current_generation), local.previous_generation])
}
resource "conveyor_service_account_token" "rotating" {
for_each = toset(local.generations)
service_account_id = conveyor_service_account.my_service_account.id
}
# Always sourced from the most-recently-minted, not-yet-retired generation.
ephemeral "conveyor_service_account_token" "current" {
service_account_id = conveyor_service_account.my_service_account.id
client_id = conveyor_service_account_token.rotating[tostring(local.current_generation)].client_id
}
resource "aws_ssm_parameter" "service_account_token" {
name = "/my-app/service-account-token"
type = "SecureString"
value_wo = ephemeral.conveyor_service_account_token.current.secret
value_wo_version = local.current_generation
}
Schema
Required
service_account_id(String) The id of the service account this token belongs to.
Read-Only
client_id(String) The client id of the token, generated on creation.created_at(String) The RFC3339 timestamp at which the token was created.id(String) The id of this resource, in the formservice_account_id/client_id.
Import
Import is supported using the following syntax:
export SERVICE_ACCOUNT_ID=$(conveyor service-account get --name my_service_account -ojson | jq -r ".id")
export CLIENT_ID=$(conveyor service-account token list --service-account-id "$SERVICE_ACCOUNT_ID" -ojson | jq -r ".[0].client_id")
terraform import 'conveyor_service_account_token.rotating["<generation-key>"]' "$SERVICE_ACCOUNT_ID/$CLIENT_ID"