Compare commits
1 commit
main
...
fix/cloud-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a4a454090 |
36 changed files with 20 additions and 1212 deletions
10
.github/workflows/default-ci.yaml
vendored
10
.github/workflows/default-ci.yaml
vendored
|
|
@ -21,6 +21,16 @@ on:
|
|||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
secret-scan:
|
||||
name: "Secret Scanner (TruffleHog)"
|
||||
runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'stackit-docker' }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: TruffleHog Scan
|
||||
uses: edplato/trufflehog-actions-scan@master
|
||||
|
||||
todo-check:
|
||||
name: "Check for Open TODOs"
|
||||
runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'stackit-ubuntu-22' }}
|
||||
|
|
|
|||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,6 +1,6 @@
|
|||
.### Terraform template
|
||||
# Local .terraform directories
|
||||
**/.terraform/**
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
|
|
@ -72,8 +72,3 @@ keys
|
|||
### K8s
|
||||
.kubeconfig
|
||||
/examples/telemetry-router-hub-spoke-setup/scripts/downloads/
|
||||
|
||||
*.DS_Store
|
||||
|
||||
# ignore backend.conf files, but keep backend.conf.example
|
||||
*backend.conf
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ repos:
|
|||
args: [--allow-multiple-documents]
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.18.2
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
|
||||
- repo: https://github.com/antonbabenko/pre-commit-terraform
|
||||
rev: v1.88.0
|
||||
hooks:
|
||||
|
|
@ -53,18 +58,13 @@ repos:
|
|||
- id: prettier
|
||||
types_or: [javascript, yaml, json, markdown]
|
||||
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.24.2
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
# Requires `addlicense` to be installed locally (go install github.com/google/addlicense@latest)
|
||||
- id: addlicense
|
||||
name: Add License Headers
|
||||
description: Ensures all files have the Apache 2.0 license header (skips files starting with #cloud-config)
|
||||
entry: bash -c 'for f in "$@"; do head -n 1 "$f" | grep -q "^#cloud-config" || addlicense -c "Schwarz Digits Cloud GmbH & Co. KG" -l apache "$f"; done' --
|
||||
description: Ensures all files have the Apache 2.0 license header
|
||||
entry: addlicense -c "Schwarz Digits Cloud GmbH & Co. KG" -l apache
|
||||
language: system
|
||||
types_or: [terraform, python, go, javascript, yaml, json, html, css]
|
||||
pass_filenames: true
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ To maintain a clean and secure codebase, we enforce a strict CI pipeline on all
|
|||
```
|
||||
|
||||
- **Terraform file naming:** All `.tf` files in examples **must** be prefixed with exactly 3 digits to enforce consistent ordering (e.g., `010-provider.tf`, `020-variables.tf`, `030-resources.tf`, `100-outputs.tf`). Files inside `modules/` directories are exempt from this rule. This check is enforced automatically by pre-commit.
|
||||
- **Scan for Secrets:** Never commit credentials. We use `gitleaks` in the CI pipeline. Ensure you have no hardcoded tokens or passwords in your code.
|
||||
- **Scan for Secrets:** Never commit credentials. We use `trufflehog` in the CI pipeline. Ensure you have no hardcoded tokens or passwords in your code.
|
||||
|
||||
### Repository structure
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ To ensure high standards and security, we follow a strict contribution process:
|
|||
- **Automated Validation:** Every Pull Request must pass the CI pipeline, which includes:
|
||||
- Linting and formatting checks.
|
||||
- License header verification (Apache 2.0).
|
||||
- Secret scanning (GitLeaks).
|
||||
- Secret scanning (Trufflehog).
|
||||
- **Best Effort Policy:** While we strive for quality, the content is provided "as-is." Use in production environments requires independent validation by the user.
|
||||
|
||||
## 4. Mirroring Process
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
v1.5.7
|
||||
24
examples/iaas-image-upload/.terraform.lock.hcl
generated
24
examples/iaas-image-upload/.terraform.lock.hcl
generated
|
|
@ -1,24 +0,0 @@
|
|||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/stackitcloud/stackit" {
|
||||
version = "0.99.0"
|
||||
constraints = ">= 0.99.0"
|
||||
hashes = [
|
||||
"h1:a9z0j1z/8GmGjz+VygIhgyBbMqxx7jlXGqCvWBDD1NY=",
|
||||
"zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f",
|
||||
"zh:396c0392b9ef5ec7f8613c29a64e183545cc16dda0ceb876393fc003dba71c73",
|
||||
"zh:40d86a1fb1c9ed4579583acb8ecc219edca44f9ee5221bfdcbc1bee2ce6654e7",
|
||||
"zh:4ccbbecc3575737d87195ad13448d06071be9925760a2da5b7e5e8b91517f876",
|
||||
"zh:506d786647c4566a82487fc3ffe0792f37a63ec8d6b54821aa3c7485e5ed6760",
|
||||
"zh:848f638c500f1928f8593ae189472add1a0871c1e056d7df06871652ddee3409",
|
||||
"zh:9ed739aec2c60cdfae3a33e4f349fa630fd0fd0ab50fcec5745774d42a6d6e70",
|
||||
"zh:c0ac883dd73bd886e419d912c28ec29bb90a611b023cf4ae1b0534945cce1694",
|
||||
"zh:df28663578694b25453b9d0a1cd7633a0f7fb1c113870cd3c133e9dc05d35946",
|
||||
"zh:eaacb4a4512f41d44e46f82f042a19ab96c9d90d470890e2fd82c6cafb33bf0e",
|
||||
"zh:ef9dd9b10571804f3a4dd6062405d0e473df270d75f05f897901c54d7d6c3d9d",
|
||||
"zh:f40add9cd4fd4a7cda53f4a418c5f47a220b5ba5c4fc2377f60b1e16368f87d9",
|
||||
"zh:f65deb30c1e3e8018a888d1aed56e895ea1e26b880f22a5772771e9836c9b5a4",
|
||||
"zh:f8d14feddfd9d785d3ee6469937234a631998758ea5e8c16ecf61cdb94b07564",
|
||||
]
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.5.7"
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "stackitcloud/stackit"
|
||||
version = ">= 0.99.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
default_region = var.stackit_region
|
||||
service_account_key_path = var.stackit_service_account_key_path
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# ─── Provider ─────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "stackit_region" {
|
||||
description = "STACKIT region, e.g. eu01"
|
||||
type = string
|
||||
default = "eu01"
|
||||
}
|
||||
|
||||
variable "stackit_service_account_key_path" {
|
||||
description = "Path to the STACKIT service account key JSON file"
|
||||
type = string
|
||||
default = "keys/sa-key.json"
|
||||
}
|
||||
|
||||
# ─── Project ──────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "project_id" {
|
||||
description = "STACKIT project ID to which the image is uploaded — find it in the Portal or via: stackit project list"
|
||||
type = string
|
||||
}
|
||||
|
||||
# ─── Image ────────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "image_name" {
|
||||
description = "Name of the custom image as it will appear in STACKIT"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "image_file_path" {
|
||||
description = "Local path to the image file to upload, e.g. ./images/custom-image.qcow2 — the file must exist before running terraform apply"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "disk_format" {
|
||||
description = "Disk format of the image. Supported values: qcow2, raw, iso"
|
||||
type = string
|
||||
default = "qcow2"
|
||||
|
||||
validation {
|
||||
condition = contains(["qcow2", "raw", "iso"], var.disk_format)
|
||||
error_message = "disk_format must be one of: qcow2, raw, iso."
|
||||
}
|
||||
}
|
||||
|
||||
variable "min_disk_size" {
|
||||
description = "Minimum disk size required to boot instances from this image, in GB"
|
||||
type = number
|
||||
default = 20
|
||||
|
||||
validation {
|
||||
condition = var.min_disk_size >= 1
|
||||
error_message = "min_disk_size must be at least 1 GB."
|
||||
}
|
||||
}
|
||||
|
||||
variable "min_ram" {
|
||||
description = "Minimum RAM required to boot instances from this image, in MB"
|
||||
type = number
|
||||
default = 2048
|
||||
|
||||
validation {
|
||||
condition = var.min_ram >= 1
|
||||
error_message = "min_ram must be at least 1 MB."
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Image Config ─────────────────────────────────────────────────────────────
|
||||
|
||||
variable "uefi" {
|
||||
description = "Enable UEFI boot for instances created from this image. Set to false for BIOS-only images."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "secure_boot" {
|
||||
description = "Enable Secure Boot for instances created from this image. Requires UEFI (uefi = true)."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
# ─── Server ───────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "server_name" {
|
||||
description = "Name of the server to create from the uploaded image"
|
||||
type = string
|
||||
default = "custom-image-server"
|
||||
}
|
||||
|
||||
variable "machine_type" {
|
||||
description = "STACKIT machine type for the server — list available: stackit server machine-type list --project-id <id>"
|
||||
type = string
|
||||
default = "g1.1"
|
||||
}
|
||||
|
||||
variable "availability_zone" {
|
||||
description = "Availability zone for the server, e.g. eu01-1, eu01-2, eu01-3"
|
||||
type = string
|
||||
default = "eu01-1"
|
||||
}
|
||||
|
||||
variable "boot_volume_size_gb" {
|
||||
description = "Boot volume size in GB — must be >= min_disk_size of the image"
|
||||
type = number
|
||||
default = 20
|
||||
|
||||
validation {
|
||||
condition = var.boot_volume_size_gb >= 1
|
||||
error_message = "boot_volume_size_gb must be at least 1 GB."
|
||||
}
|
||||
}
|
||||
|
||||
variable "network_cidr" {
|
||||
description = "IPv4 CIDR block for the server's private network"
|
||||
type = string
|
||||
default = "10.10.0.0/24"
|
||||
|
||||
validation {
|
||||
condition = can(cidrnetmask(var.network_cidr))
|
||||
error_message = "network_cidr must be a valid CIDR, e.g. 10.10.0.0/24."
|
||||
}
|
||||
}
|
||||
|
||||
variable "keypair_name" {
|
||||
description = "Name of the SSH key pair to register in STACKIT"
|
||||
type = string
|
||||
default = "custom-image-key"
|
||||
}
|
||||
|
||||
variable "ssh_public_key" {
|
||||
description = "SSH public key string (ssh-ed25519 AAAA... or ssh-rsa AAAA...) — only required when deploy_server = true"
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
}
|
||||
|
||||
# ─── Labels ───────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "labels" {
|
||||
description = "Key-value labels to attach to the image resource"
|
||||
type = map(string)
|
||||
default = {
|
||||
managed-by = "terraform"
|
||||
example = "image-upload"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
resource "stackit_image" "custom_image" {
|
||||
project_id = var.project_id
|
||||
name = var.image_name
|
||||
disk_format = var.disk_format
|
||||
local_file_path = var.image_file_path
|
||||
|
||||
min_disk_size = var.min_disk_size
|
||||
min_ram = var.min_ram
|
||||
|
||||
labels = var.labels
|
||||
|
||||
config = {
|
||||
uefi = var.uefi
|
||||
secure_boot = var.secure_boot
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
output "image_id" {
|
||||
description = "ID of the uploaded custom image — use this UUID when creating servers or volumes"
|
||||
value = stackit_image.custom_image.image_id
|
||||
}
|
||||
|
||||
output "image_name" {
|
||||
description = "Name of the uploaded custom image"
|
||||
value = stackit_image.custom_image.name
|
||||
}
|
||||
|
||||
output "image_scope" {
|
||||
description = "Scope of the image (private or public)"
|
||||
value = stackit_image.custom_image.scope
|
||||
}
|
||||
|
||||
output "checksum_algorithm" {
|
||||
description = "Algorithm used for the image checksum"
|
||||
value = stackit_image.custom_image.checksum.algorithm
|
||||
}
|
||||
|
||||
output "checksum_digest" {
|
||||
description = "Checksum digest of the uploaded image — verify this against your local file"
|
||||
value = stackit_image.custom_image.checksum.digest
|
||||
}
|
||||
|
||||
output "server_id" {
|
||||
description = "ID of the server created from the custom image"
|
||||
value = stackit_server.from_custom_image.server_id
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Example: boot a server from the uploaded custom image.
|
||||
# The image_id is referenced directly from the stackit_image resource above.
|
||||
|
||||
resource "stackit_network" "main" {
|
||||
project_id = var.project_id
|
||||
name = "${var.server_name}-network"
|
||||
ipv4_prefix_length = tonumber(split("/", var.network_cidr)[1])
|
||||
}
|
||||
|
||||
resource "stackit_network_interface" "server" {
|
||||
project_id = var.project_id
|
||||
network_id = stackit_network.main.network_id
|
||||
name = "${var.server_name}-nic"
|
||||
}
|
||||
|
||||
resource "stackit_key_pair" "server" {
|
||||
name = var.keypair_name
|
||||
public_key = chomp(var.ssh_public_key)
|
||||
}
|
||||
|
||||
resource "stackit_server" "from_custom_image" {
|
||||
project_id = var.project_id
|
||||
name = var.server_name
|
||||
machine_type = var.machine_type
|
||||
availability_zone = var.availability_zone
|
||||
keypair_name = stackit_key_pair.server.name
|
||||
|
||||
boot_volume = {
|
||||
source_type = "image"
|
||||
source_id = stackit_image.custom_image.image_id
|
||||
size = var.boot_volume_size_gb
|
||||
}
|
||||
|
||||
network_interfaces = [stackit_network_interface.server.network_interface_id]
|
||||
|
||||
labels = var.labels
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
# Maintainers
|
||||
|
||||
General maintainers:
|
||||
|
||||
- Sven Schmidt (sven.schmidt@digits.schwarz)
|
||||
|
||||
This example is actively maintained. The owner is responsible for reviewing and updating dependencies and functionalities on a monthly basis.
|
||||
For questions, issues, or feature requests, please email general maintainers.
|
||||
Please include the BP name and version in your request. We will track your request as an issue.
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
# iaas-image-upload
|
||||
|
||||
Upload a custom VM image to STACKIT using Terraform.
|
||||
|
||||
This example provisions a single `stackit_image` resource from a local image file. It covers the minimal configuration needed to make a custom image available in a STACKIT project, including disk format, boot requirements, and UEFI/Secure Boot settings.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant FS as Local Filesystem
|
||||
participant TF as Terraform / STACKIT API
|
||||
participant IMG as STACKIT Image Service
|
||||
participant SRV as STACKIT Compute
|
||||
|
||||
Note over User,SRV: terraform apply
|
||||
|
||||
User->>FS: read image file (local_file_path)
|
||||
FS-->>TF: binary image data
|
||||
|
||||
User->>TF: create image metadata (name, format, min_disk, min_ram, config)
|
||||
TF-->>IMG: POST /v1/projects/{project_id}/images
|
||||
IMG-->>TF: image_id · status: uploading
|
||||
|
||||
TF-->>IMG: PUT upload binary image data
|
||||
IMG-->>IMG: compute checksum · validate format
|
||||
IMG-->>TF: status: active · checksum_digest
|
||||
|
||||
TF-->>User: ✅ image_id · checksum_digest
|
||||
|
||||
Note over User,SRV: 04-server.tf
|
||||
|
||||
User->>TF: create Key Pair + Server (source_id = image_id)
|
||||
TF-->>SRV: POST /v1/projects/{project_id}/servers
|
||||
SRV-->>TF: server_id
|
||||
|
||||
TF-->>User: ✅ server_id
|
||||
```
|
||||
|
||||
```
|
||||
STACKIT Project
|
||||
├── Image: custom-image-v1 (scope: private)
|
||||
│ ├── Format: qcow2
|
||||
│ ├── Min disk: 20 GB
|
||||
│ ├── Min RAM: 2048 MB
|
||||
│ └── Config: uefi=true · secure_boot=false
|
||||
│
|
||||
└── Server: custom-image-server
|
||||
├── Machine: g1.1
|
||||
├── Zone: eu01-1
|
||||
└── Boot: source_type=image · source_id=<image_id>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
| Component | Description |
|
||||
| ------------ | -------------------------------------------------------- |
|
||||
| Image upload | Uploads a local image file to the STACKIT Image Service |
|
||||
| Boot config | Configures UEFI and Secure Boot flags via `config` block |
|
||||
| Labels | Attaches key-value labels for resource management |
|
||||
|
||||
| In this example | Not in this example |
|
||||
| ----------------------------- | ----------------------------- |
|
||||
| Upload a custom image | Image sharing across projects |
|
||||
| UEFI and Secure Boot settings | Auto-scaling / multiple VMs |
|
||||
| Boot a server from the image | Storage encryption |
|
||||
| Image labels | DNS / Load Balancer |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Tool | Version |
|
||||
| --------------- | -------------- |
|
||||
| Terraform | >= 1.5.7 |
|
||||
| STACKIT CLI | latest |
|
||||
| STACKIT account | Project access |
|
||||
|
||||
### Required STACKIT permissions
|
||||
|
||||
The service account used by Terraform must have the following roles assigned in the target project:
|
||||
|
||||
| Service | Role | Required for |
|
||||
| --------------- | -------- | ----------------------------------- |
|
||||
| Compute / Image | `editor` | Upload and manage custom images |
|
||||
| Compute | `editor` | Create servers, networks, key pairs |
|
||||
|
||||
Assign roles via the STACKIT Portal (Project → Access → Service Accounts) or the CLI:
|
||||
|
||||
```bash
|
||||
stackit project role assign \
|
||||
--project-id <project-id> \
|
||||
--role compute.editor \
|
||||
--service-account-email <sa-email>
|
||||
```
|
||||
|
||||
### Image file
|
||||
|
||||
The image file must exist locally before running `terraform apply`. It is **not** included in this repository and must never be committed.
|
||||
|
||||
Place your image file in the `images/` directory:
|
||||
|
||||
```
|
||||
images/
|
||||
└── custom-image.qcow2 ← your local image file (gitignored)
|
||||
```
|
||||
|
||||
Supported formats: `qcow2`, `raw`, `iso`
|
||||
|
||||
The most common format for Linux-based virtual machine images is `qcow2`.
|
||||
|
||||
### Service account
|
||||
|
||||
Create a service account and download its key:
|
||||
|
||||
```bash
|
||||
stackit iam service-account create \
|
||||
--project-id <project-id> \
|
||||
--name "tf-image-upload-sa"
|
||||
|
||||
mkdir -p keys
|
||||
stackit iam service-account key create \
|
||||
--project-id <project-id> \
|
||||
--service-account-email <sa-email> \
|
||||
--output-format json > keys/sa-key.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### 1. Place the image file
|
||||
|
||||
```bash
|
||||
cp /path/to/your/image.qcow2 images/custom-image.qcow2
|
||||
```
|
||||
|
||||
### 2. Configure variables
|
||||
|
||||
```bash
|
||||
cp examples/terraform.tfvars.example terraform.tfvars
|
||||
# Fill in: project_id, image_name, image_file_path
|
||||
```
|
||||
|
||||
Find your project ID:
|
||||
|
||||
```bash
|
||||
stackit project list
|
||||
```
|
||||
|
||||
### 3. Deploy
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
Duration: depends on image size and upload speed. A 2 GB image typically takes 1–3 minutes.
|
||||
|
||||
### 4. Outputs
|
||||
|
||||
```bash
|
||||
terraform output
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
After a successful `terraform apply`, verify the image in STACKIT:
|
||||
|
||||
```bash
|
||||
# List images in your project
|
||||
stackit image list --project-id <project-id>
|
||||
|
||||
# Show details for the uploaded image
|
||||
stackit image show --project-id <project-id> --image-id $(terraform output -raw image_id)
|
||||
```
|
||||
|
||||
The `checksum_digest` output can be used to verify the uploaded image matches your local file:
|
||||
|
||||
```bash
|
||||
# qcow2 image checksum (SHA-256)
|
||||
sha256sum images/custom-image.qcow2
|
||||
terraform output checksum_digest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
iaas-image-upload/
|
||||
├── .terraform-version # Terraform version pin (v1.5.7)
|
||||
├── .gitignore
|
||||
├── 000-provider.tf # stackitcloud/stackit provider
|
||||
├── 010-variables.tf # All variables with descriptions and defaults
|
||||
├── 020-image.tf # stackit_image resource
|
||||
├── 030-outputs.tf # Image ID, name, scope, checksum, server outputs
|
||||
├── 040-server.tf # Optional: server + network from the uploaded image
|
||||
├── examples/
|
||||
│ └── terraform.tfvars.example # Example variable values (safe to commit)
|
||||
├── images/ # Place your image file here (gitignored)
|
||||
│ └── .gitkeep
|
||||
└── keys/ # SA key JSON — gitignored
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UEFI and Secure Boot
|
||||
|
||||
| Variable | Default | Description |
|
||||
| ------------- | ------- | -------------------------------------------------------- |
|
||||
| `uefi` | `true` | Enables UEFI boot; set to `false` for legacy BIOS images |
|
||||
| `secure_boot` | `false` | Enables Secure Boot; requires `uefi = true` |
|
||||
|
||||
Most modern Linux distributions support UEFI. If your image was built for BIOS boot only, set `uefi = false` and `secure_boot = false`.
|
||||
|
||||
Secure Boot requires a signed bootloader. Enable it only if your image explicitly supports it.
|
||||
|
||||
---
|
||||
|
||||
## Deploy a server from the uploaded image
|
||||
|
||||
`04-server.tf` creates a server that boots directly from the uploaded image.
|
||||
The `source_id` is wired to `stackit_image.custom_image.image_id` — no manual copy-paste of the image UUID needed.
|
||||
|
||||
Provide your SSH public key in `terraform.tfvars`:
|
||||
|
||||
```hcl
|
||||
ssh_public_key = "ssh-ed25519 AAAA... your-key-comment"
|
||||
```
|
||||
|
||||
Extend `04-server.tf` with `stackit_network` and `stackit_network_interface` resources if network connectivity is required.
|
||||
|
||||
The default SSH user depends on the operating system of your image (e.g. `debian`, `ubuntu`, `root`).
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
| File | Git status | Contains |
|
||||
| ------------------ | ---------- | ---------------------------- |
|
||||
| `terraform.tfvars` | gitignored | Project ID, sensitive config |
|
||||
| `keys/` | gitignored | Service account JSON key |
|
||||
| `images/` | gitignored | Local image files |
|
||||
|
||||
Never commit image files, service account keys, or `terraform.tfvars` to the repository.
|
||||
|
||||
---
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
terraform destroy
|
||||
```
|
||||
|
||||
Removes the uploaded image from STACKIT. This does not affect any running instances that were created from the image.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [STACKIT Terraform Provider — stackit_image](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/image)
|
||||
- [STACKIT Developer Documentation](https://docs.stackit.cloud)
|
||||
- [STACKIT CLI](https://github.com/stackitcloud/stackit-cli)
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
# Copy this file to terraform.tfvars and fill in the required values.
|
||||
# terraform.tfvars is gitignored — never commit real project IDs or credentials.
|
||||
|
||||
# ─── Provider ─────────────────────────────────────────────────────────────────
|
||||
|
||||
stackit_region = "eu01"
|
||||
stackit_service_account_key_path = "keys/sa-key.json"
|
||||
|
||||
# ─── Project ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# Find your project ID in the STACKIT Portal or via: stackit project list
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
|
||||
# ─── Image ────────────────────────────────────────────────────────────────────
|
||||
|
||||
image_name = "custom-image-v1"
|
||||
|
||||
# Path to the local image file — this file must exist before running terraform apply.
|
||||
# The images/ directory is gitignored; place your image file there.
|
||||
image_file_path = "./images/custom-image.qcow2"
|
||||
|
||||
disk_format = "qcow2" # supported: qcow2, raw, iso
|
||||
min_disk_size = 20
|
||||
min_ram = 2048
|
||||
|
||||
# ─── Image Config ─────────────────────────────────────────────────────────────
|
||||
|
||||
uefi = true
|
||||
secure_boot = false
|
||||
|
||||
# ─── Server ───────────────────────────────────────────────────────────────────
|
||||
|
||||
server_name = "custom-image-server"
|
||||
machine_type = "g1.1"
|
||||
availability_zone = "eu01-1"
|
||||
boot_volume_size_gb = 20
|
||||
network_cidr = "10.10.0.0/24"
|
||||
keypair_name = "custom-image-key"
|
||||
|
||||
# Paste your SSH public key here (never the private key)
|
||||
ssh_public_key = "ssh-ed25519 AAAA... your-key-comment"
|
||||
|
||||
# ─── Labels ───────────────────────────────────────────────────────────────────
|
||||
|
||||
labels = {
|
||||
managed-by = "terraform"
|
||||
example = "image-upload"
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
.gitkeep
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/stackitcloud/stackit" {
|
||||
version = "0.99.0"
|
||||
constraints = ">= 0.99.0"
|
||||
hashes = [
|
||||
"h1:a9z0j1z/8GmGjz+VygIhgyBbMqxx7jlXGqCvWBDD1NY=",
|
||||
"zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f",
|
||||
"zh:396c0392b9ef5ec7f8613c29a64e183545cc16dda0ceb876393fc003dba71c73",
|
||||
"zh:40d86a1fb1c9ed4579583acb8ecc219edca44f9ee5221bfdcbc1bee2ce6654e7",
|
||||
"zh:4ccbbecc3575737d87195ad13448d06071be9925760a2da5b7e5e8b91517f876",
|
||||
"zh:506d786647c4566a82487fc3ffe0792f37a63ec8d6b54821aa3c7485e5ed6760",
|
||||
"zh:848f638c500f1928f8593ae189472add1a0871c1e056d7df06871652ddee3409",
|
||||
"zh:9ed739aec2c60cdfae3a33e4f349fa630fd0fd0ab50fcec5745774d42a6d6e70",
|
||||
"zh:c0ac883dd73bd886e419d912c28ec29bb90a611b023cf4ae1b0534945cce1694",
|
||||
"zh:df28663578694b25453b9d0a1cd7633a0f7fb1c113870cd3c133e9dc05d35946",
|
||||
"zh:eaacb4a4512f41d44e46f82f042a19ab96c9d90d470890e2fd82c6cafb33bf0e",
|
||||
"zh:ef9dd9b10571804f3a4dd6062405d0e473df270d75f05f897901c54d7d6c3d9d",
|
||||
"zh:f40add9cd4fd4a7cda53f4a418c5f47a220b5ba5c4fc2377f60b1e16368f87d9",
|
||||
"zh:f65deb30c1e3e8018a888d1aed56e895ea1e26b880f22a5772771e9836c9b5a4",
|
||||
"zh:f8d14feddfd9d785d3ee6469937234a631998758ea5e8c16ecf61cdb94b07564",
|
||||
]
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
variable "stackit_service_account_key_path" {
|
||||
description = "Path to the STACKIT service account key file (JSON). Keep this file out of version control."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_organization_id" {
|
||||
description = "STACKIT Organization ID (UUID). Found in the portal under Organization > Settings."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_project_name" {
|
||||
description = "Display name of the hub project in STACKIT."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_org_admin" {
|
||||
description = "Email address of the STACKIT user who will be set as project owner."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_region" {
|
||||
description = "STACKIT region (e.g. eu01)."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "default_zone" {
|
||||
description = "Availability zone within the region (e.g. eu01-1)."
|
||||
type = string
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "stackitcloud/stackit"
|
||||
version = ">= 0.99.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
default_region = var.stackit_region
|
||||
service_account_key_path = var.stackit_service_account_key_path
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
resource "stackit_resourcemanager_project" "this" {
|
||||
parent_container_id = var.stackit_organization_id
|
||||
name = var.stackit_project_name
|
||||
owner_email = var.stackit_org_admin
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Provision PostgreSQL Flex Database Instance
|
||||
resource "stackit_postgresflex_instance" "this" {
|
||||
project_id = stackit_resourcemanager_project.this.project_id
|
||||
name = "tf-state-instance"
|
||||
version = "17"
|
||||
|
||||
flavor = {
|
||||
cpu = 2
|
||||
ram = 4
|
||||
}
|
||||
storage = {
|
||||
class = "premium-perf2-stackit"
|
||||
size = 10
|
||||
}
|
||||
|
||||
replicas = 1
|
||||
backup_schedule = "00 00 * * *"
|
||||
|
||||
acl = [
|
||||
# WARNING: Open ACL is for development only. Restrict to your specific egress IP ranges in production.
|
||||
"0.0.0.0/0"
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
# Provision PostgreSQL Flex Database Owner
|
||||
resource "stackit_postgresflex_user" "db_owner" {
|
||||
project_id = stackit_resourcemanager_project.this.project_id
|
||||
instance_id = stackit_postgresflex_instance.this.instance_id
|
||||
username = "tf_state_user"
|
||||
roles = ["login", "createdb"]
|
||||
}
|
||||
|
||||
# Provision PostgreSQL Flex Database
|
||||
resource "stackit_postgresflex_database" "this" {
|
||||
project_id = stackit_resourcemanager_project.this.project_id
|
||||
instance_id = stackit_postgresflex_instance.this.instance_id
|
||||
owner = stackit_postgresflex_user.db_owner.username
|
||||
name = "tf-states"
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
locals {
|
||||
pg_username = stackit_postgresflex_user.db_owner.username
|
||||
pg_password = stackit_postgresflex_user.db_owner.password
|
||||
pg_host = stackit_postgresflex_user.db_owner.host
|
||||
pg_port = stackit_postgresflex_user.db_owner.port
|
||||
pg_database = stackit_postgresflex_database.this.name
|
||||
}
|
||||
|
||||
output "pg_connection_uri" {
|
||||
description = "PostgreSQL Flex User Connection String"
|
||||
value = "postgres://${local.pg_username}:${local.pg_password}@${local.pg_host}:${local.pg_port}/${local.pg_database}?sslmode=require"
|
||||
sensitive = true
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# Phase 0: Bootstrap
|
||||
|
||||
This module provisions the STACKIT PostgreSQL Flex instance, the `terraform_state` database, and the dedicated `tf_state_user`. Its state is kept locally (or in an independent CI/CD backend) to prevent dependency conflicts.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Initialize Terraform with the default local backend:
|
||||
|
||||
```sh
|
||||
terraform init
|
||||
```
|
||||
|
||||
2. Provision the PostgreSQL Flex resources:
|
||||
|
||||
```sh
|
||||
terraform apply
|
||||
```
|
||||
|
||||
3. Extract the generated PostgreSQL connection string from the Terraform outputs. This URI is required to configure the remote backend in the next phase.
|
||||
|
||||
```sh
|
||||
terraform output -raw pg_connection_uri
|
||||
```
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# ---------------------------------------------------------------------------
|
||||
# terraform.tfvars.example
|
||||
#
|
||||
# Copy this file into a project directory (e.g. 00-bootcamp/terraform.tfvars)
|
||||
# and fill in your values. Do NOT commit terraform.tfvars to version control.
|
||||
#
|
||||
# Alternatively, export variables as environment variables:
|
||||
# export TF_VAR_stackit_organization_id="<uuid>"
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# --- STACKIT Identity --------------------------------------------------------
|
||||
|
||||
# Your STACKIT Organization ID.
|
||||
# Portal: Organization > Settings > Organization ID
|
||||
stackit_organization_id = "<your-organization-id>"
|
||||
|
||||
## Name of the bootstrapping project
|
||||
stackit_project_name = "00-bootstrap"
|
||||
|
||||
# Email address of the STACKIT user set as project owner.
|
||||
stackit_org_admin = "<your-admin@mail.com"
|
||||
|
||||
# --- Service Account ---------------------------------------------------------
|
||||
|
||||
# Path to the STACKIT service account key file.
|
||||
# Download: STACKIT portal > Service Accounts > Keys > Create key
|
||||
stackit_service_account_key_path = "./keys/service-account.json"
|
||||
|
||||
# --- Region ------------------------------------------------------------------
|
||||
stackit_region = "eu01"
|
||||
default_zone = "eu01-1"
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/stackitcloud/stackit" {
|
||||
version = "0.99.0"
|
||||
constraints = ">= 0.99.0"
|
||||
hashes = [
|
||||
"h1:a9z0j1z/8GmGjz+VygIhgyBbMqxx7jlXGqCvWBDD1NY=",
|
||||
"zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f",
|
||||
"zh:396c0392b9ef5ec7f8613c29a64e183545cc16dda0ceb876393fc003dba71c73",
|
||||
"zh:40d86a1fb1c9ed4579583acb8ecc219edca44f9ee5221bfdcbc1bee2ce6654e7",
|
||||
"zh:4ccbbecc3575737d87195ad13448d06071be9925760a2da5b7e5e8b91517f876",
|
||||
"zh:506d786647c4566a82487fc3ffe0792f37a63ec8d6b54821aa3c7485e5ed6760",
|
||||
"zh:848f638c500f1928f8593ae189472add1a0871c1e056d7df06871652ddee3409",
|
||||
"zh:9ed739aec2c60cdfae3a33e4f349fa630fd0fd0ab50fcec5745774d42a6d6e70",
|
||||
"zh:c0ac883dd73bd886e419d912c28ec29bb90a611b023cf4ae1b0534945cce1694",
|
||||
"zh:df28663578694b25453b9d0a1cd7633a0f7fb1c113870cd3c133e9dc05d35946",
|
||||
"zh:eaacb4a4512f41d44e46f82f042a19ab96c9d90d470890e2fd82c6cafb33bf0e",
|
||||
"zh:ef9dd9b10571804f3a4dd6062405d0e473df270d75f05f897901c54d7d6c3d9d",
|
||||
"zh:f40add9cd4fd4a7cda53f4a418c5f47a220b5ba5c4fc2377f60b1e16368f87d9",
|
||||
"zh:f65deb30c1e3e8018a888d1aed56e895ea1e26b880f22a5772771e9836c9b5a4",
|
||||
"zh:f8d14feddfd9d785d3ee6469937234a631998758ea5e8c16ecf61cdb94b07564",
|
||||
]
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
variable "stackit_service_account_key_path" {
|
||||
description = "Path to the STACKIT service account key file (JSON). Keep this file out of version control."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_organization_id" {
|
||||
description = "STACKIT Organization ID (UUID). Found in the portal under Organization > Settings."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_project_name" {
|
||||
description = "Display name of the hub project in STACKIT."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_org_admin" {
|
||||
description = "Email address of the STACKIT user who will be set as project owner."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "stackit_region" {
|
||||
description = "STACKIT region (e.g. eu01)."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "default_zone" {
|
||||
description = "Availability zone within the region (e.g. eu01-1)."
|
||||
type = string
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
backend "pg" {}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "stackitcloud/stackit"
|
||||
version = ">= 0.99.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
default_region = var.stackit_region
|
||||
service_account_key_path = var.stackit_service_account_key_path
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
resource "stackit_resourcemanager_project" "this" {
|
||||
parent_container_id = var.stackit_organization_id
|
||||
name = var.stackit_project_name
|
||||
owner_email = var.stackit_org_admin
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
# Phase 1: Example Infrastructure
|
||||
|
||||
This module contains the core infrastructure configuration. It uses the `pg` backend to store state and enforce state locks via the STACKIT PostgreSQL Flex database provisioned in Phase 0.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Create a `backend.conf` file in this directory and define the connection string using the credentials generated by the bootstrap module:
|
||||
|
||||
```ini
|
||||
conn_str = "postgres://tf_state_user:<PASSWORD>@<STACKIT_INSTANCE_HOST>:5432/terraform_state?sslmode=require"
|
||||
```
|
||||
|
||||
2. Initialize Terraform and bind it to the remote PostgreSQL backend
|
||||
|
||||
```sh
|
||||
terraform init -backend-config=backend.conf
|
||||
```
|
||||
|
||||
3. Provision the infrastructure or run the lock validation script:
|
||||
|
||||
```sh
|
||||
chmod +x ./scripts/validate_lock.sh
|
||||
./scripts/validate_lock.sh
|
||||
```
|
||||
|
||||
## Log Output
|
||||
|
||||
```sh
|
||||
➜ 01-example-project ~ ./scripts/test-state-lock.sh
|
||||
[INFO] Initiating background 'terraform apply' to acquire the state lock...
|
||||
[INFO] Attempting concurrent 'terraform plan'...
|
||||
[INFO] ------------------------------------------------------------------
|
||||
╷
|
||||
│ Error: Error acquiring the state lock
|
||||
│
|
||||
│ Error message: Already locked for workspace creation: default
|
||||
│ Lock Info:
|
||||
│ ID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX
|
||||
│ Path:
|
||||
│ Operation: OperationTypePlan
|
||||
│ Who: XXXX
|
||||
│ Version: 1.14.9
|
||||
│ Created: 2026-06-25 16:21:59.636986 +0000 UTC
|
||||
│ Info:
|
||||
│
|
||||
│
|
||||
│ Terraform acquires a state lock to protect the state from being written
|
||||
│ by multiple users at the same time. Please resolve the issue above and try
|
||||
│ again. For most commands, you can disable locking with the "-lock=false"
|
||||
│ flag, but this is not recommended.
|
||||
╵
|
||||
[INFO] ------------------------------------------------------------------
|
||||
[SUCCESS] Concurrent operation rejected. State locking is active and functional.
|
||||
[INFO] Waiting for the background 'terraform apply' process to terminate...
|
||||
[INFO] Evaluation complete. Cleaning up temporary logs...
|
||||
```
|
||||
|
|
@ -1 +0,0 @@
|
|||
conn_str=""
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -u
|
||||
|
||||
echo "[INFO] Initiating background 'terraform apply' to acquire the state lock..."
|
||||
# Redirecting output to avoid console clutter during the concurrent test
|
||||
terraform apply -auto-approve > apply_bg.log 2>&1 &
|
||||
APPLY_PID=$!
|
||||
|
||||
echo "[INFO] Attempting concurrent 'terraform plan'..."
|
||||
echo "[INFO] ------------------------------------------------------------------"
|
||||
|
||||
# Disable exit-on-error to capture the expected failure code
|
||||
set +e
|
||||
terraform plan
|
||||
PLAN_EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
echo "[INFO] ------------------------------------------------------------------"
|
||||
|
||||
if [ $PLAN_EXIT_CODE -ne 0 ]; then
|
||||
echo "[SUCCESS] Concurrent operation rejected. State locking is active and functional."
|
||||
else
|
||||
echo "[ERROR] Concurrent operation succeeded. State locking failed or is misconfigured."
|
||||
fi
|
||||
|
||||
echo "[INFO] Waiting for the background 'terraform apply' process to terminate..."
|
||||
wait $APPLY_PID
|
||||
|
||||
echo "[INFO] Evaluation complete. Cleaning up temporary logs..."
|
||||
rm -f apply_bg.log
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# ---------------------------------------------------------------------------
|
||||
# terraform.tfvars.example
|
||||
#
|
||||
# Copy this file into a project directory (e.g. 00-bootcamp/terraform.tfvars)
|
||||
# and fill in your values. Do NOT commit terraform.tfvars to version control.
|
||||
#
|
||||
# Alternatively, export variables as environment variables:
|
||||
# export TF_VAR_stackit_organization_id="<uuid>"
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# --- STACKIT Identity --------------------------------------------------------
|
||||
|
||||
# Your STACKIT Organization ID.
|
||||
# Portal: Organization > Settings > Organization ID
|
||||
stackit_organization_id = "<your-organization-id>"
|
||||
|
||||
## Name of the bootstrapping project
|
||||
stackit_project_name = "01-example-project"
|
||||
|
||||
# Email address of the STACKIT user set as project owner.
|
||||
stackit_org_admin = "<your-admin@mail.com"
|
||||
|
||||
# --- Service Account ---------------------------------------------------------
|
||||
|
||||
# Path to the STACKIT service account key file.
|
||||
# Download: STACKIT portal > Service Accounts > Keys > Create key
|
||||
stackit_service_account_key_path = "./keys/service-account.json"
|
||||
|
||||
# --- Region ------------------------------------------------------------------
|
||||
stackit_region = "eu01"
|
||||
default_zone = "eu01-1"
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
# Maintainers
|
||||
|
||||
General maintainers:
|
||||
|
||||
- Tim Reibe (<tim.reibe@digits.schwarz>)
|
||||
|
||||
This example is actively maintained. The owner is responsible for reviewing and updating dependencies and functionalities on a monthly basis.
|
||||
For questions, issues, or feature requests, please email general maintainers.
|
||||
Please include the BP name and version in your request. We will track your request as an issue.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# STACKIT Terraform PostgreSQL Backend with State Locking
|
||||
|
||||
This repository demonstrates how to configure STACKIT PostgreSQL Flex as a Terraform backend to enable remote state storage and native state locking.
|
||||
|
||||
To resolve the circular dependency of provisioning a state backend using Terraform, the deployment is split into two isolated stages:
|
||||
|
||||
1. **`00-bootstrap/`**: Provisions the backend infrastructure (PostgreSQL Flex instance, database and service user).
|
||||
2. **`01-example/`**: Represents the primary infrastructure, utilizing the provisioned PostgreSQL database as its remote backend.
|
||||
|
||||
---
|
||||
|
||||
**⚠️ Security Notice:** The PostgreSQL Flex instance in `00-bootstrap/` is configured with an open ACL (`0.0.0.0/0`) for development convenience. Before deploying to production, restrict the ACL to your specific egress IP ranges to prevent the database from being accessible via the public internet.
|
||||
Loading…
Add table
Add a link
Reference in a new issue