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

make iam condition ga #6748

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/3729.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
iam: made the `condition` block GA for all IAM resource and datasource types.
```
27 changes: 25 additions & 2 deletions google/data_source_google_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,27 @@ func dataSourceGoogleIamPolicy() *schema.Resource {
},
Set: schema.HashString,
},
"condition": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"expression": {
Type: schema.TypeString,
Required: true,
},
"title": {
Type: schema.TypeString,
Required: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},
Expand Down Expand Up @@ -106,13 +127,15 @@ func dataSourceGoogleIamPolicyRead(d *schema.ResourceData, meta interface{}) err
for i, v := range bset.List() {
binding := v.(map[string]interface{})
members := convertStringSet(binding["members"].(*schema.Set))
condition := expandIamCondition(binding["condition"])

// Sort members to get simpler diffs as it's what the API does
sort.Strings(members)

policy.Bindings[i] = &cloudresourcemanager.Binding{
Role: binding["role"].(string),
Members: members,
Role: binding["role"].(string),
Members: members,
Condition: condition,
}
}

Expand Down
53 changes: 53 additions & 0 deletions google/resource_google_project_iam_binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,38 @@ func TestAccProjectIamBinding_noMembers(t *testing.T) {
})
}

func TestAccProjectIamBinding_withCondition(t *testing.T) {
t.Parallel()

org := getTestOrgFromEnv(t)
pid := fmt.Sprintf("tf-test-%d", randInt(t))
role := "roles/compute.instanceAdmin"
conditionTitle := "expires_after_2019_12_31"
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// Create a new project
{
Config: testAccProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccProjectExistingPolicy(t, pid),
),
},
// Apply an IAM binding
{
Config: testAccProjectAssociateBinding_withCondition(pid, pname, org, role, conditionTitle),
},
{
ResourceName: "google_project_iam_binding.acceptance",
ImportStateId: fmt.Sprintf("%s %s %s", pid, role, conditionTitle),
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccProjectAssociateBindingBasic(pid, name, org, role string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
Expand Down Expand Up @@ -301,3 +333,24 @@ resource "google_project_iam_binding" "acceptance" {
}
`, pid, name, org, role)
}

func testAccProjectAssociateBinding_withCondition(pid, name, org, role, conditionTitle string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
}

resource "google_project_iam_binding" "acceptance" {
project = google_project.acceptance.project_id
members = ["user:admin@hashicorptest.com"]
role = "%s"
condition {
title = "%s"
description = "Expiring at midnight of 2019-12-31"
expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
}
}
`, pid, name, org, role, conditionTitle)
}
55 changes: 55 additions & 0 deletions google/resource_google_project_iam_member_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,40 @@ func TestAccProjectIamMember_remove(t *testing.T) {
})
}

func TestAccProjectIamMember_withCondition(t *testing.T) {
t.Parallel()

org := getTestOrgFromEnv(t)
pid := fmt.Sprintf("tf-test-%d", randInt(t))
resourceName := "google_project_iam_member.acceptance"
role := "roles/compute.instanceAdmin"
member := "user:admin@hashicorptest.com"
conditionTitle := "expires_after_2019_12_31"
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// Create a new project
{
Config: testAccProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccProjectExistingPolicy(t, pid),
),
},
// Apply an IAM binding
{
Config: testAccProjectAssociateMember_withCondition(pid, pname, org, role, member, conditionTitle),
},
{
ResourceName: resourceName,
ImportStateId: fmt.Sprintf("%s %s %s %s", pid, role, member, conditionTitle),
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccProjectAssociateMemberBasic(pid, name, org, role, member string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
Expand Down Expand Up @@ -170,3 +204,24 @@ resource "google_project_iam_member" "multiple" {
}
`, pid, name, org, role, member, role2, member2)
}

func testAccProjectAssociateMember_withCondition(pid, name, org, role, member, conditionTitle string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
}

resource "google_project_iam_member" "acceptance" {
project = google_project.acceptance.project_id
role = "%s"
member = "%s"
condition {
title = "%s"
description = "Expiring at midnight of 2019-12-31"
expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
}
}
`, pid, name, org, role, member, conditionTitle)
}
65 changes: 65 additions & 0 deletions google/resource_google_project_iam_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,35 @@ func TestAccProjectIamPolicy_expandedAuditConfig(t *testing.T) {
})
}

func TestAccProjectIamPolicy_withCondition(t *testing.T) {
t.Parallel()

org := getTestOrgFromEnv(t)
pid := fmt.Sprintf("tf-test-%d", randInt(t))
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// Create a new project
{
Config: testAccProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccProjectExistingPolicy(t, pid),
),
},
// Apply an IAM policy from a data source. The application
// merges policies, so we validate the expected state.
{
Config: testAccProjectAssociatePolicy_withCondition(pid, pname, org),
},
{
ResourceName: "google_project_iam_policy.acceptance",
ImportState: true,
},
},
})
}

func getStatePrimaryResource(s *terraform.State, res, expectedID string) (*terraform.InstanceState, error) {
// Get the project resource
resource, ok := s.RootModule().Resources[res]
Expand Down Expand Up @@ -398,3 +427,39 @@ data "google_iam_policy" "expanded" {
}
`, pid, name, org)
}

func testAccProjectAssociatePolicy_withCondition(pid, name, org string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
}

resource "google_project_iam_policy" "acceptance" {
project = google_project.acceptance.id
policy_data = data.google_iam_policy.admin.policy_data
}

data "google_iam_policy" "admin" {
binding {
role = "roles/storage.objectViewer"
members = [
"user:evanbrown@google.com",
]
}
binding {
role = "roles/compute.instanceAdmin"
members = [
"user:evanbrown@google.com",
"user:evandbrown@gmail.com",
]
condition {
title = "expires_after_2019_12_31"
description = "Expiring at midnight of 2019-12-31"
expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
}
}
}
`, pid, name, org)
}