Resolve the default security group UUID dynamically instead of hardcoding it

The "default" security group VK Cloud auto-creates in every project has
a UUID unique to that project, but main.tf hardcoded one project's UUID
across all 4 instance resources (router, priv_srv_01/02/03) - not
portable to another project. Replaced with data.vkcs_networking_secgroup
(matched by name = "default", verified against the real provider schema
via terraform providers schema -json on the local provider mirror) behind
local.default_security_group_id. The new default_security_group_id
variable is a last-resort manual override via coalesce() for projects
where the lookup doesn't fit (non-standard name/SDN) - not the normal path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r
This commit is contained in:
ayurishchevandClaude Sonnet 5 committed 2026-09-06 20:32:05 +03:00
1 parent 1ef4b12143
commit b5d6367fd8
7 files changed
+174 -6

No files matched your search

+20 -4
View File
@@ -12,6 +12,22 @@ data "vkcs_networking_network" "extnet" {
sdn = "sprut"
}
# Every VK Cloud project auto-creates a "default" security group with a
# UUID unique to that project - resolve it dynamically instead of
# hardcoding one project's UUID. var.default_security_group_id is a
# last-resort manual override (e.g. non-standard name/SDN in a project).
data "vkcs_networking_secgroup" "default" {
name = "default"
sdn = "sprut"
}
locals {
default_security_group_id = coalesce(
var.default_security_group_id,
data.vkcs_networking_secgroup.default.id
)
}
# LAN Network
resource "vkcs_networking_network" "lan_net" {
name = "router-lan-net"
@@ -164,7 +180,7 @@ resource "vkcs_compute_instance" "router" {
security_group_ids = [
vkcs_networking_secgroup.router_sg.id,
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
local.default_security_group_id
]
config_drive = true
@@ -213,7 +229,7 @@ resource "vkcs_compute_instance" "priv_srv_01" {
security_group_ids = [
vkcs_networking_secgroup.private_sg.id,
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
local.default_security_group_id
]
network {
@@ -241,7 +257,7 @@ resource "vkcs_compute_instance" "priv_srv_02" {
security_group_ids = [
vkcs_networking_secgroup.private_sg.id,
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
local.default_security_group_id
]
network {
@@ -268,7 +284,7 @@ resource "vkcs_compute_instance" "priv_srv_03" {
security_group_ids = [
vkcs_networking_secgroup.private_sg.id,
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
local.default_security_group_id
]
network {
+80 -2
View File
@@ -75,6 +75,21 @@ def find_variable(doc, name):
return None
def find_local(doc, name):
"""main.tf has more than one `locals { ... }` block - search all of them."""
for block in doc.get("locals", []):
if name in block:
return block[name]
return None
def find_data_sources(doc, dtype):
"""Yield (name, attrs) for every data source of a given type in a parsed doc."""
for block in doc.get("data", []):
if dtype in block:
yield from block[dtype].items()
# ---------------------------------------------------------------------------
# Delivery layout
# ---------------------------------------------------------------------------
@@ -251,6 +266,21 @@ def test_router_count_validation_is_enforced(count, should_pass):
assert ok == should_pass, f"unexpected result for router_count={count}:\n{output}"
@pytest.mark.parametrize(
"override,should_pass",
[
(None, True), # default null - no override, dynamic lookup is used
("11111111-1111-1111-1111-111111111111", True), # explicit override accepted
],
)
def test_default_security_group_id_override_accepted(override, should_pass):
overrides = {}
if override is not None:
overrides["TF_VAR_default_security_group_id"] = override
ok, output = _plan_variables_only(overrides)
assert ok == should_pass, f"unexpected result for default_security_group_id={override!r}:\n{output}"
# ---------------------------------------------------------------------------
# HCL parses cleanly
# ---------------------------------------------------------------------------
@@ -343,8 +373,8 @@ def test_no_legacy_hardcoded_router_resources():
def test_private_roles_local_driven_by_variable():
main = load_tf("main.tf")
locals_block = main["locals"][0]
assert locals_block["private_roles"] == [
private_roles = find_local(main, "private_roles")
assert private_roles == [
'${[for idx in range(length(var.private_network_cidrs)) : "priv${idx + 1}"]}'
], "locals.private_roles must be generated from length(var.private_network_cidrs)"
@@ -359,6 +389,54 @@ def test_router_network_blocks_scale_with_private_roles():
)
# ---------------------------------------------------------------------------
# main.tf: the "default" security group UUID is resolved dynamically, not
# hardcoded (it's unique per VK Cloud project)
# ---------------------------------------------------------------------------
def test_default_security_group_data_source_exists():
main = load_tf("main.tf")
secgroups = dict(find_data_sources(main, "vkcs_networking_secgroup"))
assert "default" in secgroups, "expected data.vkcs_networking_secgroup.default"
assert secgroups["default"]["name"] == ["default"]
def test_default_security_group_id_local_prefers_override_then_lookup():
main = load_tf("main.tf")
value = find_local(main, "default_security_group_id")
assert value == [
"${coalesce(var.default_security_group_id,"
"data.vkcs_networking_secgroup.default.id)}"
], (
"locals.default_security_group_id must fall back to the dynamic "
"lookup unless var.default_security_group_id is explicitly overridden"
)
def test_no_hardcoded_security_group_uuid_in_main():
text = (TERRAFORM_DIR / "main.tf").read_text()
uuid_pattern = re.compile(
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", re.I
)
assert not uuid_pattern.search(text), (
"main.tf must not contain a literal UUID (e.g. a hardcoded security "
"group ID) - it's unique per project and must be resolved dynamically "
"via data.vkcs_networking_secgroup or overridden via "
"var.default_security_group_id"
)
def test_all_instances_use_default_security_group_local():
main = load_tf("main.tf")
for name, attrs in find_resources(main, "vkcs_compute_instance"):
sg_ids = attrs["security_group_ids"][0]
assert "${local.default_security_group_id}" in sg_ids, (
f"vkcs_compute_instance.{name} does not reference "
f"local.default_security_group_id in security_group_ids"
)
# ---------------------------------------------------------------------------
# terraform.tfvars example CIDRs: sanity-check the values actually shipped
# (no auto-carving anymore - these come straight from the admin/example)
+6
View File
@@ -61,3 +61,9 @@ variable "private_network_cidrs" {
error_message = "private_network_cidrs entries must be unique."
}
}
variable "default_security_group_id" {
description = "Explicit override for the project's 'default' security group UUID. Last resort only - by default it's resolved dynamically via data.vkcs_networking_secgroup (see main.tf), since this UUID is unique per project and must not be hardcoded."
type = string
default = null
}