This commit is contained in:
viktorbarzin 2021-02-07 23:45:55 +00:00
commit 7a7bc34ae3
32 changed files with 4857 additions and 0 deletions

35
.gitignore vendored Normal file
View file

@ -0,0 +1,35 @@
# Created by https://www.toptal.com/developers/gitignore/api/terraform
# Edit at https://www.toptal.com/developers/gitignore?templates=terraform
### Terraform ###
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
# .tfvars files are managed as part of configuration and so should be included in
# version control.
#
# example.tfvars
*.tfvars
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

11
idrac-power-cycle.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/bash
# Get power supply on outside system voltage
curl -s -k -u root:calvin -H"Content-type: application/json" -X GET https://idrac/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2 |jq .LineInputVoltage
# Power off
curl -s -k -u root:calvin -X POST -d '{"Action": "Reset", "ResetType": "GracefulShutdown"}' -H"Content-type: application/json" https://idrac/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset
# Power on
curl -s -k -u root:calvin -X POST -d '{"Action": "Reset", "ResetType": "On"}' -H"Content-type: application/json" https://idrac/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset

164
main.tf Normal file
View file

@ -0,0 +1,164 @@
variable "vsphere_password" {}
variable "vsphere_user" {}
variable "vsphere_server" {}
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "client_certificate_secret_name" {}
variable "mailserver_accounts" {}
variable "mailserver_aliases" {}
variable "pihole_web_password" {}
variable "webhook_handler_secret" {}
variable "wireguard_wg_0_conf" {}
variable "wireguard_firewall_sh" {}
variable "hackmd_db_password" {}
variable "bind_db_viktorbarzin_me" {}
variable "bind_db_viktorbarzin_lan" {}
variable "bind_named_conf_options" {}
variable "alertmanager_account_password" {}
variable "wireguard_wg_0_key" {}
variable "ansible_prefix" {
default = "ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault_pass.txt ansible-playbook -i playbook/hosts.yaml playbook/linux.yml -t linux/initial_setup"
description = "Provisioner command"
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "helm" {
kubernetes {
config_path = "~/.kube/config"
}
}
# Main module to init infra from
module "pxe_server" {
source = "./modules/create-vm"
vm_name = "pxe-server"
network = "dManagementVMs"
# provisioner_command = "${var.ansible_prefix} -t linux/pxe-server/add-distro"
provisioner_command = "# no provisioner needed #" # Noop until ubuntu autoinstall is setup
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
cdrom_path = "ISO/ubuntu-server-20.04.1.iso"
vm_disk_size = 50
vm_mac_address = "00:50:56:87:4a:2d"
}
module "k8s_master" {
source = "./modules/create-vm"
vm_name = "k8s-master"
vm_mac_address = "00:50:56:b0:a1:39"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/master -e hostname=k8s-master"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
module "k8s_node1" {
source = "./modules/create-vm"
vm_name = "k8s-node1"
vm_mac_address = "00:50:56:b0:e0:c9"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/node -e hostname=k8s-node1 -e k8s_master='wizard@${module.k8s_master.guest_ip}'"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
module "k8s_node2" {
source = "./modules/create-vm"
vm_name = "k8s-node2"
vm_mac_address = "00:50:56:b0:a1:36"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/node -e hostname=k8s-node2 -e k8s_master='wizard@${module.k8s_master.guest_ip}'"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
module "k8s_node3" {
source = "./modules/create-vm"
vm_name = "k8s-node3"
vm_mac_address = "00:50:56:b0:a1:37"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/node -e hostname=k8s-node3 -e k8s_master='wizard@${module.k8s_master.guest_ip}'"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
module "k8s_node4" {
source = "./modules/create-vm"
vm_name = "k8s-node4"
vm_mac_address = "00:50:56:b0:a1:38"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/node -e hostname=k8s-node4 -e k8s_master='wizard@${module.k8s_master.guest_ip}'"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
module "k8s_node5" {
source = "./modules/create-vm"
vm_name = "k8s-node5"
vm_mac_address = "00:50:56:b0:a1:40"
network = "dKubernetes"
provisioner_command = "${var.ansible_prefix} -t linux/k8s/node -e hostname=k8s-node5 -e k8s_master='wizard@${module.k8s_master.guest_ip}'"
vsphere_password = var.vsphere_password
vsphere_user = var.vsphere_user
vsphere_server = var.vsphere_server
vsphere_datastore = "r730-datastore"
vsphere_resource_pool = "R730"
}
# resource "null_resource" "test" {
# provisioner "local-exec" {
# working_dir = "/home/viktor/"
# command = "ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault_pass.txt ansible-playbook -i playbook/hosts.yaml playbook/linux.yml -t linux/k8s/node -e host='10.0.40.126'"
# }
# }
module "kubernetes_cluster" {
source = "./modules/kubernetes"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
client_certificate_secret_name = var.client_certificate_secret_name
mailserver_accounts = var.mailserver_accounts
mailserver_aliases = var.mailserver_aliases
pihole_web_password = var.pihole_web_password
webhook_handler_secret = var.webhook_handler_secret
wireguard_wg_0_conf = var.wireguard_wg_0_conf
wireguard_wg_0_key = var.wireguard_wg_0_key
wireguard_firewall_sh = var.wireguard_firewall_sh
hackmd_db_password = var.hackmd_db_password
bind_db_viktorbarzin_me = var.bind_db_viktorbarzin_me
bind_db_viktorbarzin_lan = var.bind_db_viktorbarzin_lan
bind_named_conf_options = var.bind_named_conf_options
alertmanager_account_password = var.alertmanager_account_password
}

4
migrate_tfstate.txt Normal file
View file

@ -0,0 +1,4 @@
# Steps to migrate 1 .tfstate into another
# Inside the dir to be migrated out from do:
for s in $(tf state list); do tf state mv -state-out=../../terraform.tfstate $s "module.UPPER_WORKSPACE_MODULE_NAME.$s"; done

153
modules/create-vm/main.tf Normal file
View file

@ -0,0 +1,153 @@
variable "vsphere_user" {
default = "Administrator@viktorbarzin.lan"
}
variable "vsphere_password" {}
variable "vsphere_server" {
default = "vcenter"
}
variable "vm_name" {
default = "terraform-test"
}
variable "vm_cpus" {
type = number
default = 4
}
variable "vm_mem" {
type = number
default = 4096
}
variable "vm_guest_id" {
default = "ubuntu64Guest"
}
variable "vm_disk_size" {
type = number
default = 64
}
variable "provisioner_command" {
description = "Additional provisioning commands to run"
# default = "#"
type = string
}
variable "network" {
description = "Network to attach the vm guest to"
}
variable "ceph_disk_size" {
type = number
default = 0
}
variable "cdrom_path" {
type = string
default = ""
}
variable "vsphere_datastore" {
type = string
default = "r730-datastore"
}
variable "vsphere_resource_pool" {
type = string
default = "R730"
}
variable "vm_mac_address" {
type = string
default = ""
}
provider "vsphere" {
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
# If you have a self-signed cert
allow_unverified_ssl = true
}
data "vsphere_datacenter" "dc" {
name = "Home"
}
data "vsphere_datastore" "datastore" {
name = var.vsphere_datastore
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_resource_pool" "pool" {
name = var.vsphere_resource_pool
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_network" "network" {
name = var.network
datacenter_id = data.vsphere_datacenter.dc.id
}
resource "vsphere_virtual_machine" "vm" {
name = var.vm_name
resource_pool_id = data.vsphere_resource_pool.pool.id
datastore_id = data.vsphere_datastore.datastore.id
num_cpus = var.vm_cpus
memory = var.vm_mem
guest_id = var.vm_guest_id
# If mac address is set create NIC with that MAC
dynamic "network_interface" {
for_each = var.vm_mac_address != "" ? [1] : []
content {
network_id = data.vsphere_network.network.id
use_static_mac = true
mac_address = var.vm_mac_address
}
}
# Else create a NIC with random MAC
dynamic "network_interface" {
for_each = var.vm_mac_address == "" ? [1] : []
content {
network_id = data.vsphere_network.network.id
}
}
disk {
label = "disk0"
size = var.vm_disk_size
}
dynamic "disk" {
for_each = var.ceph_disk_size > 0 ? [1] : []
content {
label = "ceph-disk0"
size = var.ceph_disk_size
unit_number = 1
}
}
dynamic "cdrom" {
for_each = var.cdrom_path != "" ? [1] : []
content {
datastore_id = data.vsphere_datastore.datastore.id
path = var.cdrom_path
}
}
wait_for_guest_net_timeout = 600
provisioner "local-exec" {
# for_each = var.provisioner_command != "" ? [1] : []
# content {
command = "${var.provisioner_command} -e 'host=${vsphere_virtual_machine.vm.default_ip_address}'"
# }
}
}
output "guest_ip" {
value = vsphere_virtual_machine.vm.default_ip_address
}

View file

@ -0,0 +1,85 @@
variable "named_conf_mounts" {}
variable "deployment_name" {}
resource "kubernetes_deployment" "bind" {
metadata {
name = var.deployment_name
namespace = "bind"
labels = {
"app" = "bind"
"kubernetes.io/cluster-service" : "true"
}
}
spec {
replicas = "3"
selector {
match_labels = {
"app" = var.deployment_name
}
}
template {
metadata {
labels = {
"app" = var.deployment_name
"kubernetes.io/cluster-service" : "true"
}
}
spec {
container {
name = "bind"
image = "resystit/bind9:latest"
image_pull_policy = "IfNotPresent"
port {
container_port = 53
protocol = "UDP"
}
volume_mount {
mount_path = "/etc/bind/named.conf"
sub_path = "named.conf"
name = "bindconf"
}
dynamic "volume_mount" {
for_each = [for m in var.named_conf_mounts :
{
name = m.name
mount_path = m.mount_path
sub_path = m.sub_path
}]
content {
name = volume_mount.value.name
mount_path = volume_mount.value.mount_path
sub_path = volume_mount.value.sub_path
}
}
volume_mount {
mount_path = "/etc/bind/db.viktorbarzin.me"
sub_path = "db.viktorbarzin.me"
name = "bindconf"
}
volume_mount {
mount_path = "/etc/bind/db.viktorbarzin.lan"
sub_path = "db.viktorbarzin.lan"
name = "bindconf"
}
}
container {
name = "bind-exporter"
image = "prometheuscommunity/bind-exporter:latest"
image_pull_policy = "IfNotPresent"
port {
container_port = 9119
}
}
volume {
name = "bindconf"
config_map {
name = "bind-configmap"
}
}
}
}
}
}

View file

@ -0,0 +1,72 @@
variable "db_viktorbarzin_me" {}
variable "db_viktorbarzin_lan" {}
variable "named_conf_options" {}
resource "kubernetes_namespace" "bind" {
metadata {
name = "bind"
}
}
resource "kubernetes_config_map" "bind_configmap" {
metadata {
name = "bind-configmap"
namespace = "bind"
}
data = {
"db.viktorbarzin.lan" = var.db_viktorbarzin_lan
"db.viktorbarzin.me" = var.db_viktorbarzin_me
"named.conf" = var.named_conf
"named.conf.local" = var.named_conf_local
"named.conf.options" = var.named_conf_options
"public-named.conf.local" = var.public_named_conf_local
"public-named.conf.options" = var.public_named_conf_options
}
}
module "bind-local-deployment" {
source = "./deployment-factory"
deployment_name = "bind"
named_conf_mounts = [
{
"mount_path" = "/etc/bind/named.conf.local"
"sub_path" = "named.conf.local"
"name" = "bindconf"
},
{
mount_path = "/etc/bind/named.conf.options"
sub_path = "named.conf.options"
name = "bindconf"
}
]
}
module "bind-local-service" {
source = "./service-factory"
service_name = "bind"
port = 5354
}
module "bind-public-deployment" {
source = "./deployment-factory"
deployment_name = "bind-public"
named_conf_mounts = [
{
"mount_path" = "/etc/bind/named.conf.local"
"sub_path" = "public-named.conf.local"
"name" = "bindconf"
},
{
mount_path = "/etc/bind/named.conf.options"
sub_path = "public-named.conf.options"
name = "bindconf"
}
]
}
module "bind-public-service" {
source = "./service-factory"
service_name = "bind-public"
port = 10053
}

View file

@ -0,0 +1,28 @@
variable "service_name" {}
variable "port" {}
resource "kubernetes_service" "bind" {
metadata {
name = var.service_name
namespace = "bind"
annotations = {
"metallb.universe.tf/allow-shared-ip" = "shared"
}
labels = {
"app" = var.service_name
}
}
spec {
type = "LoadBalancer"
external_traffic_policy = "Cluster"
selector = {
"app" = var.service_name
}
port {
name = "dns"
protocol = "UDP"
port = var.port
target_port = "53"
}
}
}

View file

@ -0,0 +1,71 @@
variable "named_conf" {
default = <<EOT
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
//include "/etc/bind/named.conf.default-zones";
EOT
}
variable "named_conf_local" {
default = <<EOT
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
zone "viktorbarzin.me" {
type master;
file "/etc/bind/db.viktorbarzin.me";
};
zone "viktorbarzin.lan" {
type master;
file "/etc/bind/db.viktorbarzin.lan";
};
EOT
}
variable "public_named_conf_local" {
default = <<EOT
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
zone "viktorbarzin.me" {
type master;
file "/etc/bind/db.viktorbarzin.me";
};
EOT
}
variable "public_named_conf_options" {
default = <<EOT
options {
querylog yes;
directory "/tmp/";
listen-on {
any;
};
dnssec-validation auto;
allow-recursion {
none;
};
};
EOT
}

View file

@ -0,0 +1,130 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
resource "kubernetes_namespace" "website" {
metadata {
name = "website"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "website"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_deployment" "blog" {
metadata {
name = "blog"
namespace = "website"
labels = {
run = "blog"
}
}
spec {
replicas = 3
selector {
match_labels = {
run = "blog"
}
}
template {
metadata {
labels = {
run = "blog"
}
}
spec {
container {
image = "viktorbarzin/blog:latest"
name = "blog"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "50Mi"
}
}
port {
container_port = 80
}
}
container {
image = "nginx/nginx-prometheus-exporter"
name = "nginx-exporter"
args = ["-nginx.scrape-uri", "http://127.0.0.1:8080/nginx_status"]
port {
container_port = 9113
}
}
}
}
}
}
resource "kubernetes_service" "blog" {
metadata {
name = "blog"
namespace = "website"
labels = {
"run" = "blog"
}
annotations = {
"prometheus.io/scrape" = "true"
"prometheus.io/path" = "/metrics"
"prometheus.io/port" = "9113"
}
}
spec {
selector = {
run = "blog"
}
port {
name = "http"
port = "80"
target_port = "80"
}
port {
name = "prometheus"
port = "9113"
target_port = "9113"
}
}
}
resource "kubernetes_ingress" "blog" {
metadata {
name = "blog-ingress"
namespace = "website"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "blog"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,92 @@
resource "kubernetes_namespace" "dnscrypt" {
metadata {
name = "dnscrypt"
}
}
resource "kubernetes_config_map" "dnscrypt" {
metadata {
name = "dnscrypt-proxy-configmap"
namespace = "dnscrypt"
}
data = {
"dnscrypt-proxy.toml" = var.dnscrypt_proxy_toml
}
}
resource "kubernetes_deployment" "dnscrypt" {
metadata {
name = "dnscrypt-proxy"
namespace = "dnscrypt"
labels = {
app = "dnscrypt-proxy"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
replicas = 3
selector {
match_labels = {
app = "dnscrypt-proxy"
}
}
template {
metadata {
labels = {
app = "dnscrypt-proxy"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
container {
image = "gists/dnscrypt-proxy:latest"
name = "dnscrypt-proxy"
image_pull_policy = "IfNotPresent"
port {
container_port = 53
protocol = "UDP"
}
volume_mount {
name = "config"
mount_path = "/etc/dnscrypt-proxy/"
}
}
volume {
name = "config"
config_map {
name = "dnscrypt-proxy-configmap"
items {
key = "dnscrypt-proxy.toml"
path = "dnscrypt-proxy.toml"
}
}
}
}
}
}
}
resource "kubernetes_service" "dnscrypt" {
metadata {
name = "dnscrypt-proxy"
namespace = "dnscrypt"
labels = {
"app" = "dnscrypt-proxy"
}
annotations = {
"metallb.universe.tf/allow-shared-ip" = "shared"
}
}
spec {
type = "LoadBalancer"
selector = {
app = "dnscrypt-proxy"
}
port {
name = "dns"
protocol = "UDP"
port = "5353"
target_port = "53"
}
}
}

View file

@ -0,0 +1,113 @@
variable tls_secret_name {}
variable "tls_crt" {}
variable "tls_key" {}
resource "kubernetes_namespace" "f1-stream" {
metadata {
name = "f1-stream"
}
}
resource "kubernetes_deployment" "f1-stream" {
metadata {
name = "f1-stream"
namespace = "f1-stream"
labels = {
app = "f1-stream"
}
}
spec {
replicas = 3
selector {
match_labels = {
app = "f1-stream"
}
}
template {
metadata {
labels = {
app = "f1-stream"
}
}
spec {
container {
image = "viktorbarzin/f1-stream:latest"
name = "f1-stream"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "512Mi"
}
}
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "f1-stream" {
metadata {
name = "f1-stream"
namespace = "f1-stream"
labels = {
"app" = "f1-stream"
}
}
spec {
selector = {
app = "f1-stream"
}
port {
port = "80"
}
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "f1-stream"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_ingress" "f1-stream" {
metadata {
name = "f1-ingress"
namespace = "f1-stream"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
"nginx.ingress.kubernetes.io/force-ssl-redirect" : "false"
"nginx.ingress.kubernetes.io/ssl-redirect" : "false"
}
}
spec {
tls {
hosts = ["f1.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "f1.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "f1-stream"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,168 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "hackmd_db_password" {}
resource "kubernetes_namespace" "hackmd" {
metadata {
name = "hackmd"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "hackmd"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_deployment" "hackmd" {
metadata {
name = "hackmd"
namespace = "hackmd"
labels = {
app = "hackmd"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
replicas = 1
strategy {
type = "Recreate"
}
selector {
match_labels = {
app = "hackmd"
}
}
template {
metadata {
labels = {
app = "hackmd"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
container {
image = "postgres:11.6-alpine"
name = "postgres"
image_pull_policy = "IfNotPresent"
env {
name = "POSTGRES_USER"
value = "codimd"
}
env {
name = "POSTGRES_PASSWORD"
value = var.hackmd_db_password
}
env {
name = "POSTGRES_DB"
value = "codimd"
}
resources {
limits = {
cpu = "1"
memory = "1Gi"
}
requests = {
cpu = "1"
memory = "1Gi"
}
}
port {
container_port = 80
}
volume_mount {
name = "data"
mount_path = "/var/lib/postgresql/data"
sub_path = "postgres"
}
}
container {
name = "codumd"
image = "nabo.codimd.dev/hackmdio/hackmd:2.0.1"
image_pull_policy = "IfNotPresent"
env {
name = "CMD_DB_URL"
value = format("%s%s%s", "postgres://codimd:", var.hackmd_db_password, "@localhost/codimd")
}
env {
name = "CMD_USECDN"
value = "false"
}
volume_mount {
name = "data"
mount_path = "/home/hackmd/app/public/uploads"
sub_path = "hackmd"
}
port {
name = "http"
container_port = 3000
protocol = "TCP"
}
}
volume {
name = "data"
iscsi {
target_portal = "iscsi.viktorbarzin.lan:3260"
fs_type = "ext4"
iqn = "iqn.2020-12.lan.viktorbarzin:storage:hackmd"
lun = 0
read_only = false
}
}
}
}
}
}
resource "kubernetes_service" "hackmd" {
metadata {
name = "hackmd"
namespace = "hackmd"
labels = {
"app" = "hackmd"
}
}
spec {
selector = {
app = "hackmd"
}
port {
port = "80"
target_port = "3000"
}
}
}
resource "kubernetes_ingress" "hackmd" {
metadata {
name = "hackmd-ingress"
namespace = "hackmd"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["hackmd.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "hackmd.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "hackmd"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,12 @@
#!/bin/bash
user="user"
pass="pass"
# Get power supply on outside system voltage
curl -s -k -u $user:$pass -H"Content-type: application/json" -X GET https://idrac/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2 |jq .LineInputVoltage
# Power off
curl -s -k -u $user:$pass -X POST -d '{"Action": "Reset", "ResetType": "GracefulShutdown"}' -H"Content-type: application/json" https://idrac/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset
# Power on
curl -s -k -u $user:$pass -X POST -d '{"Action": "Reset", "ResetType": "On"}' -H"Content-type: application/json" https://idrac/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset

View file

@ -0,0 +1,95 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "client_certificate_secret_name" {}
module "dashboard" {
# source = "cookielab/dashboard/kubernetes"
# source = "ViktorBarzin/dashboard/kubernetes"
# version = "0.13.0"
# TODO: update this once merged
source = "/opt/terraform-kubernetes-dashboard"
# insert the 1 required variable here
kubernetes_dashboard_csrf = "kekerino"
kubernetes_dashboard_deployment_args = list(
"--auto-generate-certificates",
"--token-ttl=0"
)
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "kubernetes-dashboard"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
# # locals {
# # resources = split("---\n", file("${path.module}/recommended.yaml"))
# # }
# # resource "k8s_manifest" "kubernetes-dashboard-manifests" {
# # count = length(local.resources) - 1
# # # count = 2
# # # content = local.resources[1 + count.index]
# # # content = file("${path.module}/recommended.yaml")
# # content = local.resources[1]
# # depends_on = [kubernetes_namespace.kubernetes-dashboard]
# # }
# resource "kubectl_manifest" "kubernetes-dashboard-manifests" {
# yaml_body = file("${path.module}/recommended.yaml")
# force_new = true
# depends_on = [kubernetes_namespace.kubernetes-dashboard]
# }
resource "kubernetes_ingress" "kubernetes-dashboard" {
metadata {
name = "kubernetes-dashboard"
namespace = "kubernetes-dashboard"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTPS"
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
"nginx.ingress.kubernetes.io/auth-tls-secret" = var.client_certificate_secret_name
}
}
spec {
tls {
hosts = ["k8s.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "k8s.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "kubernetes-dashboard"
service_port = "443"
}
}
}
}
}
depends_on = [module.dashboard]
}
# Give cluster-admin permissions to dashboard
resource "kubernetes_cluster_role_binding" "kubernetes-dashboard" {
metadata {
name = "admin-user"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "cluster-admin"
}
subject {
kind = "ServiceAccount"
name = "kubernetes-dashboard"
namespace = "kubernetes-dashboard"
}
depends_on = [module.dashboard]
}

View file

@ -0,0 +1,209 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
resource "kubernetes_namespace" "kms" {
metadata {
name = "kms"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "kms"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_config_map" "kms-web-page" {
metadata {
name = "kms-web-page-config"
namespace = "kms"
}
data = {
"index.html" = var.index_html
}
}
resource "kubernetes_deployment" "kms-web-page" {
metadata {
name = "kms-web-page"
namespace = "kms"
labels = {
"app" = "kms-web-page"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
replicas = 3
selector {
match_labels = {
"app" = "kms-web-page"
}
}
template {
metadata {
labels = {
"app" = "kms-web-page"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
container {
image = "nginx"
name = "kms-web-page"
image_pull_policy = "IfNotPresent"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "0.5"
memory = "512Mi"
}
}
port {
container_port = 80
protocol = "TCP"
}
volume_mount {
name = "config"
mount_path = "/usr/share/nginx/html/"
}
}
volume {
name = "config"
config_map {
name = "kms-web-page-config"
items {
key = "index.html"
path = "index.html"
}
}
}
}
}
}
depends_on = [kubernetes_config_map.kms-web-page]
}
resource "kubernetes_service" "kms-web-page" {
metadata {
name = "kms-web-page"
namespace = "kms"
labels = {
"app" = "kms-web-page"
}
}
spec {
selector = {
"app" = "kms-web-page"
}
port {
port = "80"
protocol = "TCP"
}
}
}
resource "kubernetes_ingress" "kms-web-page" {
metadata {
name = "kms-web-page"
namespace = "kms"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["kms.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "kms.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "kms-web-page"
service_port = "80"
}
}
}
}
}
}
resource "kubernetes_deployment" "windows_kms" {
metadata {
name = "kms"
namespace = "kms"
labels = {
app = "kms-service"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "kms-service"
}
}
template {
metadata {
labels = {
app = "kms-service"
}
}
spec {
container {
image = "kebe/vlmcsd:latest"
name = "windows-kms"
resources {
limits = {
cpu = "1"
memory = "512Mi"
}
requests = {
cpu = "1"
memory = "50Mi"
}
}
port {
container_port = 1688
}
}
}
}
}
}
resource "kubernetes_service" "windows_kms" {
metadata {
name = "windows-kms"
namespace = "kms"
labels = {
"app" = "windows-kms"
}
annotations = {
"metallb.universe.tf/allow-shared-ip" = "shared"
}
}
spec {
type = "LoadBalancer"
external_traffic_policy = "Cluster"
selector = {
"app" = "windows-kms"
}
port {
port = "1688"
}
}
}

View file

@ -0,0 +1,68 @@
variable "index_html" {
default = <<EOT
<h1>How to activate windows</h1>
Open the following link and find a key for you version of windows: </br>
<b><a href="https://goo.gl/BcrPjW" target="_blank">https://goo.gl/BcrPjW</a></b>
</br>
</br>
Open cmd as <b>Administrator</b> and run the following: </br>
</br>
<b>slmgr.vbs /ipk key_for_your_windows</b>
</br>
<b>slmgr.vbs /skms kms.viktorbarzin.me </b>
<br>
<b>
slmgr /ato
</b>
<br>
<p>
<h3> If you have an evaluation windows, you need to change it to retail one. This is how:</h3>
<br>
From an elevated command prompt, determine the current edition name with the command <br>
<strong>DISM /online /Get-CurrentEdition</strong>.
<br>Make note of the edition ID, an abbreviated form of the edition name. Then run
<br>
<strong>DISM /online /Set-Edition:<edition ID> /ProductKey:XXXXX-XXXXX-XXXXX-XXXXX-XXXXX /AcceptEula</strong>
<br> providing the edition ID and a retail product key. The server will restart
</p>
<hr>
<h1>How to activate Microsoft Office</h1>
<br>
<b>
CD \Program Files\Microsoft Office\Office16 </b> OR <b>CD \Program Files (x86)\Microsoft Office\Office16
</b>
<br>
<b>
cscript ospp.vbs /sethst:kms.viktorbarzin.me
</b>
<br>
<b>
cscript ospp.vbs /inpkey:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
</b>
<br>
where 'xxxx' is a key for your office. Some examples for office 2016 - <a
href="https://www.techdee.com/microsoft-office-2016-product-key/">https://www.techdee.com/microsoft-office-2016-product-key/</a>
<br>
<b>
cscript ospp.vbs /act
</b>
<br>
<br>
If you messed up activation settings reset them using
<br>
slmgr /upk
<br>
slmgr /cpky
<br>
and
<br>
slmgr /rearm
<h3>Buy me a beer :P</h3>
EOT
}

View file

@ -0,0 +1,65 @@
variable "mailserver_accounts" {}
variable postfix_account_aliases {}
resource "kubernetes_namespace" "mailserver" {
metadata {
name = "mailserver"
}
}
resource "kubernetes_config_map" "mailserver_env_config" {
metadata {
name = "mailserver.env.config"
namespace = "mailserver"
labels = {
app = "mailserver"
}
}
data = {
DMS_DEBUG = "0"
ENABLE_CLAMAV = "0"
ENABLE_FAIL2BAN = "1"
ENABLE_FETCHMAIL = "0"
ENABLE_POSTGREY = "0"
ENABLE_SPAMASSASSIN = "0"
ENABLE_SRS = "1"
FETCHMAIL_POLL = "120"
ONE_DIR = "1"
OVERRIDE_HOSTNAME = "mail.viktorbarzin.me"
TLS_LEVEL = "intermediate"
}
}
locals {
postfix_accounts_cf = join("\n", [for user, pass in var.mailserver_accounts : "${user}|${bcrypt(pass, 6)}"])
# postfix_accounts_cf = join("\n", [for user, pass in var.mailserver_accounts : format("%s%s%s", user, "|{SHA512-CRYPT}$6$$", sha512(pass))]) # Does not work :/
}
resource "kubernetes_config_map" "mailserver_config" {
metadata {
name = "mailserver.config"
namespace = "mailserver"
labels = {
app = "mailserver"
}
}
data = {
# Actual mail settings
"postfix-accounts.cf" = local.postfix_accounts_cf
"postfix-main.cf" = var.postfix_cf
"postfix-virtual.cf" = var.postfix_account_aliases
KeyTable = "mail._domainkey.viktorbarzin.me viktorbarzin.me:mail:/etc/opendkim/keys/viktorbarzin.me-mail.key\n"
SigningTable = "*@viktorbarzin.me mail._domainkey.viktorbarzin.me\n"
TrustedHosts = "127.0.0.1\nlocalhost\n"
}
# Password hashes are different each time and avoid changing secret constantly.
# Either 1.Create consistent hashes or 2.Find a way to ignore_changes on per password
lifecycle {
ignore_changes = [data["postfix-accounts.cf"]]
}
}

View file

@ -0,0 +1,118 @@
variable "postfix_cf" {
default = <<EOT
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
smtpd_banner = $myhostname ESMTP $mail_name (Debian)
biff = no
append_dot_mydomain = no
readme_directory = no
# Basic configuration
# myhostname =
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, localhost.$mydomain, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::1]/128 [fe80::]/64 10.47.0.11/32
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
#smtpd_tls_CAfile=
#smtp_tls_CAfile=
smtpd_tls_security_level = may
smtpd_use_tls=yes
smtpd_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_loglevel = 1
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist = ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
tls_preempt_cipherlist = yes
smtpd_tls_protocols = !SSLv2,!SSLv3
smtp_tls_protocols = !SSLv2,!SSLv3
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3
smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256, RSA+AES, eNULL
smtpd_tls_dh1024_param_file = /etc/postfix/dhparams.pem
smtpd_tls_CApath = /etc/ssl/certs
smtp_tls_CApath = /etc/ssl/certs
# Settings to prevent SPAM early
smtpd_helo_required = yes
smtpd_delay_reject = yes
smtpd_helo_restrictions = permit_mynetworks, reject_invalid_helo_hostname, permit
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_recipient_domain, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net
smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_unauth_pipelining
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain
disable_vrfy_command = yes
# Postscreen settings to drop zombies/open relays/spam early
postscreen_dnsbl_action = enforce
postscreen_dnsbl_sites = zen.spamhaus.org*3
bl.mailspike.net
b.barracudacentral.org*2
bl.spameatingmonkey.net
bl.spamcop.net
dnsbl.sorbs.net
psbl.surriel.com
list.dnswl.org=127.0.[0..255].0*-2
list.dnswl.org=127.0.[0..255].1*-3
list.dnswl.org=127.0.[0..255].[2..3]*-4
postscreen_dnsbl_threshold = 3
postscreen_dnsbl_whitelist_threshold = -1
postscreen_greet_action = enforce
postscreen_bare_newline_action = enforce
# SASL
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = /var/spool/postfix/private/auth
smtpd_sasl_type = dovecot
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
# Mail directory
virtual_transport = lmtp:unix:/var/run/dovecot/lmtp
virtual_mailbox_domains = /etc/postfix/vhost
virtual_mailbox_maps = texthash:/etc/postfix/vmailbox
virtual_alias_maps = texthash:/etc/postfix/virtual
# Additional option for filtering
content_filter = smtp-amavis:[127.0.0.1]:10024
# Milters used by DKIM
milter_protocol = 6
milter_default_action = accept
dkim_milter = inet:localhost:8891
dmarc_milter = inet:localhost:8893
smtpd_milters = $dkim_milter,$dmarc_milter
non_smtpd_milters = $dkim_milter
# SPF policy settings
policyd-spf_time_limit = 3600
# Header checks for content inspection on receiving
header_checks = pcre:/etc/postfix/maps/header_checks.pcre
# Remove unwanted headers that reveail our privacy
smtp_header_checks = pcre:/etc/postfix/maps/sender_header_filter.pcre
myhostname = mail.viktorbarzin.me
mydomain = viktorbarzin.me
smtputf8_enable = no
message_size_limit = 10240000
sender_canonical_maps = tcp:localhost:10001
sender_canonical_classes = envelope_sender
recipient_canonical_maps = tcp:localhost:10002
recipient_canonical_classes = envelope_recipient,header_recipient
compatibility_level = 2
always_add_missing_headers = yes
EOT
}

133
modules/kubernetes/main.tf Normal file
View file

@ -0,0 +1,133 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "client_certificate_secret_name" {}
variable "hackmd_db_password" {}
variable "mailserver_accounts" {}
variable "mailserver_aliases" {}
variable "pihole_web_password" {}
variable "webhook_handler_secret" {}
variable "wireguard_wg_0_conf" {}
variable "wireguard_wg_0_key" {}
variable "wireguard_firewall_sh" {}
variable "bind_db_viktorbarzin_me" {}
variable "bind_db_viktorbarzin_lan" {}
variable "bind_named_conf_options" {}
variable "alertmanager_account_password" {}
module "blog" {
source = "./blog"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
module "bind" {
source = "./bind"
db_viktorbarzin_me = var.bind_db_viktorbarzin_me
db_viktorbarzin_lan = var.bind_db_viktorbarzin_lan
named_conf_options = var.bind_named_conf_options
}
module "dnscrypt" {
source = "./dnscrypt"
}
module "f1-stream" {
source = "./f1-stream"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
module "hackmd" {
source = "./hackmd"
hackmd_db_password = var.hackmd_db_password
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
# TODO
# module "ingress-nginx" {
# source = "./ingress-nginx"
# }
module "kms" {
source = "./kms"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
# TODO
# module "kube-system"{}
module "k8s-dashboard" {
source = "./k8s-dashboard"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
client_certificate_secret_name = var.client_certificate_secret_name
}
module "mailserver" {
source = "./mailserver"
mailserver_accounts = var.mailserver_accounts
postfix_account_aliases = var.mailserver_aliases
}
module "metallb" {
source = "./metallb"
}
module monitoring {
source = "./monitoring"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
alertmanager_account_password = var.alertmanager_account_password
}
module openid_help_page {
source = "./openid_help_page"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
module pihole {
source = "./pihole"
web_password = var.pihole_web_password
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
depends_on = [module.bind] # DNS goes like pihole -> bind -> dnscrypt
}
module privatebin {
source = "./privatebin"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
module webhook_handler {
source = "./webhook_handler"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
webhook_secret = var.webhook_handler_secret
}
module wireguard {
source = "./wireguard"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
wg_0_conf = var.wireguard_wg_0_conf
wg_0_key = var.wireguard_wg_0_key
firewall_sh = var.wireguard_firewall_sh
}

View file

@ -0,0 +1,21 @@
# Creates namespace and everythin needed
module "metallb" {
source = "colinwilson/metallb/kubernetes"
version = "0.1.5"
}
resource "kubernetes_config_map" "config" {
metadata {
name = "config"
namespace = "metallb-system"
}
data = {
config = <<EOT
address-pools:
- name: default
protocol: layer2
addresses:
- 10.0.20.200-10.0.20.220
EOT
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,148 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "alertmanager_account_password" {}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "monitoring"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "helm_release" "prometheus" {
namespace = "monitoring"
create_namespace = true
name = "prometheus"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "prometheus"
values = [templatefile("${path.module}/prometheus_chart_values.tpl", { alertmanager_mail_pass = var.alertmanager_account_password })]
}
# Terraform get angry with the 30k values file :/ use ansible until solved
# resource "helm_release" "prometheus_snmp_exporter" {
# namespace = "monitoring"
# create_namespace = true
# name = "prometheus_exporter"
# repository = "https://prometheus-community.github.io/helm-charts"
# chart = "prometheus-snmp-exporter"
# values = [file("${path.module}/prometheus_snmp_chart_values.yaml")]
# }
resource "kubernetes_secret" "prometheus_grafana_datasource" {
metadata {
name = "prometheus-grafana-datasource"
namespace = "monitoring"
labels = {
grafana_datasource = "1"
}
}
data = {
"datasource.yaml" = <<EOT
# config file version
apiVersion: 1
# list of datasources that should be deleted from the database
#deleteDatasources:
# - name: Prometheus
# orgId: 1
# list of datasources to insert/update depending
# whats available in the database
datasources:
# <string, required> name of the datasource. Required
- name: Prometheus
# <string, required> datasource type. Required
type: prometheus
# <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
access: proxy
# <int> org id. will default to orgId 1 if not specified
orgId: 1
# <string> url
url: http://prometheus-server
# <string> database password, if used
password:
# <string> database user, if used
user:
# <string> database name, if used
database:
# <bool> enable/disable basic auth
basicAuth:
# <string> basic auth username
basicAuthUser:
# <string> basic auth password
basicAuthPassword:
# <bool> enable/disable with credentials headers
withCredentials:
# <bool> mark as default datasource. Max one per org
isDefault:
# <map> fields that will be converted to json and stored in json_data
#jsonData:
# graphiteVersion: \"1.1\"
# tlsAuth: true
# tlsAuthWithCACert: true
# <string> json object of data that will be encrypted.
#secureJsonData:
# tlsCACert: \"...\"
# tlsClientCert: \"...\"
# tlsClientKey: \"...\"
version: 1
# <bool> allow users to edit datasources from the UI.
editable: false
EOT
}
type = "Opaque"
}
resource "kubernetes_persistent_volume" "prometheus_grafana_pv" {
metadata {
name = "grafana-iscsi-pv"
}
spec {
capacity = {
"storage" = "2Gi"
}
access_modes = ["ReadWriteOnce"]
persistent_volume_source {
iscsi {
target_portal = "iscsi.viktorbarzin.lan:3260"
iqn = "iqn.2020-12.lan.viktorbarzin:storage:monitoring:grafana"
lun = 0
fs_type = "ext4"
}
}
}
}
resource "kubernetes_persistent_volume_claim" "prometheus_grafana_pvc" {
metadata {
name = "grafana-iscsi-pvc"
namespace = "monitoring"
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
"storage" = "2Gi"
}
}
}
}
resource "helm_release" "grafana" {
namespace = "monitoring"
create_namespace = true
name = "grafana"
repository = "https://grafana.github.io/helm-charts"
chart = "grafana"
values = [file("${path.module}/grafana_chart_values.yaml")]
}

View file

@ -0,0 +1,176 @@
# Helm values
# all values - https://github.com/prometheus-community/helm-charts/blob/main/charts/prometheus/values.yaml
alertmanager:
persistentVolume:
# enabled: false
existingClaim: alertmanager-iscsi-pvc
# storageClass: rook-cephfs
strategy:
type: Recreate
ingress:
enabled: "true"
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# Enable client certificate authentication
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
# Create the secret containing the trusted ca certificates
nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
tls:
- secretName: "tls-secret"
hosts:
- "alertmanager.viktorbarzin.me"
hosts:
- "alertmanager.viktorbarzin.me"
alertmanagerFiles:
alertmanager.yml:
global:
smtp_from: "alertmanager@viktorbarzin.me"
# smtp_smarthost: "smtp.viktorbarzin.me:587"
smtp_smarthost: "mailserver.mailserver.svc.cluster.local:587"
smtp_auth_username: "alertmanager@viktorbarzin.me"
smtp_auth_password: "${alertmanager_mail_pass}"
smtp_require_tls: true
templates:
- "/etc/alertmanager/template/*.tmpl"
route:
group_by: ["alertname"]
group_wait: 3s
group_interval: 5s
repeat_interval: 1h
receiver: SMTP_STARTTLS
receivers:
- name: 'SMTP_STARTTLS'
email_configs:
- to: "me@viktorbarzin.me"
send_resolved: true
tls_config:
insecure_skip_verify: true
server:
# Enable me to delete metrics
# extraFlags:
# - "web.enable-admin-api"
persistentVolume:
# enabled: false
existingClaim: prometheus-iscsi-pvc
# storageClass: rook-cephfs
retention: "12w" # ~100GB storage
strategy:
type: Recreate
ingress:
enabled: "true"
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# Enable client certificate authentication
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
# Create the secret containing the trusted ca certificates
nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
tls:
- secretName: "tls-secret"
hosts:
- "prometheus.viktorbarzin.me"
hosts:
- "prometheus.viktorbarzin.me"
alertmanagers:
- static_configs:
- targets:
- "prometheus-alertmanager.monitoring.svc.cluster.local"
# - "alertmanager.viktorbarzin.me"
tls_config:
insecure_skip_verify: true
serverFiles:
# prometheus.yml:
# alertingaaa:
# alertmanagers:
# - static_configs:
# targets: "alertmanager.viktorbarzin.lan"
alerting_rules.yml:
groups:
- name: NodeDown
rules:
- alert: NodeDown
expr: up{job="kubernetes-nodes"} == 0
for: 1m
labels:
severity: page
annotations:
summary: Node down.
- name: NodeHighCPUUsage
rules:
- alert: NodeHighCPUUsage
expr: node_load1 > 2
# for: 10m
for: 1m # DEBUG
labels:
severity: page
annotations:
summary: High CPU usage on node.
# - name: PodStuckNotReady
# rules:
# - alert: PodStuckNotReady
# expr: kube_pod_status_ready{condition="true"} == 0
# for: 5m
# labels:
# severity: page
# annotations:
# summary: Pod stuck not ready.
- name: ReadyPodsInDeploymentLessThanSpec
rules:
- alert: ReadyPodsInDeploymentLessThanSpec
expr: kube_deployment_status_replicas_available - on(namespace, deployment) kube_deployment_spec_replicas < 0
for: 10m
labels:
severity: page
annotations:
summary: Number of ready pods in deployment is less than what is defined in spec.
- name: PowerOutage
rules:
- alert: PowerOutage
expr: r730_idrac_powerSupplyCurrentInputVoltage < 200
labels:
severity: page
annotations:
summary: Power voltage on a power supply is critically low indicating power outage.
extraScrapeConfigs: |
- job_name: 'snmp-idrac'
static_configs:
- targets:
- "idrac.viktorbarzin.lan:161"
metrics_path: '/snmp'
params:
module: [dell_idrac]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 'prometheus-snmp-exporter.monitoring.svc.cluster.local:9116'
metric_relabel_configs:
- source_labels: [ __name__ ]
target_label: '__name__'
action: replace
regex: '(.*)'
replacement: 'r730_idrac_${1}'
- job_name: 'openwrt'
static_configs:
- targets:
- "home.viktorbarzin.lan:9100"
metrics_path: '/metrics'
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 'home.viktorbarzin.lan:9100'
metric_relabel_configs:
- source_labels: [ __name__ ]
target_label: '__name__'
action: replace
regex: '(.*)'
replacement: 'openwrt_${1}'

View file

@ -0,0 +1,112 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
resource "kubernetes_namespace" "openid_help_page" {
metadata {
name = "openid-help-page"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "openid-help-page"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_deployment" "openid_help_page" {
metadata {
name = "openid-help-page"
namespace = "openid-help-page"
labels = {
app = "openid-help-page"
}
}
spec {
replicas = 3
selector {
match_labels = {
app = "openid-help-page"
}
}
template {
metadata {
labels = {
app = "openid-help-page"
}
}
spec {
container {
image = "viktorbarzin/openid-create-account-help-webpage:latest"
name = "openid-help-page"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "50Mi"
}
}
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "openid_help_page" {
metadata {
name = "openid-help-page"
namespace = "openid-help-page"
}
spec {
port {
name = "service-port"
protocol = "TCP"
port = 80
target_port = "80"
}
selector = {
app = "openid-help-page"
}
type = "ClusterIP"
session_affinity = "None"
}
}
resource "kubernetes_ingress" "openid_help_page" {
metadata {
name = "openid-help-page"
namespace = "openid-help-page"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["kubectl.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "kubectl.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "openid-help-page"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,200 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "web_password" {}
resource "kubernetes_namespace" "pihole" {
metadata {
name = "pihole"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "pihole"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_config_map" "external_conf" {
metadata {
name = "external-conf"
namespace = "pihole"
labels = {
app = "pihole"
}
}
data = {
"external.conf" = "$HTTP[\"host\"] == \"pihole.viktorbarzin.me\" {\n server.document-root = \"/var/www/html/admin/\"\n}\n"
}
}
resource "kubernetes_deployment" "pihole" {
metadata {
name = "pihole"
namespace = "pihole"
labels = {
app = "pihole"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "pihole"
}
}
template {
metadata {
labels = {
app = "pihole"
}
}
spec {
container {
image = "pihole/pihole:latest"
name = "pihole"
resources {
limits = {
cpu = "1"
memory = "1Gi"
}
requests = {
cpu = "1"
memory = "1Gi"
}
}
port {
container_port = 80
}
env {
name = "DNS1"
value = "10.0.20.200#5354" # bind
}
env {
name = "VIRTUAL_HOST"
value = "pihole.viktorbarzin.me"
}
env {
name = "WEBPASSWORD"
value = var.web_password
}
env {
name = "TZ"
value = "Europe/Sofia"
}
volume_mount {
name = "external-conf"
mount_path = "/tmp/external.conf"
sub_path = "external.conf"
}
volume_mount {
name = "pihole-local-etc-volume"
mount_path = "/etc/pihole"
}
volume_mount {
name = "pihole-local-dnsmasq-volume"
mount_path = "/etc/dnsmasq.d"
}
}
volume {
name = "external-conf"
config_map {
name = "external-conf"
}
}
volume {
name = "pihole-local-etc-volume"
empty_dir {} # no hard dependencies on truenas which needs dns
}
volume {
name = "pihole-local-dnsmasq-volume"
empty_dir {} # no hard dependencies on truenas which needs dns
}
}
}
}
}
resource "kubernetes_service" "pihole-dns" {
metadata {
name = "pihole-dns"
namespace = "pihole"
labels = {
"app" = "pihole"
}
annotations = {
"metallb.universe.tf/allow-shared-ip" : "shared"
}
}
spec {
type = "LoadBalancer"
external_traffic_policy = "Cluster"
selector = {
app = "pihole"
}
port {
name = "dns-udp"
port = "53"
protocol = "UDP"
}
}
}
resource "kubernetes_service" "pihole-web" {
metadata {
name = "pihole-web"
namespace = "pihole"
labels = {
"app" = "pihole"
}
annotations = {
"metallb.universe.tf/allow-shared-ip" : "shared"
}
}
spec {
selector = {
app = "pihole"
}
port {
name = "dns-web"
port = "80"
}
}
}
resource "kubernetes_ingress" "pihole" {
metadata {
name = "pihole-ingress"
namespace = "pihole"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
"nginx.ingress.kubernetes.io/auth-tls-secret" = "default/ca-secret"
}
}
spec {
tls {
hosts = ["pihole.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "pihole.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "pihole-web"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,144 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
resource "kubernetes_namespace" "privatebin" {
metadata {
name = "privatebin"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "privatebin"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_deployment" "privatebin" {
metadata {
name = "privatebin"
namespace = "privatebin"
labels = {
app = "privatebin"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
replicas = 1
strategy {
type = "Recreate"
}
selector {
match_labels = {
app = "privatebin"
}
}
template {
metadata {
labels = {
app = "privatebin"
"kubernetes.io/cluster-service" = "true"
}
}
spec {
container {
image = "privatebin/nginx-fpm-alpine"
name = "privatebin"
image_pull_policy = "IfNotPresent"
resources {
limits = {
cpu = "1"
memory = "1Gi"
}
requests = {
cpu = "1"
memory = "1Gi"
}
}
port {
container_port = 8080
}
volume_mount {
name = "data"
mount_path = "/srv/data"
sub_path = "data"
}
}
volume {
name = "data"
iscsi {
target_portal = "iscsi.viktorbarzin.lan:3260"
fs_type = "ext4"
iqn = "iqn.2020-12.lan.viktorbarzin:storage:privatebin"
lun = 0
read_only = false
}
}
}
}
}
}
resource "kubernetes_service" "privatebin" {
metadata {
name = "privatebin"
namespace = "privatebin"
labels = {
"app" = "privatebin"
}
}
spec {
selector = {
app = "privatebin"
}
port {
port = "80"
target_port = "8080"
}
}
}
resource "kubernetes_ingress" "privatebin" {
metadata {
name = "privatebin-ingress"
namespace = "privatebin"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["privatebin.viktorbarzin.me", "pb.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "privatebin.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "privatebin"
service_port = "80"
}
}
}
}
rule {
host = "pb.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "privatebin"
service_port = "80"
}
}
}
}
}
}

View file

@ -0,0 +1,16 @@
variable namespace {}
variable tls_secret_name {}
variable tls_crt {}
variable tls_key {}
resource "kubernetes_secret" "tls_secret" {
metadata {
name = var.tls_secret_name
namespace = var.namespace
}
data = {
"tls.crt" = var.tls_crt
"tls.key" = var.tls_key
}
type = "kubernetes.io/tls"
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
}
}
required_version = ">= 0.13"
}

View file

@ -0,0 +1,146 @@
variable "tls_secret_name" {}
variable "tls_crt" {}
variable "tls_key" {}
variable "webhook_secret" {}
resource "kubernetes_namespace" "webhook-handler" {
metadata {
name = "webhook-handler"
}
}
module "tls_secret" {
source = "../setup_tls_secret"
namespace = "webhook-handler"
tls_secret_name = var.tls_secret_name
tls_crt = var.tls_crt
tls_key = var.tls_key
}
resource "kubernetes_cluster_role" "deployment_updater" {
metadata {
name = "deployment-updater"
}
rule {
verbs = ["create", "update", "get", "patch", "list"]
api_groups = ["extensions", "apps", ""]
resources = ["deployments", "namespaces", "pods", "services"]
}
}
resource "kubernetes_cluster_role_binding" "update_deployment_binding" {
metadata {
name = "update-deployment-binding"
}
subject {
kind = "ServiceAccount"
name = "default"
namespace = "webhook-handler"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "deployment-updater"
}
}
resource "kubernetes_deployment" "webhook_handler" {
metadata {
name = "webhook-handler"
namespace = "webhook-handler"
labels = {
app = "webhook-handler"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "webhook-handler"
}
}
template {
metadata {
labels = {
app = "webhook-handler"
}
}
spec {
container {
image = "viktorbarzin/webhook-handler:latest"
name = "webhook-handler"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "50Mi"
}
}
port {
container_port = 80
}
env {
name = "WEBHOOKSECRET"
value = var.webhook_secret
}
}
}
}
}
}
resource "kubernetes_service" "webhook_handler" {
metadata {
name = "webhook-handler"
namespace = "webhook-handler"
labels = {
"app" = "webhook-handler"
}
}
spec {
selector = {
app = "webhook-handler"
}
port {
port = "80"
target_port = "3000"
}
}
}
resource "kubernetes_ingress" "webhook_handler" {
metadata {
name = "webhook-handler-ingress"
namespace = "webhook-handler"
annotations = {
"kubernetes.io/ingress.class" = "nginx"
}
}
spec {
tls {
hosts = ["webhook.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "webhook.viktorbarzin.me"
http {
path {
path = "/"
backend {
service_name = "webhook-handler"
service_port = "80"
}
}
}
}
}
}

1
playbook Symbolic link
View file

@ -0,0 +1 @@
../playbook

8
versions.tf Normal file
View file

@ -0,0 +1,8 @@
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
}
}
required_version = ">= 0.13"
}