Skip to content

Commit 6ed3ccd

Browse files
authored
Merge pull request ovh#483 from psauvage0/dev/psauvage/UIAM-688/add-iam-deny
feat(iam): add support for deny in policies
2 parents 795ba7a + 41ee1eb commit 6ed3ccd

File tree

7 files changed

+104
-18
lines changed

7 files changed

+104
-18
lines changed

ovh/data_iam_policy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ func dataSourceIamPolicy() *schema.Resource {
5151
Type: schema.TypeString,
5252
},
5353
},
54+
"deny": {
55+
Type: schema.TypeSet,
56+
Optional: true,
57+
Elem: &schema.Schema{
58+
Type: schema.TypeString,
59+
},
60+
},
5461
"owner": {
5562
Type: schema.TypeString,
5663
Computed: true,

ovh/data_iam_policy_test.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
1818
resource1 := "urn:v1:eu:resource:vrack:*"
1919
resource2 := "urn:v1:eu:resource:vps:*"
2020
allow1 := "*"
21-
allow2 := "*"
21+
except1 := "vrack:apiovh:dedicatedServer/remove"
22+
deny2 := "*"
2223

2324
preSetup := fmt.Sprintf(
2425
testAccIamPolicyDatasourceConfig_preSetup,
@@ -29,10 +30,11 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
2930
desc,
3031
resource1,
3132
allow1,
33+
except1,
3234
policyName2,
3335
desc,
3436
resource2,
35-
allow2,
37+
deny2,
3638
)
3739
config := fmt.Sprintf(
3840
testAccIamPolicyDatasourceConfig_keys,
@@ -43,14 +45,15 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
4345
desc,
4446
resource1,
4547
allow1,
48+
except1,
4649
policyName2,
4750
desc,
4851
resource2,
49-
allow2,
52+
deny2,
5053
)
5154

52-
checks := checkIamPolicyResourceAttr("ovh_iam_policy.policy_1", policyName1, desc, resource1)
53-
checks = append(checks, checkIamPolicyResourceAttr("ovh_iam_policy.policy_2", policyName2, desc, resource2)...)
55+
checks := checkIamPolicyResourceAttr("ovh_iam_policy.policy_1", policyName1, desc, resource1, allow1, except1, "")
56+
checks = append(checks, checkIamPolicyResourceAttr("ovh_iam_policy.policy_2", policyName2, desc, resource2, "", "", deny2)...)
5457

5558
resource.Test(t, resource.TestCase{
5659
PreCheck: func() { testAccPreCheckCredentials(t) },
@@ -70,13 +73,23 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
7073
})
7174
}
7275

73-
func checkIamPolicyResourceAttr(name, polName, desc, resourceURN string) []resource.TestCheckFunc {
76+
func checkIamPolicyResourceAttr(name, polName, desc, resourceURN, allowAction, exceptAction, denyAction string) []resource.TestCheckFunc {
7477
// we are not checking identity urn because they are dynamic and depend on the test account NIC
75-
return []resource.TestCheckFunc{
78+
checks := []resource.TestCheckFunc{
7679
resource.TestCheckResourceAttr(name, "name", polName),
7780
resource.TestCheckResourceAttr(name, "description", desc),
7881
resource.TestCheckTypeSetElemAttr(name, "resources.*", resourceURN),
7982
}
83+
if allowAction != "" {
84+
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "allow.*", allowAction))
85+
}
86+
if exceptAction != "" {
87+
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "except.*", exceptAction))
88+
}
89+
if denyAction != "" {
90+
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "deny.*", denyAction))
91+
}
92+
return checks
8093
}
8194

8295
const testAccIamPolicyDatasourceConfig_preSetup = `
@@ -96,14 +109,15 @@ resource "ovh_iam_policy" "policy_1" {
96109
identities = [ovh_me_identity_user.user_1.urn]
97110
resources = ["%s"]
98111
allow = ["%s"]
112+
except = ["%s"]
99113
}
100114
101115
resource "ovh_iam_policy" "policy_2" {
102116
name = "%s"
103117
description = "%s"
104118
identities = [ovh_me_identity_group.group_1.urn]
105119
resources = ["%s"]
106-
allow = ["%s"]
120+
deny = ["%s"]
107121
}
108122
`
109123

@@ -124,14 +138,15 @@ resource "ovh_iam_policy" "policy_1" {
124138
identities = [ovh_me_identity_user.user_1.urn]
125139
resources = ["%s"]
126140
allow = ["%s"]
141+
except = ["%s"]
127142
}
128143
129144
resource "ovh_iam_policy" "policy_2" {
130145
name = "%s"
131146
description = "%s"
132147
identities = [ovh_me_identity_group.group_1.urn]
133148
resources = ["%s"]
134-
allow = ["%s"]
149+
deny = ["%s"]
135150
}
136151
137152
data "ovh_iam_policies" "policies" {}

ovh/resource_iam_policy.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ func resourceIamPolicy() *schema.Resource {
5252
Type: schema.TypeString,
5353
},
5454
},
55+
"deny": {
56+
Type: schema.TypeSet,
57+
Optional: true,
58+
Elem: &schema.Schema{
59+
Type: schema.TypeString,
60+
},
61+
},
5562
"owner": {
5663
Type: schema.TypeString,
5764
Computed: true,
@@ -163,7 +170,13 @@ func prepareIamPolicyCall(d *schema.ResourceData) IamPolicy {
163170

164171
if except, ok := d.GetOk("except"); ok {
165172
for _, e := range except.(*schema.Set).List() {
166-
out.Permissions.Except = append(out.Permissions.Allow, IamAction{Action: e.(string)})
173+
out.Permissions.Except = append(out.Permissions.Except, IamAction{Action: e.(string)})
174+
}
175+
}
176+
177+
if deny, ok := d.GetOk("deny"); ok {
178+
for _, e := range deny.(*schema.Set).List() {
179+
out.Permissions.Deny = append(out.Permissions.Deny, IamAction{Action: e.(string)})
167180
}
168181
}
169182
return out

ovh/resource_iam_policy_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ func TestAccIamPolicy_basic(t *testing.T) {
6767
desc := "IAM policy created by Terraform Acc"
6868
userName := acctest.RandomWithPrefix(test_prefix)
6969
res := "urn:v1:eu:resource:vps:*"
70-
config := fmt.Sprintf(testAccIamPolicyConfig, userName, userName, name, desc, res)
70+
exceptAction := "vps:apiovh:reinstall"
71+
config := fmt.Sprintf(testAccIamPolicyConfig, userName, userName, name, desc, res, exceptAction)
7172

7273
resource.Test(t, resource.TestCase{
7374
PreCheck: func() { testAccPreCheckCredentials(t) },
@@ -76,7 +77,29 @@ func TestAccIamPolicy_basic(t *testing.T) {
7677
{
7778
Config: config,
7879
Check: resource.ComposeTestCheckFunc(
79-
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res)...,
80+
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res, "*", exceptAction, "")...,
81+
),
82+
},
83+
},
84+
})
85+
}
86+
87+
func TestAccIamPolicy_deny(t *testing.T) {
88+
name := acctest.RandomWithPrefix(test_prefix)
89+
desc := "IAM policy created by Terraform Acc"
90+
userName := acctest.RandomWithPrefix(test_prefix)
91+
res := "urn:v1:eu:resource:vps:*"
92+
denyAction := "vps:apiovh:reinstall"
93+
config := fmt.Sprintf(testAccIamPolicyDenyConfig, userName, userName, name, desc, res, denyAction)
94+
95+
resource.Test(t, resource.TestCase{
96+
PreCheck: func() { testAccPreCheckCredentials(t) },
97+
Providers: testAccProviders,
98+
Steps: []resource.TestStep{
99+
{
100+
Config: config,
101+
Check: resource.ComposeTestCheckFunc(
102+
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res, "", "", denyAction)...,
80103
),
81104
},
82105
},
@@ -96,5 +119,22 @@ resource "ovh_iam_policy" "policy1" {
96119
identities = [ovh_me_identity_user.test_user.urn]
97120
resources = ["%s"]
98121
allow = ["*"]
122+
except = ["%s"]
123+
}
124+
`
125+
126+
const testAccIamPolicyDenyConfig = `
127+
resource "ovh_me_identity_user" "test_user" {
128+
login = "%s"
129+
email = "%[email protected]"
130+
password = "qwe123!@#"
131+
}
132+
133+
resource "ovh_iam_policy" "policy1" {
134+
name = "%s"
135+
description = "%s"
136+
identities = [ovh_me_identity_user.test_user.urn]
137+
resources = ["%s"]
138+
deny = ["%s"]
99139
}
100140
`

ovh/types_iam.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ func (p IamPolicy) ToMap() map[string]any {
4444
}
4545
out["resources"] = resources
4646

47-
// inline allow and except
48-
allow, except := p.Permissions.ToLists()
47+
// inline allow, except and deny
48+
allow, except, deny := p.Permissions.ToLists()
4949
if len(allow) != 0 {
5050
out["allow"] = allow
5151
}
5252
if len(except) != 0 {
5353
out["except"] = except
5454
}
55+
if len(deny) != 0 {
56+
out["deny"] = deny
57+
}
5558

5659
if p.Description != "" {
5760
out["description"] = p.Description
@@ -90,11 +93,13 @@ type IamResourceDetails struct {
9093
type IamPermissions struct {
9194
Allow []IamAction `json:"allow"`
9295
Except []IamAction `json:"except"`
96+
Deny []IamAction `json:"deny"`
9397
}
9498

95-
func (p IamPermissions) ToLists() ([]string, []string) {
99+
func (p IamPermissions) ToLists() ([]string, []string, []string) {
96100
var allow []string
97101
var except []string
102+
var deny []string
98103

99104
for _, r := range p.Allow {
100105
allow = append(allow, r.Action)
@@ -103,7 +108,11 @@ func (p IamPermissions) ToLists() ([]string, []string) {
103108
for _, r := range p.Except {
104109
except = append(except, r.Action)
105110
}
106-
return allow, except
111+
112+
for _, r := range p.Deny {
113+
deny = append(deny, r.Action)
114+
}
115+
return allow, except, deny
107116
}
108117

109118
type IamAction struct {

website/docs/d/iam_policy.html.markdown

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ data "ovh_iam_policy" "my_policy" {
2525
* `identities` - List of identities affected by the policy.
2626
* `resources` - List of resources affected by the policy.
2727
* `allow` - List of actions allowed by the policy.
28-
* `except` - List of actions.
28+
* `except` - List of actions that will be subtracted from the `allow` list.
29+
* `deny` - List of actions that will be denied no matter what policy exists.
2930
* `owner` - Owner of the policy.
3031
* `created_at` - Creation date of this group.
3132
* `updated_at` - Date of the last update of this group.

website/docs/r/iam_policy.html.markdown

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ resource "ovh_iam_policy" "manager" {
2121
description = "Users are allowed to use the OVH manager"
2222
identities = [ovh_me_identity_group.my_group.urn]
2323
resources = [data.ovh_me.account.urn]
24-
# these are all the actions
24+
# these are all the actions
2525
allow = [
2626
"account:apiovh:me/get",
2727
"account:apiovh:me/supportLevel/get",
@@ -41,6 +41,7 @@ resource "ovh_iam_policy" "manager" {
4141
* `resources` - List of resources affected by the policy
4242
* `allow` - List of actions allowed on resources by identities
4343
* `except` - List of overrides of action that must not be allowed even if they are caught by allow. Only makes sens if allow contains wildcards.
44+
* `deny` - List of actions that will be denied no matter what policy exists.
4445

4546
## Attributes Reference
4647

0 commit comments

Comments
 (0)