This commit is contained in:
Mike McFetridge
2026-07-20 09:23:17 -04:00
parent c1315882da
commit 72272e4006
3179 changed files with 562960 additions and 14 deletions
+9
View File
@@ -0,0 +1,9 @@
# CIVO Credentials
# ---
# Credential Variables needed for CIVO
# Civo Config
variable "civo_token" {
description = "Civo API Token"
type = string
}
+5
View File
@@ -0,0 +1,5 @@
resource "civo_firewall" "your_firewall" {
name = "your-firewall-name"
network_id = civo_network.your_network.id
create_default_rules = true
}
+23
View File
@@ -0,0 +1,23 @@
# CIVO Kubernetes
# ---
# Templates to create a Kubernetes Cluster on CIVO
# Create a new Kubernetes Cluster
resource "civo_kubernetes_cluster" "your-kubernetes-cluster" {
name = "your-kubernetes-cluster"
applications = ""
firewall_id = civo_firewall.your_firewall.id
network_id = civo_network.your_network.id
pools {
size = element(data.civo_size.k8s_std_small.sizes, 0).name
node_count = 3
}
# (Optional) add depenencies on other resources
depends_on = [ civo_firewall.your_firewall, civo_network.your_network ]
}
# (Optional) Time Sleep elements for other Objects that need to wait a few seconds after the Cluster deployment
# resource "time_sleep" "wait_for_kubernetes" {
# depends_on = [civo_kubernetes_cluster.your-kubernetes-cluster]
# create_duration = "20s"
# }
+3
View File
@@ -0,0 +1,3 @@
resource "civo_network" "your_network" {
label = "your-network-label"
}
+20
View File
@@ -0,0 +1,20 @@
# CIVO Provider
# ---
# Initial Provider Configuration for CIVO
terraform {
required_version = ">= 1.5.0"
required_providers {
civo = {
source = "civo/civo"
version = "~> 1.0.9"
}
}
}
provider "civo" {
token = var.civo_token
# (optional): Specify your region
# region = "FRA1"
}
+139
View File
@@ -0,0 +1,139 @@
# CIVO Queries
# ---
# Query commonly used cloud resources from CIVO API
# CIVO Instance Sizes
data "civo_size" "instance_xsmall" {
filter {
key = "name"
values = ["g3.xsmall"]
match_by = "re"
}
}
data "civo_size" "instance_small" {
filter {
key = "name"
values = ["g3.small"]
match_by = "re"
}
}
data "civo_size" "instance_medium" {
filter {
key = "name"
values = ["g3.medium"]
match_by = "re"
}
}
data "civo_size" "instance_large" {
filter {
key = "name"
values = ["g3.large"]
match_by = "re"
}
}
data "civo_size" "instance_xlarge" {
filter {
key = "name"
values = ["g3.xlarge"]
match_by = "re"
}
}
data "civo_size" "instance_2xlarge" {
filter {
key = "name"
values = ["g3.2xlarge"]
match_by = "re"
}
}
# CIVO Kubernetes Standard Sizes
data "civo_size" "k8s_std_xsmall" {
filter {
key = "name"
values = ["g3.k3s.xsmall"]
match_by = "re"
}
}
data "civo_size" "k8s_std_small" {
filter {
key = "name"
values = ["g3.k3s.small"]
match_by = "re"
}
}
data "civo_size" "k8s_std_medium" {
filter {
key = "name"
values = ["g3.k3s.medium"]
match_by = "re"
}
}
data "civo_size" "k8s_std_large" {
filter {
key = "name"
values = ["g3.k3s.large"]
match_by = "re"
}
}
data "civo_size" "k8s_std_xlarge" {
filter {
key = "name"
values = ["g3.k3s.xlarge"]
match_by = "re"
}
}
data "civo_size" "k8s_std_2xlarge" {
filter {
key = "name"
values = ["g3.k3s.2xlarge"]
match_by = "re"
}
}
# CIVO Instance Diskimages
data "civo_disk_image" "debian" {
filter {
key = "name"
values = ["debian-10"]
}
}
data "civo_disk_image" "debian_9" {
filter {
key = "name"
values = ["debian-9"]
}
}
data "civo_disk_image" "ubuntu" {
filter {
key = "name"
values = ["ubuntu-focal"]
}
}
data "civo_disk_image" "ubuntu_bionic" {
filter {
key = "name"
values = ["ubuntu-bionic"]
}
}
data "civo_disk_image" "centos" {
filter {
key = "name"
values = ["centos-7"]
}
}
+14
View File
@@ -0,0 +1,14 @@
# CIVO Servers
# ---
# Templates to create a Linux Server on CIVO
# CIVO Instance Server
resource "civo_instance" "your-server" {
hostname = "your-fqdn-server-name"
size = data.civo_size.instance_xsmall.sizes.0.name
disk_image = data.civo_disk_image.debian.diskimages.0.id
# initial_user = "your-initial-user"
# sshkey_id = data.civo_ssh_key.your-ssh-key.id
# reverse_dns = "your-server.your-domain"
}
+14
View File
@@ -0,0 +1,14 @@
# CIVO SSH Keys
# ---
# Query or Create SSH Keys to authenticate to Servers on CIVO
# Query existing CIVO SSH Key
data "civo_ssh_key" "your-ssh-key" {
name = "your-ssh-key-name"
}
# Create new SSH Key
resource "civo_ssh_key" "your-ssh-key"{
name = "your-ssh-key-name"
public_key = file("~/.ssh/id_rsa.pub")
}
@@ -0,0 +1,29 @@
data "cloudflare_zone" "zone" {
zone_id = "<< cloudflare_zone_id >>"
}
resource "cloudflare_dns_record" "<< resource_name >>" {
zone_id = data.cloudflare_zone.zone.zone_id
name = "<< name >>"
type = "<< record_type >>"
<%- if record_type == "A" %>
content = "<< ipv4_address >>"
proxied = << proxied | lower >>
<%- endif %>
<%- if record_type == "AAAA" %>
content = "<< ipv6_address >>"
proxied = << proxied | lower >>
<%- endif %>
<%- if record_type == "CNAME" %>
content = "<< target_hostname >>"
proxied = << proxied | lower >>
<%- endif %>
<%- if record_type == "TXT" %>
content = "<< text_value >>"
<%- endif %>
<%- if record_type == "MX" %>
content = "<< mail_server >>"
priority = << priority >>
<%- endif %>
ttl = << ttl >>
}
@@ -0,0 +1,175 @@
{
"slug": "cloudflare-dns-record",
"kind": "terraform",
"metadata": {
"name": "Cloudflare DNS Record",
"description": "Creates a single Cloudflare DNS record for A, AAAA, CNAME, TXT, or MX with type-specific inputs, TTL, and proxying where supported.",
"icon": {
"provider": "selfhst",
"id": "cloudflare",
"color": "default"
},
"draft": false,
"version": {
"name": "1.0.0",
"source_dep_name": "manual/cloudflare-dns-record"
}
},
"variables": [
{
"name": "terraform",
"title": "Terraform",
"items": [
{
"name": "resource_name",
"title": "Resource Name",
"type": "str",
"default": "dns_record",
"config": {
"placeholder": "dns_record"
}
}
]
},
{
"name": "record",
"title": "DNS Record",
"items": [
{
"name": "cloudflare_zone_id",
"title": "Cloudflare Zone ID",
"type": "str",
"config": {
"placeholder": "123456789"
},
"required": true
},
{
"name": "name",
"title": "Record Name",
"description": "DNS record name (use @ for the root domain).",
"type": "str",
"default": "app",
"config": {
"placeholder": "app"
}
},
{
"name": "record_type",
"title": "DNS record type",
"type": "enum",
"default": "A",
"config": {
"options": [
"A",
"AAAA",
"CNAME",
"TXT",
"MX"
]
}
},
{
"name": "ttl",
"title": "TTL",
"description": "Time to live (1 = automatic, or 60-86400 seconds)",
"type": "int",
"default": 1,
"config": {
"placeholder": "1",
"unit": "seconds"
}
},
{
"name": "ipv4_address",
"title": "IPv4 Address",
"description": "IPv4 address for an A record.",
"type": "str",
"required": true,
"needs": [
"record_type=A"
],
"config": {
"placeholder": "192.0.2.1"
}
},
{
"name": "ipv6_address",
"title": "IPv6 Address",
"description": "IPv6 address for an AAAA record.",
"type": "str",
"required": true,
"needs": [
"record_type=AAAA"
],
"config": {
"placeholder": "2001:db8::1"
}
},
{
"name": "target_hostname",
"title": "Target Hostname",
"description": "Canonical hostname target for a CNAME record.",
"type": "str",
"required": true,
"needs": [
"record_type=CNAME"
],
"config": {
"placeholder": "origin.example.com"
}
},
{
"name": "text_value",
"title": "TXT Value",
"description": "Text value for a TXT record.",
"type": "str",
"required": true,
"needs": [
"record_type=TXT"
],
"config": {
"placeholder": "v=spf1 include:_spf.example.com ~all",
"textarea": true
}
},
{
"name": "mail_server",
"title": "Mail Server",
"description": "Mail server hostname for an MX record.",
"type": "str",
"required": true,
"needs": [
"record_type=MX"
],
"config": {
"placeholder": "mail.example.com"
}
},
{
"name": "priority",
"title": "Priority",
"description": "MX record priority (lower value = higher priority).",
"type": "int",
"default": 10,
"required": true,
"needs": [
"record_type=MX"
],
"config": {
"placeholder": "10"
}
},
{
"name": "proxied",
"title": "Proxy",
"type": "bool",
"default": true,
"needs": [
"record_type=A,AAAA,CNAME"
]
}
]
}
]
}
@@ -0,0 +1,17 @@
resource "cloudflare_zero_trust_tunnel_cloudflared_config" "<< resource_name >>" {
account_id = "<< account_id_value >>"
tunnel_id = "<< tunnel_id >>"
config = {
ingress = [
{
hostname = "<< ingress_hostname >>"
service = "<< ingress_service >>"
},
{
service = "<< fallback_service >>"
}
]
}
}
@@ -0,0 +1,89 @@
{
"slug": "cloudflare-zero-trust-tunnel-config",
"kind": "terraform",
"metadata": {
"name": "Cloudflare Zero Trust Tunnel Config",
"description": "Creates a Cloudflare Zero Trust tunnel ingress configuration for a cloudflared tunnel with a primary hostname and fallback service.",
"tags": [],
"icon": {
"provider": "selfhst",
"id": "cloudflare-zero-trust"
},
"draft": false,
"version": {
"name": "5.12.0",
"source_dep_name": "manual/cloudflare-zero-trust-tunnel-config"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "resource_name",
"type": "str",
"title": "Resource Name",
"required": false,
"default": "tunnel_config",
"config": {
"placeholder": "tunnel_config"
}
},
{
"name": "account_id_value",
"type": "str",
"title": "Cloudflare account ID",
"required": true
},
{
"name": "tunnel_id",
"type": "str",
"title": "Cloudflare tunnel ID",
"required": true,
"description": "Cloudflare tunnel identifier.",
"config": {
"placeholder": "Tunnel ID"
}
}
]
},
{
"title": "Ingress",
"name": "ingress",
"items": [
{
"name": "ingress_hostname",
"type": "str",
"title": "Hostname",
"required": true,
"description": "Public hostname routed through the tunnel",
"config": {
"placeholder": "app.home.arpa"
}
},
{
"name": "ingress_service",
"type": "str",
"title": "Service URL",
"required": true,
"description": "Backend service URL for the hostname",
"config": {
"placeholder": "https://app.internal"
}
},
{
"name": "fallback_service",
"type": "str",
"title": "Fallback Service",
"required": false,
"default": "http_status:404",
"description": "Fallback service for unmatched requests",
"config": {
"placeholder": "http_status:404"
}
}
]
}
]
}
@@ -0,0 +1,3 @@
data "cloudflare_zone" "<< resource_name >>" {
zone_id = "<< cloudflare_zone_id >>"
}
@@ -0,0 +1,44 @@
{
"slug": "cloudflare-zone-data",
"kind": "terraform",
"metadata": {
"name": "Cloudflare Zone (datasource)",
"description": "",
"icon": {
"provider": "selfhst",
"id": "cloudflare",
"color": "default"
},
"draft": false,
"version": {
"name": "1.0.0",
"source_dep_name": "manual/cloudflare-zone-data"
}
},
"variables": [
{
"name": "terraform",
"title": "Terraform",
"items": [
{
"name": "resource_name",
"title": "Resource Name",
"type": "str",
"required": true,
"config": {
"placeholder": "my_cloudflare_zone"
}
},
{
"name": "cloudflare_zone_id",
"title": "Cloudflare Zone ID",
"type": "str",
"config": {
"placeholder": "123456789"
},
"required": true
}
]
}
]
}
@@ -0,0 +1,23 @@
resource "cloudflare_zero_trust_access_application" "<< resource_name >>" {
zone_id = data.cloudflare_zone.main.zone_id
name = "<< app_name >>"
domain = "<< domain >>"
type = "self_hosted"
session_duration = "<< session_duration >>"
policies = [
<%- if service_token_enabled %>
{
id = cloudflare_zero_trust_access_policy.<< resource_name >>_service_token.id
}
<%- if ip_policy_enabled %>
,
<%- endif %>
<%- endif %>
<%- if ip_policy_enabled %>
{
id = cloudflare_zero_trust_access_policy.<< resource_name >>_ip.id
}
<%- endif %>
]
}
@@ -0,0 +1,28 @@
<%- if service_token_enabled %>
resource "cloudflare_zero_trust_access_policy" "<< resource_name >>_service_token" {
account_id = data.cloudflare_account.main.account_id
name = "<< service_token_policy_name >>"
decision = "non_identity"
include = [{
service_token = {
token_id = "<< service_token_id >>"
}
}]
session_duration = "<< session_duration >>"
}
<%- endif %>
<%- if ip_policy_enabled %>
resource "cloudflare_zero_trust_access_policy" "<< resource_name >>_ip" {
account_id = data.cloudflare_account.main.account_id
name = "<< ip_policy_name >>"
decision = "non_identity"
include = [
for ip_range in split(",", "<< ip_ranges >>") : {
ip = {
ip = trimspace(ip_range)
}
}
]
session_duration = "<< session_duration >>"
}
<%- endif %>
@@ -0,0 +1,7 @@
data "cloudflare_account" "main" {
account_id = "<< account_id_value >>"
}
data "cloudflare_zone" "main" {
zone_id = "<< zone_id_value >>"
}
@@ -0,0 +1,157 @@
{
"slug": "cloudflare-ztna-application",
"kind": "terraform",
"metadata": {
"name": "Cloudflare Zero Trust Access Application",
"description": "Creates a Cloudflare Zero Trust Access application with service token and IP-based access policies.",
"tags": [],
"icon": {
"provider": "selfhst",
"id": "cloudflare-zero-trust"
},
"draft": false,
"version": {
"name": "5.12.0",
"source_dep_name": "manual/cloudflare-ztna-application"
}
},
"variables": [
{
"title": "Application",
"name": "application",
"items": [
{
"name": "app_name",
"type": "str",
"title": "Application name",
"required": false,
"default": "application",
"config": {
"placeholder": "application"
}
},
{
"name": "domain",
"type": "str",
"title": "Application domain",
"required": true,
"config": {
"placeholder": "app.home.arpa"
}
},
{
"name": "session_duration",
"type": "str",
"title": "Session Duration",
"required": false,
"default": "15m",
"description": "Session duration (e.g., 15m, 1h, 24h)",
"config": {
"placeholder": "15m"
}
}
]
},
{
"title": "General",
"name": "general",
"items": [
{
"name": "account_id_value",
"type": "str",
"title": "Cloudflare Account ID",
"required": true
},
{
"name": "resource_name",
"type": "str",
"title": "Resource Name",
"required": false,
"default": "ztna_app",
"config": {
"placeholder": "ztna_app"
}
},
{
"name": "zone_id_value",
"type": "str",
"title": "Cloudflare Zone ID",
"required": true
}
]
},
{
"title": "IP-Based Policy",
"name": "ip-policy",
"items": [
{
"name": "ip_policy_enabled",
"type": "bool",
"title": "IP Policy",
"required": false,
"default": false
},
{
"name": "ip_policy_name",
"type": "str",
"title": "IP Policy Name",
"required": false,
"default": "ip_policy",
"description": "Policy name for IP-based access",
"config": {
"placeholder": "ip_policy"
}
},
{
"name": "ip_ranges",
"type": "str",
"title": "IP Ranges",
"required": false,
"default": "IP_RANGE",
"description": "Comma-separated list of IP ranges (CIDR notation)",
"needs": [
"ip_policy_enabled=true"
],
"config": {
"placeholder": "IP_RANGE"
}
}
]
},
{
"title": "Service Token Policy",
"name": "service-token-policy",
"items": [
{
"name": "service_token_enabled",
"type": "bool",
"title": "Service Token",
"required": false,
"default": false
},
{
"name": "service_token_id",
"type": "str",
"title": "Service Token ID",
"required": false,
"needs": [
"service_token_enabled=true"
]
},
{
"name": "service_token_policy_name",
"type": "str",
"title": "Service Token Name",
"required": false,
"default": "service_token_policy",
"needs": [
"service_token_enabled=true"
],
"config": {
"placeholder": "service_token_policy"
}
}
]
}
]
}
+13
View File
@@ -0,0 +1,13 @@
# Cloudflare Credentials
# ---
# Credential Variables needed for Cloudflare
# Cloudflare Config
variable "cloudflare_email" {
description = "The email address for your Cloudflare account"
type = string
}
variable "cloudflare_api_key" {
description = "The API key for your Cloudflare account"
type = string
}
+12
View File
@@ -0,0 +1,12 @@
# Cloudflare DNS
# ---
# Templates to manage DNS Records on Cloudflare
# A Record
resource "cloudflare_record" "your-dns-record-name" {
zone_id = "your-zone-id"
name = "your-public-dns-value"
value = "your-public-ip-address"
type = "A"
proxied = false # set to true, to hide public IP
}
+19
View File
@@ -0,0 +1,19 @@
# Cloudflare Provider
# ---
# Initial Provider Configuration for Cloudflare
terraform {
required_version = ">= 0.13.0"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
provider "cloudflare" {
email = var.cloudflare_email
api_key = var.cloudflare_api_key
}
@@ -0,0 +1,8 @@
resource "dns_a_record_set" "dns_record" {
zone = "<< dns_zone >>"
name = "<< dns_hostname >>"
addresses = [
"<< ip_address >>"
]
ttl = "<< dns_ttl | default('3600') >>"
}
+69
View File
@@ -0,0 +1,69 @@
{
"slug": "dns-a-record-tsig",
"kind": "terraform",
"metadata": {
"name": "DNS Record A (TSIG)",
"description": "Creates a DNS A record using TSIG-authenticated dynamic DNS updates. Maps a hostname to an IP address on a TSIG-enabled DNS server.",
"icon": {
"provider": "selfhst",
"id": "bind-9",
"color": "default"
},
"draft": false,
"version": {
"name": "3.5.0",
"source_dep_name": "hashicorp/dns",
"source_dep_version": "3.5.0"
}
},
"variables": [
{
"name": "record",
"title": "DNS Record Configuration",
"items": [
{
"name": "dns_hostname",
"title": "Hostname",
"type": "str",
"config": {
"placeholder": "hostname"
},
"required": true
},
{
"name": "dns_zone",
"title": "Zone",
"type": "str",
"config": {
"placeholder": "home.arpa."
},
"required": true
},
{
"name": "ip_address",
"title": "IP Address",
"type": "str",
"config": {
"placeholder": "192.168.0.1/24"
},
"required": true
},
{
"name": "dns_ttl",
"title": "TTL",
"description": "Time to live (TTL) for the DNS record in seconds (default: 3600)",
"type": "int",
"default": 3600,
"config": {
"unit": "seconds",
"slider": true,
"min": 60,
"max": 86400,
"step": 60,
"placeholder": "3600"
}
}
]
}
]
}
+31
View File
@@ -0,0 +1,31 @@
resource "kubernetes_namespace" "certmanager" {
metadata {
name = "certmanager"
}
}
resource "helm_release" "certmanager" {
depends_on = [kubernetes_namespace.certmanager]
name = "certmanager"
namespace = "certmanager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
# Install Kubernetes CRDs
set {
name = "installCRDs"
value = "true"
}
}
# (Optional) Create a Time-Sleep for Certificates and Issuer Manifests to deploy later
# resource "time_sleep" "wait_for_certmanager" {
#
# depends_on = [helm_release.certmanager]
#
# create_duration = "10s"
# }
+46
View File
@@ -0,0 +1,46 @@
resource "kubernetes_namespace" "traefik" {
metadata {
name = "traefik"
}
}
resource "helm_release" "traefik" {
depends_on = [kubernetes_namespace.traefik]
name = "traefik"
namespace = "traefik"
repository = "https://helm.traefik.io/traefik"
chart = "traefik"
# Set Traefik as the Default Ingress Controller
set {
name = "ingressClass.enabled"
value = "true"
}
set {
name = "ingressClass.isDefaultClass"
value = "true"
}
# Default Redirect
set {
name = "ports.web.redirectTo"
value = "websecure"
}
# Enable TLS on Websecure
set {
name = "ports.websecure.tls.enabled"
value = "true"
}
# TLS Options (that's not working for some reason...)
set {
name = "tlsOptions.default.minVersion"
value = "VersionTLS12"
}
}
+7
View File
@@ -0,0 +1,7 @@
resource "kubectl_manifest" "your-manifest-file" {
yaml_body = <<YAML
# Put your Manifest-file Content right here...
# ...
YAML
}
+24
View File
@@ -0,0 +1,24 @@
# Kubectl Provider
# ---
# Initial Provider Configuration for Kubectl
terraform {
required_version = ">= 0.13.0"
required_providers {
kubectl = {
source = "gavinbunney/kubectl"
version = "1.14.0"
}
}
}
# Dynamic Configuration from CIVO Kubernetes deployment
# provider "kubectl" {
# host = "${yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).clusters.0.cluster.server}"
# client_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).users.0.user.client-certificate-data)}"
# client_key = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).users.0.user.client-key-data)}"
# cluster_ca_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).clusters.0.cluster.certificate-authority-data)}"
# load_config_file = false
# }
+41
View File
@@ -0,0 +1,41 @@
resource "kubernetes_deployment" "your-deployment" {
depends_on = [kubernetes_namespace.your-namespace]
metadata {
name = "your-deployment"
namespace = "your-namespace"
labels = {
app = "your-app-selector"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "your-app-selector"
}
}
template {
metadata {
labels = {
app = "your-app-selector"
}
}
spec {
container {
image = "your-image:latest"
name = "your-container"
port {
container_port = 80
}
}
}
}
}
}
+39
View File
@@ -0,0 +1,39 @@
resource "kubernetes_ingress_v1" "your-ingress" {
depends_on = [kubernetes_namespace.your-namespace]
metadata {
name = "your-ingress"
namespace = "your-namespace"
}
spec {
rule {
host = "your-domain"
http {
path {
path = "/"
backend {
service {
name = "your-service"
port {
number = 80
}
}
}
}
}
}
# (Optional) Add an SSL Certificate
# tls {
# secret_name = "ssl-certificate-object"
# hosts = ["your-domain"]
# }
}
}
+23
View File
@@ -0,0 +1,23 @@
# Kubernetes Provider
# ---
# Initial Provider Configuration for Kubernetes
terraform {
required_version = ">= 0.13.0"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.31.0"
}
}
}
# Dynamic Configuration from CIVO Kubernetes deployment
# provider "kubernetes" {
# host = "${yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).clusters.0.cluster.server}"
# client_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).users.0.user.client-certificate-data)}"
# client_key = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).users.0.user.client-key-data)}"
# cluster_ca_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.your-kubernetes-cluster.kubeconfig).clusters.0.cluster.certificate-authority-data)}"
# }
+15
View File
@@ -0,0 +1,15 @@
resource "kubernetes_secret" "cloudflare_api_key_secret" {
depends_on = [kubernetes_namespace.your-namespace-object]
metadata {
name = "cloudflare-api-key-secret"
namespace = "your-namespace"
}
data = {
api-key = var.your-api-key-variable
}
type = "Opaque"
}
+19
View File
@@ -0,0 +1,19 @@
resource "kubernetes_service" "your-service" {
depends_on = [kubernetes_namespace.your-namespace]
metadata {
name = "your-service"
namespace = "your-namespace"
}
spec {
selector = {
app = "your-app-selector"
}
port {
port = 80
}
type = "ClusterIP"
}
}
+53
View File
@@ -0,0 +1,53 @@
<%- if peer_names %>
locals {
netbird_group_peer_names = [
for name in split(",", "<< peer_names >>") : trimspace(name)
if trimspace(name) != ""
]
}
data "netbird_peer" "group_peers" {
for_each = toset(local.netbird_group_peer_names)
name = each.value
}
<%- endif %>
<%- if resource_lookups %>
locals {
netbird_group_resource_items = [
for item in split(";", "<< resource_lookups >>") : trimspace(item)
if trimspace(item) != ""
]
netbird_group_resource_lookup_map = {
for item in local.netbird_group_resource_items :
item => {
network = trimspace(split("|", item)[0])
name = trimspace(split("|", item)[1])
}
}
netbird_group_resource_network_names = distinct([
for lookup in values(local.netbird_group_resource_lookup_map) : lookup.network
])
}
data "netbird_network" "group_resource_networks" {
for_each = toset(local.netbird_group_resource_network_names)
name = each.value
}
data "netbird_network_resource" "group_resources" {
for_each = local.netbird_group_resource_lookup_map
network_id = data.netbird_network.group_resource_networks[each.value.network].id
name = each.value.name
}
<%- endif %>
resource "netbird_group" "group" {
name = "<< group_name >>"
<%- if peer_names %>
peers = [for name in local.netbird_group_peer_names : data.netbird_peer.group_peers[name].id]
<%- endif %>
<%- if resource_lookups %>
resources = [for item in local.netbird_group_resource_items : data.netbird_network_resource.group_resources[item].id]
<%- endif %>
}
+66
View File
@@ -0,0 +1,66 @@
{
"slug": "netbird-group",
"kind": "terraform",
"metadata": {
"name": "NetBird Group",
"description": "Creates a NetBird group and can optionally attach peers and network resources.",
"tags": [
"netbird",
"terraform"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": false,
"version": {
"name": "0.0.12",
"source_dep_name": "manual/netbird-group"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "group_name",
"type": "str",
"title": "Group Name",
"required": true,
"config": {
"placeholder": "Engineering"
}
}
]
},
{
"title": "Membership",
"name": "membership",
"items": [
{
"name": "peer_names",
"type": "str",
"title": "Peer Names",
"required": false,
"description": "Comma-separated existing NetBird peer names to attach to the group.",
"config": {
"placeholder": "web-app,db-app",
"textarea": true
}
},
{
"name": "resource_lookups",
"type": "str",
"title": "Resource Lookups",
"required": false,
"description": "Semicolon-separated `network_name|resource_name` entries for existing NetBird network resources to attach to the group.",
"config": {
"placeholder": "production-network|internal-app;production-network|corp-lan",
"textarea": true
}
}
]
}
]
}
@@ -0,0 +1,29 @@
data "netbird_network" "parent_network" {
name = "<< network_name >>"
}
<%- for group_name in group_names.split(',') %>
<%- if group_name|trim %>
data "netbird_group" "group_<< group_name|trim|replace(' ', '_')|replace('-', '_') >>" {
name = "<< group_name|trim >>"
}
<%- endif %>
<%- endfor %>
resource "netbird_network_resource" "network_resource" {
network_id = data.netbird_network.parent_network.id
name = "<< resource_name >>"
<%- if resource_description %>
description = "<< resource_description >>"
<%- endif %>
address = "<< resource_address >>"
groups = [
<%- for group_name in group_names.split(',') %>
<%- if group_name|trim %>
data.netbird_group.group_<< group_name|trim|replace(' ', '_')|replace('-', '_') >>.id,
<%- endif %>
<%- endfor %>
]
enabled = << resource_enabled | lower >>
}
@@ -0,0 +1,88 @@
{
"slug": "netbird-network-resource",
"kind": "terraform",
"metadata": {
"name": "NetBird Network Resource",
"description": "Creates a NetBird network resource and attaches it to one or more groups.",
"tags": [
"netbird",
"terraform"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": true,
"version": {
"name": "0.0.15",
"source_dep_name": "manual/netbird-network-resource"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "resource_name",
"type": "str",
"title": "Name",
"required": true,
"config": {
"placeholder": "My Network Resource"
}
},
{
"name": "network_name",
"type": "str",
"title": "Network Name",
"required": true,
"description": "Existing NetBird network name for the parent network resource lookup.",
"config": {
"placeholder": "production-network"
}
},
{
"name": "resource_address",
"type": "str",
"title": "Address",
"required": true,
"description": "Host, subnet, or domain address for the resource.",
"config": {
"placeholder": "10.20.0.0/24"
}
},
{
"name": "group_names",
"type": "str",
"title": "Group Names",
"required": true,
"description": "Comma-separated existing NetBird group names to attach to this resource.",
"config": {
"placeholder": "Administrators, DevOps",
"textarea": true
},
"default": "Administrators"
},
{
"name": "resource_description",
"type": "str",
"title": "Description",
"required": false,
"description": "Optional description for the NetBird network resource.",
"config": {
"placeholder": "Internal application endpoint",
"textarea": true
}
},
{
"name": "resource_enabled",
"type": "bool",
"title": "Enabled",
"required": false,
"default": true
}
]
}
]
}
@@ -0,0 +1,36 @@
data "netbird_network" "router_network" {
name = "<< network_name >>"
}
<%- if router_target_mode == "peer" %>
data "netbird_peer" "router_peer" {
name = "<< peer_name >>"
}
<%- endif %>
<%- if router_target_mode == "peer_groups" %>
locals {
router_peer_group_names = [
for name in split(",", "<< peer_group_names >>") : trimspace(name)
if trimspace(name) != ""
]
}
data "netbird_group" "router_peer_groups" {
for_each = toset(local.router_peer_group_names)
name = each.value
}
<%- endif %>
resource "netbird_network_router" "network_router" {
network_id = data.netbird_network.router_network.id
enabled = << router_enabled | lower >>
masquerade = << router_masquerade | lower >>
metric = << router_metric >>
<%- if router_target_mode == "peer" %>
peer = data.netbird_peer.router_peer.id
<%- endif %>
<%- if router_target_mode == "peer_groups" %>
peer_groups = [for name in local.router_peer_group_names : data.netbird_group.router_peer_groups[name].id]
<%- endif %>
}
@@ -0,0 +1,112 @@
{
"slug": "netbird-network-router",
"kind": "terraform",
"metadata": {
"name": "NetBird Network Router",
"description": "Creates a NetBird network router and targets either a single peer or a peer group.",
"tags": [
"netbird",
"terraform"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": false,
"version": {
"name": "0.0.12",
"source_dep_name": "manual/netbird-network-router"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "router_enabled",
"type": "bool",
"title": "Enabled",
"required": false,
"default": true
},
{
"name": "router_masquerade",
"type": "bool",
"title": "Masquerade",
"required": false,
"default": true,
"description": "Masquerade routed traffic on the selected router peer."
},
{
"name": "router_metric",
"type": "int",
"title": "Metric",
"required": false,
"default": 9999,
"description": "Router metric. Lower values have higher priority.",
"config": {
"placeholder": "9999"
}
},
{
"name": "router_target_mode",
"type": "enum",
"title": "Target Mode",
"required": true,
"default": "peer_groups",
"description": "Route through a single peer or a peer group.",
"config": {
"options": [
"peer_groups",
"peer"
]
}
}
]
},
{
"title": "Lookups",
"name": "lookups",
"items": [
{
"name": "network_name",
"type": "str",
"title": "Network Name",
"required": true,
"description": "Existing NetBird network name for the parent network lookup.",
"config": {
"placeholder": "production-network"
}
},
{
"name": "peer_name",
"type": "str",
"title": "Peer Name",
"required": true,
"description": "Existing NetBird peer name for the router peer lookup.",
"needs": [
"router_target_mode=peer"
],
"config": {
"placeholder": "gateway-peer"
}
},
{
"name": "peer_group_names",
"type": "str",
"title": "Peer Group Names",
"required": true,
"description": "Comma-separated existing NetBird group names for router groups.",
"needs": [
"router_target_mode=peer_groups"
],
"config": {
"placeholder": "Routers,Gateways",
"textarea": true
}
}
]
}
]
}
+6
View File
@@ -0,0 +1,6 @@
resource "netbird_network" "network" {
name = "<< network_name >>"
<%- if network_description %>
description = "<< network_description >>"
<%- endif %>
}
+49
View File
@@ -0,0 +1,49 @@
{
"slug": "netbird-network",
"kind": "terraform",
"metadata": {
"name": "NetBird Network",
"description": "Creates a NetBird network for organizing resources and routers.",
"tags": [
"netbird",
"terraform"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": false,
"version": {
"name": "0.0.10",
"source_dep_name": "manual/netbird-network"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "network_name",
"type": "str",
"title": "Network Name",
"required": true,
"config": {
"placeholder": "Homelab"
}
},
{
"name": "network_description",
"type": "str",
"title": "Description",
"required": false,
"description": "Optional description for the NetBird network.",
"config": {
"placeholder": "Internal services network",
"textarea": true
}
}
]
}
]
}
+84
View File
@@ -0,0 +1,84 @@
locals {
policy_source_group_names = [
for name in split(",", "<< source_group_names >>") : trimspace(name)
if trimspace(name) != ""
]
policy_destination_group_names = [
for name in split(",", "<< destination_group_names >>") : trimspace(name)
if trimspace(name) != ""
]
<%- if source_posture_check_names %>
policy_source_posture_check_names = [
for name in split(",", "<< source_posture_check_names >>") : trimspace(name)
if trimspace(name) != ""
]
<%- endif %>
<%- if authorized_group_entries %>
policy_authorized_group_entries = [
for entry in split(";", "<< authorized_group_entries >>") : trimspace(entry)
if trimspace(entry) != ""
]
policy_authorized_group_map = {
for entry in local.policy_authorized_group_entries :
trimspace(split("|", entry)[0]) => [
for username in split(",", split("|", entry)[1]) : trimspace(username)
if trimspace(username) != ""
]
}
<%- endif %>
policy_group_names = distinct(concat(
local.policy_source_group_names,
local.policy_destination_group_names,
<%- if authorized_group_entries %>
keys(local.policy_authorized_group_map),
<%- endif %>
[]
))
}
data "netbird_group" "policy_groups" {
for_each = toset(local.policy_group_names)
name = each.value
}
<%- if source_posture_check_names %>
data "netbird_posture_check" "source_posture_checks" {
for_each = toset(local.policy_source_posture_check_names)
name = each.value
}
<%- endif %>
resource "netbird_policy" "policy" {
name = "<< policy_name >>"
<%- if policy_description %>
description = "<< policy_description >>"
<%- endif %>
enabled = << policy_enabled | lower >>
<%- if source_posture_check_names %>
source_posture_checks = [for name in local.policy_source_posture_check_names : data.netbird_posture_check.source_posture_checks[name].id]
<%- endif %>
rule {
name = "<< rule_name >>"
action = "<< rule_action >>"
bidirectional = << rule_bidirectional | lower >>
enabled = << rule_enabled | lower >>
protocol = "<< rule_protocol >>"
sources = [for name in local.policy_source_group_names : data.netbird_group.policy_groups[name].id]
destinations = [for name in local.policy_destination_group_names : data.netbird_group.policy_groups[name].id]
<%- if rule_description %>
description = "<< rule_description >>"
<%- endif %>
<%- if ports %>
ports = [<< ports >>]
<%- endif %>
<%- if rule_protocol == "netbird-ssh" %>
<%- if authorized_group_entries %>
authorized_groups = {
for group_name, users in local.policy_authorized_group_map :
data.netbird_group.policy_groups[group_name].id => users
}
<%- endif %>
<%- endif %>
}
}
+192
View File
@@ -0,0 +1,192 @@
{
"slug": "netbird-policy",
"kind": "terraform",
"metadata": {
"name": "NetBird Policy",
"description": "Creates a NetBird access policy with a single rule and optional posture checks.",
"tags": [
"netbird",
"terraform"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": false,
"version": {
"name": "0.0.12",
"source_dep_name": "manual/netbird-policy"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "policy_name",
"type": "str",
"title": "Policy Name",
"required": true,
"config": {
"placeholder": "Allow Internal HTTPS"
}
},
{
"name": "policy_description",
"type": "str",
"title": "Description",
"required": false,
"description": "Optional description for the policy.",
"config": {
"placeholder": "Allow app traffic from users to services",
"textarea": true
}
},
{
"name": "policy_enabled",
"type": "bool",
"title": "Enabled",
"required": false,
"default": true
}
]
},
{
"title": "Rule",
"name": "rule",
"items": [
{
"name": "rule_name",
"type": "str",
"title": "Rule Name",
"required": true,
"config": {
"placeholder": "HTTPS"
}
},
{
"name": "rule_description",
"type": "str",
"title": "Rule Description",
"required": false,
"description": "Optional description for the rule.",
"config": {
"placeholder": "Allow HTTPS from users to the app group",
"textarea": true
}
},
{
"name": "rule_action",
"type": "enum",
"title": "Action",
"required": false,
"default": "accept",
"description": "Policy action to take.",
"config": {
"options": [
"accept",
"drop"
]
}
},
{
"name": "rule_protocol",
"type": "enum",
"title": "Protocol",
"required": false,
"default": "tcp",
"description": "Protocol enforced by the policy rule.",
"config": {
"options": [
"tcp",
"udp",
"icmp",
"all",
"netbird-ssh"
]
}
},
{
"name": "rule_bidirectional",
"type": "bool",
"title": "Bidirectional",
"required": false,
"default": true,
"description": "Allow traffic in both directions between the selected groups."
},
{
"name": "rule_enabled",
"type": "bool",
"title": "Rule Enabled",
"required": false,
"default": true
},
{
"name": "source_group_names",
"type": "str",
"title": "Source Group Names",
"required": true,
"description": "Comma-separated existing NetBird source group names.",
"config": {
"placeholder": "Users,Developers",
"textarea": true
}
},
{
"name": "destination_group_names",
"type": "str",
"title": "Destination Group Names",
"required": true,
"description": "Comma-separated existing NetBird destination group names.",
"config": {
"placeholder": "Services,Internal Apps",
"textarea": true
}
},
{
"name": "ports",
"type": "str",
"title": "Ports",
"required": false,
"description": "Raw HCL list entries for ports, for example `\"443\", \"8443\"`.",
"config": {
"placeholder": "\"443\"",
"textarea": true
}
},
{
"name": "authorized_group_entries",
"type": "str",
"title": "Authorized Group Entries",
"required": false,
"description": "Semicolon-separated `group_name|user1,user2` entries for NetBird SSH local-user authorization.",
"needs": [
"rule_protocol=netbird-ssh"
],
"config": {
"placeholder": "Admins|ubuntu;SRE|root,ec2-user",
"textarea": true
}
}
]
},
{
"title": "Posture Checks",
"name": "posture-checks",
"items": [
{
"name": "source_posture_check_names",
"type": "str",
"title": "Posture Check Names",
"required": false,
"description": "Comma-separated existing NetBird posture check names.",
"config": {
"placeholder": "Managed Devices,Minimum Version",
"textarea": true
}
}
]
}
]
}
@@ -0,0 +1,145 @@
<%- if domain_mode == "free" %>
data "netbird_reverse_proxy_domain" "free" {
type = "free"
}
<%- endif %>
<%- if domain_mode == "custom" %>
data "netbird_reverse_proxy_domain" "custom" {
domain = "<< custom_domain >>"
validated = true
}
<%- endif %>
<%- if target_type == "peer" %>
data "netbird_peer" "target_peer" {
name = "<< target_peer_name >>"
}
<%- endif %>
<%- if target_type == "host" %>
data "netbird_network" "target_network" {
name = "<< target_network_name >>"
}
data "netbird_network_resource" "target_resource" {
network_id = data.netbird_network.target_network.id
name = "<< target_host_name >>"
}
<%- endif %>
<%- if target_type == "domain" %>
data "netbird_network" "target_network" {
name = "<< target_network_name >>"
}
data "netbird_network_resource" "target_resource" {
network_id = data.netbird_network.target_network.id
name = "<< target_domain_name >>"
}
<%- endif %>
<%- if target_type == "subnet" %>
data "netbird_network" "target_network" {
name = "<< target_network_name >>"
}
data "netbird_network_resource" "target_resource" {
network_id = data.netbird_network.target_network.id
name = "<< target_subnet_name >>"
}
<%- endif %>
<%- if target_type != "peer" %>
locals {
reverse_proxy_target_resource_type = can(cidrnetmask(data.netbird_network_resource.target_resource.address)) ? "subnet" : (length(regexall(":", data.netbird_network_resource.target_resource.address)) > 0 ? "host" : (length(regexall("[A-Za-z*]", data.netbird_network_resource.target_resource.address)) > 0 ? "domain" : "host"))
}
<%- endif %>
<%- if bearer_distribution_group_names %>
locals {
reverse_proxy_bearer_group_names = [
for name in split(",", "<< bearer_distribution_group_names >>") : trimspace(name)
if trimspace(name) != ""
]
}
data "netbird_group" "bearer_distribution_groups" {
for_each = toset(local.reverse_proxy_bearer_group_names)
name = each.value
}
<%- endif %>
resource "netbird_reverse_proxy_service" "reverse_proxy_service" {
name = "<< service_name >>"
<%- if domain_mode == "free" %>
domain = data.netbird_reverse_proxy_domain.free.domain
<%- endif %>
<%- if domain_mode == "custom" %>
domain = data.netbird_reverse_proxy_domain.custom.domain
<%- endif %>
enabled = << service_enabled | lower >>
pass_host_header = << pass_host_header | lower >>
rewrite_redirects = << rewrite_redirects | lower >>
targets = [{
<%- if target_type == "peer" %>
target_id = data.netbird_peer.target_peer.id
<%- endif %>
<%- if target_type == "host" %>
target_id = data.netbird_network_resource.target_resource.id
<%- endif %>
<%- if target_type == "domain" %>
target_id = data.netbird_network_resource.target_resource.id
<%- endif %>
<%- if target_type == "subnet" %>
target_id = data.netbird_network_resource.target_resource.id
<%- endif %>
<%- if target_type == "peer" %>
target_type = "peer"
<%- endif %>
<%- if target_type != "peer" %>
target_type = local.reverse_proxy_target_resource_type
<%- endif %>
port = << target_port >>
protocol = "<< target_protocol >>"
enabled = << target_enabled | lower >>
<%- if target_host %>
host = "<< target_host >>"
<%- endif %>
<%- if not target_host and target_type != "peer" %>
host = local.reverse_proxy_target_resource_type == "subnet" ? split("/", data.netbird_network_resource.target_resource.address)[0] : null
<%- endif %>
<%- if target_path %>
path = "<< target_path >>"
<%- endif %>
}]
auth = {
<%- if auth_mode == "link" %>
link_auth = {
enabled = true
}
<%- endif %>
<%- if auth_mode == "password" %>
password_auth = {
enabled = true
password = "<< auth_password >>"
}
<%- endif %>
<%- if auth_mode == "pin" %>
pin_auth = {
enabled = true
pin = "<< auth_pin >>"
}
<%- endif %>
<%- if auth_mode == "bearer" %>
bearer_auth = {
enabled = true
<%- if bearer_distribution_group_names %>
distribution_groups = [for name in local.reverse_proxy_bearer_group_names : data.netbird_group.bearer_distribution_groups[name].id]
<%- endif %>
}
<%- endif %>
}
}
@@ -0,0 +1,283 @@
{
"slug": "netbird-reverse-proxy-service",
"kind": "terraform",
"metadata": {
"name": "NetBird Reverse Proxy Service",
"description": "Creates a NetBird reverse proxy service with one backend target and configurable authentication.",
"tags": [
"netbird",
"terraform",
"reverse-proxy"
],
"icon": {
"provider": "selfhst",
"id": "netbird"
},
"draft": false,
"version": {
"name": "0.0.17",
"source_dep_name": "manual/netbird-reverse-proxy-service"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "service_name",
"type": "str",
"title": "Service Name",
"required": true,
"config": {
"placeholder": "web-app"
}
},
{
"name": "domain_mode",
"type": "enum",
"title": "Domain Mode",
"required": true,
"default": "free",
"config": {
"options": [
"free",
"custom"
]
}
},
{
"name": "custom_domain",
"type": "str",
"title": "Custom Domain",
"required": true,
"description": "Validated custom domain for the reverse proxy service.",
"needs": [
"domain_mode=custom"
],
"config": {
"placeholder": "app.example.com"
}
},
{
"name": "service_enabled",
"type": "bool",
"title": "Enabled",
"required": false,
"default": true
},
{
"name": "pass_host_header",
"type": "bool",
"title": "Pass Host Header",
"required": false,
"default": false,
"description": "Pass the original client Host header through to the backend."
},
{
"name": "rewrite_redirects",
"type": "bool",
"title": "Rewrite Redirects",
"required": false,
"default": false,
"description": "Rewrite backend redirect locations to the public-facing service domain."
}
]
},
{
"title": "Target",
"name": "target",
"items": [
{
"name": "target_type",
"type": "enum",
"title": "Target Type",
"required": true,
"default": "peer",
"description": "Target type for the backend service.",
"config": {
"options": [
"peer",
"host",
"domain",
"subnet"
]
}
},
{
"name": "target_peer_name",
"type": "str",
"title": "Peer Name",
"required": true,
"description": "Existing NetBird peer name to resolve via `data \"netbird_peer\"` when `target_type=peer`.",
"needs": [
"target_type=peer"
],
"config": {
"placeholder": "web-app"
}
},
{
"name": "target_network_name",
"type": "str",
"title": "Network Name",
"required": true,
"description": "Existing NetBird network name that contains the selected host, domain, or subnet resource.",
"needs": [
"target_type=host,domain,subnet"
],
"config": {
"placeholder": "production-network"
}
},
{
"name": "target_host_name",
"type": "str",
"title": "Host Resource Name",
"required": true,
"description": "Existing NetBird network resource name for a host target.",
"needs": [
"target_type=host"
],
"config": {
"placeholder": "internal-app-host"
}
},
{
"name": "target_domain_name",
"type": "str",
"title": "Domain Resource Name",
"required": true,
"description": "Existing NetBird network resource name for a domain target.",
"needs": [
"target_type=domain"
],
"config": {
"placeholder": "app.example.internal"
}
},
{
"name": "target_subnet_name",
"type": "str",
"title": "Subnet Resource Name",
"required": true,
"description": "Existing NetBird network resource name for a subnet target.",
"needs": [
"target_type=subnet"
],
"config": {
"placeholder": "corp-lan"
}
},
{
"name": "target_port",
"type": "int",
"title": "Target Port",
"required": true,
"default": 8080,
"description": "Backend port for the target.",
"config": {
"placeholder": "8080"
}
},
{
"name": "target_protocol",
"type": "enum",
"title": "Target Protocol",
"required": true,
"default": "http",
"config": {
"options": [
"http",
"https"
]
}
},
{
"name": "target_enabled",
"type": "bool",
"title": "Target Enabled",
"required": false,
"default": true
},
{
"name": "target_host",
"type": "str",
"title": "Resolved Host",
"required": false,
"description": "Optional backend IP or domain override for the target. Subnet targets need a host IP within the CIDR range.",
"config": {
"placeholder": "10.20.30.40"
}
},
{
"name": "target_path",
"type": "str",
"title": "Path Prefix",
"required": false,
"description": "Optional URL path prefix for the backend target.",
"config": {
"placeholder": "/"
}
}
]
},
{
"title": "Authentication",
"name": "authentication",
"items": [
{
"name": "auth_mode",
"type": "enum",
"title": "Authentication Mode",
"required": true,
"default": "link",
"description": "Authentication method exposed by the reverse proxy service.",
"config": {
"options": [
"link",
"none",
"password",
"pin",
"bearer"
]
}
},
{
"name": "auth_password",
"type": "secret",
"title": "Password",
"required": true,
"description": "Shared password for password-based access.",
"needs": [
"auth_mode=password"
]
},
{
"name": "auth_pin",
"type": "secret",
"title": "PIN",
"required": true,
"description": "Shared PIN for PIN-based access.",
"needs": [
"auth_mode=pin"
]
},
{
"name": "bearer_distribution_group_names",
"type": "str",
"title": "Bearer Distribution Groups",
"required": false,
"description": "Comma-separated existing NetBird group names allowed for bearer-auth access.",
"needs": [
"auth_mode=bearer"
],
"config": {
"placeholder": "SRE,Incident Response",
"textarea": true
}
}
]
}
]
}
+63
View File
@@ -0,0 +1,63 @@
data "netbox_cluster" "<< resource_name >>_cluster" {
name = "<< cluster_name >>"
}
<%- if site_name %>
data "netbox_site" "<< resource_name >>_site" {
name = "<< site_name >>"
}
<%- endif %>
<%- if device_name %>
data "netbox_devices" "<< resource_name >>_device_lookup" {
limit = 1
filter {
name = "name"
value = "<< device_name >>"
}
}
<%- endif %>
resource "netbox_virtual_machine" "<< resource_name >>" {
name = "<< vm_name >>"
cluster_id = data.netbox_cluster.<< resource_name >>_cluster.id
<%- if site_name %>
site_id = data.netbox_site.<< resource_name >>_site.id
<%- endif %>
status = "<< status >>"
<%- if device_name %>
device_id = data.netbox_devices.<< resource_name >>_device_lookup.devices[0].device_id
<%- endif %>
<%- if resources_enabled %>
vcpus = << vcpus >>
memory = << memory_mb >>
disk = << disk_gb >>
<%- endif %>
<%- if description_enabled %>
comments = "<< description_text >>"
<%- endif %>
}
<%- if ipam_enabled %>
resource "netbox_interface" "<< resource_name >>_interface" {
name = "<< interface_name >>"
virtual_machine_id = netbox_virtual_machine.<< resource_name >>.id
}
resource "netbox_ip_address" "<< resource_name >>_ip" {
ip_address = "<< primary_ip4 >>"
status = "active"
<%- if dns_name %>
dns_name = "<< dns_name >>"
<%- endif %>
interface_id = netbox_interface.<< resource_name >>_interface.id
object_type = "virtualization.vminterface"
}
resource "netbox_primary_ip" "<< resource_name >>_primary_ip" {
ip_address_id = netbox_ip_address.<< resource_name >>_ip.id
virtual_machine_id = netbox_virtual_machine.<< resource_name >>.id
}
<%- endif %>
+222
View File
@@ -0,0 +1,222 @@
{
"slug": "netbox-vm",
"kind": "terraform",
"metadata": {
"name": "NetBox Virtual Machine",
"description": "Registers a virtual machine in NetBox with cluster, site, and host device associations. Defines VM metadata including resource allocation and optional IPAM integration.",
"tags": [],
"icon": {
"provider": "selfhst",
"id": "netbox"
},
"draft": false,
"version": {
"name": "5.0.1",
"source_dep_name": "manual/netbox-vm"
}
},
"variables": [
{
"title": "General",
"name": "general",
"items": [
{
"name": "resource_name",
"type": "str",
"title": "Resource Name",
"required": false,
"default": "vm",
"config": {
"placeholder": "vm"
}
}
]
},
{
"title": "Virtual Machine Configuration",
"name": "vm",
"items": [
{
"name": "vm_name",
"type": "str",
"title": "Virtual machine name",
"required": true,
"config": {
"placeholder": "servername"
}
},
{
"name": "cluster_name",
"type": "str",
"title": "Cluster name",
"required": true,
"default": "clustername",
"description": "Existing NetBox cluster name to resolve via data source.",
"config": {
"placeholder": "clustername"
}
},
{
"name": "status",
"type": "enum",
"title": "VM status",
"required": false,
"default": "active",
"config": {
"options": [
"active",
"planned",
"staged",
"offline",
"decommissioning"
]
}
}
]
},
{
"title": "Site Assignment",
"name": "site",
"items": [
{
"name": "site_name",
"type": "str",
"title": "Site Name",
"required": false,
"description": "Existing NetBox site name to resolve via data source (leave empty to skip)"
}
]
},
{
"title": "Host Device",
"name": "device",
"items": [
{
"name": "device_name",
"type": "str",
"title": "Device Name",
"required": false,
"description": "Existing NetBox device name for host assignment (leave empty to skip)"
}
]
},
{
"title": "IP Address Management",
"name": "ipam",
"items": [
{
"name": "ipam_enabled",
"type": "bool",
"title": "IPAM",
"required": false,
"default": false
},
{
"name": "interface_name",
"type": "str",
"title": "Network interface name",
"required": true,
"default": "eth0",
"config": {
"placeholder": "eth0"
}
},
{
"name": "primary_ip4",
"type": "str",
"title": "Primary IPv4",
"required": true,
"description": "Primary IPv4 address with CIDR notation"
},
{
"name": "dns_name",
"type": "str",
"title": "DNS Name",
"required": false,
"description": "DNS name for the IP address (leave empty to skip)"
}
]
},
{
"title": "Resource Allocation",
"name": "resources",
"items": [
{
"name": "resources_enabled",
"type": "bool",
"title": "Resources",
"required": false,
"default": false
},
{
"name": "vcpus",
"type": "int",
"title": "vCPUs",
"required": false,
"default": 2,
"config": {
"slider": true,
"min": 1,
"max": 24,
"step": 1,
"placeholder": "2",
"unit": "vCPU"
}
},
{
"name": "memory_mb",
"type": "int",
"title": "Memory",
"required": false,
"default": 4096,
"config": {
"slider": true,
"min": 512,
"max": 24576,
"step": 512,
"placeholder": "4096",
"unit": "MB"
}
},
{
"name": "disk_gb",
"type": "int",
"title": "Disk Size",
"required": false,
"default": 50,
"config": {
"slider": true,
"min": 10,
"max": 1000,
"step": 10,
"placeholder": "50",
"unit": "GB"
}
}
]
},
{
"title": "Description",
"name": "description",
"items": [
{
"name": "description_enabled",
"type": "bool",
"title": "Description",
"required": false,
"default": false
},
{
"name": "description_text",
"type": "str",
"title": "VM description",
"required": false,
"config": {
"placeholder": "Add a description here...",
"textarea": true
}
}
]
}
]
}
+39
View File
@@ -0,0 +1,39 @@
resource "proxmox_lxc" "<< resource_name >>" {
hostname = "<< hostname >>"
<%- if description %>
description = "<< description >>"
<%- endif %>
target_node = "<< target_node >>"
unprivileged = << unprivileged | lower >>
ostemplate = "<< ostemplate >>"
cores = << cores >>
swap = << swap_mb >>
memory = << memory_mb >>
start = << start_container | lower >>
rootfs {
storage = "<< rootfs_storage >>"
size = "<< rootfs_size_gb >>G"
}
nameserver = "<< nameserver >>"
<%- if searchdomain %>
searchdomain = "<< searchdomain >>"
<%- endif %>
network {
name = "<< network_name >>"
bridge = "<< bridge >>"
ip = "<< ip_address >>"
}
lifecycle {
ignore_changes = [
rootfs,
network,
cmode
]
}
}
+231
View File
@@ -0,0 +1,231 @@
{
"slug": "proxmox-lxc",
"kind": "terraform",
"metadata": {
"name": "Proxmox LXC",
"description": "Creates a Proxmox Linux container with configurable template, compute, root filesystem, and single-interface network settings.",
"tags": [],
"icon": {
"provider": "selfhst",
"id": "proxmox"
},
"draft": false,
"version": {
"name": "3.0.2-rc07",
"source_dep_name": "telmate/proxmox",
"source_dep_version": "3.0.2-rc07"
}
},
"variables": [
{
"title": "Terraform",
"name": "terraform",
"items": [
{
"name": "resource_name",
"type": "str",
"title": "Resource Name",
"required": false,
"default": "lxc",
"config": {
"placeholder": "lxc"
}
}
]
},
{
"title": "Container Identity",
"name": "identity",
"items": [
{
"name": "hostname",
"type": "str",
"title": "Container hostname",
"required": true,
"config": {
"placeholder": "Container Name"
}
},
{
"name": "description",
"type": "str",
"title": "Container description",
"required": false,
"description": "Add a description here...",
"config": {
"placeholder": "Application container",
"textarea": true
}
},
{
"name": "target_node",
"type": "str",
"title": "Target Node",
"required": true,
"description": "Proxmox node that will host the container",
"config": {
"placeholder": "Proxmox node"
}
},
{
"name": "unprivileged",
"type": "bool",
"title": "Unprivileged",
"required": false,
"default": false
},
{
"name": "ostemplate",
"type": "str",
"title": "Template",
"required": true,
"config": {
"placeholder": "template reference"
}
}
]
},
{
"title": "Compute",
"name": "compute",
"items": [
{
"name": "cores",
"type": "int",
"title": "CPU Cores",
"required": false,
"default": 4,
"config": {
"slider": true,
"min": 1,
"max": 32,
"step": 1,
"placeholder": "4"
}
},
{
"name": "memory_mb",
"type": "int",
"title": "Memory",
"required": false,
"default": 8192,
"config": {
"slider": true,
"min": 256,
"max": 262144,
"step": 256,
"placeholder": "8192",
"unit": "MB"
}
},
{
"name": "swap_mb",
"type": "int",
"title": "Swap",
"required": false,
"default": 512,
"config": {
"slider": true,
"min": 0,
"max": 65536,
"step": 128,
"placeholder": "512",
"unit": "MB"
}
},
{
"name": "start_container",
"type": "bool",
"title": "Auto Start",
"required": false,
"default": true,
"description": "Start the container after creation"
}
]
},
{
"title": "Storage and Network",
"name": "storage-network",
"items": [
{
"name": "rootfs_storage",
"type": "str",
"title": "Rootfs Storage",
"required": false,
"default": "local-lvm",
"description": "Storage pool for the root filesystem",
"config": {
"placeholder": "local-lvm"
}
},
{
"name": "rootfs_size_gb",
"type": "int",
"title": "Rootfs Size",
"required": false,
"default": 256,
"description": "Root filesystem size in GB",
"config": {
"slider": true,
"min": 4,
"max": 4096,
"step": 1,
"placeholder": "256",
"unit": "GB"
}
},
{
"name": "nameserver",
"type": "str",
"title": "Container DNS server",
"required": true,
"description": "DNS server used by the container.",
"config": {
"placeholder": "DNS_SERVER"
}
},
{
"name": "searchdomain",
"type": "str",
"title": "Container search domain",
"required": false,
"default": "",
"description": "Search domain used by the container.",
"config": {
"placeholder": "home.arpa"
}
},
{
"name": "network_name",
"type": "str",
"title": "Network Name",
"required": false,
"default": "eth0",
"config": {
"placeholder": "eth0"
}
},
{
"name": "bridge",
"type": "str",
"title": "Proxmox bridge name",
"required": false,
"default": "vmbr1",
"description": "Bridge name to use in Proxmox.",
"config": {
"placeholder": "vmbr1"
}
},
{
"name": "ip_address",
"type": "str",
"title": "Container IP address",
"required": true,
"config": {
"placeholder": "IP_ADDRESS"
}
}
]
}
]
}
+77
View File
@@ -0,0 +1,77 @@
resource "proxmox_vm_qemu" "<< resource_name >>" {
name = "<< vm_name >>"
<%- if vm_id %>
vmid = "<< vm_id >>"
<%- endif %>
<%- if description %>
description = "<< description >>"
<%- endif %>
<%- if tags %>
tags = "<< tags >>"
<%- endif %>
agent = 1
agent_timeout = 90
target_node = "<< target_node >>"
define_connection_info = false
full_clone = << full_clone | lower >>
clone = "<< clone_template >>"
onboot = << onboot | lower >>
<%- if startup %>
startup = "<< startup >>"
<%- endif %>
automatic_reboot = << automatic_reboot | lower >>
qemu_os = "<< qemu_os >>"
bios = "<< bios >>"
cpu {
cores = << cpu_cores >>
sockets = << cpu_sockets >>
type = "<< cpu_type >>"
}
memory = << memory_mb >>
balloon = << memory_mb >>
network {
id = 0
bridge = "<< bridge >>"
model = "<< network_model >>"
}
scsihw = "virtio-scsi-pci"
disks {
ide {
ide0 {
cloudinit {
storage = "<< cloudinit_storage >>"
}
}
}
virtio {
virtio0 {
disk {
storage = "<< disk_storage >>"
size = "<< disk_size_gb >>G"
iothread = << disk_iothread | lower >>
replicate = << disk_replicate | lower >>
}
}
}
}
ipconfig0 = "<< ipconfig0 >>"
<%- if nameserver %>
nameserver = "<< nameserver >>"
<%- endif %>
ciuser = "<< ci_user >>"
<%- if ssh_key %>
sshkeys = "<< ssh_key >>"
<%- endif %>
}
+355
View File
@@ -0,0 +1,355 @@
{
"slug": "proxmox-vm-qemu",
"kind": "terraform",
"metadata": {
"name": "Proxmox VM (QEMU)",
"description": "Creates a Proxmox virtual machine from a cloud-init-ready template with configurable clone, CPU, memory, disk, networking, and guest settings.",
"tags": [],
"icon": {
"provider": "selfhst",
"id": "proxmox"
},
"draft": false,
"version": {
"name": "3.0.2-rc07",
"source_dep_name": "telmate/proxmox",
"source_dep_version": "3.0.2-rc07"
}
},
"variables": [
{
"title": "Terraform",
"name": "terraform",
"items": [
{
"name": "resource_name",
"type": "str",
"title": "Resource Name",
"required": false,
"default": "vmqemu",
"config": {
"placeholder": "vmqemu"
}
}
]
},
{
"title": "VM Identity",
"name": "identity",
"items": [
{
"name": "vm_name",
"type": "str",
"title": "Proxmox VM name",
"required": true,
"config": {
"placeholder": "servername"
}
},
{
"name": "vm_id",
"type": "str",
"title": "Proxmox VMID",
"required": false,
"config": {
"placeholder": "20001"
}
},
{
"name": "description",
"type": "str",
"title": "VM description",
"required": false,
"config": {
"placeholder": "Application server",
"textarea": true
}
},
{
"name": "tags",
"type": "str",
"title": "Tags",
"required": false,
"config": {
"placeholder": "docker"
}
},
{
"name": "target_node",
"type": "str",
"title": "Target Node",
"required": true,
"description": "Proxmox node that will host the VM.",
"config": {
"placeholder": "proxmox-node"
}
}
]
},
{
"title": "Clone Configuration",
"name": "clone",
"items": [
{
"name": "clone_template",
"type": "str",
"title": "Template",
"required": true,
"description": "Source template name to clone",
"config": {
"placeholder": "pkr-ubuntu-noble-1"
}
},
{
"name": "full_clone",
"type": "bool",
"title": "Full Clone",
"required": false,
"default": true,
"description": "Create a full clone instead of a linked clone"
}
]
},
{
"title": "Boot Settings",
"name": "guest",
"items": [
{
"name": "onboot",
"type": "bool",
"title": "Auto Start",
"required": false,
"default": true,
"description": "Start the VM automatically with the node."
},
{
"name": "startup",
"type": "str",
"title": "Startup",
"required": false,
"description": "Proxmox startup order and delay string",
"config": {
"placeholder": "order=1,up=10"
}
},
{
"name": "automatic_reboot",
"type": "bool",
"title": "Auto Reboot",
"required": false,
"default": false,
"description": "Allow provider-triggered automatic reboot on change"
},
{
"name": "ci_user",
"type": "str",
"title": "Cloud-init user",
"required": false,
"default": "admin",
"config": {
"placeholder": "admin"
}
},
{
"name": "ssh_key",
"type": "str",
"title": "SSH Key",
"required": false,
"description": "SSH public key passed to cloud-init",
"config": {
"placeholder": "SSH public key",
"textarea": true
}
},
{
"name": "ipconfig0",
"type": "str",
"title": "Network Config",
"required": false,
"default": "ip=dhcp",
"description": "Cloud-init network config for the first NIC",
"config": {
"placeholder": "ip=IP_ADDRESS/24,gw=GATEWAY"
}
},
{
"name": "nameserver",
"type": "str",
"title": "Nameserver",
"required": false,
"description": "DNS server for guest cloud-init config",
"config": {
"placeholder": "DNS_SERVER"
}
}
]
},
{
"title": "Compute",
"name": "compute",
"items": [
{
"name": "cpu_cores",
"type": "int",
"title": "CPU Cores",
"required": false,
"default": 2,
"config": {
"slider": true,
"min": 1,
"max": 32,
"step": 1,
"placeholder": "2",
"unit": "cores"
}
},
{
"name": "cpu_sockets",
"type": "int",
"title": "CPU Sockets",
"required": false,
"default": 1,
"config": {
"slider": true,
"min": 1,
"max": 8,
"step": 1,
"placeholder": "1",
"unit": "sockets"
}
},
{
"name": "cpu_type",
"type": "str",
"title": "Proxmox CPU type",
"required": false,
"default": "host",
"description": "CPU type to use in Proxmox.",
"config": {
"placeholder": "host"
}
},
{
"name": "memory_mb",
"type": "int",
"title": "Memory",
"required": false,
"default": 4096,
"config": {
"slider": true,
"min": 512,
"max": 262144,
"step": 512,
"placeholder": "4096",
"unit": "MB"
}
},
{
"name": "bios",
"type": "enum",
"title": "VM BIOS type",
"required": false,
"default": "seabios",
"description": "BIOS type for the VM.",
"config": {
"options": [
"seabios",
"ovmf"
]
}
},
{
"name": "qemu_os",
"type": "str",
"title": "QEMU OS type",
"required": false,
"default": "other",
"description": "Guest OS type for QEMU.",
"config": {
"placeholder": "other"
}
}
]
},
{
"title": "Storage and Network",
"name": "storage-network",
"items": [
{
"name": "bridge",
"type": "str",
"title": "Bridge",
"required": false,
"default": "vmbr1",
"description": "Proxmox bridge for the first NIC",
"config": {
"placeholder": "vmbr1"
}
},
{
"name": "network_model",
"type": "str",
"title": "NIC model",
"required": false,
"default": "virtio",
"description": "Network adapter model.",
"config": {
"placeholder": "virtio"
}
},
{
"name": "disk_storage",
"type": "str",
"title": "Disk Storage",
"required": false,
"default": "local-lvm",
"description": "Storage pool for the main disk",
"config": {
"placeholder": "local-lvm"
}
},
{
"name": "cloudinit_storage",
"type": "str",
"title": "Cloud-init Storage",
"required": false,
"default": "local-lvm",
"description": "Storage pool for the cloud-init disk",
"config": {
"placeholder": "local-lvm"
}
},
{
"name": "disk_size_gb",
"type": "int",
"title": "Disk Size",
"required": false,
"default": 32,
"description": "Main disk size in GB",
"config": {
"slider": true,
"min": 8,
"max": 4096,
"step": 1,
"placeholder": "32",
"unit": "GB"
}
},
{
"name": "disk_iothread",
"type": "bool",
"title": "IO Thread",
"required": false,
"default": true
},
{
"name": "disk_replicate",
"type": "bool",
"title": "Disk Replication",
"required": false,
"default": true
}
]
}
]
}
+24
View File
@@ -0,0 +1,24 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/telmate/proxmox" {
version = "3.0.1-rc9"
constraints = "3.0.1-rc9"
hashes = [
"h1:TAkzCbpjazX/iNqkodNI63OvqtP6NsWI3CHcHdjieXY=",
"zh:037bae31005419d5ca6921940fc572d5acba264f5b80a09f9e8cf14edff9c189",
"zh:0decfc022e6e40f6e4d5dd60073b6d62dc7ec582e2e398fb4a0cbc88c61b9389",
"zh:16024c6ee5d0fa9c7041f8197e854f73026fd06e8b19ec61e40291ef50171d8a",
"zh:4839fa10755023b26305d519b6ad2a8d83b5f83d3a8f58bc9ac9a7e6ed20cb6a",
"zh:6b50a44d20b5bfa62580f7cd00c64a7b47f9b9d5dd32a7392ca218e33f9bda07",
"zh:83f67ac118e4e2c0ad4d93c50f3f05a262724b374c9ad34342826a384d1ce284",
"zh:84e51f6bbff5b4e016fdb0f2b594672917e053fbd7b99612cfef7eebf1ca6465",
"zh:9fd6fe66507e8ebd4b462f53c8f4e898d12a6b4e8f0d38ad24ea8d5b04b3d7a9",
"zh:b3a6cbb5bc56c1ed658218a21aa1a864fcde0ce24eb07ae7735b4a327dbe833f",
"zh:bd9bfea930e43d47b65ed26254192e19584432227d64588ed280507ae46f2295",
"zh:d8cbc0e13477acf7bd85362a89a25ab377cbef566e7a1ddf4a577eebfd89de19",
"zh:e45d0fa9a895157c4ebc2faa6b7f8252351426bc06c09537a5d9a2a918b76b20",
"zh:f032d90900b00ed5a8d9d990cd382d3427366f1f394ccbd681a372f436a45b7c",
"zh:f54b2cfc0f26c2ad44b0eba1383642c1c27a5f1a3b1c167115196c818c3b94dd",
]
}
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,51 @@
[![Build Status](https://travis-ci.com/Telmate/terraform-provider-proxmox.svg?branch=master)](https://travis-ci.com/Telmate/terraform-provider-proxmox)
# Terraform provider plugin for Proxmox
This repository provides a Terraform provider for
the [Proxmox virtualization platform](https://pve.proxmox.com/pve-docs/) and exposes Terraform resources to provision
QEMU VMs and LXC Containers.
## Getting Started
In order to get started, use [the documentation included in this repository](docs/index.md). The documentation contains
a list of the options for the provider. Moreover, there are some guides available how to combine options and start
specific VMs.
## Quick Start
Follow this [install guide](docs/guides/installation.md) to install the plugin.
## Known Limitations
* `proxmox_vm_qemu`.`disk`.`size` attribute does not match what is displayed in the Proxmox UI.
* Updates to `proxmox_vm_qemu` resources almost always result as a failed task within the Proxmox UI. This appears to be
harmless and the desired configuration changes do get applied.
* When using the `proxmox_lxc` resource, the provider will crash unless `rootfs` is defined.
* When using the Network Boot mode (PXE), a valid NIC must be defined for the VM, and the boot order must specify network first.
## Contributing
When contributing, please also add documentation to help other users.
### Debugging the provider
Debugging is available for this provider through the Terraform Plugin SDK versions 2.0.0. Therefore, the plugin can be
started with the debugging flag `--debug`.
For example (using [delve](https://github.com/go-delve/delve) as Debugger):
```bash
dlv exec --headless ./terraform-provider-my-provider -- --debug
```
For more information about debugging a provider please
see: [Debugger-Based Debugging](https://www.terraform.io/docs/extend/debugging.html#debugger-based-debugging)
## Useful links
* [Proxmox](https://www.proxmox.com/en/)
* [Proxmox documentation](https://pve.proxmox.com/pve-docs/)
* [Terraform](https://www.terraform.io/)
* [Terraform documentation](https://www.terraform.io/docs/index.html)
* [Recommended ISO builder](https://github.com/Telmate/terraform-ubuntu-proxmox-iso)
+3
View File
@@ -0,0 +1,3 @@
# Terraform Proxmox
You can add an additional description here.
@@ -0,0 +1,3 @@
proxmox_api_url = "https://192.168.2.2:8006/api2/json" # Your Proxmox IP Address
proxmox_api_token_id = "root@pam!terraform" # API Token ID
proxmox_api_token_secret = "8a1f9308-cc3b-498b-ae2d-274313a17592"
+7
View File
@@ -0,0 +1,7 @@
services:
terraform:
image: hashicorp/terraform
volumes:
- .:/terraform
working_dir: /terraform
network_mode: host
+58
View File
@@ -0,0 +1,58 @@
# Proxmox Full-Clone
# ---
# Create a new VM from a clone
resource "proxmox_vm_qemu" "ubuntu-2504-003" {
# VM General Settings
target_node = "pve"
vmid = "100"
name = "ubuntu-2504-003"
desc = "Test Server"
# VM Advanced General Settings
onboot = true
# VM OS Settings
clone = "ubuntu-2504-template"
# VM System Settings
agent = 0
# VM CPU Settings
cores = 1
sockets = 1
#cpu = "x86-64-v2-AES"
# VM Hard Drive Setting
scsihw = "virtio-scsi-single"
disks {
scsi {
scsi0 {
disk {
size = "100G"
storage = "Data"
format = "qcow2"
}
}
}
}
# VM Memory Settings
memory = 1024
# VM Cloud-Init Settings
os_type = "cloud-init"
# (Optional) IP Address and Gateway
ipconfig0 = "ip=192.168.2.99/22,gw=192.168.0.1"
# (Optional) Default User
# ciuser = "your-username"
# (Optional) Add your SSH KEY
# sshkeys = <<EOF
# #YOUR-PUBLIC-SSH-KEY
# EOF
}
+36
View File
@@ -0,0 +1,36 @@
# Proxmox Provider
# ---
# Initial Provider Configuration for Proxmox
terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "3.0.1-rc9"
}
}
}
variable "proxmox_api_url" {
type = string
}
variable "proxmox_api_token_id" {
type = string
}
variable "proxmox_api_token_secret" {
type = string
}
provider "proxmox" {
pm_api_url = var.proxmox_api_url
pm_api_token_id = var.proxmox_api_token_id
pm_api_token_secret = var.proxmox_api_token_secret
# (Optional) Skip TLS Verification
pm_tls_insecure = true
}
+146
View File
@@ -0,0 +1,146 @@
{
"version": 4,
"terraform_version": "1.12.1",
"serial": 1,
"lineage": "ba312982-a404-7a77-e37f-5af5e21d18cb",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "proxmox_vm_qemu",
"name": "ubuntu-2504-003",
"provider": "provider[\"registry.terraform.io/telmate/proxmox\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"additional_wait": 5,
"agent": 0,
"agent_timeout": 90,
"args": "",
"automatic_reboot": true,
"balloon": 0,
"bios": "seabios",
"boot": "order=scsi0",
"bootdisk": "",
"ci_wait": null,
"cicustom": null,
"cipassword": "",
"ciupgrade": false,
"ciuser": "",
"clone": "ubuntu-2504-template",
"clone_id": null,
"clone_wait": 10,
"cores": 1,
"cpu": [],
"cpu_type": "host",
"current_node": "pve",
"default_ipv4_address": "",
"default_ipv6_address": "",
"define_connection_info": true,
"desc": "Test Server",
"disk": [],
"disks": [],
"efidisk": [],
"force_create": false,
"force_recreate_on_change_of": null,
"full_clone": true,
"hagroup": "",
"hastate": "",
"hostpci": [],
"hotplug": "network,disk,usb",
"id": "pve/qemu/100",
"ipconfig0": "ip=192.168.2.99/22,gw=192.168.0.1",
"ipconfig1": null,
"ipconfig10": null,
"ipconfig11": null,
"ipconfig12": null,
"ipconfig13": null,
"ipconfig14": null,
"ipconfig15": null,
"ipconfig2": null,
"ipconfig3": null,
"ipconfig4": null,
"ipconfig5": null,
"ipconfig6": null,
"ipconfig7": null,
"ipconfig8": null,
"ipconfig9": null,
"kvm": true,
"linked_vmid": 0,
"machine": "",
"memory": 1024,
"name": "ubuntu-2504-003",
"nameserver": null,
"network": [],
"numa": false,
"onboot": true,
"os_network_config": null,
"os_type": "cloud-init",
"pci": [],
"pcis": [],
"pool": "",
"protection": false,
"pxe": null,
"qemu_os": "l26",
"reboot_required": false,
"scsihw": "virtio-scsi-single",
"searchdomain": null,
"serial": [],
"skip_ipv4": false,
"skip_ipv6": false,
"smbios": [
{
"family": "",
"manufacturer": "",
"product": "",
"serial": "",
"sku": "",
"uuid": "1f071dda-115d-4e8a-9a71-cc7b0b60e709",
"version": ""
}
],
"sockets": 1,
"ssh_forward_ip": null,
"ssh_host": "",
"ssh_port": "22",
"ssh_private_key": null,
"ssh_user": null,
"sshkeys": null,
"startup": "",
"tablet": true,
"tags": "",
"target_node": "pve",
"target_nodes": null,
"timeouts": null,
"tpm_state": [],
"unused_disk": [],
"usb": [],
"usbs": [],
"vcpus": null,
"vga": [],
"vm_state": "running",
"vmid": 100
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "cipassword"
}
],
[
{
"type": "get_attr",
"value": "ssh_private_key"
}
]
],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWZhdWx0IjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19"
}
]
}
],
"check_results": null
}
@@ -0,0 +1,15 @@
data "civo_ssh_key" "sshkey" {
name = "your-ssh-key-name"
}
resource "civo_instance" "server" {
hostname = "servername"
size = "g3.small"
disk_image = "ubuntu-focal"
# (optional):
# ---
# tags = ["python", "nginx"]
# notes = "this is a note for the server"
# initial_user = "user"
# sshkey_id = data.civo_ssh_key.sshkey.id
}
@@ -0,0 +1,9 @@
variable "zone_id" {}
resource "cloudflare_record" "server" {
zone_id = var.zone_id
name = "your-dns-name"
value = civo_instance.server.public_ip
type = "A"
proxied = false
}
@@ -0,0 +1,40 @@
# General Terraform Settings
# ---
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
civo = {
source = "civo/civo"
}
}
}
# Declare Variables
# ---
# TODO: Create a yourfile.auto.tfvars file in the project directory and add your variables in it.
# Example:
# cloudflare_email = "youremail@yourmail.com"
# cloudflare_api_key = "your-api-key"
# civo_token = "your-token"
variable "cloudflare_email" {}
variable "cloudflare_api_key" {}
variable "civo_token" {}
# Set Default Provider Settings
# ---
provider "cloudflare" {
email = var.cloudflare_email
api_key = var.cloudflare_api_key
}
provider "civo" {
token = var.civo_token
# (optional) change the defaullt region
# region = "FRA1"
}
@@ -0,0 +1,79 @@
resource "kubernetes_namespace" "certmanager" {
depends_on = [
time_sleep.wait_for_kubernetes
]
metadata {
name = "certmanager"
}
}
resource "helm_release" "certmanager" {
depends_on = [
kubernetes_namespace.certmanager
]
name = "certmanager"
namespace = "certmanager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
# Install Kubernetes CRDs
set {
name = "installCRDs"
value = "true"
}
}
resource "time_sleep" "wait_for_certmanager" {
depends_on = [
helm_release.certmanager
]
create_duration = "10s"
}
# Create a ClusterIssuer
resource "kubectl_manifest" "cloudflare_prod" {
depends_on = [
time_sleep.wait_for_certmanager
]
# TODO: add your mail address according to your configuration and API authentication settings!
# ---
yaml_body = <<YAML
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-prod
spec:
acme:
email: your-mail-address
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-prod-account-key
solvers:
- dns01:
cloudflare:
email: your-mail-address
apiKeySecretRef:
name: cloudflare-api-key-secret
key: api-key
YAML
}
resource "time_sleep" "wait_for_clusterissuer" {
depends_on = [
kubectl_manifest.cloudflare_prod
]
create_duration = "30s"
}
@@ -0,0 +1,77 @@
# Kubernetes Cluster
data "civo_size" "xsmall" {
# TODO: (optional): change the values according to your desired instance image sizing
# ---
filter {
key = "name"
values = ["g4s.kube.xsmall"]
match_by = "re"
}
}
resource "civo_kubernetes_cluster" "k8s_demo_1" {
name = "k8s_demo_1"
applications = ""
num_target_nodes = 2
target_nodes_size = element(data.civo_size.xsmall.sizes, 0).name
firewall_id = civo_firewall.fw_demo_1.id
}
resource "civo_firewall" "fw_demo_1" {
name = "fw_demo_1"
create_default_rules = false
}
resource "civo_firewall_rule" "kubernetes_http" {
firewall_id = civo_firewall.fw_demo_1.id
protocol = "tcp"
start_port = "80"
end_port = "80"
cidr = ["0.0.0.0/0"]
direction = "ingress"
action = "allow"
label = "kubernetes_http"
}
resource "civo_firewall_rule" "kubernetes_https" {
firewall_id = civo_firewall.fw_demo_1.id
protocol = "tcp"
start_port = "443"
end_port = "443"
cidr = ["0.0.0.0/0"]
direction = "ingress"
action = "allow"
label = "kubernetes_https"
}
resource "civo_firewall_rule" "kubernetes_api" {
firewall_id = civo_firewall.fw_demo_1.id
protocol = "tcp"
start_port = "6443"
end_port = "6443"
cidr = ["0.0.0.0/0"]
direction = "ingress"
action = "allow"
label = "kubernetes_api"
}
resource "time_sleep" "wait_for_kubernetes" {
depends_on = [
civo_kubernetes_cluster.k8s_demo_1
]
create_duration = "20s"
}
data "civo_loadbalancer" "traefik_lb" {
depends_on = [
helm_release.traefik
]
name = "k8s_demo_1-traefik-traefik"
}
@@ -0,0 +1,20 @@
# Cloudflare DNS records and API Secret
resource "kubernetes_secret" "cloudflare_api_key_secret" {
depends_on = [
kubernetes_namespace.certmanager
]
metadata {
name = "cloudflare-api-key-secret"
namespace = "certmanager"
}
data = {
api-key = var.cloudflare_api_key
}
type = "Opaque"
}
@@ -0,0 +1,153 @@
# NGINX 1 Test Deployment
#
# TODO: Change your-domain according to your DNS record that you want to create
# TODO: Change your-zone-id according to your DNS zone ID in Cloudflare
# ---
resource "kubernetes_namespace" "nginx1" {
depends_on = [
time_sleep.wait_for_kubernetes
]
metadata {
name = "nginx1"
}
}
resource "kubernetes_deployment" "nginx1" {
depends_on = [
kubernetes_namespace.nginx1
]
metadata {
name = "nginx1"
namespace = "nginx1"
labels = {
app = "nginx1"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "nginx1"
}
}
template {
metadata {
labels = {
app = "nginx1"
}
}
spec {
container {
image = "nginx:latest"
name = "nginx"
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "nginx1" {
depends_on = [
kubernetes_namespace.nginx1
]
metadata {
name = "nginx1"
namespace = "nginx1"
}
spec {
selector = {
app = "nginx1"
}
port {
port = 80
}
type = "ClusterIP"
}
}
resource "kubectl_manifest" "nginx1-certificate" {
depends_on = [kubernetes_namespace.nginx1, time_sleep.wait_for_clusterissuer]
yaml_body = <<YAML
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: nginx1
namespace: nginx1
spec:
secretName: nginx1
issuerRef:
name: cloudflare-prod
kind: ClusterIssuer
dnsNames:
- 'your-domain'
YAML
}
resource "kubernetes_ingress_v1" "nginx1" {
depends_on = [kubernetes_namespace.nginx1]
metadata {
name = "nginx1"
namespace = "nginx1"
}
spec {
rule {
host = "your-domain"
http {
path {
path = "/"
backend {
service {
name = "nginx1"
port {
number = 80
}
}
}
}
}
}
tls {
secret_name = "nginx1"
hosts = ["your-domain"]
}
}
}
resource "cloudflare_record" "clcreative-main-cluster" {
zone_id = "your-zone-id"
name = "your-domain"
value = data.civo_loadbalancer.traefik_lb.public_ip
type = "A"
proxied = false
}
@@ -0,0 +1,76 @@
terraform {
required_version = ">= 0.13.0"
required_providers {
civo = {
source = "civo/civo"
version = "~> 1.0.13"
}
helm = {
source = "hashicorp/helm"
version = "2.14.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.31.0"
}
kubectl = {
source = "gavinbunney/kubectl"
version = "1.14.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
variable "civo_token" {
type = string
}
variable "cloudflare_email" {
type = string
}
variable "cloudflare_api_key" {
type = string
}
provider "civo" {
token = var.civo_token
# TODO: (optional) change region to your desired datacenter location
# ---
# region = "FRA1"
}
provider "helm" {
kubernetes {
host = "${yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.server}"
client_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-certificate-data)}"
client_key = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-key-data)}"
cluster_ca_certificate ="${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.certificate-authority-data)}"
}
}
provider "kubernetes" {
host = "${yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.server}"
client_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-certificate-data)}"
client_key = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-key-data)}"
cluster_ca_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.certificate-authority-data)}"
}
provider "kubectl" {
host = "${yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.server}"
client_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-certificate-data)}"
client_key = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).users.0.user.client-key-data)}"
cluster_ca_certificate = "${base64decode(yamldecode(civo_kubernetes_cluster.k8s_demo_1.kubeconfig).clusters.0.cluster.certificate-authority-data)}"
load_config_file = false
}
provider "cloudflare" {
email = var.cloudflare_email
api_key = var.cloudflare_api_key
}
@@ -0,0 +1,47 @@
# Traefik Deployment
resource "kubernetes_namespace" "traefik" {
depends_on = [
time_sleep.wait_for_kubernetes
]
metadata {
name = "traefik"
}
}
resource "helm_release" "traefik" {
depends_on = [
kubernetes_namespace.traefik
]
name = "traefik"
namespace = "traefik"
repository = "https://helm.traefik.io/traefik"
chart = "traefik"
# Set Traefik as the Default Ingress Controller
set {
name = "ingressClass.enabled"
value = "true"
}
set {
name = "ingressClass.isDefaultClass"
value = "true"
}
# Default Redirect
set {
name = "ports.web.redirectTo"
value = "websecure"
}
# Enable TLS on Websecure
set {
name = "ports.websecure.tls.enabled"
value = "true"
}
}
@@ -0,0 +1,24 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.0"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.latest
name = "tutorial"
ports {
internal = 80
external = 8000
}
}