Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Google Cloud Identity Platform for staging and production #698

Merged
merged 2 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ instructions assume you have access to the following projects:
- webstatus-dev-internal-staging
- webstatus-dev-public-staging
- production
- web-compass-staging
- web-compass-prod
- webstatus-dev-internal-prod
- webstatus-dev-public-prod

Google Cloud Identity Platform:

- [Enable](https://console.cloud.google.com/marketplace/details/google-cloud-platform/customer-identity) Cloud Identity Platform for the internal project.
- [Enable](https://cloud.google.com/identity-platform/docs/multi-tenancy-quickstart) multi-tenancy in the Google Cloud Console.

## Deploying your own copy

```sh
Expand Down Expand Up @@ -83,6 +88,10 @@ Or you could populate with fake data by running.
go run ./util/cmd/load_fake_data/main.go -spanner_project=${SPANNER_PROJECT_ID} -spanner_instance=${SPANNER_INSTANCE_ID} -spanner_database=${SPANNER_DATABASE_ID} -datastore_project=${DATASTORE_PROJECT_ID} -datastore_database=${DATASTORE_DATABASE}
```

Setup auth:

Add your domain to the allow-list of domains in the [console](https://console.cloud.google.com/customer-identity/settings?project=webstatus-dev-internal-staging).

When you are done with your own copy

```sh
Expand All @@ -96,6 +105,8 @@ terraform workspace select default
terraform workspace delete $ENV_ID
```

Also, remove your domain from the allow-list of domains in the [console](https://console.cloud.google.com/customer-identity/settings?project=webstatus-dev-internal-staging).

## Deploy Staging

```sh
Expand Down
1 change: 1 addition & 0 deletions frontend/src/common/app-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface FirebaseAppSettings {

interface FirebaseAuthSettings {
emulatorURL: string;
tenantID: string;
}

interface FirebaseSettings {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"authDomain": "$FIREBASE_APP_AUTH_DOMAIN"
},
"auth": {
"emulatorURL": "$FIREBASE_AUTH_EMULATOR_URL"
"emulatorURL": "$FIREBASE_AUTH_EMULATOR_URL",
"tenantID": "$FIREBASE_AUTH_TENANT_ID"
}
}
}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('webstatus-app', () => {
},
auth: {
emulatorURL: 'http://localhost:9099',
tenantID: 'tenantID',
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('WebstatusServiceContainer', () => {
},
auth: {
emulatorURL: 'http://localhost:9099',
tenantID: 'tenantID',
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('webstatus-app-settings-service', () => {
},
auth: {
emulatorURL: 'http://localhost:9099',
tenantID: 'tenantID',
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class FakeParentElement extends LitElement {
describe('webstatus-firebase-auth-service', () => {
const settings = {
emulatorURL: '',
tenantID: 'tenantID',
};
it('can be added to the page with the settings', async () => {
const component = await fixture<WebstatusFirebaseAuthService>(
Expand Down Expand Up @@ -144,6 +145,11 @@ describe('webstatus-firebase-auth-service', () => {
'github',
'icon should be github'
);
assert.equal(
component.firebaseAuthConfig?.auth.tenantId,
'tenantID',
'unexpected tenantID'
);
// Ensure it gets it via context.
assert.equal(
component.firebaseAuthConfig,
Expand Down Expand Up @@ -193,6 +199,7 @@ describe('webstatus-firebase-auth-service', () => {
const testSettings = {
// Set emulator URL
emulatorURL: 'http://localhost:9099',
tenantID: '',
};
const root = document.createElement('div');
document.body.appendChild(root);
Expand Down Expand Up @@ -228,6 +235,10 @@ describe('webstatus-firebase-auth-service', () => {
await component.updateComplete;

assert.isTrue(emulatorConnectorStub.calledOnce);
assert.notExists(
component.firebaseAuthConfig?.auth.tenantId,
'unexpected tenantID'
);
expect(emulatorConnectorStub).to.have.been.calledWith(
authStub,
'http://localhost:9099'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {ServiceElement} from './service-element.js';

interface FirebaseAuthSettings {
emulatorURL: string;
tenantID: string;
}

@customElement('webstatus-firebase-auth-service')
Expand All @@ -62,6 +63,10 @@ export class WebstatusFirebaseAuthService extends ServiceElement {
initFirebaseAuth() {
if (this.firebaseApp) {
const auth = this.authInitializer(this.firebaseApp);
// Local environment will not have a tenantID.
if (this.settings.tenantID !== '') {
auth.tenantId = this.settings.tenantID;
}
const provider = new GithubAuthProvider();
this.firebaseAuthConfig = {
auth: auth,
Expand Down
7 changes: 7 additions & 0 deletions infra/.envs/prod.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,10 @@ wpt_region_schedules = {
"us-central1" = "0 21 * * *" # Daily at 9:00 PM
"europe-west1" = "0 9 * * *" # Daily at 9:00 AM
}

firebase_api_key_location = "prod-firebase-app-api-key"

auth_github_config_locations = {
client_id = "prod-github-client-id"
client_secret = "prod-github-client-secret"
}
7 changes: 7 additions & 0 deletions infra/.envs/staging.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,10 @@ wpt_region_schedules = {
"us-central1" = "0 21 * * *" # Daily at 9:00 PM
"europe-west1" = "0 9 * * *" # Daily at 9:00 AM
}

firebase_api_key_location = "staging-firebase-app-api-key"

auth_github_config_locations = {
client_id = "staging-github-client-id"
client_secret = "staging-github-client-secret"
}
44 changes: 44 additions & 0 deletions infra/auth/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

locals {
gh_client_id = sensitive(data.google_secret_manager_secret_version_access.gh_client_id.secret_data)
gh_client_secret = sensitive(data.google_secret_manager_secret_version_access.gh_client_secret.secret_data)
}

data "google_secret_manager_secret_version_access" "gh_client_id" {
provider = google.internal_project
secret = var.github_config_locations.client_id
}

data "google_secret_manager_secret_version_access" "gh_client_secret" {
provider = google.internal_project
secret = var.github_config_locations.client_secret
}

resource "google_identity_platform_tenant" "tenant" {
provider = google.internal_project
display_name = var.env_id
allow_password_signup = false
enable_email_link_signin = false
}

resource "google_identity_platform_tenant_default_supported_idp_config" "github_idp_config" {
provider = google.internal_project
enabled = true
tenant = google_identity_platform_tenant.tenant.name
idp_id = "github.com"
client_id = local.gh_client_id
client_secret = local.gh_client_secret
}
18 changes: 18 additions & 0 deletions infra/auth/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


output "tenant_id" {
value = google_identity_platform_tenant.tenant.name
}
24 changes: 24 additions & 0 deletions infra/auth/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

terraform {
required_providers {
google = {
source = "hashicorp/google"
configuration_aliases = [
google.internal_project,
]
}
}
}
25 changes: 25 additions & 0 deletions infra/auth/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

variable "env_id" {
type = string
}

variable "github_config_locations" {
description = "Location of the github configuration in secret manager"
type = object({
client_id = string
client_secret = string
})
}
12 changes: 12 additions & 0 deletions infra/frontend/service.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ resource "google_cloud_run_v2_service" "service" {
name = "PROJECT_ID"
value = data.google_project.datastore_project.number
}
env {
name = "FIREBASE_APP_AUTH_DOMAIN"
value = var.firebase_settings.auth_domain
}
env {
name = "FIREBASE_APP_API_KEY"
value = var.firebase_settings.api_key
}
env {
name = "FIREBASE_AUTH_TENANT_ID"
value = var.firebase_settings.tenant_id
}
}
vpc_access {
network_interfaces {
Expand Down
8 changes: 8 additions & 0 deletions infra/frontend/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,11 @@ variable "projects" {
variable "deletion_protection" {
type = bool
}

variable "firebase_settings" {
type = object({
auth_domain = string
api_key = string
tenant_id = string
})
}
23 changes: 23 additions & 0 deletions infra/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.

locals {
firebase_api_key = sensitive(data.google_secret_manager_secret_version_access.firebase_api_key.secret_data)
}

data "google_secret_manager_secret_version_access" "firebase_api_key" {
provider = google.internal_project
secret = var.firebase_api_key_location
}

module "auth" {
source = "./auth"
providers = {
google.internal_project = google.internal_project
}
env_id = var.env_id
github_config_locations = var.auth_github_config_locations
}

module "services" {
source = "./services"
providers = {
Expand Down Expand Up @@ -118,4 +136,9 @@ module "frontend" {
ssl_certificates = var.ssl_certificates
domains_for_gcp_managed_certificates = var.frontend_domains_for_gcp_managed_certificates
projects = var.projects
firebase_settings = {
api_key = local.firebase_api_key
auth_domain = "${var.projects.internal}.firebaseapp.com"
tenant_id = module.auth.tenant_id
}
}
5 changes: 4 additions & 1 deletion infra/providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ provider "google" {
provider "google" {
alias = "internal_project"
project = var.projects.internal
# Need user_project_override=true for identity platform
# https://stackoverflow.com/a/78203631
user_project_override = true
}

provider "google" {
Expand All @@ -46,4 +49,4 @@ provider "docker" {
address = module.storage.docker_repository_details.hostname
config_file = pathexpand("~/.docker/config.json")
}
}
}
14 changes: 14 additions & 0 deletions infra/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,17 @@ variable "chromium_region_schedules" {
variable "web_features_region_schedules" {
type = map(string)
}


variable "firebase_api_key_location" {
description = "Location of the firebase api key in secret manager"
type = string
}

variable "auth_github_config_locations" {
description = "Location of the github configuration in secret manager"
type = object({
client_id = string
client_secret = string
})
}