From 51cd81b1e98361b897d16e33652f5017a2ed3a0c Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 14 Feb 2024 11:45:19 -0800 Subject: [PATCH] AppAttest and PlayIntegrity for App Check (#9970) (#17279) * AppAttest and PlayIntegrity for App Check * use camelCase for updateMask for consistency * Enhance examples to use precondition checks [upstream:5a6abe3f97dc5a97e206c0d2cddfdf7f82cdd0c8] Signed-off-by: Modular Magician --- .changelog/9970.txt | 6 + google/provider/provider_mmv1_resources.go | 6 +- ...ce_firebase_app_check_app_attest_config.go | 308 ++++++++++++++++++ ..._check_app_attest_config_generated_test.go | 153 +++++++++ ...rebase_app_check_app_attest_config_test.go | 61 ++++ ...irebase_app_check_play_integrity_config.go | 308 ++++++++++++++++++ ...ck_play_integrity_config_generated_test.go | 153 +++++++++ ...se_app_check_play_integrity_config_test.go | 60 ++++ ..._app_check_app_attest_config.html.markdown | 170 ++++++++++ ..._check_play_integrity_config.html.markdown | 172 ++++++++++ 10 files changed, 1395 insertions(+), 2 deletions(-) create mode 100644 .changelog/9970.txt create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config.go create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_generated_test.go create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config.go create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_generated_test.go create mode 100644 google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go create mode 100644 website/docs/r/firebase_app_check_app_attest_config.html.markdown create mode 100644 website/docs/r/firebase_app_check_play_integrity_config.html.markdown diff --git a/.changelog/9970.txt b/.changelog/9970.txt new file mode 100644 index 00000000000..c21919ecf70 --- /dev/null +++ b/.changelog/9970.txt @@ -0,0 +1,6 @@ +```release-note:new-resource +`google_firebase_app_check_app_attest_config` +``` +```release-note:new-resource +`google_firebase_app_check_play_integrity_config` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 153bd4b492c..55014945f38 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -385,9 +385,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 380 +// Generated resources: 382 // Generated IAM resources: 225 -// Total generated resources: 605 +// Total generated resources: 607 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -724,7 +724,9 @@ var generatedResources = map[string]*schema.Resource{ "google_filestore_backup": filestore.ResourceFilestoreBackup(), "google_filestore_instance": filestore.ResourceFilestoreInstance(), "google_filestore_snapshot": filestore.ResourceFilestoreSnapshot(), + "google_firebase_app_check_app_attest_config": firebaseappcheck.ResourceFirebaseAppCheckAppAttestConfig(), "google_firebase_app_check_debug_token": firebaseappcheck.ResourceFirebaseAppCheckDebugToken(), + "google_firebase_app_check_play_integrity_config": firebaseappcheck.ResourceFirebaseAppCheckPlayIntegrityConfig(), "google_firebase_app_check_service_config": firebaseappcheck.ResourceFirebaseAppCheckServiceConfig(), "google_firestore_backup_schedule": firestore.ResourceFirestoreBackupSchedule(), "google_firestore_database": firestore.ResourceFirestoreDatabase(), diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config.go b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config.go new file mode 100644 index 00000000000..23ff7f30c95 --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config.go @@ -0,0 +1,308 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package firebaseappcheck + +import ( + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceFirebaseAppCheckAppAttestConfig() *schema.Resource { + return &schema.Resource{ + Create: resourceFirebaseAppCheckAppAttestConfigCreate, + Read: resourceFirebaseAppCheckAppAttestConfigRead, + Update: resourceFirebaseAppCheckAppAttestConfigUpdate, + Delete: resourceFirebaseAppCheckAppAttestConfigDelete, + + Importer: &schema.ResourceImporter{ + State: resourceFirebaseAppCheckAppAttestConfigImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of an +[Apple App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.iosApps#IosApp.FIELDS.app_id).`, + }, + "token_ttl": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `Specifies the duration for which App Check tokens exchanged from App Attest artifacts will be valid. +If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + +A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s".`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The relative resource name of the App Attest configuration object`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceFirebaseAppCheckAppAttestConfigCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + tokenTtlProp, err := expandFirebaseAppCheckAppAttestConfigTokenTtl(d.Get("token_ttl"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("token_ttl"); !tpgresource.IsEmptyValue(reflect.ValueOf(tokenTtlProp)) && (ok || !reflect.DeepEqual(v, tokenTtlProp)) { + obj["tokenTtl"] = tokenTtlProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/appAttestConfig?updateMask=tokenTtl") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new AppAttestConfig: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for AppAttestConfig: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating AppAttestConfig: %s", err) + } + if err := d.Set("name", flattenFirebaseAppCheckAppAttestConfigName(res["name"], d, config)); err != nil { + return fmt.Errorf(`Error setting computed identity field "name": %s`, err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/apps/{{app_id}}/appAttestConfig") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating AppAttestConfig %q: %#v", d.Id(), res) + + return resourceFirebaseAppCheckAppAttestConfigRead(d, meta) +} + +func resourceFirebaseAppCheckAppAttestConfigRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/appAttestConfig") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for AppAttestConfig: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("FirebaseAppCheckAppAttestConfig %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading AppAttestConfig: %s", err) + } + + if err := d.Set("name", flattenFirebaseAppCheckAppAttestConfigName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading AppAttestConfig: %s", err) + } + if err := d.Set("token_ttl", flattenFirebaseAppCheckAppAttestConfigTokenTtl(res["tokenTtl"], d, config)); err != nil { + return fmt.Errorf("Error reading AppAttestConfig: %s", err) + } + + return nil +} + +func resourceFirebaseAppCheckAppAttestConfigUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for AppAttestConfig: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + tokenTtlProp, err := expandFirebaseAppCheckAppAttestConfigTokenTtl(d.Get("token_ttl"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("token_ttl"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tokenTtlProp)) { + obj["tokenTtl"] = tokenTtlProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/appAttestConfig") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating AppAttestConfig %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("token_ttl") { + updateMask = append(updateMask, "tokenTtl") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating AppAttestConfig %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating AppAttestConfig %q: %#v", d.Id(), res) + } + + } + + return resourceFirebaseAppCheckAppAttestConfigRead(d, meta) +} + +func resourceFirebaseAppCheckAppAttestConfigDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARNING] FirebaseAppCheck AppAttestConfig resources"+ + " cannot be deleted from Google Cloud. The resource %s will be removed from Terraform"+ + " state, but will still be present on Google Cloud.", d.Id()) + d.SetId("") + + return nil +} + +func resourceFirebaseAppCheckAppAttestConfigImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/apps/(?P[^/]+)/appAttestConfig$", + "^(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/apps/{{app_id}}/appAttestConfig") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenFirebaseAppCheckAppAttestConfigName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenFirebaseAppCheckAppAttestConfigTokenTtl(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandFirebaseAppCheckAppAttestConfigTokenTtl(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_generated_test.go b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_generated_test.go new file mode 100644 index 00000000000..b9e80c57ead --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_generated_test.go @@ -0,0 +1,153 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} + +func testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_firebase_apple_app" "default" { + project = "%{project_id}" + display_name = "Apple app" + bundle_id = "bundle.id.appattest%{random_suffix}" + team_id = "%{team_id}" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "%{project_id}" + app_id = google_firebase_apple_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} +`, context) +} + +func TestAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "token_ttl": "7200s", + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} + +func testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_firebase_apple_app" "default" { + project = "%{project_id}" + display_name = "Apple app" + bundle_id = "bundle.id.appattest%{random_suffix}" + team_id = "%{team_id}" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "%{project_id}" + app_id = google_firebase_apple_app.default.app_id + token_ttl = "%{token_ttl}" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} +`, context) +} diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go new file mode 100644 index 00000000000..5febb01343c --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go @@ -0,0 +1,61 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "random_suffix": acctest.RandString(t, 10), + "token_ttl": "7200s", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config.go b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config.go new file mode 100644 index 00000000000..5aeaf6427ff --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config.go @@ -0,0 +1,308 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package firebaseappcheck + +import ( + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceFirebaseAppCheckPlayIntegrityConfig() *schema.Resource { + return &schema.Resource{ + Create: resourceFirebaseAppCheckPlayIntegrityConfigCreate, + Read: resourceFirebaseAppCheckPlayIntegrityConfigRead, + Update: resourceFirebaseAppCheckPlayIntegrityConfigUpdate, + Delete: resourceFirebaseAppCheckPlayIntegrityConfigDelete, + + Importer: &schema.ResourceImporter{ + State: resourceFirebaseAppCheckPlayIntegrityConfigImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of an +[Android App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.androidApps#AndroidApp.FIELDS.app_id).`, + }, + "token_ttl": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `Specifies the duration for which App Check tokens exchanged from Play Integrity artifacts will be valid. +If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + +A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s".`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The relative resource name of the Play Integrity configuration object`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceFirebaseAppCheckPlayIntegrityConfigCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + tokenTtlProp, err := expandFirebaseAppCheckPlayIntegrityConfigTokenTtl(d.Get("token_ttl"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("token_ttl"); !tpgresource.IsEmptyValue(reflect.ValueOf(tokenTtlProp)) && (ok || !reflect.DeepEqual(v, tokenTtlProp)) { + obj["tokenTtl"] = tokenTtlProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/playIntegrityConfig?updateMask=tokenTtl") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new PlayIntegrityConfig: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for PlayIntegrityConfig: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating PlayIntegrityConfig: %s", err) + } + if err := d.Set("name", flattenFirebaseAppCheckPlayIntegrityConfigName(res["name"], d, config)); err != nil { + return fmt.Errorf(`Error setting computed identity field "name": %s`, err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/apps/{{app_id}}/playIntegrityConfig") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating PlayIntegrityConfig %q: %#v", d.Id(), res) + + return resourceFirebaseAppCheckPlayIntegrityConfigRead(d, meta) +} + +func resourceFirebaseAppCheckPlayIntegrityConfigRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/playIntegrityConfig") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for PlayIntegrityConfig: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("FirebaseAppCheckPlayIntegrityConfig %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading PlayIntegrityConfig: %s", err) + } + + if err := d.Set("name", flattenFirebaseAppCheckPlayIntegrityConfigName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading PlayIntegrityConfig: %s", err) + } + if err := d.Set("token_ttl", flattenFirebaseAppCheckPlayIntegrityConfigTokenTtl(res["tokenTtl"], d, config)); err != nil { + return fmt.Errorf("Error reading PlayIntegrityConfig: %s", err) + } + + return nil +} + +func resourceFirebaseAppCheckPlayIntegrityConfigUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for PlayIntegrityConfig: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + tokenTtlProp, err := expandFirebaseAppCheckPlayIntegrityConfigTokenTtl(d.Get("token_ttl"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("token_ttl"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tokenTtlProp)) { + obj["tokenTtl"] = tokenTtlProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{FirebaseAppCheckBasePath}}projects/{{project}}/apps/{{app_id}}/playIntegrityConfig") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating PlayIntegrityConfig %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("token_ttl") { + updateMask = append(updateMask, "tokenTtl") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating PlayIntegrityConfig %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating PlayIntegrityConfig %q: %#v", d.Id(), res) + } + + } + + return resourceFirebaseAppCheckPlayIntegrityConfigRead(d, meta) +} + +func resourceFirebaseAppCheckPlayIntegrityConfigDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARNING] FirebaseAppCheck PlayIntegrityConfig resources"+ + " cannot be deleted from Google Cloud. The resource %s will be removed from Terraform"+ + " state, but will still be present on Google Cloud.", d.Id()) + d.SetId("") + + return nil +} + +func resourceFirebaseAppCheckPlayIntegrityConfigImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/apps/(?P[^/]+)/playIntegrityConfig$", + "^(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/apps/{{app_id}}/playIntegrityConfig") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenFirebaseAppCheckPlayIntegrityConfigName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenFirebaseAppCheckPlayIntegrityConfigTokenTtl(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandFirebaseAppCheckPlayIntegrityConfigTokenTtl(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_generated_test.go b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_generated_test.go new file mode 100644 index 00000000000..9ebc3b221c2 --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_generated_test.go @@ -0,0 +1,153 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} + +func testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_firebase_android_app" "default" { + project = "%{project_id}" + display_name = "Play Integrity app" + package_name = "package.name.playintegrity%{random_suffix}" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "%{project_id}" + app_id = google_firebase_android_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} +`, context) +} + +func TestAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "token_ttl": "7200s", + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} + +func testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_firebase_android_app" "default" { + project = "%{project_id}" + display_name = "Play Integrity app" + package_name = "package.name.playintegrity%{random_suffix}" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "%{project_id}" + app_id = google_firebase_android_app.default.app_id + token_ttl = "%{token_ttl}" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} +`, context) +} diff --git a/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go new file mode 100644 index 00000000000..a48b6afd934 --- /dev/null +++ b/google/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go @@ -0,0 +1,60 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "random_suffix": acctest.RandString(t, 10), + "token_ttl": "7200s", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} diff --git a/website/docs/r/firebase_app_check_app_attest_config.html.markdown b/website/docs/r/firebase_app_check_app_attest_config.html.markdown new file mode 100644 index 00000000000..78b604df21c --- /dev/null +++ b/website/docs/r/firebase_app_check_app_attest_config.html.markdown @@ -0,0 +1,170 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Firebase App Check" +description: |- + An app's App Attest configuration object. +--- + +# google\_firebase\_app\_check\_app\_attest\_config + +An app's App Attest configuration object. Note that the Team ID registered with your +app is used as part of the validation process. Make sure your `google_firebase_apple_app` has a team_id present. + + +To get more information about AppAttestConfig, see: + +* [API documentation](https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.appAttestConfig) +* How-to Guides + * [Official Documentation](https://firebase.google.com/docs/app-check) + +## Example Usage - Firebase App Check App Attest Config Minimal + + +```hcl +resource "google_firebase_apple_app" "default" { + project = "my-project-name" + display_name = "Apple app" + bundle_id = "bundle.id.appattest" + team_id = "9987654321" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "my-project-name" + app_id = google_firebase_apple_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} +``` +## Example Usage - Firebase App Check App Attest Config Full + + +```hcl +resource "google_firebase_apple_app" "default" { + project = "my-project-name" + display_name = "Apple app" + bundle_id = "bundle.id.appattest" + team_id = "9987654321" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "my-project-name" + app_id = google_firebase_apple_app.default.app_id + token_ttl = "7200s" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `app_id` - + (Required) + The ID of an + [Apple App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.iosApps#IosApp.FIELDS.app_id). + + +- - - + + +* `token_ttl` - + (Optional) + Specifies the duration for which App Check tokens exchanged from App Attest artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/apps/{{app_id}}/appAttestConfig` + +* `name` - + The relative resource name of the App Attest configuration object + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +AppAttestConfig can be imported using any of these accepted formats: + +* `projects/{{project}}/apps/{{app_id}}/appAttestConfig` +* `{{project}}/{{app_id}}` +* `{{app_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AppAttestConfig using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/apps/{{app_id}}/appAttestConfig" + to = google_firebase_app_check_app_attest_config.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), AppAttestConfig can be imported using one of the formats above. For example: + +``` +$ terraform import google_firebase_app_check_app_attest_config.default projects/{{project}}/apps/{{app_id}}/appAttestConfig +$ terraform import google_firebase_app_check_app_attest_config.default {{project}}/{{app_id}} +$ terraform import google_firebase_app_check_app_attest_config.default {{app_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override). diff --git a/website/docs/r/firebase_app_check_play_integrity_config.html.markdown b/website/docs/r/firebase_app_check_play_integrity_config.html.markdown new file mode 100644 index 00000000000..a4febb9a988 --- /dev/null +++ b/website/docs/r/firebase_app_check_play_integrity_config.html.markdown @@ -0,0 +1,172 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Firebase App Check" +description: |- + An app's Play Integrity configuration object. +--- + +# google\_firebase\_app\_check\_play\_integrity\_config + +An app's Play Integrity configuration object. Note that your registered SHA-256 certificate fingerprints are used to validate tokens issued by the Play Integrity API. +Make sure your `google_firebase_android_app` has at least one `sha256_hashes` present. + + +To get more information about PlayIntegrityConfig, see: + +* [API documentation](https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.playIntegrityConfig) +* How-to Guides + * [Official Documentation](https://firebase.google.com/docs/app-check) + +## Example Usage - Firebase App Check Play Integrity Config Minimal + + +```hcl +resource "google_firebase_android_app" "default" { + project = "my-project-name" + display_name = "Play Integrity app" + package_name = "package.name.playintegrity" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "my-project-name" + app_id = google_firebase_android_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} +``` +## Example Usage - Firebase App Check Play Integrity Config Full + + +```hcl +resource "google_firebase_android_app" "default" { + project = "my-project-name" + display_name = "Play Integrity app" + package_name = "package.name.playintegrity" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "my-project-name" + app_id = google_firebase_android_app.default.app_id + token_ttl = "7200s" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `app_id` - + (Required) + The ID of an + [Android App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.androidApps#AndroidApp.FIELDS.app_id). + + +- - - + + +* `token_ttl` - + (Optional) + Specifies the duration for which App Check tokens exchanged from Play Integrity artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/apps/{{app_id}}/playIntegrityConfig` + +* `name` - + The relative resource name of the Play Integrity configuration object + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +PlayIntegrityConfig can be imported using any of these accepted formats: + +* `projects/{{project}}/apps/{{app_id}}/playIntegrityConfig` +* `{{project}}/{{app_id}}` +* `{{app_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import PlayIntegrityConfig using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/apps/{{app_id}}/playIntegrityConfig" + to = google_firebase_app_check_play_integrity_config.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), PlayIntegrityConfig can be imported using one of the formats above. For example: + +``` +$ terraform import google_firebase_app_check_play_integrity_config.default projects/{{project}}/apps/{{app_id}}/playIntegrityConfig +$ terraform import google_firebase_app_check_play_integrity_config.default {{project}}/{{app_id}} +$ terraform import google_firebase_app_check_play_integrity_config.default {{app_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).