diff --git a/.gitignore b/.gitignore index 15201ac..6d81f32 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,9 @@ cython_debug/ # PyPI configuration file .pypirc + + +# Terraform +*.tfstate +*.tfstate.* +.terraform/ \ No newline at end of file diff --git a/infra/fridge-openstack-infra/terraform/.terraform.lock.hcl b/infra/fridge-openstack-infra/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..c134795 --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/terraform-provider-openstack/openstack" { + version = "1.48.0" + constraints = "~> 1.48.0" + hashes = [ + "h1:qjf/qyH9oKOMujQk59bNxV8yLRbUhmihxMRrKOeA8qI=", + "zh:1fe237fa1153e05879fd26857416a1d029a3f108e32e83c4931dd874c777aa6a", + "zh:2c4587b4c810d569aafd69e287ecc2ee910e6c16cfc784e49861e0a8066b8655", + "zh:3f1a42fce3c925afeeaa96efae0bc9be95acfc80ba147a8123d03038d429df6b", + "zh:430511b62dc2fdafa070e9bd88e5e1fc39b3d667151aa9bf8e21b2c2c5421281", + "zh:4452279f6f23d3f2c5969deebf24ae2c38af8e02d52ee589b658c52b321835e5", + "zh:5525d1ca817f28ec9f0f648ea38b94fd0741130eaed2260bbd734efd03aecfb8", + "zh:675001e8cec8d0d4f006ce01b0608b7c5a378b4e56c6a27fbf5562f04371de70", + "zh:6c0f4da6da81da562e16af6fbb36035c0797de2a0384d0ef7c9a8b4676f8eca9", + "zh:79db708664ecbcf9d1a6d20e6a294716bff21a2641a8f58bfce60f3d11b944ef", + "zh:7bfc5ee6765694779fbfc00954fe04795035e85dfefd916dc6601717116b7005", + "zh:899a17c1547aa1bf732a55c903f3df25c8a0c107c16e0753677aecb8ed32130c", + "zh:9e02fb5267dc415a763ef55a24f3890f7e63de8d61e05e220d90a5a4a4b891ed", + "zh:a224e6e677e92cd31d0806a2d11c9bb17d032eaa0086e2aa8136ae0e9ce2fa83", + "zh:b3905869f6fea27ffd144eb8221ea67aeca63e23c06af43a221e55634faef3e2", + ] +} diff --git a/infra/fridge-openstack-infra/terraform/instances.tf b/infra/fridge-openstack-infra/terraform/instances.tf new file mode 100644 index 0000000..8c9131f --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/instances.tf @@ -0,0 +1,206 @@ +# create a port + +resource "openstack_networking_port_v2" "controller_isolated_port" { + name = "controller-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + + +resource "openstack_networking_port_v2" "worker1_isolated_port" { + name = "worker1-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + +# worker 2 port +resource "openstack_networking_port_v2" "worker2_isolated_port" { + name = "worker2-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + + +# Create port for private network + +resource "openstack_networking_port_v2" "controller_private_port" { + name = "controller-access-port" + network_id = openstack_networking_network_v2.private_network.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.private_subnet.id + } +} + + +resource "openstack_networking_port_v2" "worker1_private_port" { + name = "worker1-access-port" + network_id = openstack_networking_network_v2.private_network.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.private_subnet.id + } +} + +resource "openstack_networking_port_v2" "worker2_private_port" { + name = "worker2-access-port" + network_id = openstack_networking_network_v2.private_network.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.private_subnet.id + } +} + + +# instances + +resource "openstack_compute_instance_v2" "controller" { + name = "controller" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.proxy_sg.name ] + network { + port = openstack_networking_port_v2.controller_private_port.id #kubeproxy_private_port.id + } + network { + port = openstack_networking_port_v2.controller_isolated_port.id # kubeproxy_isolated_port.id + } +} + + +#worker1 + +resource "openstack_compute_instance_v2" "worker1" { + name = "worker1" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.proxy_sg.name ] + network { + port = openstack_networking_port_v2.worker1_private_port.id + } + network { + port = openstack_networking_port_v2.worker1_isolated_port.id + } +} + + + +#worker2 instance +resource "openstack_compute_instance_v2" "worker2" { + name = "worker2" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.proxy_sg.name ] + network { + port = openstack_networking_port_v2.worker2_private_port.id + } + network { + port = openstack_networking_port_v2.worker2_isolated_port.id + } +} + + +# create port for bastion +resource "openstack_networking_port_v2" "bastion_private_port" { + name = "bastion-access-port" + network_id = openstack_networking_network_v2.private_network.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.private_subnet.id + } +} + + + +# instances - bastion + +resource "openstack_compute_instance_v2" "bastion" { + name = "operator-bastion" + image_name = var.image_name + flavor_name = var.flavor_name_xsmall + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.bastion_sg.name ] + network { + port = openstack_networking_port_v2.bastion_private_port.id + } + +} + +# allocate floating ip +resource "openstack_networking_floatingip_v2" "bastion_fip" { + pool = var.external_network_name +} + +#associate floating ip + +resource "openstack_compute_floatingip_associate_v2" "bastion_fip_assoc" { + floating_ip = openstack_networking_floatingip_v2.bastion_fip.address + instance_id = openstack_compute_instance_v2.bastion.id +} + +# instance kube API VM in isolated network + +# create port for kubeapi +resource "openstack_networking_port_v2" "kubeapi_controller_isolated_port" { + name = "kubeapi_controller-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + + +resource "openstack_compute_instance_v2" "kubeapi_controller" { + name = "kubeapi_controller" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.isolated_sg.name ] + network { + port = openstack_networking_port_v2.kubeapi_controller_isolated_port.id + } +} + +resource "openstack_networking_port_v2" "kubeapi_worker1_isolated_port" { + name = "kubeapi_worker1-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + +resource "openstack_compute_instance_v2" "kubeapi_worker1" { + name = "kubeapi_worker1" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.isolated_sg.name ] + network { + port = openstack_networking_port_v2.kubeapi_worker1_isolated_port.id + } +} + +resource "openstack_networking_port_v2" "kubeapi_worker2_isolated_port" { + name = "kubeapi_worker2-isolated-port" + network_id = openstack_networking_network_v2.isolated_net.id + fixed_ip { + subnet_id = openstack_networking_subnet_v2.isolated_subnet.id + } +} + +resource "openstack_compute_instance_v2" "kubeapi_worker2" { + name = "kubeapi_worker2" + image_name = var.image_name + flavor_name = var.flavor_name_small + key_pair = var.keypair_name + security_groups = [ openstack_networking_secgroup_v2.isolated_sg.name ] + network { + port = openstack_networking_port_v2.kubeapi_worker2_isolated_port.id + } +} + diff --git a/infra/fridge-openstack-infra/terraform/main.tf b/infra/fridge-openstack-infra/terraform/main.tf new file mode 100644 index 0000000..ea8b2e0 --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/main.tf @@ -0,0 +1,13 @@ +terraform { + required_version = ">= 1.1.0" + required_providers { + openstack = { + source = "terraform-provider-openstack/openstack" + version = "~> 1.48.0" + } + } +} + +provider "openstack" { + cloud = var.openstack_cloud +} \ No newline at end of file diff --git a/infra/fridge-openstack-infra/terraform/networking.tf b/infra/fridge-openstack-infra/terraform/networking.tf new file mode 100644 index 0000000..5ee0a17 --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/networking.tf @@ -0,0 +1,59 @@ +# private netwrok with access to the internet + +resource "openstack_networking_network_v2" "private_network" { + name = var.private_network +} + +resource "openstack_networking_subnet_v2" "private_subnet" { + name = "${var.private_network}-subnet" + network_id = openstack_networking_network_v2.private_network.id + cidr = var.private_subnet_cidr + ip_version = 4 + dns_nameservers = [ "131.111.8.42", "131.111.12.20" ] + enable_dhcp = true +} + +# router conneting private network to the external network +resource "openstack_networking_router_v2" "private_router" { + name = "${var.private_network}-router" + external_network_id = data.openstack_networking_network_v2.external_network.id + +} + +resource "openstack_networking_router_interface_v2" "private_router_interface" { + router_id = openstack_networking_router_v2.private_router.id + subnet_id = openstack_networking_subnet_v2.private_subnet.id +} + +# isolated network +resource "openstack_networking_network_v2" "isolated_net" { + name = var.isolated_network +} + +resource "openstack_networking_subnet_v2" "isolated_subnet" { + name = "${var.isolated_network}-subnet" + network_id = openstack_networking_network_v2.isolated_net.id + cidr = var.isolated_subnet_cidr + ip_version = 4 + dns_nameservers = [ "131.111.8.42", "131.111.12.20" ] + enable_dhcp = true +} + + +data "openstack_networking_network_v2" "external_network"{ + name = var.external_network_name +} + + +# create temporary router to route traffic in isolated network to install k3s etc +# router conneting private network to the external network +# resource "openstack_networking_router_v2" "isolated_router" { +# name = "${var.isolated_network}-router" +# external_network_id = data.openstack_networking_network_v2.external_network.id + +# } + +# resource "openstack_networking_router_interface_v2" "isolated_router_interface" { +# router_id = openstack_networking_router_v2.isolated_router.id +# subnet_id = openstack_networking_subnet_v2.isolated_subnet.id +# } diff --git a/infra/fridge-openstack-infra/terraform/outputs.tf b/infra/fridge-openstack-infra/terraform/outputs.tf new file mode 100644 index 0000000..1cffd50 --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/outputs.tf @@ -0,0 +1,22 @@ +output "bastion_fip_floating_ip" { + value = openstack_networking_floatingip_v2.bastion_fip.address +} + +# output "controller_isolated_ip" { +# value = openstack_networking_port_v2.controller_isolated_port.fixed_ip[0].ip_address +# } + +# output "worker1_isolated_ip" { +# value = openstack_networking_port_v2.worker1_isolated_port.fixed_ip[0].ip_address +# } +output "private_subnet_cidr" { + value = openstack_networking_subnet_v2.private_subnet.cidr +} + +output "isolated_subnet_cidr" { + value = openstack_networking_subnet_v2.isolated_subnet.cidr +} + +# output "kubeapi_isolated_ip" { +# value = openstack_compute_instance_v2.kubeapi.access_ip_v4 +# } \ No newline at end of file diff --git a/infra/fridge-openstack-infra/terraform/security-group.tf b/infra/fridge-openstack-infra/terraform/security-group.tf new file mode 100644 index 0000000..930926d --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/security-group.tf @@ -0,0 +1,110 @@ +# security group to access proxies +resource "openstack_networking_secgroup_v2" "proxy_sg" { + name = "allow-ssh-proxy" +} + +resource "openstack_networking_secgroup_rule_v2" "ssh_in_proxy" { + security_group_id = openstack_networking_secgroup_v2.proxy_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + remote_ip_prefix = var.ssh_private_cidr +} + +resource "openstack_networking_secgroup_rule_v2" "ssh_in_https" { + security_group_id = openstack_networking_secgroup_v2.proxy_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 443 + port_range_max = 443 + # remote_ip_prefix = var.ssh_private_cidr + remote_ip_prefix = "0.0.0.0/0" +} + +resource "openstack_networking_secgroup_rule_v2" "icmp_in_proxy" { + security_group_id = openstack_networking_secgroup_v2.proxy_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "icmp" + remote_ip_prefix = var.ssh_private_cidr +} + +resource "openstack_networking_secgroup_rule_v2" "ks3_in_proxy" { + security_group_id = openstack_networking_secgroup_v2.proxy_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 6443 + port_range_max = 6443 + remote_ip_prefix = var.ssh_private_cidr + # remote_ip_prefix = "0.0.0.0/0" +} + +# allow internetwork - private to isolated +# resource "openstack_networking_secgroup_rule_v2" "access_to_isolated" { +# security_group_id = openstack_networking_secgroup_v2.proxy_sg.id +# direction = "ingress" +# ethertype = "IPv4" +# protocol = "tcp" +# port_range_min = 1 +# port_range_max = 65535 +# remote_ip_prefix = var.isolated_subnet_cidr +# } + +# security group to access bastion +resource "openstack_networking_secgroup_v2" "bastion_sg" { + name = "allow-ssh-bastion" + description = "allow ssh to bastion" +} + +resource "openstack_networking_secgroup_rule_v2" "ssh_in_bastion" { + security_group_id = openstack_networking_secgroup_v2.bastion_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + remote_ip_prefix = var.ssh_cidr_bastion +} + +resource "openstack_networking_secgroup_rule_v2" "ssh_in_httpsba" { + security_group_id = openstack_networking_secgroup_v2.bastion_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 443 + port_range_max = 443 + remote_ip_prefix = var.ssh_cidr_bastion +} + +#security group restricted to isolated network + +resource "openstack_networking_secgroup_v2" "isolated_sg" { + name = "allow-proxy-instance" + description = "allow only proxy instances" +} + +resource "openstack_networking_secgroup_rule_v2" "ssh_in_isolated" { + security_group_id = openstack_networking_secgroup_v2.isolated_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + remote_ip_prefix = var.ssh_cidr_isolated +} + + +resource "openstack_networking_secgroup_rule_v2" "ks3_in_isolated" { + security_group_id = openstack_networking_secgroup_v2.isolated_sg.id + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 6443 + port_range_max = 6443 + remote_ip_prefix = var.ssh_cidr_isolated + # remote_ip_prefix = "0.0.0.0/0" +} diff --git a/infra/fridge-openstack-infra/terraform/terraform.tfvars b/infra/fridge-openstack-infra/terraform/terraform.tfvars new file mode 100644 index 0000000..a8a846d --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/terraform.tfvars @@ -0,0 +1,9 @@ +external_network_name = "CUDN-Internet" +private_network = "private-net" +private_subnet_cidr = "10.10.0.0/24" +isolated_subnet_cidr = "10.20.0.0/24" +isolated_network = "isolated-net" +keypair_name = "bo307-mywsl1" +image_name = "Ubuntu-Jammy-22.04-20250318" +# flavor_name = "vm.v1.xsmall" +# ssh_private_cidr = "0.0.0.0/0" \ No newline at end of file diff --git a/infra/fridge-openstack-infra/terraform/variables.tf b/infra/fridge-openstack-infra/terraform/variables.tf new file mode 100644 index 0000000..32dc425 --- /dev/null +++ b/infra/fridge-openstack-infra/terraform/variables.tf @@ -0,0 +1,99 @@ +variable "openstack_cloud" { + type = string + description = "openstack project name" + default = "ai-fridge-dev" +} + +variable "kube_proxy_instance_name" { + type = string + description = "kube proxy instance name" + default = "kubeproxy" +} + +variable "fridge_proxy_instance_name" { + type = string + description = "fridge proxy instance name" + default = "fridgeproxy" +} + +variable "operator_bastion_name" { + type = string + description = "operator bastion instance name" + default = "operator-bastion" +} + +variable "kubeapi_instance_name" { + type = string + description = "kubeapi instance name" + default = "kubeapi" +} + +variable "flavor_name_xsmall" { + type = string + default = "vm.v1.xsmall" +} + +variable "flavor_name_large" { + type = string + default = "vm.v1.large" +} + +variable "flavor_name_small" { + type = string + default = "vm.v1.small" +} + +variable "image_name" { + type = string + default = "Ubuntu-Jammy-22.04-20250318" +} + +variable "private_network" { + type = string + description = "private network" + default = "private-net" +} + +variable "isolated_network" { + type = string + description = "isolated network" + default = "isolated-net" +} + +variable "private_subnet_cidr" { + type = string + description = "CIDR - private netwrok" + default = "10.10.0.0/24" +} +variable "isolated_subnet_cidr" { + type = string + description = "CIDR - isolated network" + default = "10.20.0.0/24" +} +variable "external_network_name" { + type = string + description = "External floating IP network" + default = "CUDN-Internet" +} + +variable "keypair_name" { + type = string + default = "bo307-mywsl1" +} + +variable "ssh_private_cidr" { # note + description = "ssh allowed cidr" + type = string + default = "10.10.0.0/24" +} +variable "ssh_cidr_bastion" { + description = "ssh allowed cidr for bastion" + type = string + default = "0.0.0.0/0" +} + +variable "ssh_cidr_isolated" { + description = "only allow ssh from proxies" + type = string + default = "10.20.0.0/24" +} \ No newline at end of file