github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/terraform/google/iam/project_iam.go (about)

     1  package iam
     2  
     3  import (
     4  	"strings"
     5  
     6  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     7  
     8  	"github.com/khulnasoft-lab/defsec/pkg/terraform"
     9  
    10  	"github.com/khulnasoft-lab/defsec/pkg/providers/google/iam"
    11  )
    12  
    13  // see https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam
    14  
    15  func (a *adapter) adaptProjectIAM() {
    16  	a.adaptProjectMembers()
    17  	a.adaptProjectBindings()
    18  }
    19  
    20  func (a *adapter) adaptMember(iamBlock *terraform.Block) iam.Member {
    21  	return AdaptMember(iamBlock, a.modules)
    22  }
    23  
    24  func AdaptMember(iamBlock *terraform.Block, modules terraform.Modules) iam.Member {
    25  	member := iam.Member{
    26  		Metadata:              iamBlock.GetMetadata(),
    27  		Member:                iamBlock.GetAttribute("member").AsStringValueOrDefault("", iamBlock),
    28  		Role:                  iamBlock.GetAttribute("role").AsStringValueOrDefault("", iamBlock),
    29  		DefaultServiceAccount: defsecTypes.BoolDefault(false, iamBlock.GetMetadata()),
    30  	}
    31  
    32  	memberAttr := iamBlock.GetAttribute("member")
    33  	if referencedBlock, err := modules.GetReferencedBlock(memberAttr, iamBlock); err == nil {
    34  		if strings.HasSuffix(referencedBlock.TypeLabel(), "_default_service_account") {
    35  			member.DefaultServiceAccount = defsecTypes.Bool(true, memberAttr.GetMetadata())
    36  		}
    37  	}
    38  
    39  	return member
    40  }
    41  
    42  var projectMemberResources = []string{
    43  	"google_project_iam_member",
    44  	"google_cloud_run_service_iam_member",
    45  	"google_compute_instance_iam_member",
    46  	"google_compute_subnetwork_iam_member",
    47  	"google_data_catalog_entry_group_iam_member",
    48  	"google_folder_iam_member",
    49  	"google_pubsub_subscription_iam_member",
    50  	"google_pubsub_topic_iam_member",
    51  	"google_sourcerepo_repository_iam_member",
    52  	"google_spanner_database_iam_member",
    53  	"google_spanner_instance_iam_member",
    54  	"google_storage_bucket_iam_member",
    55  }
    56  
    57  func (a *adapter) adaptProjectMembers() {
    58  
    59  	for _, memberType := range projectMemberResources {
    60  		for _, iamBlock := range a.modules.GetResourcesByType(memberType) {
    61  			member := a.adaptMember(iamBlock)
    62  			projectAttr := iamBlock.GetAttribute("project")
    63  			if projectAttr.IsString() {
    64  				var foundProject bool
    65  				projectID := projectAttr.Value().AsString()
    66  				for i, project := range a.projects {
    67  					if project.id == projectID {
    68  						project.project.Members = append(project.project.Members, member)
    69  						a.projects[i] = project
    70  						foundProject = true
    71  						break
    72  					}
    73  				}
    74  				if foundProject {
    75  					continue
    76  				}
    77  			}
    78  
    79  			if refBlock, err := a.modules.GetReferencedBlock(projectAttr, iamBlock); err == nil {
    80  				if refBlock.TypeLabel() == "google_project" {
    81  					var foundProject bool
    82  					for i, project := range a.projects {
    83  						if project.blockID == refBlock.ID() {
    84  							project.project.Members = append(project.project.Members, member)
    85  							a.projects[i] = project
    86  							foundProject = true
    87  							break
    88  						}
    89  					}
    90  					if foundProject {
    91  						continue
    92  					}
    93  
    94  				}
    95  			}
    96  
    97  			// we didn't find the project - add an unmanaged one
    98  			// unless it already belongs to an existing folder
    99  			var foundFolder bool
   100  			if refBlock, err := a.modules.GetReferencedBlock(iamBlock.GetAttribute("folder"), iamBlock); err == nil {
   101  				for _, folder := range a.folders {
   102  					if folder.blockID == refBlock.ID() {
   103  						foundFolder = true
   104  					}
   105  				}
   106  			}
   107  			if foundFolder {
   108  				continue
   109  			}
   110  
   111  			a.projects = append(a.projects, parentedProject{
   112  				project: iam.Project{
   113  					Metadata:          defsecTypes.NewUnmanagedMetadata(),
   114  					AutoCreateNetwork: defsecTypes.BoolDefault(false, defsecTypes.NewUnmanagedMetadata()),
   115  					Members:           []iam.Member{member},
   116  					Bindings:          nil,
   117  				},
   118  			})
   119  		}
   120  	}
   121  }
   122  
   123  func (a *adapter) adaptBinding(iamBlock *terraform.Block) iam.Binding {
   124  	return AdaptBinding(iamBlock, a.modules)
   125  }
   126  
   127  func AdaptBinding(iamBlock *terraform.Block, modules terraform.Modules) iam.Binding {
   128  	binding := iam.Binding{
   129  		Metadata:                      iamBlock.GetMetadata(),
   130  		Members:                       nil,
   131  		Role:                          iamBlock.GetAttribute("role").AsStringValueOrDefault("", iamBlock),
   132  		IncludesDefaultServiceAccount: defsecTypes.BoolDefault(false, iamBlock.GetMetadata()),
   133  	}
   134  	membersAttr := iamBlock.GetAttribute("members")
   135  	members := membersAttr.AsStringValues().AsStrings()
   136  	for _, member := range members {
   137  		binding.Members = append(binding.Members, defsecTypes.String(member, membersAttr.GetMetadata()))
   138  	}
   139  	if referencedBlock, err := modules.GetReferencedBlock(membersAttr, iamBlock); err == nil {
   140  		if strings.HasSuffix(referencedBlock.TypeLabel(), "_default_service_account") {
   141  			binding.IncludesDefaultServiceAccount = defsecTypes.Bool(true, membersAttr.GetMetadata())
   142  		}
   143  	}
   144  	return binding
   145  }
   146  
   147  var projectBindingResources = []string{
   148  	"google_project_iam_binding",
   149  	"google_cloud_run_service_iam_binding",
   150  	"google_compute_instance_iam_binding",
   151  	"google_compute_subnetwork_iam_binding",
   152  	"google_data_catalog_entry_group_iam_binding",
   153  	"google_folder_iam_binding",
   154  	"google_pubsub_subscription_iam_binding",
   155  	"google_pubsub_topic_iam_binding",
   156  	"google_sourcerepo_repository_iam_binding",
   157  	"google_spanner_database_iam_binding",
   158  	"google_spanner_instance_iam_binding",
   159  	"google_storage_bucket_iam_binding",
   160  }
   161  
   162  func (a *adapter) adaptProjectDataBindings() {
   163  	for _, iamBlock := range a.modules.GetResourcesByType("google_project_iam_policy") {
   164  
   165  		policyAttr := iamBlock.GetAttribute("policy_data")
   166  		if policyAttr.IsNil() {
   167  			continue
   168  		}
   169  		policyBlock, err := a.modules.GetReferencedBlock(policyAttr, iamBlock)
   170  		if err != nil {
   171  			continue
   172  		}
   173  		bindings := ParsePolicyBlock(policyBlock)
   174  		projectAttr := iamBlock.GetAttribute("project")
   175  		if projectAttr.IsString() {
   176  			var foundProject bool
   177  			projectID := projectAttr.Value().AsString()
   178  			for i, project := range a.projects {
   179  				if project.id == projectID {
   180  					project.project.Bindings = append(project.project.Bindings, bindings...)
   181  					a.projects[i] = project
   182  					foundProject = true
   183  					break
   184  				}
   185  			}
   186  			if foundProject {
   187  				continue
   188  			}
   189  		}
   190  
   191  		if refBlock, err := a.modules.GetReferencedBlock(projectAttr, iamBlock); err == nil {
   192  			if refBlock.TypeLabel() == "google_project" {
   193  				var foundProject bool
   194  				for i, project := range a.projects {
   195  					if project.blockID == refBlock.ID() {
   196  						project.project.Bindings = append(project.project.Bindings, bindings...)
   197  						a.projects[i] = project
   198  						foundProject = true
   199  						break
   200  					}
   201  				}
   202  				if foundProject {
   203  					continue
   204  				}
   205  
   206  			}
   207  		}
   208  
   209  		// we didn't find the project - add an unmanaged one
   210  		a.projects = append(a.projects, parentedProject{
   211  			project: iam.Project{
   212  				Metadata:          defsecTypes.NewUnmanagedMetadata(),
   213  				AutoCreateNetwork: defsecTypes.BoolDefault(false, defsecTypes.NewUnmanagedMetadata()),
   214  				Members:           nil,
   215  				Bindings:          bindings,
   216  			},
   217  		})
   218  	}
   219  
   220  }
   221  
   222  func (a *adapter) adaptProjectBindings() {
   223  
   224  	a.adaptProjectDataBindings()
   225  
   226  	for _, bindingType := range projectBindingResources {
   227  		for _, iamBlock := range a.modules.GetResourcesByType(bindingType) {
   228  			binding := a.adaptBinding(iamBlock)
   229  			projectAttr := iamBlock.GetAttribute("project")
   230  			if projectAttr.IsString() {
   231  				var foundProject bool
   232  				projectID := projectAttr.Value().AsString()
   233  				for i, project := range a.projects {
   234  					if project.id == projectID {
   235  						project.project.Bindings = append(project.project.Bindings, binding)
   236  						a.projects[i] = project
   237  						foundProject = true
   238  						break
   239  					}
   240  				}
   241  				if foundProject {
   242  					continue
   243  				}
   244  			}
   245  
   246  			if refBlock, err := a.modules.GetReferencedBlock(projectAttr, iamBlock); err == nil {
   247  				if refBlock.TypeLabel() == "google_project" {
   248  					var foundProject bool
   249  					for i, project := range a.projects {
   250  						if project.blockID == refBlock.ID() {
   251  							project.project.Bindings = append(project.project.Bindings, binding)
   252  							a.projects[i] = project
   253  							foundProject = true
   254  							break
   255  						}
   256  					}
   257  					if foundProject {
   258  						continue
   259  					}
   260  
   261  				}
   262  			}
   263  
   264  			// we didn't find the project - add an unmanaged one
   265  			// unless it already belongs to an existing folder
   266  			var foundFolder bool
   267  			if refBlock, err := a.modules.GetReferencedBlock(iamBlock.GetAttribute("folder"), iamBlock); err == nil {
   268  				for _, folder := range a.folders {
   269  					if folder.blockID == refBlock.ID() {
   270  						foundFolder = true
   271  					}
   272  				}
   273  			}
   274  			if foundFolder {
   275  				continue
   276  			}
   277  			a.projects = append(a.projects, parentedProject{
   278  				project: iam.Project{
   279  					Metadata:          defsecTypes.NewUnmanagedMetadata(),
   280  					AutoCreateNetwork: defsecTypes.BoolDefault(false, defsecTypes.NewUnmanagedMetadata()),
   281  					Members:           nil,
   282  					Bindings:          []iam.Binding{binding},
   283  				},
   284  			})
   285  		}
   286  	}
   287  }