# # Dedicated network of the PostgreSQL service. # No gateway: it carries database traffic only, the instances reach the rest of # the world through their port on the main private network. # resource "openstack_networking_network_v2" "postgresql_net" { name = var.postgresql_data.network_name description = var.postgresql_data.network_description admin_state_up = "true" external = "false" dns_domain = var.dns_zone_name mtu = var.mtu_size port_security_enabled = true shared = false region = var.main_region } resource "openstack_networking_subnet_v2" "postgresql_subnet" { name = var.postgresql_data.subnet_name description = var.postgresql_data.subnet_description network_id = openstack_networking_network_v2.postgresql_net.id cidr = var.postgresql_data.network_cidr dns_nameservers = var.resolvers_ip ip_version = 4 enable_dhcp = true no_gateway = true allocation_pool { start = var.postgresql_data.allocation_pool_start end = var.postgresql_data.allocation_pool_end } } # # Security group of the server: the service is reachable only from the # dedicated network, and only on its port # resource "openstack_networking_secgroup_v2" "postgresql_access" { name = "access_to_the_postgresql_service" delete_default_rules = "true" description = "Access to the PostgreSQL service through the dedicated network" } resource "openstack_networking_secgroup_rule_v2" "postgresql_ingress" { security_group_id = openstack_networking_secgroup_v2.postgresql_access.id description = "Connections to port ${var.postgresql_data.port} from the ${var.postgresql_data.network_cidr} network" direction = "ingress" ethertype = "IPv4" protocol = "tcp" port_range_min = var.postgresql_data.port port_range_max = var.postgresql_data.port remote_ip_prefix = var.postgresql_data.network_cidr } resource "openstack_networking_secgroup_rule_v2" "postgresql_ingress_icmp" { security_group_id = openstack_networking_secgroup_v2.postgresql_access.id description = "ICMP from the dedicated network" direction = "ingress" ethertype = "IPv4" protocol = "icmp" remote_ip_prefix = var.postgresql_data.network_cidr } # The port of the server has no default egress rule (delete_default_rules), so # the answers and DHCP have to be allowed explicitly resource "openstack_networking_secgroup_rule_v2" "postgresql_egress" { security_group_id = openstack_networking_secgroup_v2.postgresql_access.id description = "Egress traffic on the dedicated network" direction = "egress" ethertype = "IPv4" remote_ip_prefix = var.postgresql_data.network_cidr } resource "openstack_networking_secgroup_rule_v2" "postgresql_egress_bootps" { security_group_id = openstack_networking_secgroup_v2.postgresql_access.id description = "DHCP requests on the dedicated network" direction = "egress" ethertype = "IPv4" protocol = "udp" port_range_min = 67 port_range_max = 67 } resource "openstack_networking_secgroup_rule_v2" "postgresql_ingress_bootpc" { security_group_id = openstack_networking_secgroup_v2.postgresql_access.id description = "DHCP answers on the dedicated network" direction = "ingress" ethertype = "IPv4" protocol = "udp" port_range_min = 68 port_range_max = 68 } # # Monitoring: the Prometheus postgres_exporter, installed on the server by the # postgresql role (see infrastructure-playbooks, postgresql-cloud.yml). # # It is a group of its own, on the MAIN network port, because that is where the # exporter is scraped from: the two groups above live on the service port, in # the dedicated database network, which Prometheus has no reason to join. Only # the server gets it, so nothing else in the project has 9187 opened. # resource "openstack_networking_secgroup_v2" "postgresql_monitoring" { name = "prometheus_access_to_the_postgresql_exporter" delete_default_rules = "true" description = "Prometheus access to the postgres_exporter of the PostgreSQL server" } resource "openstack_networking_secgroup_rule_v2" "postgresql_exporter_ingress" { security_group_id = openstack_networking_secgroup_v2.postgresql_monitoring.id description = "Connections to the postgres_exporter port ${var.postgresql_data.exporter_port} from Prometheus" direction = "ingress" ethertype = "IPv4" protocol = "tcp" port_range_min = var.postgresql_data.exporter_port port_range_max = var.postgresql_data.exporter_port remote_ip_prefix = var.prometheus_cidr } # # Security group of the clients: it goes on the port that every client of the # database has on the dedicated network # resource "openstack_networking_secgroup_v2" "postgresql_client_access" { name = "vm_access_to_the_postgresql_service" delete_default_rules = "true" description = "Access to the PostgreSQL service from the port of a VM in the dedicated network" } resource "openstack_networking_secgroup_rule_v2" "client_egress_postgresql" { security_group_id = openstack_networking_secgroup_v2.postgresql_client_access.id description = "Connections to port ${var.postgresql_data.port} of the PostgreSQL server" direction = "egress" ethertype = "IPv4" protocol = "tcp" port_range_min = var.postgresql_data.port port_range_max = var.postgresql_data.port remote_ip_prefix = var.postgresql_data.server_cidr } resource "openstack_networking_secgroup_rule_v2" "client_egress_icmp" { security_group_id = openstack_networking_secgroup_v2.postgresql_client_access.id description = "ICMP to the PostgreSQL server" direction = "egress" ethertype = "IPv4" protocol = "icmp" remote_ip_prefix = var.postgresql_data.server_cidr } resource "openstack_networking_secgroup_rule_v2" "client_egress_bootps" { security_group_id = openstack_networking_secgroup_v2.postgresql_client_access.id description = "DHCP requests on the dedicated network" direction = "egress" ethertype = "IPv4" protocol = "udp" port_range_min = 67 port_range_max = 67 } resource "openstack_networking_secgroup_rule_v2" "client_ingress_bootpc" { security_group_id = openstack_networking_secgroup_v2.postgresql_client_access.id description = "DHCP answers on the dedicated network" direction = "ingress" ethertype = "IPv4" protocol = "udp" port_range_min = 68 port_range_max = 68 } # # Volumes: data and WAL on separate SSD backed volumes # resource "openstack_blockstorage_volume_v3" "postgresql_data_vol" { name = var.postgresql_data.vol_data_name description = "PostgreSQL data directory" size = var.postgresql_data.vol_data_size volume_type = var.postgresql_data.volume_type enable_online_resize = true } resource "openstack_blockstorage_volume_v3" "postgresql_wal_vol" { name = var.postgresql_data.vol_wal_name description = "PostgreSQL write ahead log" size = var.postgresql_data.vol_wal_size volume_type = var.postgresql_data.volume_type enable_online_resize = true } # # Ports. They are defined outside the instance so that the addresses and the # security groups do not depend on the life cycle of the VM # resource "openstack_networking_port_v2" "postgresql_main_port" { name = "${var.postgresql_data.name}-main-port" description = "Administration port of the PostgreSQL server on the main private network" admin_state_up = true network_id = var.main_private_network_id # The default group carries SSH from the jump proxy, ICMP, the node exporter # and the egress rule; the monitoring one adds the postgres_exporter port security_group_ids = [ var.default_security_group_id, openstack_networking_secgroup_v2.postgresql_monitoring.id, ] fixed_ip { subnet_id = var.main_private_subnet_id ip_address = var.postgresql_main_ip } } resource "openstack_networking_port_v2" "postgresql_service_port" { name = "${var.postgresql_data.name}-service-port" description = "Service port of the PostgreSQL server on the dedicated network" admin_state_up = true network_id = openstack_networking_network_v2.postgresql_net.id security_group_ids = [openstack_networking_secgroup_v2.postgresql_access.id] fixed_ip { subnet_id = openstack_networking_subnet_v2.postgresql_subnet.id ip_address = var.postgresql_data.server_ip } } # # Instance # resource "openstack_compute_instance_v2" "postgresql_server" { name = var.postgresql_data.name availability_zone_hints = var.availability_zone flavor_name = var.postgresql_data.flavor key_pair = var.ssh_key_name block_device { uuid = var.image.uuid source_type = "image" volume_size = var.postgresql_data.boot_vol_size boot_index = 0 destination_type = "volume" delete_on_termination = false } network { port = openstack_networking_port_v2.postgresql_main_port.id } network { port = openstack_networking_port_v2.postgresql_service_port.id } user_data = file(var.image.user_data_file) # Do not replace the instance when the ssh key or the user data change lifecycle { ignore_changes = [ key_pair, user_data, network ] } } resource "openstack_compute_volume_attach_v2" "postgresql_data_attach" { instance_id = openstack_compute_instance_v2.postgresql_server.id volume_id = openstack_blockstorage_volume_v3.postgresql_data_vol.id device = var.postgresql_data.vol_data_device } resource "openstack_compute_volume_attach_v2" "postgresql_wal_attach" { instance_id = openstack_compute_instance_v2.postgresql_server.id volume_id = openstack_blockstorage_volume_v3.postgresql_wal_vol.id device = var.postgresql_data.vol_wal_device # The devices are assigned in order, so the WAL volume is attached after the # data one depends_on = [openstack_compute_volume_attach_v2.postgresql_data_attach] } # # Optional A record on the main network address # resource "openstack_dns_recordset_v2" "postgresql_recordset" { count = length(var.postgresql_recordset_name) > 0 ? 1 : 0 zone_id = var.dns_zone_id name = var.postgresql_recordset_name description = "Address of the PostgreSQL server on the main private network" ttl = 8600 type = "A" records = [var.postgresql_main_ip] }