Skip to main content

Stacks

Stacks is an Infrastructure as Code (IaC) system that enables declarative deployment of complete application stacks including infrastructure resources, secrets, bootstrap jobs, and services.

Overview

Stacks provides four major capabilities:

  1. Secrets Management - Generate, store, and inject secrets via HashiCorp Vault
  2. Bootstrap Jobs - Run initialization tasks like database migrations
  3. Service Deployments - Deploy Helm charts or raw Kubernetes manifests
  4. Multi-Tenant Isolation - Vault policies scoped per tenant

Execution Phases

Stack deployment follows a strict four-phase execution model:

PhaseDescriptionComponents
1. InfrastructureProvision resourcesDatabases, Namespaces, Storage
2. SecretsGenerate and store secretsVault KV, Dynamic credentials
3. BootstrapRun initialization jobsMigrations, Seeds, Init scripts
4. ServicesDeploy applicationsHelm Charts, K8s Manifests

Template Structure

Complete Template Example

version: "1"
name: my-application
tenant: acme-corp

# Phase 1: Infrastructure Resources
resources:
database:
type: database
properties:
engine: postgres
version: "15"
storage_size: 10Gi

cache:
type: valkey
properties:
memory: 256Mi

# Phase 2: Secrets
secrets:
db_password:
type: generated
generator_type: password
length: 32
charset: alphanumeric_special

api_key:
type: generated
generator_type: token
length: 64

external_api_token:
type: static
vault_path: "external/stripe/api-key"

# Phase 3: Bootstrap Jobs
bootstrap:
migrate:
image: "myapp/migrations:v1.2.0"
command: ["./migrate", "up"]
secrets:
DATABASE_URL: "${resources.database.connection_string}"
DB_PASSWORD: "${secrets.db_password.vault_path}"
timeout: "10m"
backoff_limit: 3

seed:
image: "myapp/seeds:v1.2.0"
command: ["./seed", "--env", "production"]
depends_on:
- migrate
secrets:
DATABASE_URL: "${resources.database.connection_string}"

# Phase 4: Services
services:
backend:
type: helm
depends_on:
- migrate
properties:
chart: "oci://registry.sparbz.cloud/charts/backend"
version: "1.2.0"
values:
replicas: 3
image:
tag: "v1.2.0"
database:
host: "${resources.database.host}"
port: "${resources.database.port}"
name: "${resources.database.name}"
secrets:
inject_method: external_secrets
mappings:
- secret: db_password
inject_as: env
env_prefix: DB
- secret: api_key
inject_as: env

# Stack Outputs
outputs:
api_endpoint:
value: "${services.backend.endpoint}"
database_host:
value: "${resources.database.host}"
sensitive: false

Reference Resolution

Stacks supports cross-phase references using the ${namespace.name.attribute} syntax:

Supported Namespaces

NamespaceDescriptionAvailable After
resourcesInfrastructure resource outputsPhase 1
secretsSecret vault paths and metadataPhase 2
bootstrapJob execution outputsPhase 3
servicesService deployment outputsPhase 4

Reference Examples

# Reference a resource output
database_url: "${resources.database.connection_string}"

# Reference a secret's vault path
secret_path: "${secrets.db_password.vault_path}"

# Reference a bootstrap job output
migration_version: "${bootstrap.migrate.outputs.version}"

# Reference a service endpoint
api_url: "${services.backend.endpoint}"

Secrets Management

Secret Types

Generated Secrets

Automatically generate secure values:

secrets:
# Password with special characters
db_password:
type: generated
generator_type: password
length: 32
charset: alphanumeric_special # or: alphanumeric, hex

# UUID
instance_id:
type: generated
generator_type: uuid

# URL-safe token
api_token:
type: generated
generator_type: token
length: 64

# RSA key pair
signing_key:
type: generated
generator_type: rsa
generator_config:
key_size: 4096

Static Secrets

Reference existing secrets in Vault:

secrets:
stripe_key:
type: static
vault_path: "external/stripe/secret-key"

Dynamic Secrets

Use Vault's database secrets engine for rotating credentials:

secrets:
db_creds:
type: dynamic
engine: database
role: "myapp-readonly"
ttl: "1h"

Secret Injection

Secrets can be injected into services using two methods:

services:
backend:
type: helm
secrets:
inject_method: external_secrets
mappings:
- secret: db_password
inject_as: env
env_prefix: DATABASE
- secret: api_key
inject_as: env

Vault Agent

services:
backend:
type: helm
secrets:
inject_method: vault_agent
mappings:
- secret: db_password
inject_as: file
mount_path: /secrets

Bootstrap Jobs

Bootstrap jobs run Kubernetes Jobs for initialization tasks:

bootstrap:
migrate:
image: "myapp/migrations:latest"
command: ["./migrate"]
args: ["up", "--env", "production"]
secrets:
DATABASE_URL: "${resources.database.connection_string}"
timeout: "15m"
backoff_limit: 3
namespace: "myapp" # optional, defaults to stack namespace

seed:
image: "myapp/seeds:latest"
depends_on:
- migrate # Waits for migrate to complete

Service Deployments

Helm Charts

services:
backend:
type: helm
properties:
chart: "oci://registry.sparbz.cloud/charts/backend"
version: "1.2.0"
release_name: "myapp-backend"
values:
replicas: 3
resources:
requests:
memory: "256Mi"
cpu: "250m"

Raw Manifests

services:
custom_resource:
type: manifest
properties:
manifest: |
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: "${resources.database.host}"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: custom-app
spec:
replicas: 1
# ... deployment spec

API Endpoints

MethodEndpointDescription
POST/v1/stacksCreate a new stack
GET/v1/stacksList all stacks
GET/v1/stacks/{id}Get stack details
PUT/v1/stacks/{id}Update stack template
DELETE/v1/stacks/{id}Delete stack
POST/v1/stacks/{id}/applyApply stack changes
POST/v1/stacks/{id}/destroyDestroy stack resources
GET/v1/stacks/{id}/planPreview changes
GET/v1/stacks/{id}/outputsGet stack outputs

CLI Commands

# Create a new stack
szc stack create --name my-app --file stack.yaml

# List all stacks
szc stack list

# Get stack details
szc stack get my-stack

# Apply changes
szc stack apply my-stack

# Preview changes (dry-run)
szc stack plan my-stack

# View stack outputs
szc stack outputs my-stack

# Destroy stack
szc stack destroy my-stack

Best Practices

  1. Use Generated Secrets - Never hardcode secrets in templates
  2. Dependency Order - Declare explicit dependencies between components
  3. Idempotent Bootstrap - Design migration scripts to be re-runnable
  4. Version Helm Charts - Always pin chart versions
  5. Tenant Isolation - Use unique tenant IDs per environment
  6. Secret Rotation - Use dynamic secrets where possible

Troubleshooting

Common Issues

IssueCauseSolution
Secret not foundVault path doesn't existVerify static secret exists in Vault
Job timeoutMigration taking too longIncrease timeout value
Reference errorCircular dependencyCheck depends_on declarations
Helm install failedChart not foundVerify chart registry access

Debug Commands

# Check stack status
szc stack get my-stack

# View execution logs
szc stack logs my-stack

# List secrets
szc stack secrets my-stack

# Check job status
szc stack jobs my-stack