Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iam): add support for deny in policies #483

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ovh/data_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ func dataSourceIamPolicy() *schema.Resource {
Type: schema.TypeString,
},
},
"deny": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"owner": {
Type: schema.TypeString,
Computed: true,
Expand Down
33 changes: 24 additions & 9 deletions ovh/data_iam_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
resource1 := "urn:v1:eu:resource:vrack:*"
resource2 := "urn:v1:eu:resource:vps:*"
allow1 := "*"
allow2 := "*"
except1 := "vrack:apiovh:dedicatedServer/remove"
deny2 := "*"

preSetup := fmt.Sprintf(
testAccIamPolicyDatasourceConfig_preSetup,
Expand All @@ -29,10 +30,11 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
desc,
resource1,
allow1,
except1,
policyName2,
desc,
resource2,
allow2,
deny2,
)
config := fmt.Sprintf(
testAccIamPolicyDatasourceConfig_keys,
Expand All @@ -43,14 +45,15 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
desc,
resource1,
allow1,
except1,
policyName2,
desc,
resource2,
allow2,
deny2,
)

checks := checkIamPolicyResourceAttr("ovh_iam_policy.policy_1", policyName1, desc, resource1)
checks = append(checks, checkIamPolicyResourceAttr("ovh_iam_policy.policy_2", policyName2, desc, resource2)...)
checks := checkIamPolicyResourceAttr("ovh_iam_policy.policy_1", policyName1, desc, resource1, allow1, except1, "")
checks = append(checks, checkIamPolicyResourceAttr("ovh_iam_policy.policy_2", policyName2, desc, resource2, "", "", deny2)...)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckCredentials(t) },
Expand All @@ -70,13 +73,23 @@ func TestAccIamPolicyDataSource_basic(t *testing.T) {
})
}

func checkIamPolicyResourceAttr(name, polName, desc, resourceURN string) []resource.TestCheckFunc {
func checkIamPolicyResourceAttr(name, polName, desc, resourceURN, allowAction, exceptAction, denyAction string) []resource.TestCheckFunc {
// we are not checking identity urn because they are dynamic and depend on the test account NIC
return []resource.TestCheckFunc{
checks := []resource.TestCheckFunc{
resource.TestCheckResourceAttr(name, "name", polName),
resource.TestCheckResourceAttr(name, "description", desc),
resource.TestCheckTypeSetElemAttr(name, "resources.*", resourceURN),
}
if allowAction != "" {
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "allow.*", allowAction))
}
if exceptAction != "" {
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "except.*", exceptAction))
}
if denyAction != "" {
checks = append(checks, resource.TestCheckTypeSetElemAttr(name, "deny.*", denyAction))
}
return checks
}

const testAccIamPolicyDatasourceConfig_preSetup = `
Expand All @@ -96,14 +109,15 @@ resource "ovh_iam_policy" "policy_1" {
identities = [ovh_me_identity_user.user_1.urn]
resources = ["%s"]
allow = ["%s"]
except = ["%s"]
}

resource "ovh_iam_policy" "policy_2" {
name = "%s"
description = "%s"
identities = [ovh_me_identity_group.group_1.urn]
resources = ["%s"]
allow = ["%s"]
deny = ["%s"]
}
`

Expand All @@ -124,14 +138,15 @@ resource "ovh_iam_policy" "policy_1" {
identities = [ovh_me_identity_user.user_1.urn]
resources = ["%s"]
allow = ["%s"]
except = ["%s"]
}

resource "ovh_iam_policy" "policy_2" {
name = "%s"
description = "%s"
identities = [ovh_me_identity_group.group_1.urn]
resources = ["%s"]
allow = ["%s"]
deny = ["%s"]
}

data "ovh_iam_policies" "policies" {}
Expand Down
15 changes: 14 additions & 1 deletion ovh/resource_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ func resourceIamPolicy() *schema.Resource {
Type: schema.TypeString,
},
},
"deny": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"owner": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -163,7 +170,13 @@ func prepareIamPolicyCall(d *schema.ResourceData) IamPolicy {

if except, ok := d.GetOk("except"); ok {
for _, e := range except.(*schema.Set).List() {
out.Permissions.Except = append(out.Permissions.Allow, IamAction{Action: e.(string)})
out.Permissions.Except = append(out.Permissions.Except, IamAction{Action: e.(string)})
}
}

if deny, ok := d.GetOk("deny"); ok {
for _, e := range deny.(*schema.Set).List() {
out.Permissions.Deny = append(out.Permissions.Deny, IamAction{Action: e.(string)})
}
}
return out
Expand Down
44 changes: 42 additions & 2 deletions ovh/resource_iam_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ func TestAccIamPolicy_basic(t *testing.T) {
desc := "IAM policy created by Terraform Acc"
userName := acctest.RandomWithPrefix(test_prefix)
res := "urn:v1:eu:resource:vps:*"
config := fmt.Sprintf(testAccIamPolicyConfig, userName, userName, name, desc, res)
exceptAction := "vps:apiovh:reinstall"
config := fmt.Sprintf(testAccIamPolicyConfig, userName, userName, name, desc, res, exceptAction)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckCredentials(t) },
Expand All @@ -76,7 +77,29 @@ func TestAccIamPolicy_basic(t *testing.T) {
{
Config: config,
Check: resource.ComposeTestCheckFunc(
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res)...,
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res, "*", exceptAction, "")...,
),
},
},
})
}

func TestAccIamPolicy_deny(t *testing.T) {
name := acctest.RandomWithPrefix(test_prefix)
desc := "IAM policy created by Terraform Acc"
userName := acctest.RandomWithPrefix(test_prefix)
res := "urn:v1:eu:resource:vps:*"
denyAction := "vps:apiovh:reinstall"
config := fmt.Sprintf(testAccIamPolicyDenyConfig, userName, userName, name, desc, res, denyAction)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckCredentials(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res, "", "", denyAction)...,
),
},
},
Expand All @@ -96,5 +119,22 @@ resource "ovh_iam_policy" "policy1" {
identities = [ovh_me_identity_user.test_user.urn]
resources = ["%s"]
allow = ["*"]
except = ["%s"]
}
`

const testAccIamPolicyDenyConfig = `
resource "ovh_me_identity_user" "test_user" {
login = "%s"
email = "%[email protected]"
password = "qwe123!@#"
}

resource "ovh_iam_policy" "policy1" {
name = "%s"
description = "%s"
identities = [ovh_me_identity_user.test_user.urn]
resources = ["%s"]
deny = ["%s"]
}
`
17 changes: 13 additions & 4 deletions ovh/types_iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,17 @@ func (p IamPolicy) ToMap() map[string]any {
}
out["resources"] = resources

// inline allow and except
allow, except := p.Permissions.ToLists()
// inline allow, except and deny
allow, except, deny := p.Permissions.ToLists()
if len(allow) != 0 {
out["allow"] = allow
}
if len(except) != 0 {
out["except"] = except
}
if len(deny) != 0 {
out["deny"] = deny
}

if p.Description != "" {
out["description"] = p.Description
Expand Down Expand Up @@ -89,11 +92,13 @@ type IamResourceDetails struct {
type IamPermissions struct {
Allow []IamAction `json:"allow"`
Except []IamAction `json:"except"`
Deny []IamAction `json:"deny"`
}

func (p IamPermissions) ToLists() ([]string, []string) {
func (p IamPermissions) ToLists() ([]string, []string, []string) {
var allow []string
var except []string
var deny []string

for _, r := range p.Allow {
allow = append(allow, r.Action)
Expand All @@ -102,7 +107,11 @@ func (p IamPermissions) ToLists() ([]string, []string) {
for _, r := range p.Except {
except = append(except, r.Action)
}
return allow, except

for _, r := range p.Deny {
deny = append(deny, r.Action)
}
return allow, except, deny
}

type IamAction struct {
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/iam_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ data "ovh_iam_policy" "my_policy" {
* `identities` - List of identities affected by the policy.
* `resources` - List of resources affected by the policy.
* `allow` - List of actions allowed by the policy.
* `except` - List of actions.
* `except` - List of actions that will be subtracted from the `allow` list.
* `deny` - List of actions that will be denied no matter what policy exists.
* `owner` - Owner of the policy.
* `created_at` - Creation date of this group.
* `updated_at` - Date of the last update of this group.
Expand Down
3 changes: 2 additions & 1 deletion website/docs/r/iam_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ resource "ovh_iam_policy" "manager" {
description = "Users are allowed to use the OVH manager"
identities = [ovh_me_identity_group.my_group.urn]
resources = [data.ovh_me.account.urn]
# these are all the actions
# these are all the actions
allow = [
"account:apiovh:me/get",
"account:apiovh:me/supportLevel/get",
Expand All @@ -41,6 +41,7 @@ resource "ovh_iam_policy" "manager" {
* `resources` - List of resources affected by the policy
* `allow` - List of actions allowed on resources by identities
* `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.
* `deny` - List of actions that will be denied no matter what policy exists.

## Attributes Reference

Expand Down