Skip to content

Commit 9b85e11

Browse files
authored
feat(vpc): add ACLs (#2995)
* bump sdk go * add vpc acls * add docs * lint
1 parent 838401c commit 9b85e11

File tree

6 files changed

+1376
-0
lines changed

6 files changed

+1376
-0
lines changed

docs/resources/vpc_acl.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
subcategory: "VPC"
3+
page_title: "Scaleway: scaleway_vpc_acl"
4+
---
5+
6+
# Resource: scaleway_vpc_acl
7+
8+
Creates and manages Scaleway VPC ACLs.
9+
10+
## Example Usage
11+
12+
### Basic
13+
14+
```terraform
15+
resource "scaleway_vpc" "vpc01" {
16+
name = "tf-vpc-acl"
17+
}
18+
19+
resource "scaleway_vpc_acl" "acl01" {
20+
vpc_id = scaleway_vpc.vpc01.id
21+
is_ipv6 = false
22+
rules {
23+
protocol = "TCP"
24+
src_port_low = 0
25+
src_port_high = 0
26+
dst_port_low = 80
27+
dst_port_high = 80
28+
source = "0.0.0.0/0"
29+
destination = "0.0.0.0/0"
30+
description = "Allow HTTP traffic from any source"
31+
action = "accept"
32+
}
33+
default_policy = "drop"
34+
}
35+
```
36+
37+
## Argument Reference
38+
39+
The following arguments are supported:
40+
41+
- `vpc_id` - (Required) The VPC ID the ACL belongs to.
42+
- `default_policy` - (Required) The action to take for packets which do not match any rules.
43+
- `is_ipv6` - (Optional) Defines whether this set of ACL rules is for IPv6 (false = IPv4). Each Network ACL can have rules for only one IP type.
44+
- `rules` - (Optional) The list of Network ACL rules.
45+
- `protocol` - (Optional) The protocol to which this rule applies. Default value: ANY.
46+
- `source` - (Optional) The Source IP range to which this rule applies (CIDR notation with subnet mask).
47+
- `src_port_low` - (Optional) The starting port of the source port range to which this rule applies (inclusive).
48+
- `src_port_high` - (Optional) The ending port of the source port range to which this rule applies (inclusive).
49+
- `destination` - (Optional) The destination IP range to which this rule applies (CIDR notation with subnet mask).
50+
- `dst_port_low` - (Optional) The starting port of the destination port range to which this rule applies (inclusive).
51+
- `dst_port_high` - (Optional) The ending port of the destination port range to which this rule applies (inclusive).
52+
- `action` - (Optional) The policy to apply to the packet.
53+
- `description` - (Optional) The rule description.
54+
- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions) of the ACL.
55+
56+
## Attributes Reference
57+
58+
In addition to all arguments above, the following attributes are exported:
59+
60+
- `id` - The ID of the ACL.
61+
62+
~> **Important:** ACLs' IDs are [regional](../guides/regions_and_zones.md#resource-ids), which means they are of the form `{region}/{id}`, e.g. `fr-par/11111111-1111-1111-1111-111111111111
63+
64+
## Import
65+
66+
ACLs can be imported using `{region}/{id}`, e.g.
67+
68+
```bash
69+
terraform import scaleway_vpc_acl.main fr-par/11111111-1111-1111-1111-111111111111
70+
```

internal/provider/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ func Provider(config *Config) plugin.ProviderFunc {
226226
"scaleway_tem_domain_validation": tem.ResourceDomainValidation(),
227227
"scaleway_tem_webhook": tem.ResourceWebhook(),
228228
"scaleway_vpc": vpc.ResourceVPC(),
229+
"scaleway_vpc_acl": vpc.ResourceACL(),
229230
"scaleway_vpc_gateway_network": vpcgw.ResourceNetwork(),
230231
"scaleway_vpc_private_network": vpc.ResourcePrivateNetwork(),
231232
"scaleway_vpc_public_gateway": vpcgw.ResourcePublicGateway(),

internal/services/vpc/acl.go

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package vpc
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
"github.com/scaleway/scaleway-sdk-go/api/vpc/v2"
9+
"github.com/scaleway/scaleway-sdk-go/scw"
10+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
11+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
12+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
13+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
14+
)
15+
16+
func ResourceACL() *schema.Resource {
17+
return &schema.Resource{
18+
CreateContext: ResourceVPCACLCreate,
19+
ReadContext: ResourceVPCACLRead,
20+
UpdateContext: ResourceVPCACLUpdate,
21+
DeleteContext: ResourceVPCACLDelete,
22+
Importer: &schema.ResourceImporter{
23+
StateContext: schema.ImportStatePassthroughContext,
24+
},
25+
SchemaVersion: 0,
26+
Schema: map[string]*schema.Schema{
27+
"vpc_id": {
28+
Type: schema.TypeString,
29+
Required: true,
30+
Description: "The VPC in which to create the ACL rule",
31+
},
32+
"default_policy": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
Description: "The action to take for packets which do not match any rules",
36+
ValidateDiagFunc: verify.ValidateEnum[vpc.Action](),
37+
},
38+
"is_ipv6": {
39+
Type: schema.TypeBool,
40+
Optional: true,
41+
Default: false,
42+
Description: "Defines whether this set of ACL rules is for IPv6 (false = IPv4). Each Network ACL can have rules for only one IP type",
43+
},
44+
"rules": {
45+
Type: schema.TypeList,
46+
Required: true,
47+
Description: "The list of Network ACL rules",
48+
Elem: &schema.Resource{
49+
Schema: map[string]*schema.Schema{
50+
"protocol": {
51+
Type: schema.TypeString,
52+
Optional: true,
53+
Default: "ANY",
54+
Description: "The protocol to which this rule applies. Default value: ANY",
55+
ValidateDiagFunc: verify.ValidateEnum[vpc.ACLRuleProtocol](),
56+
},
57+
"source": {
58+
Type: schema.TypeString,
59+
Optional: true,
60+
Description: "Source IP range to which this rule applies (CIDR notation with subnet mask)",
61+
},
62+
"src_port_low": {
63+
Type: schema.TypeInt,
64+
Optional: true,
65+
Description: "Starting port of the source port range to which this rule applies (inclusive)",
66+
},
67+
"src_port_high": {
68+
Type: schema.TypeInt,
69+
Optional: true,
70+
Description: "Ending port of the source port range to which this rule applies (inclusive)",
71+
},
72+
"destination": {
73+
Type: schema.TypeString,
74+
Optional: true,
75+
Description: "Destination IP range to which this rule applies (CIDR notation with subnet mask)",
76+
},
77+
"dst_port_low": {
78+
Type: schema.TypeInt,
79+
Optional: true,
80+
Description: "Starting port of the destination port range to which this rule applies (inclusive)",
81+
},
82+
"dst_port_high": {
83+
Type: schema.TypeInt,
84+
Optional: true,
85+
Description: "Ending port of the destination port range to which this rule applies (inclusive)",
86+
},
87+
"action": {
88+
Type: schema.TypeString,
89+
Optional: true,
90+
Description: "The policy to apply to the packet",
91+
ValidateDiagFunc: verify.ValidateEnum[vpc.Action](),
92+
},
93+
"description": {
94+
Type: schema.TypeString,
95+
Optional: true,
96+
Description: "The rule description",
97+
},
98+
},
99+
},
100+
},
101+
"region": regional.Schema(),
102+
},
103+
}
104+
}
105+
106+
func ResourceVPCACLCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
107+
vpcAPI, region, err := vpcAPIWithRegion(d, m)
108+
if err != nil {
109+
return diag.FromErr(err)
110+
}
111+
112+
req := &vpc.SetACLRequest{
113+
VpcID: locality.ExpandID(d.Get("vpc_id").(string)),
114+
IsIPv6: d.Get("is_ipv6").(bool),
115+
DefaultPolicy: vpc.Action(d.Get("default_policy").(string)),
116+
Region: region,
117+
}
118+
119+
expandedRules, err := expandACLRules(d.Get("rules"))
120+
if err != nil {
121+
return diag.FromErr(err)
122+
}
123+
124+
if d.Get("rules") != nil {
125+
req.Rules = expandedRules
126+
}
127+
128+
_, err = vpcAPI.SetACL(req, scw.WithContext(ctx))
129+
if err != nil {
130+
return diag.FromErr(err)
131+
}
132+
133+
d.SetId(regional.NewIDString(region, regional.ExpandID(d.Get("vpc_id").(string)).ID))
134+
135+
return ResourceVPCACLRead(ctx, d, m)
136+
}
137+
138+
func ResourceVPCACLRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
139+
vpcAPI, region, ID, err := NewAPIWithRegionAndID(m, d.Id())
140+
if err != nil {
141+
return diag.FromErr(err)
142+
}
143+
144+
acl, err := vpcAPI.GetACL(&vpc.GetACLRequest{
145+
VpcID: locality.ExpandID(ID),
146+
Region: region,
147+
IsIPv6: d.Get("is_ipv6").(bool),
148+
}, scw.WithContext(ctx))
149+
if err != nil {
150+
if httperrors.Is404(err) {
151+
d.SetId("")
152+
153+
return nil
154+
}
155+
156+
return diag.FromErr(err)
157+
}
158+
159+
_ = d.Set("rules", flattenACLRules(acl.Rules))
160+
_ = d.Set("default_policy", acl.DefaultPolicy.String())
161+
162+
return nil
163+
}
164+
165+
func ResourceVPCACLUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
166+
vpcAPI, region, ID, err := NewAPIWithRegionAndID(m, d.Id())
167+
if err != nil {
168+
return diag.FromErr(err)
169+
}
170+
171+
req := &vpc.SetACLRequest{
172+
VpcID: locality.ExpandID(ID),
173+
IsIPv6: d.Get("is_ipv6").(bool),
174+
DefaultPolicy: vpc.Action(d.Get("default_policy").(string)),
175+
Region: region,
176+
}
177+
178+
expandedRules, err := expandACLRules(d.Get("rules"))
179+
if err != nil {
180+
return diag.FromErr(err)
181+
}
182+
183+
if d.Get("rules") != nil {
184+
req.Rules = expandedRules
185+
}
186+
187+
_, err = vpcAPI.SetACL(req, scw.WithContext(ctx))
188+
if err != nil {
189+
return diag.FromErr(err)
190+
}
191+
192+
return ResourceVPCACLRead(ctx, d, m)
193+
}
194+
195+
func ResourceVPCACLDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
196+
vpcAPI, region, ID, err := NewAPIWithRegionAndID(m, d.Id())
197+
if err != nil {
198+
return diag.FromErr(err)
199+
}
200+
201+
_, err = vpcAPI.SetACL(&vpc.SetACLRequest{
202+
VpcID: locality.ExpandID(ID),
203+
Region: region,
204+
DefaultPolicy: "drop",
205+
}, scw.WithContext(ctx))
206+
if err != nil {
207+
return diag.FromErr(err)
208+
}
209+
210+
return nil
211+
}

0 commit comments

Comments
 (0)