diff --git a/docs/data-sources/loadbalancer.md b/docs/data-sources/loadbalancer.md
index 553f1d7e7..32cb45400 100644
--- a/docs/data-sources/loadbalancer.md
+++ b/docs/data-sources/loadbalancer.md
@@ -37,11 +37,12 @@ data "stackit_loadbalancer" "example" {
- `external_address` (String) External Load Balancer IP address where this Load Balancer is exposed.
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`","region","`name`".
- `listeners` (Attributes List) List of all listeners which will accept traffic. Limited to 20. (see [below for nested schema](#nestedatt--listeners))
+- `load_balancer_security_group_id` (String) The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT Network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.
- `networks` (Attributes List) List of networks that listeners and targets reside in. (see [below for nested schema](#nestedatt--networks))
- `options` (Attributes) Defines any optional functionality you want to have enabled on your load balancer. (see [below for nested schema](#nestedatt--options))
- `plan_id` (String) The service plan ID. If not defined, the default service plan is `p10`. Possible values are: `p10`, `p50`, `p250`, `p750`.
- `private_address` (String) Transient private Load Balancer IP address. It can change any time.
-- `security_group_id` (String) The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT Network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.
+- `security_group_id` (String) The ID of the backend security group
- `target_pools` (Attributes List) List of all target pools which will be used in the Load Balancer. Limited to 20. (see [below for nested schema](#nestedatt--target_pools))
diff --git a/docs/resources/loadbalancer.md b/docs/resources/loadbalancer.md
index 87b33562c..fdf3a1afa 100644
--- a/docs/resources/loadbalancer.md
+++ b/docs/resources/loadbalancer.md
@@ -126,6 +126,7 @@ resource "stackit_network" "lb_network" {
resource "stackit_network" "target_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "target-network-example"
+ routed = true
ipv4_prefix = "192.168.10.0/25"
ipv4_nameservers = ["8.8.8.8"]
}
@@ -181,7 +182,7 @@ resource "stackit_security_group_rule" "allow_lb_ingress" {
}
# This is the crucial link: it allows traffic from the LB's security group.
- remote_security_group_id = stackit_loadbalancer.example.security_group_id
+ remote_security_group_id = stackit_loadbalancer.example.load_balancer_security_group_id
port_range = {
min = 80
@@ -201,15 +202,19 @@ resource "stackit_server" "example" {
size = 10
}
- network_interfaces = [
- stackit_network_interface.nic.network_interface_id
- ]
+ network_interfaces = [stackit_network_interface.nic.network_interface_id]
+
}
resource "stackit_network_interface" "nic" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
network_id = stackit_network.target_network.network_id
security_group_ids = [stackit_security_group.target_sg.security_group_id]
+ lifecycle {
+ ignore_changes = [
+ security_group_ids,
+ ]
+ }
}
# End of advanced example
@@ -242,8 +247,9 @@ import {
### Read-Only
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`","region","`name`".
+- `load_balancer_security_group_id` (String) The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.
- `private_address` (String) Transient private Load Balancer IP address. It can change any time.
-- `security_group_id` (String) The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.
+- `security_group_id` (String) The ID of the backend security group
### Nested Schema for `listeners`
diff --git a/examples/resources/stackit_loadbalancer/resource.tf b/examples/resources/stackit_loadbalancer/resource.tf
index f476e29c0..70dbfa4d4 100644
--- a/examples/resources/stackit_loadbalancer/resource.tf
+++ b/examples/resources/stackit_loadbalancer/resource.tf
@@ -107,6 +107,7 @@ resource "stackit_network" "lb_network" {
resource "stackit_network" "target_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "target-network-example"
+ routed = true
ipv4_prefix = "192.168.10.0/25"
ipv4_nameservers = ["8.8.8.8"]
}
@@ -162,7 +163,7 @@ resource "stackit_security_group_rule" "allow_lb_ingress" {
}
# This is the crucial link: it allows traffic from the LB's security group.
- remote_security_group_id = stackit_loadbalancer.example.security_group_id
+ remote_security_group_id = stackit_loadbalancer.example.load_balancer_security_group_id
port_range = {
min = 80
@@ -182,15 +183,19 @@ resource "stackit_server" "example" {
size = 10
}
- network_interfaces = [
- stackit_network_interface.nic.network_interface_id
- ]
+ network_interfaces = [stackit_network_interface.nic.network_interface_id]
+
}
resource "stackit_network_interface" "nic" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
network_id = stackit_network.target_network.network_id
security_group_ids = [stackit_security_group.target_sg.security_group_id]
+ lifecycle {
+ ignore_changes = [
+ security_group_ids,
+ ]
+ }
}
# End of advanced example
diff --git a/stackit/internal/services/loadbalancer/loadbalancer/datasource.go b/stackit/internal/services/loadbalancer/loadbalancer/datasource.go
index e51cc1e04..5149eea58 100644
--- a/stackit/internal/services/loadbalancer/loadbalancer/datasource.go
+++ b/stackit/internal/services/loadbalancer/loadbalancer/datasource.go
@@ -70,7 +70,8 @@ func (r *loadBalancerDataSource) Schema(_ context.Context, _ datasource.SchemaRe
"project_id": "STACKIT project ID to which the Load Balancer is associated.",
"external_address": "External Load Balancer IP address where this Load Balancer is exposed.",
"disable_security_group_assignment": "If set to true, this will disable the automatic assignment of a security group to the load balancer's targets. This option is primarily used to allow targets that are not within the load balancer's own network or SNA (STACKIT Network area). When this is enabled, you are fully responsible for ensuring network connectivity to the targets, including managing all routing and security group rules manually. This setting cannot be changed after the load balancer is created.",
- "security_group_id": "The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT Network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.",
+ "load_balancer_security_group_id": "The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT Network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.",
+ "security_group_id": "The ID of the backend security group",
"listeners": "List of all listeners which will accept traffic. Limited to 20.",
"port": "Port number where we listen for traffic.",
"protocol": "Protocol is the highest network protocol we understand to load balance.",
@@ -349,6 +350,10 @@ func (r *loadBalancerDataSource) Schema(_ context.Context, _ datasource.SchemaRe
Description: descriptions["security_group_id"],
Computed: true,
},
+ "load_balancer_security_group_id": schema.StringAttribute{
+ Description: descriptions["load_balancer_security_group_id"],
+ Computed: true,
+ },
},
}
}
diff --git a/stackit/internal/services/loadbalancer/loadbalancer/resource.go b/stackit/internal/services/loadbalancer/loadbalancer/resource.go
index 698286703..a4865e9f1 100644
--- a/stackit/internal/services/loadbalancer/loadbalancer/resource.go
+++ b/stackit/internal/services/loadbalancer/loadbalancer/resource.go
@@ -63,6 +63,7 @@ type Model struct {
TargetPools types.List `tfsdk:"target_pools"`
Region types.String `tfsdk:"region"`
SecurityGroupId types.String `tfsdk:"security_group_id"`
+ LoadBalancerSecurityGroupId types.String `tfsdk:"load_balancer_security_group_id"`
}
// Struct corresponding to Model.Listeners[i]
@@ -344,7 +345,8 @@ func (r *loadBalancerResource) Schema(_ context.Context, _ resource.SchemaReques
"targets.display_name": "Target display name",
"ip": "Target IP",
"region": "The resource region. If not defined, the provider region is used.",
- "security_group_id": "The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.",
+ "security_group_id": "The ID of the backend security group",
+ "load_balancer_security_group_id": "The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.",
}
resp.Schema = schema.Schema{
@@ -692,6 +694,13 @@ The example below creates the supporting infrastructure using the STACKIT Terraf
stringplanmodifier.UseStateForUnknown(),
},
},
+ "load_balancer_security_group_id": schema.StringAttribute{
+ Description: descriptions["load_balancer_security_group_id"],
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
},
}
}
@@ -1247,6 +1256,12 @@ func mapFields(ctx context.Context, lb *loadbalancer.LoadBalancer, m *Model, reg
m.PrivateAddress = types.StringPointerValue(lb.PrivateAddress)
m.DisableSecurityGroupAssignment = types.BoolPointerValue(lb.DisableTargetSecurityGroupAssignment)
+ if lb.LoadBalancerSecurityGroup != nil {
+ m.LoadBalancerSecurityGroupId = types.StringPointerValue(lb.LoadBalancerSecurityGroup.Id)
+ } else {
+ m.LoadBalancerSecurityGroupId = types.StringNull()
+ }
+
if lb.TargetSecurityGroup != nil {
m.SecurityGroupId = types.StringPointerValue(lb.TargetSecurityGroup.Id)
} else {
diff --git a/stackit/internal/services/loadbalancer/loadbalancer_acc_test.go b/stackit/internal/services/loadbalancer/loadbalancer_acc_test.go
index fe96460ce..7cc6d4d3d 100644
--- a/stackit/internal/services/loadbalancer/loadbalancer_acc_test.go
+++ b/stackit/internal/services/loadbalancer/loadbalancer_acc_test.go
@@ -126,6 +126,7 @@ func TestAccLoadBalancerResourceMin(t *testing.T) {
resource.TestCheckNoResourceAttr("stackit_loadbalancer.loadbalancer", "options.observability.metrics.credentials_ref"),
resource.TestCheckNoResourceAttr("stackit_loadbalancer.loadbalancer", "options.observability.metrics.push_url"),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "security_group_id"),
+ resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id"),
// Loadbalancer observability credentials resource
resource.TestCheckResourceAttr("stackit_loadbalancer_observability_credential.obs_credential", "project_id", testutil.ConvertConfigVariable(testConfigVarsMin["project_id"])),
@@ -182,6 +183,11 @@ func TestAccLoadBalancerResourceMin(t *testing.T) {
"stackit_loadbalancer.loadbalancer", "security_group_id",
"data.stackit_loadbalancer.loadbalancer", "security_group_id",
),
+ resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id"),
+ resource.TestCheckResourceAttrPair(
+ "stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id",
+ "data.stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id",
+ ),
)},
// Import
{
@@ -249,6 +255,7 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "external_address"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "disable_security_group_assignment", testutil.ConvertConfigVariable(testConfigVarsMax["disable_security_group_assignment"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "security_group_id"),
+ resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["healthy_threshold"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval_jitter"])),
@@ -320,6 +327,7 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "external_address"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "disable_security_group_assignment", testutil.ConvertConfigVariable(testConfigVarsMax["disable_security_group_assignment"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "security_group_id"),
+ resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["healthy_threshold"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval_jitter"])),
@@ -337,6 +345,10 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
"stackit_loadbalancer.loadbalancer", "security_group_id",
"data.stackit_loadbalancer.loadbalancer", "security_group_id",
),
+ resource.TestCheckResourceAttrPair(
+ "stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id",
+ "data.stackit_loadbalancer.loadbalancer", "load_balancer_security_group_id",
+ ),
)},
// Import
{