diff --git a/mmv1/api/resource/iam_policy.go b/mmv1/api/resource/iam_policy.go index 0f8d7f1017a0..5746e7e0b764 100644 --- a/mmv1/api/resource/iam_policy.go +++ b/mmv1/api/resource/iam_policy.go @@ -99,6 +99,10 @@ type IamPolicy struct { // How the API supports IAM conditions IamConditionsRequestType string `yaml:"iam_conditions_request_type,omitempty"` + // [Optional] Whether to include an updateMask in the setIamPolicy request. + // Mandatory for older APIs like DNS to support IAM conditions. + UpdateMask bool `yaml:"update_mask,omitempty"` + // Allows us to override the base_url of the resource. This is required for Cloud Run as the // IAM resources use an entirely different base URL from the actual resource BaseUrl string `yaml:"base_url,omitempty"` diff --git a/mmv1/products/dns/ManagedZone.yaml b/mmv1/products/dns/ManagedZone.yaml index cb3e0d63f034..e0526971498d 100644 --- a/mmv1/products/dns/ManagedZone.yaml +++ b/mmv1/products/dns/ManagedZone.yaml @@ -33,6 +33,9 @@ iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' parent_resource_attribute: 'managed_zone' + iam_conditions_request_type: 'QUERY_PARAM_NESTED' + allowed_iam_role: 'roles/dns.admin' + update_mask: true import_format: - 'projects/{{project}}/managedZones/{{managed_zone}}' - '{{project}}/{{managed_zone}}' @@ -123,6 +126,13 @@ examples: dns_name: 'services.example.com.' test_vars_overrides: 'dns_name': '"services.example.com-" + acctest.RandString(t, 10) + "."' + - name: 'dns_managed_zone_iam_condition' + primary_resource_id: 'default' + vars: + dns_name: 'example.com.' + managed_zone_name: 'example-zone' + test_vars_overrides: + 'dns_name': '"conditions.example.com-" + acctest.RandString(t, 10) + "."' virtual_fields: - name: 'force_destroy' description: 'Set this true to delete all records in the zone.' diff --git a/mmv1/templates/terraform/examples/dns_managed_zone_iam_condition.tf.tmpl b/mmv1/templates/terraform/examples/dns_managed_zone_iam_condition.tf.tmpl new file mode 100644 index 000000000000..c376eb957253 --- /dev/null +++ b/mmv1/templates/terraform/examples/dns_managed_zone_iam_condition.tf.tmpl @@ -0,0 +1,19 @@ +resource "google_dns_managed_zone" "default" { + name = "{{index $.Vars "managed_zone_name"}}" + dns_name = "{{index $.Vars "dns_name"}}" + description = "Example zone for IAM conditions" +} + +resource "google_dns_managed_zone_iam_member" "condition_test" { + project = google_dns_managed_zone.default.project + managed_zone = google_dns_managed_zone.default.name + role = "roles/dns.admin" + member = "user:admin@hashicorptest.com" + + condition { + title = "Exact Record Match" + description = "Allow modifying only api.example.com. A records" + # Mandatory pass-through clause for parent Managed Zone checks + expression = "(resource.type == 'dns.googleapis.com/ResourceRecordSet' && resource.name.endsWith('/rrsets/api.{{index $.Vars "dns_name"}}/A')) || (resource.type != 'dns.googleapis.com/ResourceRecordSet')" + } +} diff --git a/mmv1/templates/terraform/iam_policy.go.tmpl b/mmv1/templates/terraform/iam_policy.go.tmpl index 22b21fa5dc59..f7aee9562903 100644 --- a/mmv1/templates/terraform/iam_policy.go.tmpl +++ b/mmv1/templates/terraform/iam_policy.go.tmpl @@ -293,6 +293,10 @@ func (u *{{ $.ResourceName }}IamUpdater) SetResourceIamPolicy(policy *cloudresou {{ if and $.IamPolicy $.IamPolicy.WrappedPolicyObj -}} obj := make(map[string]interface{}) obj["policy"] = json + {{- if $.IamPolicy.UpdateMask }} + // Core APIs require the mask to acknowledge policy version 3 (conditions) + obj["updateMask"] = "bindings,etag,version" + {{- end }} {{- else }} obj := json {{- end }} @@ -356,4 +360,4 @@ func (u *{{ $.ResourceName }}IamUpdater) GetMutexKey() string { func (u *{{ $.ResourceName }}IamUpdater) DescribeResource() string { return fmt.Sprintf("{{ lower $.ProductMetadata.Name }} {{ lower $.Name }} %q", u.GetResourceId()) -} \ No newline at end of file +}