From 5f4f56c834e85fc122a8a824b8773aaa509c757b Mon Sep 17 00:00:00 2001 From: Martin Guibert Date: Tue, 28 Sep 2021 21:00:10 +0200 Subject: [PATCH 1/4] add support for google_storage_bucket_iam_member --- pkg/driftctl.go | 1 + .../google_legacy_bucket_iam_bindings.go | 6 +- ...orage_bucket_iam_member_tranformer_test.go | 249 ++++++++++++++++++ ...e_storage_bucket_iam_member_transformer.go | 74 ++++++ .../google_storage_bucket_iam_member.go | 3 + pkg/resource/resource_types.go | 1 + 6 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go create mode 100644 pkg/middlewares/google_storage_bucket_iam_member_transformer.go create mode 100644 pkg/resource/google/google_storage_bucket_iam_member.go diff --git a/pkg/driftctl.go b/pkg/driftctl.go index ba8268b65..778d0f8c7 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -110,6 +110,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewTagsAllManager(), middlewares.NewEipAssociationExpander(d.resourceFactory), middlewares.NewRDSClusterInstanceExpander(d.resourceFactory), + middlewares.NewGoogleStorageBucketIAMMemberTransformer(d.resourceFactory), middlewares.NewGoogleLegacyBucketIAMBindings(), middlewares.NewAzurermSubnetExpander(d.resourceFactory), middlewares.NewAwsApiGatewayDeploymentExpander(d.resourceFactory), diff --git a/pkg/middlewares/google_legacy_bucket_iam_bindings.go b/pkg/middlewares/google_legacy_bucket_iam_bindings.go index 762da12dc..baa386647 100644 --- a/pkg/middlewares/google_legacy_bucket_iam_bindings.go +++ b/pkg/middlewares/google_legacy_bucket_iam_bindings.go @@ -11,11 +11,11 @@ import ( // Creating buckets add legacy role bindings, this middleware will filter them unless they are managed. type GoogleLegacyBucketIAMBindings struct{} -func NewGoogleLegacyBucketIAMBindings() GoogleLegacyBucketIAMBindings { - return GoogleLegacyBucketIAMBindings{} +func NewGoogleLegacyBucketIAMBindings() *GoogleLegacyBucketIAMBindings { + return &GoogleLegacyBucketIAMBindings{} } -func (m GoogleLegacyBucketIAMBindings) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { +func (m *GoogleLegacyBucketIAMBindings) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { newRemoteResources := make([]*resource.Resource, 0) diff --git a/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go b/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go new file mode 100644 index 000000000..05a55f392 --- /dev/null +++ b/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go @@ -0,0 +1,249 @@ +package middlewares + +import ( + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/awsutil" + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/cloudskiff/driftctl/pkg/resource/google" + "github.com/cloudskiff/driftctl/pkg/terraform" + "github.com/r3labs/diff/v2" +) + +func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { + tests := []struct { + name string + resourcesFromState []*resource.Resource + expected []*resource.Resource + mock func(factory *terraform.MockResourceFactory) + }{ + { + "Test that bucket member are transformed into bindings", + []*resource.Resource{ + { + Id: "fake", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "admin bucket", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + }, + }, + { + Id: "b/bucket/admin/elie", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "member": "user:elie@cloudskiff.com", + }, + }, + { + Id: "b/bucket/admin/William", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "member": "user:william@cloudskiff.com", + }, + }, + { + Id: "b/bucket/viewer/William", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket", + "member": "user:william@cloudskiff.com", + }, + }, + { + Id: "b/bucket2/viewer/William", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket2", + "member": "user:william@cloudskiff.com", + }, + }, + }, + []*resource.Resource{ + { + Id: "fake", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "admin bucket", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + }, + }, + { + Id: "b/bucket/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "members": []string{ + "user:elie@cloudskiff.com", + "user:william@cloudskiff.com", + }, + }, + }, + { + Id: "b/bucket/storage.viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket", + "members": []string{ + "user:william@cloudskiff.com", + }, + }, + }, + { + Id: "b/bucket2/storage.viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket2", + "members": []string{ + "user:william@cloudskiff.com", + }, + }, + }, + }, + func(factory *terraform.MockResourceFactory) { + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/bucket/storage.admin", + map[string]interface{}{ + "id": "b/bucket/storage.admin", + "bucket": "b/bucket", + "role": "storage.admin", + "members": []string{ + "user:elie@cloudskiff.com", + "user:william@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/bucket/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "members": []string{ + "user:elie@cloudskiff.com", + "user:william@cloudskiff.com", + }, + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/bucket/storage.viewer", + map[string]interface{}{ + "id": "b/bucket/storage.viewer", + "bucket": "b/bucket", + "role": "storage.viewer", + "members": []string{ + "user:william@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/bucket/storage.viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket", + "members": []string{ + "user:william@cloudskiff.com", + }, + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/bucket2/storage.viewer", + map[string]interface{}{ + "id": "b/bucket2/storage.viewer", + "bucket": "b/bucket2", + "role": "storage.viewer", + "members": []string{ + "user:william@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/bucket2/storage.viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.viewer", + "bucket": "b/bucket2", + "members": []string{ + "user:william@cloudskiff.com", + }, + }, + }).Once() + }, + }, + { + "test that everything is fine when there is no members", + []*resource.Resource{ + { + Id: "fake", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "admin bucket", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + }, + }, + }, + []*resource.Resource{ + { + Id: "fake", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "admin bucket", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + }, + }, + }, + func(factory *terraform.MockResourceFactory) { + + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + factory := &terraform.MockResourceFactory{} + if tt.mock != nil { + tt.mock(factory) + } + + m := NewGoogleStorageBucketIAMMemberTransformer(factory) + err := m.Execute(&[]*resource.Resource{}, &tt.resourcesFromState) + if err != nil { + t.Fatal(err) + } + changelog, err := diff.Diff(tt.expected, tt.resourcesFromState) + if err != nil { + t.Fatal(err) + } + if len(changelog) > 0 { + for _, change := range changelog { + t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To)) + } + } + }) + } +} diff --git a/pkg/middlewares/google_storage_bucket_iam_member_transformer.go b/pkg/middlewares/google_storage_bucket_iam_member_transformer.go new file mode 100644 index 000000000..acbe847ab --- /dev/null +++ b/pkg/middlewares/google_storage_bucket_iam_member_transformer.go @@ -0,0 +1,74 @@ +package middlewares + +import ( + "fmt" + + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/cloudskiff/driftctl/pkg/resource/google" +) + +// GoogleStorageBucketIAMMemberTransformer Transforms Bucket IAM Member in bucket iam binding to ease comparison. +type GoogleStorageBucketIAMMemberTransformer struct { + resourceFactory resource.ResourceFactory +} + +func NewGoogleStorageBucketIAMMemberTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMMemberTransformer { + return &GoogleStorageBucketIAMMemberTransformer{resourceFactory} +} + +func (m *GoogleStorageBucketIAMMemberTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error { + + resources := make([]*resource.Resource, 0) + bindings := map[string]map[string][]string{} // map[BUCKETID][ROLENAME][]MEMBERS + + for _, stateRes := range *resourcesFromState { + // Ignore all resources other than BucketIamBinding + if stateRes.ResourceType() != google.GoogleStorageBucketIamMemberResourceType { + resources = append(resources, stateRes) + continue + } + + bucket := *stateRes.Attrs.GetString("bucket") + roleName := *stateRes.Attrs.GetString("role") + member := *stateRes.Attrs.GetString("member") + + bucketBindings := bindings[bucket] + if bucketBindings == nil { + bucketBindings = make(map[string][]string) + } + + roleBindings := bucketBindings[roleName] + if roleBindings == nil { + roleBindings = make([]string, 0, 1) + } + + roleBindings = append(roleBindings, member) + + bucketBindings[roleName] = roleBindings + bindings[bucket] = bucketBindings + } + + for bucket, roleBindings := range bindings { + for roleName, members := range roleBindings { + id := fmt.Sprintf("%s/%s", bucket, roleName) + resources = append( + resources, + m.resourceFactory.CreateAbstractResource( + google.GoogleStorageBucketIamBindingResourceType, + id, + map[string]interface{}{ + "id": id, + "bucket": bucket, + "role": roleName, + "members": members, + }, + ), + ) + } + + } + + *resourcesFromState = resources + + return nil +} diff --git a/pkg/resource/google/google_storage_bucket_iam_member.go b/pkg/resource/google/google_storage_bucket_iam_member.go new file mode 100644 index 000000000..45d2fc53e --- /dev/null +++ b/pkg/resource/google/google_storage_bucket_iam_member.go @@ -0,0 +1,3 @@ +package google + +const GoogleStorageBucketIamMemberResourceType = "google_storage_bucket_iam_member" diff --git a/pkg/resource/resource_types.go b/pkg/resource/resource_types.go index d4cb591ea..db85829d6 100644 --- a/pkg/resource/resource_types.go +++ b/pkg/resource/resource_types.go @@ -84,6 +84,7 @@ var supportedTypes = map[string]struct{}{ "google_compute_instance": {}, "google_compute_network": {}, "google_storage_bucket_iam_binding": {}, + "google_storage_bucket_iam_member": {}, "azurerm_storage_account": {}, "azurerm_storage_container": {}, From 7cd13a917dfb75f7dce82038d247c7f328d01a6f Mon Sep 17 00:00:00 2001 From: Martin Guibert Date: Wed, 29 Sep 2021 17:43:56 +0200 Subject: [PATCH 2/4] add support for google_storage_bucket_iam_policy, add tests --- pkg/driftctl.go | 1 + .../state/terraform_state_reader_test.go | 2 + .../results.golden.json | 46 ++++ .../terraform.tfstate | 105 ++++++++ .../results.golden.json | 22 ++ .../terraform.tfstate | 55 ++++ ...orage_bucket_iam_policy_tranformer_test.go | 244 ++++++++++++++++++ ...e_storage_bucket_iam_policy_transformer.go | 70 +++++ .../google_storage_bucket_iam_member_test.go | 31 +++ .../google_storage_bucket_iam_policy.go | 3 + .../terraform.tf | 50 ++++ pkg/resource/resource_types.go | 1 + 12 files changed, 630 insertions(+) create mode 100755 pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json create mode 100644 pkg/iac/terraform/state/test/google_bucket_iam_member/terraform.tfstate create mode 100755 pkg/iac/terraform/state/test/google_bucket_iam_policy/results.golden.json create mode 100644 pkg/iac/terraform/state/test/google_bucket_iam_policy/terraform.tfstate create mode 100644 pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go create mode 100644 pkg/middlewares/google_storage_bucket_iam_policy_transformer.go create mode 100644 pkg/resource/google/google_storage_bucket_iam_member_test.go create mode 100644 pkg/resource/google/google_storage_bucket_iam_policy.go create mode 100644 pkg/resource/google/testdata/acc/google_storage_bucket_iam_member/terraform.tf diff --git a/pkg/driftctl.go b/pkg/driftctl.go index 778d0f8c7..f7cd25806 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -111,6 +111,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewEipAssociationExpander(d.resourceFactory), middlewares.NewRDSClusterInstanceExpander(d.resourceFactory), middlewares.NewGoogleStorageBucketIAMMemberTransformer(d.resourceFactory), + middlewares.NewGoogleStorageBucketIAMPolicyTransformer(d.resourceFactory), middlewares.NewGoogleLegacyBucketIAMBindings(), middlewares.NewAzurermSubnetExpander(d.resourceFactory), middlewares.NewAwsApiGatewayDeploymentExpander(d.resourceFactory), diff --git a/pkg/iac/terraform/state/terraform_state_reader_test.go b/pkg/iac/terraform/state/terraform_state_reader_test.go index 9199f7563..60a47f627 100644 --- a/pkg/iac/terraform/state/terraform_state_reader_test.go +++ b/pkg/iac/terraform/state/terraform_state_reader_test.go @@ -329,6 +329,8 @@ func TestTerraformStateReader_Google_Resources(t *testing.T) { {name: "compute router", dirName: "google_compute_router", wantErr: false}, {name: "compute instance", dirName: "google_compute_instance", wantErr: false}, {name: "Bucket IAM Bindings", dirName: "google_bucket_iam_binding", wantErr: false}, + {name: "Bucket IAM members", dirName: "google_bucket_iam_member", wantErr: false}, + {name: "Bucket IAM Policy", dirName: "google_bucket_iam_policy", wantErr: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json b/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json new file mode 100755 index 000000000..d333afe35 --- /dev/null +++ b/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json @@ -0,0 +1,46 @@ +[ + { + "Id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:elie.charra@cloudskiff.com", + "Type": "google_storage_bucket_iam_member", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", + "role": "roles/storage.objectViewer" + } + }, + { + "Id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/user:elie.charra@cloudskiff.com", + "Type": "google_storage_bucket_iam_member", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", + "role": "roles/storage.admin" + } + }, + { + "Id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + "Type": "google_storage_bucket_iam_member", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", + "role": "roles/storage.objectViewer" + } + }, + { + "Id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/user:william.beuil@cloudskiff.com", + "Type": "google_storage_bucket_iam_member", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", + "role": "roles/storage.admin" + } + } +] \ No newline at end of file diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_member/terraform.tfstate b/pkg/iac/terraform/state/test/google_bucket_iam_member/terraform.tfstate new file mode 100644 index 000000000..222a0b2f6 --- /dev/null +++ b/pkg/iac/terraform/state/test/google_bucket_iam_member/terraform.tfstate @@ -0,0 +1,105 @@ +{ + "version": 4, + "terraform_version": "0.14.5", + "serial": 79, + "lineage": "c2cd867e-c930-5de3-8592-8eb915e60cb8", + "outputs": {}, + "resources": [ + { + "mode": "managed", + "type": "google_storage_bucket_iam_member", + "name": "eli2", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "condition": [], + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", + "role": "roles/storage.objectViewer" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "google_storage_bucket.dctlgstoragebucketiambinding-2" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_storage_bucket_iam_member", + "name": "elie1", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "condition": [], + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", + "role": "roles/storage.admin" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "google_storage_bucket.dctlgstoragebucketiambinding-1" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_storage_bucket_iam_member", + "name": "will1", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "condition": [], + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", + "role": "roles/storage.objectViewer" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "google_storage_bucket.dctlgstoragebucketiambinding-1" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_storage_bucket_iam_member", + "name": "will2", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "condition": [], + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", + "role": "roles/storage.admin" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "google_storage_bucket.dctlgstoragebucketiambinding-2" + ] + } + ] + } + ] +} diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_policy/results.golden.json b/pkg/iac/terraform/state/test/google_bucket_iam_policy/results.golden.json new file mode 100755 index 000000000..409ead6c0 --- /dev/null +++ b/pkg/iac/terraform/state/test/google_bucket_iam_policy/results.golden.json @@ -0,0 +1,22 @@ +[ + { + "Id": "b/dctlgstoragebucketiambinding-1", + "Type": "google_storage_bucket_iam_policy", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAU=", + "id": "b/dctlgstoragebucketiambinding-1", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}" + } + }, + { + "Id": "b/dctlgstoragebucketiambinding-2", + "Type": "google_storage_bucket_iam_policy", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAU=", + "id": "b/dctlgstoragebucketiambinding-2", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}" + } + } +] \ No newline at end of file diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_policy/terraform.tfstate b/pkg/iac/terraform/state/test/google_bucket_iam_policy/terraform.tfstate new file mode 100644 index 000000000..05478ef7d --- /dev/null +++ b/pkg/iac/terraform/state/test/google_bucket_iam_policy/terraform.tfstate @@ -0,0 +1,55 @@ +{ + "version": 4, + "terraform_version": "0.14.5", + "serial": 33, + "lineage": "3e964c0c-f80f-f7d8-621f-94c9f5b8924b", + "outputs": {}, + "resources": [ + { + "mode": "managed", + "type": "google_storage_bucket_iam_policy", + "name": "policy", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAU=", + "id": "b/dctlgstoragebucketiambinding-1", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "data.google_iam_policy.binding_admin_1", + "google_storage_bucket.dctlgstoragebucketiambinding-1" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_storage_bucket_iam_policy", + "name": "policy2", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAU=", + "id": "b/dctlgstoragebucketiambinding-2", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "data.google_iam_policy.binding_admin_2", + "google_storage_bucket.dctlgstoragebucketiambinding-2" + ] + } + ] + } + ] +} diff --git a/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go b/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go new file mode 100644 index 000000000..6862910e8 --- /dev/null +++ b/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go @@ -0,0 +1,244 @@ +package middlewares + +import ( + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/awsutil" + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/cloudskiff/driftctl/pkg/resource/google" + "github.com/cloudskiff/driftctl/pkg/terraform" + "github.com/r3labs/diff/v2" +) + +func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) { + tests := []struct { + name string + resourcesFromState []*resource.Resource + expected []*resource.Resource + mock func(factory *terraform.MockResourceFactory) + }{ + { + "Test that bucket policy are transformed into bindings", + []*resource.Resource{ + { + Id: "b/dctlgstoragebucketiambinding-1", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "b/dctlgstoragebucketiambinding-2", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "b/dctlgstoragebucketiambinding-1", + Type: google.GoogleStorageBucketIamPolicyResourceType, + Attrs: &resource.Attributes{ + "bucket": "b/dctlgstoragebucketiambinding-1", + "id": "b/dctlgstoragebucketiambinding-1", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", + }, + }, + { + Id: "dctlgstoragebucketiambinding-2", + Type: google.GoogleStorageBucketIamPolicyResourceType, + Attrs: &resource.Attributes{ + "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAU=", + "id": "b/dctlgstoragebucketiambinding-2", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", + }, + }, + }, + []*resource.Resource{ + { + Id: "b/dctlgstoragebucketiambinding-1", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "b/dctlgstoragebucketiambinding-2", + Type: google.GoogleStorageBucketResourceType, + Attrs: &resource.Attributes{}, + }, + { + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "role": "roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-1", + "members": []string{ + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + }, + }, + }, + { + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "role": "roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-1", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }, + }, + { + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "role": "roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-2", + "members": []string{ + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + }, + }, + }, + { + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "role": "roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-2", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }, + }, + }, + func(factory *terraform.MockResourceFactory) { + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + map[string]interface{}{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-1", + "role": "roles/storage.admin", + "members": []string{ + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "role": "roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-1", + "members": []string{ + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + }, + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + map[string]interface{}{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-1", + "role": "roles/storage.objectViewer", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "role": "roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-1", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + map[string]interface{}{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-2", + "role": "roles/storage.admin", + "members": []string{ + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "role": "roles/storage.admin", + "bucket": "b/dctlgstoragebucketiambinding-2", + "members": []string{ + "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + "user:elie.charra@cloudskiff.com", + "user:martin.guibert@cloudskiff.com", + }, + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, + "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + map[string]interface{}{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-2", + "role": "roles/storage.objectViewer", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }).Return(&resource.Resource{ + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + Type: google.GoogleStorageBucketIamBindingResourceType, + Attrs: &resource.Attributes{ + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "role": "roles/storage.objectViewer", + "bucket": "b/dctlgstoragebucketiambinding-2", + "members": []string{ + "user:william.beuil@cloudskiff.com", + }, + }, + }).Once() + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + factory := &terraform.MockResourceFactory{} + if tt.mock != nil { + tt.mock(factory) + } + + m := NewGoogleStorageBucketIAMPolicyTransformer(factory) + err := m.Execute(&[]*resource.Resource{}, &tt.resourcesFromState) + if err != nil { + t.Fatal(err) + } + changelog, err := diff.Diff(tt.expected, tt.resourcesFromState) + if err != nil { + t.Fatal(err) + } + if len(changelog) > 0 { + for _, change := range changelog { + t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To)) + } + } + }) + } +} diff --git a/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go b/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go new file mode 100644 index 000000000..d8087959c --- /dev/null +++ b/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go @@ -0,0 +1,70 @@ +package middlewares + +import ( + "encoding/json" + "fmt" + + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/cloudskiff/driftctl/pkg/resource/google" +) + +// GoogleStorageBucketIAMPolicyTransformer Transforms Bucket IAM policy in bucket iam binding to ease comparison. +type GoogleStorageBucketIAMPolicyTransformer struct { + resourceFactory resource.ResourceFactory +} + +func NewGoogleStorageBucketIAMPolicyTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMPolicyTransformer { + return &GoogleStorageBucketIAMPolicyTransformer{resourceFactory} +} + +func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error { + + resources := make([]*resource.Resource, 0) + + for _, stateRes := range *resourcesFromState { + // Ignore all resources other than BucketIamBinding + if stateRes.ResourceType() != google.GoogleStorageBucketIamPolicyResourceType { + resources = append(resources, stateRes) + continue + } + + bucket := *stateRes.Attrs.GetString("bucket") + policyJSON := *stateRes.Attrs.GetString("policy_data") + + policies := policyDataType{} + err := json.Unmarshal([]byte(policyJSON), &policies) + if err != nil { + return err + } + + for _, policy := range policies.Bindings { + roleName := policy.Role + members := policy.Members + id := fmt.Sprintf("%s/%s", bucket, roleName) + resources = append( + resources, + m.resourceFactory.CreateAbstractResource( + google.GoogleStorageBucketIamBindingResourceType, + id, + map[string]interface{}{ + "id": id, + "bucket": bucket, + "role": roleName, + "members": members, + }, + ), + ) + } + } + + *resourcesFromState = resources + + return nil +} + +type policyDataType struct { + Bindings []struct { + Members []string + Role string + } +} diff --git a/pkg/resource/google/google_storage_bucket_iam_member_test.go b/pkg/resource/google/google_storage_bucket_iam_member_test.go new file mode 100644 index 000000000..1d2fc4ab2 --- /dev/null +++ b/pkg/resource/google/google_storage_bucket_iam_member_test.go @@ -0,0 +1,31 @@ +package google_test + +import ( + "testing" + + "github.com/cloudskiff/driftctl/test" + "github.com/cloudskiff/driftctl/test/acceptance" +) + +func TestAcc_Google_StorageBucketIAMMember(t *testing.T) { + acceptance.Run(t, acceptance.AccTestCase{ + TerraformVersion: "0.15.5", + Paths: []string{"./testdata/acc/google_storage_bucket_iam_member"}, + Args: []string{ + "scan", + "--to", "gcp+tf", + "--filter", "Type=='google_storage_bucket_iam_binding'", + }, + Checks: []acceptance.AccCheck{ + { + Check: func(result *test.ScanResult, stdout string, err error) { + if err != nil { + t.Fatal(err) + } + result.AssertInfrastructureIsInSync() + result.AssertManagedCount(4) + }, + }, + }, + }) +} diff --git a/pkg/resource/google/google_storage_bucket_iam_policy.go b/pkg/resource/google/google_storage_bucket_iam_policy.go new file mode 100644 index 000000000..b3fbfbadd --- /dev/null +++ b/pkg/resource/google/google_storage_bucket_iam_policy.go @@ -0,0 +1,3 @@ +package google + +const GoogleStorageBucketIamPolicyResourceType = "google_storage_bucket_iam_policy" diff --git a/pkg/resource/google/testdata/acc/google_storage_bucket_iam_member/terraform.tf b/pkg/resource/google/testdata/acc/google_storage_bucket_iam_member/terraform.tf new file mode 100644 index 000000000..186745425 --- /dev/null +++ b/pkg/resource/google/testdata/acc/google_storage_bucket_iam_member/terraform.tf @@ -0,0 +1,50 @@ +provider "google" {} + +terraform { + required_version = "~> 0.15.0" + required_providers { + google = { + version = "3.78.0" + } + } +} + +resource "random_string" "postfix" { + length = 6 + upper = false + special = false +} + +resource "google_storage_bucket" "driftctl-unittest" { + name = "driftctl-unittest-1-${random_string.postfix.result}" + location = "EU" +} + +resource "google_storage_bucket_iam_member" "elie1" { + bucket = google_storage_bucket.driftctl-unittest.name + role = "roles/storage.admin" + member = "user:elie.charra@cloudskiff.com" +} + +resource "google_storage_bucket_iam_member" "will1" { + bucket = google_storage_bucket.driftctl-unittest.name + role = "roles/storage.objectViewer" + member = "user:william.beuil@cloudskiff.com" +} + +resource "google_storage_bucket" "driftctl-unittest2" { + name = "driftctl-unittest-2-${random_string.postfix.result}" + location = "EU" +} + +resource "google_storage_bucket_iam_member" "eli2" { + bucket = google_storage_bucket.driftctl-unittest2.name + role = "roles/storage.objectViewer" + member = "user:elie.charra@cloudskiff.com" +} + +resource "google_storage_bucket_iam_member" "will2" { + bucket = google_storage_bucket.driftctl-unittest2.name + role = "roles/storage.admin" + member = "user:william.beuil@cloudskiff.com" +} diff --git a/pkg/resource/resource_types.go b/pkg/resource/resource_types.go index db85829d6..b820e073e 100644 --- a/pkg/resource/resource_types.go +++ b/pkg/resource/resource_types.go @@ -85,6 +85,7 @@ var supportedTypes = map[string]struct{}{ "google_compute_network": {}, "google_storage_bucket_iam_binding": {}, "google_storage_bucket_iam_member": {}, + "google_storage_bucket_iam_policy": {}, "azurerm_storage_account": {}, "azurerm_storage_container": {}, From 9dc7d8d5d4eb5bf44f44555fe5709eb6f33fa0d4 Mon Sep 17 00:00:00 2001 From: Martin Guibert Date: Mon, 4 Oct 2021 19:03:44 +0200 Subject: [PATCH 3/4] transform every bucket iam into members --- pkg/driftctl.go | 4 +- .../results.golden.json | 28 +-- .../results.golden.json | 4 - ....go => google_legacy_bucket_iam_member.go} | 16 +- ...> google_legacy_bucket_iam_member_test.go} | 18 +- ..._storage_bucket_iam_binding_transformer.go | 55 ++++++ ...orage_bucket_iam_member_tranformer_test.go | 169 ++++++++++-------- ...e_storage_bucket_iam_member_transformer.go | 74 -------- ...orage_bucket_iam_policy_tranformer_test.go | 136 ++++++-------- ...e_storage_bucket_iam_policy_transformer.go | 30 ++-- ...e_storage_bucket_iam_member_enumerator.go} | 42 ++--- pkg/remote/google/init.go | 4 +- pkg/remote/google_storage_scanner_test.go | 18 +- .../results.golden.json | 28 ++- .../google_storage_bucket_iam_binding.go | 17 -- .../google_storage_bucket_iam_member.go | 26 +++ pkg/resource/google/metadatas.go | 2 +- 17 files changed, 318 insertions(+), 353 deletions(-) rename pkg/middlewares/{google_legacy_bucket_iam_bindings.go => google_legacy_bucket_iam_member.go} (75%) rename pkg/middlewares/{google_legacy_bucket_iam_bindings_test.go => google_legacy_bucket_iam_member_test.go} (84%) create mode 100644 pkg/middlewares/google_storage_bucket_iam_binding_transformer.go delete mode 100644 pkg/middlewares/google_storage_bucket_iam_member_transformer.go rename pkg/remote/google/{google_storage_bucket_iam_binding_enumerator.go => google_storage_bucket_iam_member_enumerator.go} (52%) rename pkg/remote/test/{google_storage_bucket_binding_multiple => google_storage_bucket_member_listing_multiple}/results.golden.json (57%) diff --git a/pkg/driftctl.go b/pkg/driftctl.go index f7cd25806..3531b658a 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -110,9 +110,11 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewTagsAllManager(), middlewares.NewEipAssociationExpander(d.resourceFactory), middlewares.NewRDSClusterInstanceExpander(d.resourceFactory), - middlewares.NewGoogleStorageBucketIAMMemberTransformer(d.resourceFactory), + + middlewares.NewGoogleStorageBucketIAMBindingTransformer(d.resourceFactory), middlewares.NewGoogleStorageBucketIAMPolicyTransformer(d.resourceFactory), middlewares.NewGoogleLegacyBucketIAMBindings(), + middlewares.NewAzurermSubnetExpander(d.resourceFactory), middlewares.NewAwsApiGatewayDeploymentExpander(d.resourceFactory), middlewares.NewAwsApiGatewayResourceExpander(d.resourceFactory), diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_binding/results.golden.json b/pkg/iac/terraform/state/test/google_bucket_iam_binding/results.golden.json index 79dc02575..b042a55ba 100755 --- a/pkg/iac/terraform/state/test/google_bucket_iam_binding/results.golden.json +++ b/pkg/iac/terraform/state/test/google_bucket_iam_binding/results.golden.json @@ -1,9 +1,23 @@ [ + { + "Id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "Type": "google_storage_bucket_iam_binding", + "Attrs": { + "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAM=", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "members": [ + "user:elie.charra@cloudskiff.com" + ], + "role": "roles/storage.admin" + } + }, { "Id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", "Type": "google_storage_bucket_iam_binding", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", "members": [ "user:william.beuil@cloudskiff.com" @@ -16,6 +30,7 @@ "Type": "google_storage_bucket_iam_binding", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-1", + "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", "members": [ "user:william.beuil@cloudskiff.com" @@ -28,23 +43,12 @@ "Type": "google_storage_bucket_iam_binding", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-2", + "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", "members": [ "user:elie.charra@cloudskiff.com" ], "role": "roles/storage.objectViewer" } - }, - { - "Id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", - "Type": "google_storage_bucket_iam_binding", - "Attrs": { - "bucket": "b/dctlgstoragebucketiambinding-1", - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", - "members": [ - "user:elie.charra@cloudskiff.com" - ], - "role": "roles/storage.admin" - } } ] \ No newline at end of file diff --git a/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json b/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json index d333afe35..ebddb337a 100755 --- a/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json +++ b/pkg/iac/terraform/state/test/google_bucket_iam_member/results.golden.json @@ -4,7 +4,6 @@ "Type": "google_storage_bucket_iam_member", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-2", - "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:elie.charra@cloudskiff.com", "member": "user:elie.charra@cloudskiff.com", "role": "roles/storage.objectViewer" @@ -15,7 +14,6 @@ "Type": "google_storage_bucket_iam_member", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-1", - "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/user:elie.charra@cloudskiff.com", "member": "user:elie.charra@cloudskiff.com", "role": "roles/storage.admin" @@ -26,7 +24,6 @@ "Type": "google_storage_bucket_iam_member", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-1", - "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "member": "user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer" @@ -37,7 +34,6 @@ "Type": "google_storage_bucket_iam_member", "Attrs": { "bucket": "b/dctlgstoragebucketiambinding-2", - "etag": "CAM=", "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/user:william.beuil@cloudskiff.com", "member": "user:william.beuil@cloudskiff.com", "role": "roles/storage.admin" diff --git a/pkg/middlewares/google_legacy_bucket_iam_bindings.go b/pkg/middlewares/google_legacy_bucket_iam_member.go similarity index 75% rename from pkg/middlewares/google_legacy_bucket_iam_bindings.go rename to pkg/middlewares/google_legacy_bucket_iam_member.go index baa386647..d6c8c7cd6 100644 --- a/pkg/middlewares/google_legacy_bucket_iam_bindings.go +++ b/pkg/middlewares/google_legacy_bucket_iam_member.go @@ -9,30 +9,30 @@ import ( ) // Creating buckets add legacy role bindings, this middleware will filter them unless they are managed. -type GoogleLegacyBucketIAMBindings struct{} +type GoogleLegacyBucketIAMMmeber struct{} -func NewGoogleLegacyBucketIAMBindings() *GoogleLegacyBucketIAMBindings { - return &GoogleLegacyBucketIAMBindings{} +func NewGoogleLegacyBucketIAMBindings() *GoogleLegacyBucketIAMMmeber { + return &GoogleLegacyBucketIAMMmeber{} } -func (m *GoogleLegacyBucketIAMBindings) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { +func (m *GoogleLegacyBucketIAMMmeber) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { newRemoteResources := make([]*resource.Resource, 0) for _, remoteResource := range *remoteResources { // Ignore all resources other than BucketIamBinding - if remoteResource.ResourceType() != google.GoogleStorageBucketIamBindingResourceType { + if remoteResource.ResourceType() != google.GoogleStorageBucketIamMemberResourceType { newRemoteResources = append(newRemoteResources, remoteResource) continue } - // Ignore all non-legacy bindings + // Ignore all non-legacy member if roleName := remoteResource.Attrs.GetString("role"); roleName != nil && !strings.Contains(*roleName, "legacy") { newRemoteResources = append(newRemoteResources, remoteResource) continue } - // Check if bindings is managed by IaC + // Check if member is managed by IaC existInState := false for _, stateResource := range *resourcesFromState { if remoteResource.Equal(stateResource) { @@ -51,7 +51,7 @@ func (m *GoogleLegacyBucketIAMBindings) Execute(remoteResources, resourcesFromSt logrus.WithFields(logrus.Fields{ "id": remoteResource.ResourceId(), "type": remoteResource.ResourceType(), - }).Debug("Ignoring legacy bucket bindings as it is not managed by IaC") + }).Debug("Ignoring legacy bucket member as it is not managed by IaC") } *remoteResources = newRemoteResources diff --git a/pkg/middlewares/google_legacy_bucket_iam_bindings_test.go b/pkg/middlewares/google_legacy_bucket_iam_member_test.go similarity index 84% rename from pkg/middlewares/google_legacy_bucket_iam_bindings_test.go rename to pkg/middlewares/google_legacy_bucket_iam_member_test.go index 3a3c5d624..9b93aac6e 100644 --- a/pkg/middlewares/google_legacy_bucket_iam_bindings_test.go +++ b/pkg/middlewares/google_legacy_bucket_iam_member_test.go @@ -27,14 +27,14 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", }, }, { Id: "legacy", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.legacyBucketOwner", }, @@ -49,7 +49,7 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", }, @@ -66,21 +66,21 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", }, }, { Id: "legacy", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.legacyBucketOwner", }, }, { Id: "legacy-managed", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.legacyBucketOwner", }, @@ -89,7 +89,7 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { []*resource.Resource{ { Id: "legacy-managed", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.legacyBucketOwner", }, @@ -103,14 +103,14 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", }, }, { Id: "legacy-managed", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.legacyBucketOwner", }, diff --git a/pkg/middlewares/google_storage_bucket_iam_binding_transformer.go b/pkg/middlewares/google_storage_bucket_iam_binding_transformer.go new file mode 100644 index 000000000..2639aabe7 --- /dev/null +++ b/pkg/middlewares/google_storage_bucket_iam_binding_transformer.go @@ -0,0 +1,55 @@ +package middlewares + +import ( + "fmt" + + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/cloudskiff/driftctl/pkg/resource/google" +) + +// GoogleStorageBucketIAMBindingTransformer Transforms Bucket IAM binding in bucket iam member to ease comparison. +type GoogleStorageBucketIAMBindingTransformer struct { + resourceFactory resource.ResourceFactory +} + +func NewGoogleStorageBucketIAMBindingTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMBindingTransformer { + return &GoogleStorageBucketIAMBindingTransformer{resourceFactory} +} + +func (m *GoogleStorageBucketIAMBindingTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error { + + resources := make([]*resource.Resource, 0) + + for _, stateRes := range *resourcesFromState { + // Ignore all resources other than BucketIamBinding + if stateRes.ResourceType() != google.GoogleStorageBucketIamBindingResourceType { + resources = append(resources, stateRes) + continue + } + + bucket := *stateRes.Attrs.GetString("bucket") + roleName := *stateRes.Attrs.GetString("role") + members, _ := stateRes.Attrs.Get("members") + + for _, member := range members.([]string) { + id := fmt.Sprintf("%s/%s/%s", bucket, roleName, member) + resources = append( + resources, + m.resourceFactory.CreateAbstractResource( + google.GoogleStorageBucketIamMemberResourceType, + id, + map[string]interface{}{ + "id": id, + "bucket": bucket, + "role": roleName, + "member": member, + }, + ), + ) + } + } + + *resourcesFromState = resources + + return nil +} diff --git a/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go b/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go index 05a55f392..a77c7a508 100644 --- a/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go +++ b/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go @@ -11,7 +11,7 @@ import ( "github.com/r3labs/diff/v2" ) -func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { +func TestGoogleBucketIAMBindingTransformer_Execute(t *testing.T) { tests := []struct { name string resourcesFromState []*resource.Resource @@ -19,7 +19,7 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { mock func(factory *terraform.MockResourceFactory) }{ { - "Test that bucket member are transformed into bindings", + "Test that bucket bindings are transformed into member", []*resource.Resource{ { Id: "fake", @@ -28,45 +28,46 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, - Attrs: &resource.Attributes{ - "role": "storage.admin", - }, - }, - { - Id: "b/bucket/admin/elie", Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ + "bucket": "coucou", "role": "storage.admin", - "bucket": "b/bucket", "member": "user:elie@cloudskiff.com", }, }, { - Id: "b/bucket/admin/William", - Type: google.GoogleStorageBucketIamMemberResourceType, + Id: "b/bucket/admin", + Type: google.GoogleStorageBucketIamBindingResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", "bucket": "b/bucket", - "member": "user:william@cloudskiff.com", + "members": []string{ + "user:elie@cloudskiff.com", + "user:william@cloudskiff.com", + }, }, }, + { - Id: "b/bucket/viewer/William", - Type: google.GoogleStorageBucketIamMemberResourceType, + Id: "b/bucket/viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket", - "member": "user:william@cloudskiff.com", + "members": []string{ + "user:william@cloudskiff.com", + }, }, }, { - Id: "b/bucket2/viewer/William", - Type: google.GoogleStorageBucketIamMemberResourceType, + Id: "b/bucket2/viewer", + Type: google.GoogleStorageBucketIamBindingResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket2", - "member": "user:william@cloudskiff.com", + "members": []string{ + "user:william@cloudskiff.com", + }, }, }, }, @@ -78,118 +79,126 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "role": "storage.admin", + "bucket": "coucou", + "role": "storage.admin", + "member": "user:elie@cloudskiff.com", }, }, { - Id: "b/bucket/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket/storage.admin/user:elie@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", "bucket": "b/bucket", - "members": []string{ - "user:elie@cloudskiff.com", - "user:william@cloudskiff.com", - }, + "member": "user:elie@cloudskiff.com", }, }, { - Id: "b/bucket/storage.viewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket/storage.admin/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "member": "user:william@cloudskiff.com", + }, + }, + { + Id: "b/bucket/storage.viewer/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }, }, { - Id: "b/bucket2/storage.viewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket2/storage.viewer/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket2", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }, }, }, func(factory *terraform.MockResourceFactory) { factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/bucket/storage.admin", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/bucket/storage.admin/user:elie@cloudskiff.com", map[string]interface{}{ - "id": "b/bucket/storage.admin", + "id": "b/bucket/storage.admin/user:elie@cloudskiff.com", "bucket": "b/bucket", "role": "storage.admin", - "members": []string{ - "user:elie@cloudskiff.com", - "user:william@cloudskiff.com", - }, + "member": "user:elie@cloudskiff.com", }).Return(&resource.Resource{ - Id: "b/bucket/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket/storage.admin/user:elie@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.admin", "bucket": "b/bucket", - "members": []string{ - "user:elie@cloudskiff.com", - "user:william@cloudskiff.com", - }, + "member": "user:elie@cloudskiff.com", + }, + }).Once() + + factory.On( + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/bucket/storage.admin/user:william@cloudskiff.com", + map[string]interface{}{ + "id": "b/bucket/storage.admin/user:william@cloudskiff.com", + "bucket": "b/bucket", + "role": "storage.admin", + "member": "user:william@cloudskiff.com", + }).Return(&resource.Resource{ + Id: "b/bucket/storage.admin/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, + Attrs: &resource.Attributes{ + "role": "storage.admin", + "bucket": "b/bucket", + "member": "user:william@cloudskiff.com", }, }).Once() factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/bucket/storage.viewer", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/bucket/storage.viewer/user:william@cloudskiff.com", map[string]interface{}{ - "id": "b/bucket/storage.viewer", + "id": "b/bucket/storage.viewer/user:william@cloudskiff.com", "bucket": "b/bucket", "role": "storage.viewer", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }).Return(&resource.Resource{ - Id: "b/bucket/storage.viewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket/storage.viewer/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }, }).Once() factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/bucket2/storage.viewer", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/bucket2/storage.viewer/user:william@cloudskiff.com", map[string]interface{}{ - "id": "b/bucket2/storage.viewer", + "id": "b/bucket2/storage.viewer/user:william@cloudskiff.com", "bucket": "b/bucket2", "role": "storage.viewer", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }).Return(&resource.Resource{ - Id: "b/bucket2/storage.viewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/bucket2/storage.viewer/user:william@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ "role": "storage.viewer", "bucket": "b/bucket2", - "members": []string{ - "user:william@cloudskiff.com", - }, + "member": "user:william@cloudskiff.com", }, }).Once() }, }, { - "test that everything is fine when there is no members", + "test that everything is fine when there is no bindings", []*resource.Resource{ { Id: "fake", @@ -198,9 +207,11 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "role": "storage.admin", + "bucket": "coucou", + "role": "storage.admin", + "member": "user:elie@cloudskiff.com", }, }, }, @@ -212,9 +223,11 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { }, { Id: "admin bucket", - Type: google.GoogleStorageBucketIamBindingResourceType, + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "role": "storage.admin", + "bucket": "coucou", + "role": "storage.admin", + "member": "user:elie@cloudskiff.com", }, }, }, @@ -230,7 +243,7 @@ func TestGoogleBucketIAMMemberTransformer_Execute(t *testing.T) { tt.mock(factory) } - m := NewGoogleStorageBucketIAMMemberTransformer(factory) + m := NewGoogleStorageBucketIAMBindingTransformer(factory) err := m.Execute(&[]*resource.Resource{}, &tt.resourcesFromState) if err != nil { t.Fatal(err) diff --git a/pkg/middlewares/google_storage_bucket_iam_member_transformer.go b/pkg/middlewares/google_storage_bucket_iam_member_transformer.go deleted file mode 100644 index acbe847ab..000000000 --- a/pkg/middlewares/google_storage_bucket_iam_member_transformer.go +++ /dev/null @@ -1,74 +0,0 @@ -package middlewares - -import ( - "fmt" - - "github.com/cloudskiff/driftctl/pkg/resource" - "github.com/cloudskiff/driftctl/pkg/resource/google" -) - -// GoogleStorageBucketIAMMemberTransformer Transforms Bucket IAM Member in bucket iam binding to ease comparison. -type GoogleStorageBucketIAMMemberTransformer struct { - resourceFactory resource.ResourceFactory -} - -func NewGoogleStorageBucketIAMMemberTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMMemberTransformer { - return &GoogleStorageBucketIAMMemberTransformer{resourceFactory} -} - -func (m *GoogleStorageBucketIAMMemberTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error { - - resources := make([]*resource.Resource, 0) - bindings := map[string]map[string][]string{} // map[BUCKETID][ROLENAME][]MEMBERS - - for _, stateRes := range *resourcesFromState { - // Ignore all resources other than BucketIamBinding - if stateRes.ResourceType() != google.GoogleStorageBucketIamMemberResourceType { - resources = append(resources, stateRes) - continue - } - - bucket := *stateRes.Attrs.GetString("bucket") - roleName := *stateRes.Attrs.GetString("role") - member := *stateRes.Attrs.GetString("member") - - bucketBindings := bindings[bucket] - if bucketBindings == nil { - bucketBindings = make(map[string][]string) - } - - roleBindings := bucketBindings[roleName] - if roleBindings == nil { - roleBindings = make([]string, 0, 1) - } - - roleBindings = append(roleBindings, member) - - bucketBindings[roleName] = roleBindings - bindings[bucket] = bucketBindings - } - - for bucket, roleBindings := range bindings { - for roleName, members := range roleBindings { - id := fmt.Sprintf("%s/%s", bucket, roleName) - resources = append( - resources, - m.resourceFactory.CreateAbstractResource( - google.GoogleStorageBucketIamBindingResourceType, - id, - map[string]interface{}{ - "id": id, - "bucket": bucket, - "role": roleName, - "members": members, - }, - ), - ) - } - - } - - *resourcesFromState = resources - - return nil -} diff --git a/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go b/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go index 6862910e8..5e259cbb9 100644 --- a/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go +++ b/pkg/middlewares/google_storage_bucket_iam_policy_tranformer_test.go @@ -37,7 +37,7 @@ func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) { Attrs: &resource.Attributes{ "bucket": "b/dctlgstoragebucketiambinding-1", "id": "b/dctlgstoragebucketiambinding-1", - "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", }, }, { @@ -47,7 +47,7 @@ func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) { "bucket": "b/dctlgstoragebucketiambinding-2", "etag": "CAU=", "id": "b/dctlgstoragebucketiambinding-2", - "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\",\"user:elie.charra@cloudskiff.com\",\"user:martin.guibert@cloudskiff.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", + "policy_data": "{\"bindings\":[{\"members\":[\"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com\"],\"role\":\"roles/storage.admin\"},{\"members\":[\"user:william.beuil@cloudskiff.com\"],\"role\":\"roles/storage.objectViewer\"}]}", }, }, }, @@ -63,156 +63,120 @@ func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) { Attrs: &resource.Attributes{}, }, { - Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "role": "roles/storage.admin", "bucket": "b/dctlgstoragebucketiambinding-1", - "members": []string{ - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }, }, { - Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer", "bucket": "b/dctlgstoragebucketiambinding-1", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }, }, { - Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "role": "roles/storage.admin", "bucket": "b/dctlgstoragebucketiambinding-2", - "members": []string{ - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }, }, { - Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer", "bucket": "b/dctlgstoragebucketiambinding-2", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }, }, }, func(factory *terraform.MockResourceFactory) { factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", map[string]interface{}{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "bucket": "b/dctlgstoragebucketiambinding-1", "role": "roles/storage.admin", - "members": []string{ - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }).Return(&resource.Resource{ - Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "role": "roles/storage.admin", "bucket": "b/dctlgstoragebucketiambinding-1", - "members": []string{ - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }, }).Once() factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", map[string]interface{}{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "bucket": "b/dctlgstoragebucketiambinding-1", "role": "roles/storage.objectViewer", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }).Return(&resource.Resource{ - Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer", "bucket": "b/dctlgstoragebucketiambinding-1", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }, }).Once() factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", map[string]interface{}{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "bucket": "b/dctlgstoragebucketiambinding-2", "role": "roles/storage.admin", - "members": []string{ - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }).Return(&resource.Resource{ - Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", "role": "roles/storage.admin", "bucket": "b/dctlgstoragebucketiambinding-2", - "members": []string{ - "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", - "user:elie.charra@cloudskiff.com", - "user:martin.guibert@cloudskiff.com", - }, + "member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com", }, }).Once() factory.On( - "CreateAbstractResource", google.GoogleStorageBucketIamBindingResourceType, - "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "CreateAbstractResource", google.GoogleStorageBucketIamMemberResourceType, + "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", map[string]interface{}{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "bucket": "b/dctlgstoragebucketiambinding-2", "role": "roles/storage.objectViewer", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }).Return(&resource.Resource{ - Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", - Type: google.GoogleStorageBucketIamBindingResourceType, + Id: "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + Type: google.GoogleStorageBucketIamMemberResourceType, Attrs: &resource.Attributes{ - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer", "bucket": "b/dctlgstoragebucketiambinding-2", - "members": []string{ - "user:william.beuil@cloudskiff.com", - }, + "member": "user:william.beuil@cloudskiff.com", }, }).Once() }, diff --git a/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go b/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go index d8087959c..ffbfbf50b 100644 --- a/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go +++ b/pkg/middlewares/google_storage_bucket_iam_policy_transformer.go @@ -40,20 +40,22 @@ func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState for _, policy := range policies.Bindings { roleName := policy.Role members := policy.Members - id := fmt.Sprintf("%s/%s", bucket, roleName) - resources = append( - resources, - m.resourceFactory.CreateAbstractResource( - google.GoogleStorageBucketIamBindingResourceType, - id, - map[string]interface{}{ - "id": id, - "bucket": bucket, - "role": roleName, - "members": members, - }, - ), - ) + for _, member := range members { + id := fmt.Sprintf("%s/%s/%s", bucket, roleName, member) + resources = append( + resources, + m.resourceFactory.CreateAbstractResource( + google.GoogleStorageBucketIamMemberResourceType, + id, + map[string]interface{}{ + "id": id, + "bucket": bucket, + "role": roleName, + "member": member, + }, + ), + ) + } } } diff --git a/pkg/remote/google/google_storage_bucket_iam_binding_enumerator.go b/pkg/remote/google/google_storage_bucket_iam_member_enumerator.go similarity index 52% rename from pkg/remote/google/google_storage_bucket_iam_binding_enumerator.go rename to pkg/remote/google/google_storage_bucket_iam_member_enumerator.go index ad0f0ffe0..e5dcecf55 100644 --- a/pkg/remote/google/google_storage_bucket_iam_binding_enumerator.go +++ b/pkg/remote/google/google_storage_bucket_iam_member_enumerator.go @@ -9,25 +9,25 @@ import ( "github.com/cloudskiff/driftctl/pkg/resource/google" ) -type GoogleStorageBucketIamBindingEnumerator struct { +type GoogleStorageBucketIamMemberEnumerator struct { repository repository.AssetRepository storageRepository repository.StorageRepository factory resource.ResourceFactory } -func NewGoogleStorageBucketIamBindingEnumerator(repo repository.AssetRepository, storageRepo repository.StorageRepository, factory resource.ResourceFactory) *GoogleStorageBucketIamBindingEnumerator { - return &GoogleStorageBucketIamBindingEnumerator{ +func NewGoogleStorageBucketIamMemberEnumerator(repo repository.AssetRepository, storageRepo repository.StorageRepository, factory resource.ResourceFactory) *GoogleStorageBucketIamMemberEnumerator { + return &GoogleStorageBucketIamMemberEnumerator{ repository: repo, storageRepository: storageRepo, factory: factory, } } -func (e *GoogleStorageBucketIamBindingEnumerator) SupportedType() resource.ResourceType { - return google.GoogleStorageBucketIamBindingResourceType +func (e *GoogleStorageBucketIamMemberEnumerator) SupportedType() resource.ResourceType { + return google.GoogleStorageBucketIamMemberResourceType } -func (e *GoogleStorageBucketIamBindingEnumerator) Enumerate() ([]*resource.Resource, error) { +func (e *GoogleStorageBucketIamMemberEnumerator) Enumerate() ([]*resource.Resource, error) { resources, err := e.repository.SearchAllBuckets() if err != nil { return nil, remoteerror.NewResourceListingErrorWithType(err, string(e.SupportedType()), google.GoogleStorageBucketResourceType) @@ -41,20 +41,22 @@ func (e *GoogleStorageBucketIamBindingEnumerator) Enumerate() ([]*resource.Resou return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType())) } for roleName, members := range bindings { - id := fmt.Sprintf("b/%s/%s", bucket.DisplayName, roleName) - results = append( - results, - e.factory.CreateAbstractResource( - string(e.SupportedType()), - id, - map[string]interface{}{ - "id": id, - "bucket": fmt.Sprintf("b/%s", bucket.DisplayName), - "role": roleName, - "members": members, - }, - ), - ) + for _, member := range members { + id := fmt.Sprintf("b/%s/%s/%s", bucket.DisplayName, roleName, member) + results = append( + results, + e.factory.CreateAbstractResource( + string(e.SupportedType()), + id, + map[string]interface{}{ + "id": id, + "bucket": fmt.Sprintf("b/%s", bucket.DisplayName), + "role": roleName, + "member": member, + }, + ), + ) + } } } diff --git a/pkg/remote/google/init.go b/pkg/remote/google/init.go index b23d9ad68..b589b4148 100644 --- a/pkg/remote/google/init.go +++ b/pkg/remote/google/init.go @@ -61,8 +61,8 @@ func Init(version string, alerter *alerter.Alerter, remoteLibrary.AddEnumerator(NewGoogleComputeInstanceEnumerator(assetRepository, factory)) - remoteLibrary.AddEnumerator(NewGoogleStorageBucketIamBindingEnumerator(assetRepository, storageRepository, factory)) - remoteLibrary.AddDetailsFetcher(google.GoogleStorageBucketIamBindingResourceType, common.NewGenericDetailsFetcher(google.GoogleStorageBucketIamBindingResourceType, provider, deserializer)) + remoteLibrary.AddEnumerator(NewGoogleStorageBucketIamMemberEnumerator(assetRepository, storageRepository, factory)) + remoteLibrary.AddDetailsFetcher(google.GoogleStorageBucketIamMemberResourceType, common.NewGenericDetailsFetcher(google.GoogleStorageBucketIamMemberResourceType, provider, deserializer)) remoteLibrary.AddEnumerator(NewGoogleComputeNetworkEnumerator(assetRepository, factory)) remoteLibrary.AddDetailsFetcher(google.GoogleComputeNetworkResourceType, common.NewGenericDetailsFetcher(google.GoogleComputeNetworkResourceType, provider, deserializer)) diff --git a/pkg/remote/google_storage_scanner_test.go b/pkg/remote/google_storage_scanner_test.go index dd27e92c8..a053bc0b9 100644 --- a/pkg/remote/google_storage_scanner_test.go +++ b/pkg/remote/google_storage_scanner_test.go @@ -159,7 +159,7 @@ func TestGoogleStorageBucket(t *testing.T) { } } -func TestGoogleStorageBucketIAMBinding(t *testing.T) { +func TestGoogleStorageBucketIAMMember(t *testing.T) { cases := []struct { test string @@ -172,7 +172,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { }{ { test: "no storage buckets", - dirName: "google_storage_bucket_empty", + dirName: "google_storage_bucket_member_empty", assetRepositoryMock: func(assetRepository *repository.MockAssetRepository) { assetRepository.On("SearchAllBuckets").Return([]*assetpb.ResourceSearchResult{}, nil) }, @@ -180,7 +180,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { }, { test: "multiples storage buckets, no bindings", - dirName: "google_storage_bucket_binding_empty", + dirName: "google_storage_bucket_member_empty", assetRepositoryMock: func(assetRepository *repository.MockAssetRepository) { assetRepository.On("SearchAllBuckets").Return([]*assetpb.ResourceSearchResult{ { @@ -201,7 +201,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { }, { test: "Cannot list bindings", - dirName: "google_storage_bucket_binding_listing_error", + dirName: "google_storage_bucket_member_listing_error", assetRepositoryMock: func(assetRepository *repository.MockAssetRepository) { assetRepository.On("SearchAllBuckets").Return([]*assetpb.ResourceSearchResult{ { @@ -218,12 +218,12 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { setupAlerterMock: func(alerter *mocks.AlerterInterface) { alerter.On( "SendAlert", - "google_storage_bucket_iam_binding", + "google_storage_bucket_iam_member", alerts.NewRemoteAccessDeniedAlert( common.RemoteGoogleTerraform, remoteerr.NewResourceListingError( errors.New("googleapi: Error 403: driftctl-acc-circle@driftctl-qa-1.iam.gserviceaccount.com does not have storage.buckets.getIamPolicy access to the Google Cloud Storage bucket., forbidden"), - "google_storage_bucket_iam_binding", + "google_storage_bucket_iam_member", ), alerts.EnumerationPhase, ), @@ -233,7 +233,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { }, { test: "multiples storage buckets, multiple bindings", - dirName: "google_storage_bucket_binding_multiple", + dirName: "google_storage_bucket_member_listing_multiple", assetRepositoryMock: func(assetRepository *repository.MockAssetRepository) { assetRepository.On("SearchAllBuckets").Return([]*assetpb.ResourceSearchResult{ { @@ -262,7 +262,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { } providerVersion := "3.78.0" - resType := resource.ResourceType(googleresource.GoogleStorageBucketIamBindingResourceType) + resType := resource.ResourceType(googleresource.GoogleStorageBucketIamMemberResourceType) schemaRepository := testresource.InitFakeSchemaRepository("google", providerVersion) googleresource.InitResourcesMetadata(schemaRepository) factory := terraform.NewTerraformResourceFactory(schemaRepository) @@ -310,7 +310,7 @@ func TestGoogleStorageBucketIAMBinding(t *testing.T) { provider := terraform2.NewFakeTerraformProvider(realProvider) provider.WithResponse(c.dirName) - remoteLibrary.AddEnumerator(google.NewGoogleStorageBucketIamBindingEnumerator(assetRepository, storageRepository, factory)) + remoteLibrary.AddEnumerator(google.NewGoogleStorageBucketIamMemberEnumerator(assetRepository, storageRepository, factory)) testFilter := &filter.MockFilter{} testFilter.On("IsTypeIgnored", mock.Anything).Return(false) diff --git a/pkg/remote/test/google_storage_bucket_binding_multiple/results.golden.json b/pkg/remote/test/google_storage_bucket_member_listing_multiple/results.golden.json similarity index 57% rename from pkg/remote/test/google_storage_bucket_binding_multiple/results.golden.json rename to pkg/remote/test/google_storage_bucket_member_listing_multiple/results.golden.json index 55d3ce5b8..5caec119e 100755 --- a/pkg/remote/test/google_storage_bucket_binding_multiple/results.golden.json +++ b/pkg/remote/test/google_storage_bucket_member_listing_multiple/results.golden.json @@ -3,40 +3,32 @@ "bucket": "b/dctlgstoragebucketiambinding-1", "condition": null, "etag": null, - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin", - "members": [ - "user:elie.charra@cloudskiff.com" - ], + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.admin/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", "role": "roles/storage.admin" }, { "bucket": "b/dctlgstoragebucketiambinding-1", "condition": null, "etag": null, - "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer", - "members": [ - "user:william.beuil@cloudskiff.com" - ], + "id": "b/dctlgstoragebucketiambinding-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", "role": "roles/storage.objectViewer" }, { "bucket": "b/dctlgstoragebucketiambinding-2", "condition": null, "etag": null, - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer", - "members": [ - "user:elie.charra@cloudskiff.com" - ], - "role": "roles/storage.objectViewer" + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin/user:william.beuil@cloudskiff.com", + "member": "user:william.beuil@cloudskiff.com", + "role": "roles/storage.admin" }, { "bucket": "b/dctlgstoragebucketiambinding-2", "condition": null, "etag": null, - "id": "b/dctlgstoragebucketiambinding-2/roles/storage.admin", - "members": [ - "user:william.beuil@cloudskiff.com" - ], - "role": "roles/storage.admin" + "id": "b/dctlgstoragebucketiambinding-2/roles/storage.objectViewer/user:elie.charra@cloudskiff.com", + "member": "user:elie.charra@cloudskiff.com", + "role": "roles/storage.objectViewer" } ] \ No newline at end of file diff --git a/pkg/resource/google/google_storage_bucket_iam_binding.go b/pkg/resource/google/google_storage_bucket_iam_binding.go index 0cab7b004..3d7c0a3e4 100644 --- a/pkg/resource/google/google_storage_bucket_iam_binding.go +++ b/pkg/resource/google/google_storage_bucket_iam_binding.go @@ -1,20 +1,3 @@ package google -import "github.com/cloudskiff/driftctl/pkg/resource" - const GoogleStorageBucketIamBindingResourceType = "google_storage_bucket_iam_binding" - -func initGoogleStorageBucketIamBindingMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) { - resourceSchemaRepository.SetNormalizeFunc(GoogleStorageBucketIamBindingResourceType, func(res *resource.Resource) { - res.Attributes().SafeDelete([]string{"force_destroy"}) - res.Attributes().SafeDelete([]string{"etag"}) - }) - resourceSchemaRepository.SetResolveReadAttributesFunc(GoogleStorageBucketIamBindingResourceType, func(res *resource.Resource) map[string]string { - return map[string]string{ - "bucket": *res.Attrs.GetString("bucket"), - "role": *res.Attrs.GetString("role"), - } - }) - resourceSchemaRepository.SetFlags(GoogleStorageBucketIamBindingResourceType, resource.FlagDeepMode) - -} diff --git a/pkg/resource/google/google_storage_bucket_iam_member.go b/pkg/resource/google/google_storage_bucket_iam_member.go index 45d2fc53e..920f48fe7 100644 --- a/pkg/resource/google/google_storage_bucket_iam_member.go +++ b/pkg/resource/google/google_storage_bucket_iam_member.go @@ -1,3 +1,29 @@ package google +import "github.com/cloudskiff/driftctl/pkg/resource" + const GoogleStorageBucketIamMemberResourceType = "google_storage_bucket_iam_member" + +func initGoogleStorageBucketIamBMemberMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) { + resourceSchemaRepository.SetNormalizeFunc(GoogleStorageBucketIamMemberResourceType, func(res *resource.Resource) { + res.Attributes().SafeDelete([]string{"force_destroy"}) + res.Attributes().SafeDelete([]string{"etag"}) + }) + resourceSchemaRepository.SetResolveReadAttributesFunc(GoogleStorageBucketIamMemberResourceType, func(res *resource.Resource) map[string]string { + return map[string]string{ + "bucket": *res.Attrs.GetString("bucket"), + "role": *res.Attrs.GetString("role"), + "member": *res.Attrs.GetString("member"), + } + }) + resourceSchemaRepository.SetHumanReadableAttributesFunc(GoogleStorageBucketIamMemberResourceType, func(res *resource.Resource) map[string]string { + attrs := map[string]string{ + "bucket": *res.Attrs.GetString("bucket"), + "role": *res.Attrs.GetString("role"), + "member": *res.Attrs.GetString("member"), + } + return attrs + }) + resourceSchemaRepository.SetFlags(GoogleStorageBucketIamMemberResourceType, resource.FlagDeepMode) + +} diff --git a/pkg/resource/google/metadatas.go b/pkg/resource/google/metadatas.go index c119b1fe5..f91fc5edd 100644 --- a/pkg/resource/google/metadatas.go +++ b/pkg/resource/google/metadatas.go @@ -7,5 +7,5 @@ func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInt initGoogleComputeFirewallMetadata(resourceSchemaRepository) initGoogleComputeRouterMetadata(resourceSchemaRepository) initGoogleComputeNetworkMetadata(resourceSchemaRepository) - initGoogleStorageBucketIamBindingMetadata(resourceSchemaRepository) + initGoogleStorageBucketIamBMemberMetadata(resourceSchemaRepository) } From c5978eccd86dfef49699bb597c34ccec681cc6f0 Mon Sep 17 00:00:00 2001 From: Martin Guibert Date: Wed, 6 Oct 2021 17:03:47 +0200 Subject: [PATCH 4/4] fix incorrect naming --- pkg/driftctl.go | 2 +- pkg/middlewares/google_legacy_bucket_iam_member.go | 8 ++++---- pkg/middlewares/google_legacy_bucket_iam_member_test.go | 4 ++-- ... google_storage_bucket_iam_binding_tranformer_test.go} | 0 4 files changed, 7 insertions(+), 7 deletions(-) rename pkg/middlewares/{google_storage_bucket_iam_member_tranformer_test.go => google_storage_bucket_iam_binding_tranformer_test.go} (100%) diff --git a/pkg/driftctl.go b/pkg/driftctl.go index 3531b658a..050aa27ea 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -113,7 +113,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewGoogleStorageBucketIAMBindingTransformer(d.resourceFactory), middlewares.NewGoogleStorageBucketIAMPolicyTransformer(d.resourceFactory), - middlewares.NewGoogleLegacyBucketIAMBindings(), + middlewares.NewGoogleLegacyBucketIAMMember(), middlewares.NewAzurermSubnetExpander(d.resourceFactory), middlewares.NewAwsApiGatewayDeploymentExpander(d.resourceFactory), diff --git a/pkg/middlewares/google_legacy_bucket_iam_member.go b/pkg/middlewares/google_legacy_bucket_iam_member.go index d6c8c7cd6..f7715b933 100644 --- a/pkg/middlewares/google_legacy_bucket_iam_member.go +++ b/pkg/middlewares/google_legacy_bucket_iam_member.go @@ -9,13 +9,13 @@ import ( ) // Creating buckets add legacy role bindings, this middleware will filter them unless they are managed. -type GoogleLegacyBucketIAMMmeber struct{} +type GoogleLegacyBucketIAMMember struct{} -func NewGoogleLegacyBucketIAMBindings() *GoogleLegacyBucketIAMMmeber { - return &GoogleLegacyBucketIAMMmeber{} +func NewGoogleLegacyBucketIAMMember() *GoogleLegacyBucketIAMMember { + return &GoogleLegacyBucketIAMMember{} } -func (m *GoogleLegacyBucketIAMMmeber) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { +func (m *GoogleLegacyBucketIAMMember) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { newRemoteResources := make([]*resource.Resource, 0) diff --git a/pkg/middlewares/google_legacy_bucket_iam_member_test.go b/pkg/middlewares/google_legacy_bucket_iam_member_test.go index 9b93aac6e..7bc5a8bcf 100644 --- a/pkg/middlewares/google_legacy_bucket_iam_member_test.go +++ b/pkg/middlewares/google_legacy_bucket_iam_member_test.go @@ -10,7 +10,7 @@ import ( "github.com/r3labs/diff/v2" ) -func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { +func TestGoogleLegacyBucketIAMMember_Execute(t *testing.T) { tests := []struct { name string remoteResources []*resource.Resource @@ -120,7 +120,7 @@ func TestGoogleLegacyBucketIAMBindings_Execute(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - m := NewGoogleLegacyBucketIAMBindings() + m := NewGoogleLegacyBucketIAMMember() err := m.Execute(&tt.remoteResources, &tt.resourcesFromState) if err != nil { t.Fatal(err) diff --git a/pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go b/pkg/middlewares/google_storage_bucket_iam_binding_tranformer_test.go similarity index 100% rename from pkg/middlewares/google_storage_bucket_iam_member_tranformer_test.go rename to pkg/middlewares/google_storage_bucket_iam_binding_tranformer_test.go