Skip to content

Commit

Permalink
feat: IAM supports identity acl (#982)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lance52259 authored Mar 17, 2021
1 parent 28be281 commit afe17fb
Show file tree
Hide file tree
Showing 11 changed files with 738 additions and 2 deletions.
70 changes: 70 additions & 0 deletions docs/resources/identity_acl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
subcategory: "Identity and Access Management (IAM)"
---

# huaweicloud\_identity\_acl

Manages a ACL resource within HuaweiCloud IAM service.
The ACL allowing user access only from specified IP address ranges and IPv4 CIDR blocks.
The ACL take effect for IAM users under the Domain account rather than the account itself.

Note: You _must_ have admin privileges in your HuaweiCloud cloud to use this resource.

## Example Usage

```hcl
resource "huaweicloud_identity_acl" "acl" {
type = "console"
ip_cidrs {
cidr = "159.138.39.192/32"
description = "This is a test ip address"
}
ip_ranges {
range = "0.0.0.0-255.255.255.0"
description = "This is a test ip range"
}
}
```

## Argument Reference

The following arguments are supported:

* `type` - (Required, String, ForceNew) Specifies the ACL is created through the Console or API.
valid value are 'console' and 'api'.
Changing this parameter will create a new ACL.

* `ip_cidrs` - (Optional, List) Specifies the IPv4 CIDR blocks from which console access or api access is allowed.
The `ip_cidrs` cannot repeat. The structure is documented below.

* `ip_ranges` - (Optional, List) Specifies the IP address ranges from which console access or api access is allowed.
The `ip_ranges` cannot repeat. The structure is documented below.

The `ip_cidrs` block supports:

* `cidr` - (Required, String) Specifies the IPv4 CIDR block, for example, __192.168.0.0/24__.

* `description` - (Optional, String) Specifies a description about an IPv4 CIDR block.
This parameter can contain a maximum of 255 characters and the following charactors are not allowed:__@#%^&*<>\\__.

The `ip_ranges` block supports:

* `range` - (Required, String) Specifies the Ip address range, for example, __0.0.0.0-255.255.255.0__.

* `description` - (Optional, String) Specifies a description about an IP address range.
This parameter can contain a maximum of 255 characters and the following charactors are not allowed:__@#%^&*<>\\__.

**note**: Up to 200 `ip_cidrs` and `ip_ranges` can be created in total for each access method.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The ID of identity acl.

## Timeouts
This resource provides the following timeouts configuration options:
- `create` - Default is 5 minute.
- `update` - Default is 5 minute.
- `delete` - Default is 3 minute.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/terraform-plugin-sdk v1.16.0
github.com/hashicorp/terraform-plugin-test v1.3.0 // indirect
github.com/huaweicloud/golangsdk v0.0.0-20210310091354-6e2f74a11d0f
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01
github.com/jen20/awspolicyequivalence v1.1.0
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect
github.com/stretchr/testify v1.4.0
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
Expand All @@ -160,13 +161,15 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw=
github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8=
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
Expand All @@ -175,6 +178,7 @@ github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uP
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8=
github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
Expand Down Expand Up @@ -225,7 +229,10 @@ github.com/huaweicloud/golangsdk v0.0.0-20210302113304-41351a12edfc h1:CBrAHWGyq
github.com/huaweicloud/golangsdk v0.0.0-20210302113304-41351a12edfc/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/huaweicloud/golangsdk v0.0.0-20210310091354-6e2f74a11d0f h1:AFZM6Vdn8dS764DaaiRKGP26iM7ta2zlQqM+SR1svGk=
github.com/huaweicloud/golangsdk v0.0.0-20210310091354-6e2f74a11d0f/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01 h1:NIh2E9JUKO2/4xGjcSFgzXLp/cCcyPj6mVmPZlMzo/Q=
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
Expand Down Expand Up @@ -307,6 +314,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
Expand Down Expand Up @@ -334,6 +342,7 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvc
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU=
github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
1 change: 1 addition & 0 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ func Provider() terraform.ResourceProvider {
"huaweicloud_gaussdb_mysql_instance": resourceGaussDBInstance(),
"huaweicloud_gaussdb_opengauss_instance": resourceOpenGaussInstance(),
"huaweicloud_ges_graph": resourceGesGraphV1(),
"huaweicloud_identity_acl": resourceIdentityACL(),
"huaweicloud_identity_agency": resourceIAMAgencyV3(),
"huaweicloud_identity_group": ResourceIdentityGroupV3(),
"huaweicloud_identity_group_membership": ResourceIdentityGroupMembershipV3(),
Expand Down
246 changes: 246 additions & 0 deletions huaweicloud/resource_huaweicloud_identity_acl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
package huaweicloud

import (
"bytes"
"fmt"
"log"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/hashcode"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/huaweicloud/golangsdk/openstack/identity/v3.0/acl"
)

func resourceIdentityACL() *schema.Resource {
return &schema.Resource{
Create: resourceIdentityACLCreate,
Read: resourceIdentityACLRead,
Update: resourceIdentityACLUpdate,
Delete: resourceIdentityACLDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(3 * time.Minute),
},

Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
"console", "api",
}, true),
},
"ip_cidrs": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 200,
AtLeastOneOf: []string{"ip_ranges"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cidr": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateCIDR,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
},
},
Set: resourceACLPolicyCIDRHash,
},
"ip_ranges": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 200,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"range": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateIPRange,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
},
},
Set: resourceACLPolicyRangeHash,
},
},
}
}

func resourceIdentityACLCreate(d *schema.ResourceData, meta interface{}) error {
id := meta.(*Config).DomainID
if err := updateACLPolicy(d, meta, id); err != nil {
return fmt.Errorf("Error creating HuaweiCloud iam acl: %s", err)
}

d.SetId(id)
return resourceIdentityACLRead(d, meta)
}

func resourceIdentityACLRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
iamClient, err := config.IAMV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud iam client: %s", err)
}

var res *acl.ACLPolicy
switch d.Get("type").(string) {
case "console":
res, err = acl.ConsoleACLPolicyGet(iamClient, d.Id()).ConsoleExtract()
if err != nil {
return fmt.Errorf("Error fetching identity acl for console access")
}
log.Printf("[DEBUG] Retrieved HuaweiCloud identity acl: %#v", res)
default:
res, err = acl.APIACLPolicyGet(iamClient, d.Id()).APIExtract()
if err != nil {
return fmt.Errorf("Error fetching identity acl for api access")
}
log.Printf("[DEBUG] Retrieved HuaweiCloud identity acl: %#v", res)
}

if len(res.AllowAddressNetmasks) > 0 {
addressNetmasks := make([]map[string]string, 0, len(res.AllowAddressNetmasks))
for _, v := range res.AllowAddressNetmasks {
addressNetmask := map[string]string{
"cidr": v.AddressNetmask,
"description": v.Description,
}
addressNetmasks = append(addressNetmasks, addressNetmask)
}
d.Set("ip_cidrs", addressNetmasks)
}
if len(res.AllowIPRanges) > 0 {
ipRanges := make([]map[string]string, 0, len(res.AllowIPRanges))
for _, v := range res.AllowIPRanges {
ipRange := map[string]string{
"range": v.IPRange,
"description": v.Description,
}
ipRanges = append(ipRanges, ipRange)
}
d.Set("ip_ranges", ipRanges)
}

return nil
}

func resourceIdentityACLUpdate(d *schema.ResourceData, meta interface{}) error {
id := d.Id()
if d.HasChanges("ip_cidrs", "ip_ranges") {
if err := updateACLPolicy(d, meta, id); err != nil {
return fmt.Errorf("Error updating HuaweiCloud iam acl: %s", err)
}
}

return resourceIdentityACLRead(d, meta)
}

func resourceIdentityACLDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
iamClient, err := config.IAMV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud iam client: %s", err)
}

netmasksList := make([]acl.AllowAddressNetmasks, 0, 1)
netmask := acl.AllowAddressNetmasks{
AddressNetmask: "0.0.0.0-255.255.255.255",
}
netmasksList = append(netmasksList, netmask)

deleteOpts := &acl.ACLPolicy{
AllowAddressNetmasks: netmasksList,
}

switch d.Get("type").(string) {
case "console":
_, err := acl.ConsoleACLPolicyUpdate(iamClient, deleteOpts, d.Id()).ConsoleExtract()
if err != nil {
return fmt.Errorf("Error updating HuaweiCloud iam acl: %s", err)
}
default:
_, err := acl.APIACLPolicyUpdate(iamClient, deleteOpts, d.Id()).APIExtract()
if err != nil {
return fmt.Errorf("Error updating HuaweiCloud iam acl: %s", err)
}
}
d.SetId("")
return nil
}

func updateACLPolicy(d *schema.ResourceData, meta interface{}, id string) error {
config := meta.(*Config)
iamClient, err := config.IAMV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud iam client: %s", err)
}

updateOpts := &acl.ACLPolicy{}
if addressNetmasks, ok := d.GetOk("ip_cidrs"); ok {
netmasksList := make([]acl.AllowAddressNetmasks, 0, addressNetmasks.(*schema.Set).Len())
for _, v := range addressNetmasks.(*schema.Set).List() {
netmask := acl.AllowAddressNetmasks{
AddressNetmask: v.(map[string]interface{})["cidr"].(string),
Description: v.(map[string]interface{})["description"].(string),
}
netmasksList = append(netmasksList, netmask)
}
updateOpts.AllowAddressNetmasks = netmasksList
}
if ipRanges, ok := d.GetOk("ip_ranges"); ok {
rangeList := make([]acl.AllowIPRanges, 0, ipRanges.(*schema.Set).Len())
for _, v := range ipRanges.(*schema.Set).List() {
ipRange := acl.AllowIPRanges{
IPRange: v.(map[string]interface{})["range"].(string),
Description: v.(map[string]interface{})["description"].(string),
}
rangeList = append(rangeList, ipRange)
}
updateOpts.AllowIPRanges = rangeList
}

switch d.Get("type").(string) {
case "console":
_, err = acl.ConsoleACLPolicyUpdate(iamClient, updateOpts, id).ConsoleExtract()
case "api":
_, err = acl.APIACLPolicyUpdate(iamClient, updateOpts, id).APIExtract()
}
if err != nil {
return fmt.Errorf("Modify identity acl failed: %s", err)
}
return nil
}

func resourceACLPolicyCIDRHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})

if m["cidr"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string)))
}

return hashcode.String(buf.String())
}

func resourceACLPolicyRangeHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})

if m["range"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["range"].(string)))
}

return hashcode.String(buf.String())
}
Loading

0 comments on commit afe17fb

Please sign in to comment.