migrate
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# CIVO Credentials
|
||||
# ---
|
||||
# Credential Variables needed for CIVO
|
||||
|
||||
# Civo Config
|
||||
variable "civo_token" {
|
||||
description = "Civo API Token"
|
||||
type = string
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
resource "civo_firewall" "your_firewall" {
|
||||
name = "your-firewall-name"
|
||||
network_id = civo_network.your_network.id
|
||||
create_default_rules = true
|
||||
}
|
||||
@@ -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"
|
||||
# }
|
||||
@@ -0,0 +1,3 @@
|
||||
resource "civo_network" "your_network" {
|
||||
label = "your-network-label"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+23
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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') >>"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
# }
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
resource "kubectl_manifest" "your-manifest-file" {
|
||||
|
||||
yaml_body = <<YAML
|
||||
# Put your Manifest-file Content right here...
|
||||
# ...
|
||||
YAML
|
||||
}
|
||||
@@ -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
|
||||
# }
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"]
|
||||
# }
|
||||
}
|
||||
}
|
||||
@@ -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)}"
|
||||
# }
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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 %>
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
resource "netbird_network" "network" {
|
||||
name = "<< network_name >>"
|
||||
<%- if network_description %>
|
||||
description = "<< network_description >>"
|
||||
<%- endif %>
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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 %>
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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 %>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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 %>
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+24
@@ -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",
|
||||
]
|
||||
}
|
||||
+21
@@ -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.
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
[](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)
|
||||
BIN
Binary file not shown.
@@ -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"
|
||||
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
terraform:
|
||||
image: hashicorp/terraform
|
||||
volumes:
|
||||
- .:/terraform
|
||||
working_dir: /terraform
|
||||
network_mode: host
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user