implement iam for project and make middleware generics
parent
7c653d0500
commit
b94c41777a
|
@ -115,8 +115,8 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
|
|||
middlewares.NewAwsApiGatewayRestApiExpander(d.resourceFactory),
|
||||
middlewares.NewAwsApiGatewayRestApiPolicyExpander(d.resourceFactory),
|
||||
|
||||
middlewares.NewGoogleStorageBucketIAMBindingTransformer(d.resourceFactory),
|
||||
middlewares.NewGoogleStorageBucketIAMPolicyTransformer(d.resourceFactory),
|
||||
middlewares.NewGoogleIAMBindingTransformer(d.resourceFactory),
|
||||
middlewares.NewGoogleIAMPolicyTransformer(d.resourceFactory),
|
||||
middlewares.NewGoogleLegacyBucketIAMMember(),
|
||||
|
||||
middlewares.NewAzurermRouteExpander(d.resourceFactory),
|
||||
|
|
|
@ -11,6 +11,256 @@ import (
|
|||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
func TestGoogleProjectIAMBindingTransformer_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcesFromState []*resource.Resource
|
||||
expected []*resource.Resource
|
||||
mock func(factory *terraform.MockResourceFactory)
|
||||
}{
|
||||
{
|
||||
"Test that project bindings are transformed into member",
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "fake",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "admin project",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "coucou",
|
||||
"role": "storage.admin",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj/admin",
|
||||
Type: google.GoogleProjectIamBindingResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.admin",
|
||||
"project": "proj",
|
||||
"members": []interface{}{
|
||||
"user:elie@cloudskiff.com",
|
||||
"user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Id: "proj/viewer",
|
||||
Type: google.GoogleProjectIamBindingResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj",
|
||||
"members": []interface{}{
|
||||
"user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj2/viewer",
|
||||
Type: google.GoogleProjectIamBindingResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj2",
|
||||
"members": []interface{}{
|
||||
"user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "fake",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "admin project",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "coucou",
|
||||
"role": "storage.admin",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj/storage.admin/user:elie@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.admin",
|
||||
"project": "proj",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj/storage.admin/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.admin",
|
||||
"project": "proj",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj/storage.viewer/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "proj2/storage.viewer/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj2",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
func(factory *terraform.MockResourceFactory) {
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"proj/storage.admin/user:elie@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "proj/storage.admin/user:elie@cloudskiff.com",
|
||||
"project": "proj",
|
||||
"role": "storage.admin",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "proj/storage.admin/user:elie@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.admin",
|
||||
"project": "proj",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"proj/storage.admin/user:william@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "proj/storage.admin/user:william@cloudskiff.com",
|
||||
"project": "proj",
|
||||
"role": "storage.admin",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "proj/storage.admin/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.admin",
|
||||
"project": "proj",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"proj/storage.viewer/user:william@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "proj/storage.viewer/user:william@cloudskiff.com",
|
||||
"project": "proj",
|
||||
"role": "storage.viewer",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "proj/storage.viewer/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"proj2/storage.viewer/user:william@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "proj2/storage.viewer/user:william@cloudskiff.com",
|
||||
"project": "proj2",
|
||||
"role": "storage.viewer",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "proj2/storage.viewer/user:william@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"role": "storage.viewer",
|
||||
"project": "proj2",
|
||||
"member": "user:william@cloudskiff.com",
|
||||
},
|
||||
}).Once()
|
||||
},
|
||||
},
|
||||
{
|
||||
"test that everything is fine when there is no bindings",
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "fake",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "admin project",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "coucou",
|
||||
"role": "storage.admin",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "fake",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "admin project",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "coucou",
|
||||
"role": "storage.admin",
|
||||
"member": "user:elie@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
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 := NewGoogleIAMBindingTransformer(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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoogleBucketIAMBindingTransformer_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -243,7 +493,7 @@ func TestGoogleBucketIAMBindingTransformer_Execute(t *testing.T) {
|
|||
tt.mock(factory)
|
||||
}
|
||||
|
||||
m := NewGoogleStorageBucketIAMBindingTransformer(factory)
|
||||
m := NewGoogleIAMBindingTransformer(factory)
|
||||
err := m.Execute(&[]*resource.Resource{}, &tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
|
@ -0,0 +1,65 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/google"
|
||||
)
|
||||
|
||||
// GoogleIAMBindingTransformer Transforms Bucket IAM binding in bucket iam member to ease comparison.
|
||||
type GoogleIAMBindingTransformer struct {
|
||||
resourceFactory resource.ResourceFactory
|
||||
resFieldByType map[string]string // map of the field to add to resource attribute for all supported type
|
||||
}
|
||||
|
||||
func NewGoogleIAMBindingTransformer(resourceFactory resource.ResourceFactory) *GoogleIAMBindingTransformer {
|
||||
return &GoogleIAMBindingTransformer{
|
||||
resourceFactory,
|
||||
map[string]string{
|
||||
google.GoogleStorageBucketIamBindingResourceType: "bucket",
|
||||
google.GoogleProjectIamBindingResourceType: "project",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *GoogleIAMBindingTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error {
|
||||
|
||||
resources := make([]*resource.Resource, 0)
|
||||
|
||||
for _, stateRes := range *resourcesFromState {
|
||||
// Ignore all resources other than IamBinding
|
||||
resType := stateRes.ResourceType()
|
||||
resField, supported := m.resFieldByType[resType]
|
||||
if !supported {
|
||||
resources = append(resources, stateRes)
|
||||
continue
|
||||
}
|
||||
|
||||
resName := *stateRes.Attrs.GetString(resField)
|
||||
roleName := *stateRes.Attrs.GetString("role")
|
||||
members, _ := stateRes.Attrs.Get("members")
|
||||
|
||||
for _, member := range members.([]interface{}) {
|
||||
id := fmt.Sprintf("%s/%s/%s", resName, roleName, member)
|
||||
resources = append(
|
||||
resources,
|
||||
m.resourceFactory.CreateAbstractResource(
|
||||
fmt.Sprintf("%s_member", strings.TrimSuffix(resType, "_binding")),
|
||||
id,
|
||||
map[string]interface{}{
|
||||
"id": id,
|
||||
resField: resName,
|
||||
"role": roleName,
|
||||
"member": member.(string),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
*resourcesFromState = resources
|
||||
|
||||
return nil
|
||||
}
|
|
@ -11,6 +11,202 @@ import (
|
|||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
func TestGoogleProjectIAMPolicyTransformer_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcesFromState []*resource.Resource
|
||||
expected []*resource.Resource
|
||||
mock func(factory *terraform.MockResourceFactory)
|
||||
}{
|
||||
{
|
||||
"Test that project policy are transformed into bindings",
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "b/bucket-1",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "b/bucket-2",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "project-1",
|
||||
Type: google.GoogleProjectIamPolicyResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "project-1",
|
||||
"id": "project-1",
|
||||
"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\"}]}",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "dctlgstorageprojectiambinding-2",
|
||||
Type: google.GoogleProjectIamPolicyResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"project": "project-2",
|
||||
"etag": "CAU=",
|
||||
"id": "project-2",
|
||||
"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\"}]}",
|
||||
},
|
||||
},
|
||||
},
|
||||
[]*resource.Resource{
|
||||
{
|
||||
Id: "b/bucket-1",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "b/bucket-2",
|
||||
Type: google.GoogleStorageBucketResourceType,
|
||||
Attrs: &resource.Attributes{},
|
||||
},
|
||||
{
|
||||
Id: "project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"role": "roles/storage.admin",
|
||||
"project": "project-1",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"project": "project-1",
|
||||
"member": "user:william.beuil@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"role": "roles/storage.admin",
|
||||
"project": "project-2",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"project": "project-2",
|
||||
"member": "user:william.beuil@cloudskiff.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
func(factory *terraform.MockResourceFactory) {
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
map[string]interface{}{
|
||||
"id": "project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "project-1",
|
||||
"role": "roles/storage.admin",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-1/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"role": "roles/storage.admin",
|
||||
"project": "project-1",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"project": "project-1",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"member": "user:william.beuil@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-1/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"project": "project-1",
|
||||
"member": "user:william.beuil@cloudskiff.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
map[string]interface{}{
|
||||
"id": "project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "project-2",
|
||||
"role": "roles/storage.admin",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-2/roles/storage.admin/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"role": "roles/storage.admin",
|
||||
"project": "project-2",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
},
|
||||
}).Once()
|
||||
|
||||
factory.On(
|
||||
"CreateAbstractResource", google.GoogleProjectIamMemberResourceType,
|
||||
"project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
map[string]interface{}{
|
||||
"id": "project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"project": "project-2",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"member": "user:william.beuil@cloudskiff.com",
|
||||
}).Return(&resource.Resource{
|
||||
Id: "project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
Type: google.GoogleProjectIamMemberResourceType,
|
||||
Attrs: &resource.Attributes{
|
||||
"id": "project-2/roles/storage.objectViewer/user:william.beuil@cloudskiff.com",
|
||||
"role": "roles/storage.objectViewer",
|
||||
"project": "project-2",
|
||||
"member": "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 := NewGoogleIAMPolicyTransformer(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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -189,7 +385,7 @@ func TestGoogleBucketIAMPolicyTransformer_Execute(t *testing.T) {
|
|||
tt.mock(factory)
|
||||
}
|
||||
|
||||
m := NewGoogleStorageBucketIAMPolicyTransformer(factory)
|
||||
m := NewGoogleIAMPolicyTransformer(factory)
|
||||
err := m.Execute(&[]*resource.Resource{}, &tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
|
@ -3,6 +3,7 @@ package middlewares
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/google"
|
||||
|
@ -11,10 +12,16 @@ import (
|
|||
// GoogleStorageBucketIAMPolicyTransformer Transforms Bucket IAM policy in bucket iam binding to ease comparison.
|
||||
type GoogleStorageBucketIAMPolicyTransformer struct {
|
||||
resourceFactory resource.ResourceFactory
|
||||
resFieldByType map[string]string // map of the field to add to resource attribute for all supported type
|
||||
}
|
||||
|
||||
func NewGoogleStorageBucketIAMPolicyTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMPolicyTransformer {
|
||||
return &GoogleStorageBucketIAMPolicyTransformer{resourceFactory}
|
||||
func NewGoogleIAMPolicyTransformer(resourceFactory resource.ResourceFactory) *GoogleStorageBucketIAMPolicyTransformer {
|
||||
return &GoogleStorageBucketIAMPolicyTransformer{
|
||||
resourceFactory,
|
||||
map[string]string{
|
||||
google.GoogleStorageBucketIamPolicyResourceType: "bucket",
|
||||
google.GoogleProjectIamPolicyResourceType: "project",
|
||||
}}
|
||||
}
|
||||
|
||||
func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState *[]*resource.Resource) error {
|
||||
|
@ -23,12 +30,14 @@ func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState
|
|||
|
||||
for _, stateRes := range *resourcesFromState {
|
||||
// Ignore all resources other than BucketIamBinding
|
||||
if stateRes.ResourceType() != google.GoogleStorageBucketIamPolicyResourceType {
|
||||
resType := stateRes.ResourceType()
|
||||
resField, supported := m.resFieldByType[resType]
|
||||
if !supported {
|
||||
resources = append(resources, stateRes)
|
||||
continue
|
||||
}
|
||||
|
||||
bucket := *stateRes.Attrs.GetString("bucket")
|
||||
resName := *stateRes.Attrs.GetString(resField)
|
||||
policyJSON := *stateRes.Attrs.GetString("policy_data")
|
||||
|
||||
policies := policyDataType{}
|
||||
|
@ -38,20 +47,20 @@ func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState
|
|||
}
|
||||
|
||||
for _, policy := range policies.Bindings {
|
||||
roleName := policy.Role
|
||||
members := policy.Members
|
||||
roleName := policy["role"].(string)
|
||||
members := policy["members"].([]interface{})
|
||||
for _, member := range members {
|
||||
id := fmt.Sprintf("%s/%s/%s", bucket, roleName, member)
|
||||
id := fmt.Sprintf("%s/%s/%s", resName, roleName, member)
|
||||
resources = append(
|
||||
resources,
|
||||
m.resourceFactory.CreateAbstractResource(
|
||||
google.GoogleStorageBucketIamMemberResourceType,
|
||||
fmt.Sprintf("%s_member", strings.TrimSuffix(resType, "_policy")),
|
||||
id,
|
||||
map[string]interface{}{
|
||||
"id": id,
|
||||
"bucket": bucket,
|
||||
resField: resName,
|
||||
"role": roleName,
|
||||
"member": member,
|
||||
"member": member.(string),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -65,8 +74,5 @@ func (m *GoogleStorageBucketIAMPolicyTransformer) Execute(_, resourcesFromState
|
|||
}
|
||||
|
||||
type policyDataType struct {
|
||||
Bindings []struct {
|
||||
Members []string
|
||||
Role string
|
||||
}
|
||||
Bindings []map[string]interface{}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/google/repository"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/google"
|
||||
)
|
||||
|
||||
type GoogleProjectIamMemberEnumerator struct {
|
||||
repository repository.CloudResourceManagerRepository
|
||||
factory resource.ResourceFactory
|
||||
}
|
||||
|
||||
func NewGoogleProjectIamMemberEnumerator(repo repository.CloudResourceManagerRepository, factory resource.ResourceFactory) *GoogleProjectIamMemberEnumerator {
|
||||
return &GoogleProjectIamMemberEnumerator{
|
||||
repository: repo,
|
||||
factory: factory,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GoogleProjectIamMemberEnumerator) SupportedType() resource.ResourceType {
|
||||
return google.GoogleProjectIamMemberResourceType
|
||||
}
|
||||
|
||||
func (e *GoogleProjectIamMemberEnumerator) Enumerate() ([]*resource.Resource, error) {
|
||||
results := make([]*resource.Resource, 0)
|
||||
|
||||
bindingsByProject, err := e.repository.ListProjectsBindings()
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType()))
|
||||
}
|
||||
for project, bindings := range bindingsByProject {
|
||||
for roleName, members := range bindings {
|
||||
for _, member := range members {
|
||||
id := fmt.Sprintf("%s/%s/%s", project, roleName, member)
|
||||
results = append(
|
||||
results,
|
||||
e.factory.CreateAbstractResource(
|
||||
string(e.SupportedType()),
|
||||
id,
|
||||
map[string]interface{}{
|
||||
"id": id,
|
||||
"project": project,
|
||||
"role": roleName,
|
||||
"member": member,
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, err
|
||||
}
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/google"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"google.golang.org/api/cloudresourcemanager/v1"
|
||||
)
|
||||
|
||||
func Init(version string, alerter *alerter.Alerter,
|
||||
|
@ -45,8 +46,14 @@ func Init(version string, alerter *alerter.Alerter,
|
|||
return err
|
||||
}
|
||||
|
||||
crmService, err := cloudresourcemanager.NewService(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
assetRepository := repository.NewAssetRepository(assetClient, provider.GetConfig(), repositoryCache)
|
||||
storageRepository := repository.NewStorageRepository(storageClient, repositoryCache)
|
||||
iamRepository := repository.NewCloudResourceManagerRepository(crmService, provider.GetConfig(), repositoryCache)
|
||||
|
||||
providerLibrary.AddProvider(terraform.GOOGLE, provider)
|
||||
deserializer := resource.NewDeserializer(factory)
|
||||
|
@ -61,6 +68,9 @@ func Init(version string, alerter *alerter.Alerter,
|
|||
|
||||
remoteLibrary.AddEnumerator(NewGoogleComputeInstanceEnumerator(assetRepository, factory))
|
||||
|
||||
remoteLibrary.AddEnumerator(NewGoogleProjectIamMemberEnumerator(iamRepository, factory))
|
||||
remoteLibrary.AddDetailsFetcher(google.GoogleProjectIamMemberResourceType, common.NewGenericDetailsFetcher(google.GoogleProjectIamMemberResourceType, provider, deserializer))
|
||||
|
||||
remoteLibrary.AddEnumerator(NewGoogleStorageBucketIamMemberEnumerator(assetRepository, storageRepository, factory))
|
||||
remoteLibrary.AddDetailsFetcher(google.GoogleStorageBucketIamMemberResourceType, common.NewGenericDetailsFetcher(google.GoogleStorageBucketIamMemberResourceType, provider, deserializer))
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/cache"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/google/config"
|
||||
"google.golang.org/api/cloudresourcemanager/v1"
|
||||
)
|
||||
|
||||
type CloudResourceManagerRepository interface {
|
||||
ListProjectsBindings() (map[string]map[string][]string, error)
|
||||
}
|
||||
|
||||
type cloudResourceManagerRepository struct {
|
||||
service *cloudresourcemanager.Service
|
||||
config config.GCPTerraformConfig
|
||||
cache cache.Cache
|
||||
lock sync.Locker
|
||||
}
|
||||
|
||||
func NewCloudResourceManagerRepository(service *cloudresourcemanager.Service, config config.GCPTerraformConfig, cache cache.Cache) CloudResourceManagerRepository {
|
||||
return &cloudResourceManagerRepository{
|
||||
service: service,
|
||||
config: config,
|
||||
cache: cache,
|
||||
lock: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *cloudResourceManagerRepository) ListProjectsBindings() (map[string]map[string][]string, error) {
|
||||
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if cachedResults := s.cache.Get("ListProjectsBindings"); cachedResults != nil {
|
||||
return cachedResults.(map[string]map[string][]string), nil
|
||||
}
|
||||
|
||||
request := new(cloudresourcemanager.GetIamPolicyRequest)
|
||||
policy, err := s.service.Projects.GetIamPolicy(s.config.Project, request).Do()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bindings := make(map[string][]string)
|
||||
|
||||
for _, binding := range policy.Bindings {
|
||||
bindings[binding.Role] = binding.Members
|
||||
}
|
||||
|
||||
bindingsByProject := make(map[string]map[string][]string)
|
||||
bindingsByProject[s.config.Project] = bindings
|
||||
|
||||
s.cache.Put("ListProjectsBindings", bindingsByProject)
|
||||
|
||||
return bindingsByProject, nil
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// Code generated by mockery v0.0.0-dev. DO NOT EDIT.
|
||||
|
||||
package repository
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
// MockCloudResourceManagerRepository is an autogenerated mock type for the CloudResourceManagerRepository type
|
||||
type MockCloudResourceManagerRepository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ListProjectsBindings provides a mock function with given fields:
|
||||
func (_m *MockCloudResourceManagerRepository) ListProjectsBindings() (map[string]map[string][]string, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 map[string]map[string][]string
|
||||
if rf, ok := ret.Get(0).(func() map[string]map[string][]string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]map[string][]string)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/cloudskiff/driftctl/pkg/filter"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/alerts"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/common"
|
||||
remoteerr "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/google"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/google/repository"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
googleresource "github.com/cloudskiff/driftctl/pkg/resource/google"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"github.com/cloudskiff/driftctl/test"
|
||||
"github.com/cloudskiff/driftctl/test/goldenfile"
|
||||
testresource "github.com/cloudskiff/driftctl/test/resource"
|
||||
terraform2 "github.com/cloudskiff/driftctl/test/terraform"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestGoogleProjectIAMMember(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
test string
|
||||
dirName string
|
||||
repositoryMock func(repository *repository.MockCloudResourceManagerRepository)
|
||||
responseErr error
|
||||
setupAlerterMock func(alerter *mocks.AlerterInterface)
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
test: "no bindings",
|
||||
dirName: "google_project_member_empty",
|
||||
repositoryMock: func(repository *repository.MockCloudResourceManagerRepository) {
|
||||
repository.On("ListProjectsBindings").Return(map[string]map[string][]string{}, nil)
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
test: "Cannot list bindings",
|
||||
dirName: "google_project_member_listing_error",
|
||||
repositoryMock: func(repository *repository.MockCloudResourceManagerRepository) {
|
||||
repository.On("ListProjectsBindings").Return(
|
||||
map[string]map[string][]string{},
|
||||
errors.New("googleapi: Error 403: driftctl-acc-circle@driftctl-qa-1.iam.gserviceaccount.com does not have project.getIamPolicy access., forbidden"))
|
||||
},
|
||||
setupAlerterMock: func(alerter *mocks.AlerterInterface) {
|
||||
alerter.On(
|
||||
"SendAlert",
|
||||
"google_project_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 project.getIamPolicy access., forbidden"),
|
||||
"google_project_iam_member",
|
||||
),
|
||||
alerts.EnumerationPhase,
|
||||
),
|
||||
).Once()
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
test: "multiples storage buckets, multiple bindings",
|
||||
dirName: "google_project_member_listing_multiple",
|
||||
repositoryMock: func(repository *repository.MockCloudResourceManagerRepository) {
|
||||
repository.On("ListProjectsBindings").Return(map[string]map[string][]string{
|
||||
"": {
|
||||
"roles/editor": {
|
||||
"user:martin.guibert@cloudskiff.com",
|
||||
"serviceAccount:drifctl-admin@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
},
|
||||
"roles/storage.admin": {"user:martin.guibert@cloudskiff.com"},
|
||||
"roles/viewer": {"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com"},
|
||||
"roles/cloudasset.viewer": {"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com"},
|
||||
"roles/iam.securityReviewer": {"serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com"},
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
providerVersion := "3.78.0"
|
||||
resType := resource.ResourceType(googleresource.GoogleProjectIamMemberResourceType)
|
||||
schemaRepository := testresource.InitFakeSchemaRepository("google", providerVersion)
|
||||
googleresource.InitResourcesMetadata(schemaRepository)
|
||||
factory := terraform.NewTerraformResourceFactory(schemaRepository)
|
||||
deserializer := resource.NewDeserializer(factory)
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.test, func(tt *testing.T) {
|
||||
|
||||
shouldUpdate := c.dirName == *goldenfile.Update
|
||||
|
||||
scanOptions := ScannerOptions{Deep: true}
|
||||
providerLibrary := terraform.NewProviderLibrary()
|
||||
remoteLibrary := common.NewRemoteLibrary()
|
||||
|
||||
// Initialize mocks
|
||||
alerter := &mocks.AlerterInterface{}
|
||||
if c.setupAlerterMock != nil {
|
||||
c.setupAlerterMock(alerter)
|
||||
}
|
||||
|
||||
realProvider, err := terraform2.InitTestGoogleProvider(providerLibrary, providerVersion)
|
||||
if err != nil {
|
||||
tt.Fatal(err)
|
||||
}
|
||||
provider := terraform2.NewFakeTerraformProvider(realProvider)
|
||||
provider.WithResponse(c.dirName)
|
||||
|
||||
managerRepository := &repository.MockCloudResourceManagerRepository{}
|
||||
if c.repositoryMock != nil {
|
||||
c.repositoryMock(managerRepository)
|
||||
}
|
||||
|
||||
remoteLibrary.AddEnumerator(google.NewGoogleProjectIamMemberEnumerator(managerRepository, factory))
|
||||
|
||||
testFilter := &filter.MockFilter{}
|
||||
testFilter.On("IsTypeIgnored", mock.Anything).Return(false)
|
||||
|
||||
s := NewScanner(remoteLibrary, alerter, scanOptions, testFilter)
|
||||
got, err := s.Resources()
|
||||
assert.Equal(tt, c.wantErr, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
alerter.AssertExpectations(tt)
|
||||
testFilter.AssertExpectations(tt)
|
||||
test.TestAgainstGoldenFile(got, resType.String(), c.dirName, provider, deserializer, shouldUpdate, tt)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/storage.admin/user:martin.guibert@cloudskiff.com",
|
||||
"member": "user:martin.guibert@cloudskiff.com",
|
||||
"project": "",
|
||||
"role": "roles/storage.admin"
|
||||
},
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/viewer/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "",
|
||||
"role": "roles/viewer"
|
||||
},
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/cloudasset.viewer/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "",
|
||||
"role": "roles/cloudasset.viewer"
|
||||
},
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/iam.securityReviewer/serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"member": "serviceAccount:driftctl@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "",
|
||||
"role": "roles/iam.securityReviewer"
|
||||
},
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/editor/serviceAccount:drifctl-admin@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"member": "serviceAccount:drifctl-admin@cloudskiff-dev-martin.iam.gserviceaccount.com",
|
||||
"project": "",
|
||||
"role": "roles/editor"
|
||||
},
|
||||
{
|
||||
"condition": null,
|
||||
"etag": null,
|
||||
"id": "/roles/editor/user:martin.guibert@cloudskiff.com",
|
||||
"member": "user:martin.guibert@cloudskiff.com",
|
||||
"project": "",
|
||||
"role": "roles/editor"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,3 @@
|
|||
package google
|
||||
|
||||
const GoogleProjectIamBindingResourceType = "google_project_iam_binding"
|
|
@ -0,0 +1,21 @@
|
|||
package google
|
||||
|
||||
import "github.com/cloudskiff/driftctl/pkg/resource"
|
||||
|
||||
const GoogleProjectIamMemberResourceType = "google_project_iam_member"
|
||||
|
||||
func initGoogleProjectIAMMemberMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) {
|
||||
resourceSchemaRepository.SetNormalizeFunc(GoogleProjectIamMemberResourceType, func(res *resource.Resource) {
|
||||
res.Attributes().SafeDelete([]string{"force_destroy"})
|
||||
res.Attributes().SafeDelete([]string{"etag"})
|
||||
})
|
||||
resourceSchemaRepository.SetResolveReadAttributesFunc(GoogleProjectIamMemberResourceType, func(res *resource.Resource) map[string]string {
|
||||
return map[string]string{
|
||||
"project": *res.Attrs.GetString("project"),
|
||||
"role": *res.Attrs.GetString("role"),
|
||||
"member": *res.Attrs.GetString("member"),
|
||||
}
|
||||
})
|
||||
resourceSchemaRepository.SetFlags(GoogleProjectIamMemberResourceType, resource.FlagDeepMode)
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package google_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cloudskiff/driftctl/test"
|
||||
"github.com/cloudskiff/driftctl/test/acceptance"
|
||||
)
|
||||
|
||||
func TestAcc_Google_ProjectIAMMember(t *testing.T) {
|
||||
acceptance.Run(t, acceptance.AccTestCase{
|
||||
TerraformVersion: "0.15.5",
|
||||
Paths: []string{"./testdata/acc/google_project_iam_member"},
|
||||
Args: []string{
|
||||
"scan",
|
||||
"--to", "gcp+tf",
|
||||
"--filter", "Type=='google_project_iam_member'",
|
||||
},
|
||||
Checks: []acceptance.AccCheck{
|
||||
{
|
||||
Check: func(result *test.ScanResult, stdout string, err error) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result.AssertInfrastructureIsInSync()
|
||||
result.AssertManagedCount(2)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package google
|
||||
|
||||
const GoogleProjectIamPolicyResourceType = "google_project_iam_policy"
|
|
@ -10,4 +10,5 @@ func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInt
|
|||
initGoogleStorageBucketIamBMemberMetadata(resourceSchemaRepository)
|
||||
initGoogleComputeInstanceGroupMetadata(resourceSchemaRepository)
|
||||
initGoogleBigqueryDatasetMetadata(resourceSchemaRepository)
|
||||
initGoogleProjectIAMMemberMetadata(resourceSchemaRepository)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
provider "google" {}
|
||||
|
||||
terraform {
|
||||
required_version = "~> 0.15.0"
|
||||
required_providers {
|
||||
google = {
|
||||
version = "3.78.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_project_iam_member" "elie1" {
|
||||
role = "roles/editor"
|
||||
member = "user:elie.charra@cloudskiff.com"
|
||||
}
|
||||
|
||||
resource "google_project_iam_member" "will1" {
|
||||
role = "roles/viewer"
|
||||
member = "user:william.beuil@cloudskiff.com"
|
||||
}
|
|
@ -145,6 +145,13 @@ var supportedTypes = map[string]ResourceTypeMeta{
|
|||
"google_dns_managed_zone": {},
|
||||
"google_compute_instance_group": {},
|
||||
"google_bigquery_dataset": {},
|
||||
"google_project_iam_member": {},
|
||||
"google_project_iam_binding": {children: []ResourceType{
|
||||
"google_project_iam_member",
|
||||
}},
|
||||
"google_project_iam_policy": {children: []ResourceType{
|
||||
"google_project_iam_member",
|
||||
}},
|
||||
|
||||
"azurerm_storage_account": {},
|
||||
"azurerm_storage_container": {},
|
||||
|
|
Loading…
Reference in New Issue