Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3a12e05
chore: update bootstrap.sh to fix npm permissions and skip oauth for …
eric-lyons Jun 12, 2026
308aa5e
fix: TFVARS_FILE_PATH scope issue in bootstrap.sh
eric-lyons Jun 12, 2026
c935027
fix: update lock files to resolve Cloud Build dependency errors
eric-lyons Jun 12, 2026
1011108
fix: remove storeAuthStateInCookie from msal cache config to fix TS e…
eric-lyons Jun 12, 2026
595b9d9
fix(auth): switch from loginPopup to loginRedirect
eric-lyons Jun 12, 2026
1327b86
fix(auth): allow personal MS accounts issuer
eric-lyons Jun 12, 2026
aadbf6f
fix(auth): fix MSAL redirect hash being stripped by angular router an…
eric-lyons Jun 12, 2026
673e0c1
fix(auth): fix typescript compile error in auth.guard.service.ts
eric-lyons Jun 12, 2026
5057eb5
fix(auth): capture initial window hash before Angular router strips i…
eric-lyons Jun 12, 2026
018d47f
chore(auth): add default entra substitutions to cloudbuild to enable …
eric-lyons Jun 12, 2026
456929c
fix(auth): restore window location hash manually instead of passing a…
eric-lyons Jun 12, 2026
3dd5529
fix(auth): disable navigateToLoginRequestUrl in MSAL and auto-redirec…
eric-lyons Jun 12, 2026
6c06c1f
fix(auth): robustly fallback to Google login if Entra client ID is mi…
eric-lyons Jun 12, 2026
0e395fb
fix(auth): remove navigateToLoginRequestUrl config option which was r…
eric-lyons Jun 12, 2026
6b2a919
chore(auth): add on-screen debug logs for MSAL redirect flow
eric-lyons Jun 12, 2026
3714292
fix(auth): disable navigateToLoginRequestUrl to prevent MSAL from wip…
eric-lyons Jun 12, 2026
cc4bae1
fix(auth): bypass msal v3 TS compiler strictness for navigateToLoginR…
eric-lyons Jun 12, 2026
12466cc
fix(auth): bypass Cloud Run IAM proxy blocking Entra token
eric-lyons Jun 12, 2026
d86422f
fix(auth): update entra authentication flow to use X-Custom-Auth and …
eric-lyons Jun 13, 2026
42c04f8
chore(security): migrate entra configuration to secret manager
eric-lyons Jun 13, 2026
c1e3b99
feat(auth): migrate token storage to secure httponly cookies
eric-lyons Jun 13, 2026
0fa5642
feat: migrate backend authentication to Workforce Identity Federation…
eric-lyons Jun 24, 2026
c56de35
feat: migrate infra to use iap expected audience instead of entra
eric-lyons Jun 24, 2026
e61e3d0
Configure Frontend on Cloud Run same-origin behind IAP Load Balancer
eric-lyons Jun 24, 2026
121568c
Fix frontend build configuration to use production settings
eric-lyons Jun 24, 2026
a138d53
Fix AuthInterceptor to send credentials on absolute backend URLs
eric-lyons Jun 24, 2026
5c8401e
feat: auto check IAP session on login page init
eric-lyons Jun 24, 2026
a5780a7
fix: reload window on expired IAP session to trigger login redirect
eric-lyons Jun 24, 2026
f7a74b4
fix: resolve clonability audit, fix IAP loop, add example env files a…
eric-lyons Jun 24, 2026
e270e0b
fix(auth): fix IAP redirect loop and update WIF email mapping fallback
eric-lyons Jun 24, 2026
0ae3d7d
feat(auth): support Entra ID claims fallback in IAP and automate Entr…
eric-lyons Jun 25, 2026
d9bfedb
docs: add Microsoft Entra ID deployment and configuration guide
eric-lyons Jun 25, 2026
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
6 changes: 4 additions & 2 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ Before you begin, ensure you have the following tools installed on your system:

## 3. Add env variables to repo where we’ll work

You can connect to your new GCP Argolis Account by setting a `backend/.env` file for the backend and a `frontend/src/environments/development.environment.ts` file for the frontend.
You can connect to your new GCP Argolis Account by setting a `backend/.env` file for the backend and a `frontend/src/environments/environment.development.ts` file for the frontend.

Copy the template from `frontend/src/environments/environment.development.ts.example` to `frontend/src/environments/environment.development.ts` and modify it.

> **Important!!!** set `isLocal = True`, in both frontend and backend, this is so that instead of loggin in with Identity Platform, we login with Firebase, and we keep Identity Platform Authorized Javascript origins clean, without the need to whitelist localhost.

Expand Down Expand Up @@ -62,7 +64,7 @@ ADMIN_USER_EMAIL="your-user-email"
> - **Safe Experimentation**: Clear volume bindings locally without risking production states or accidental cloud data drops.
> - **Instant Migrations Validation**: Speed runs Alembic updates completely isolated and offline.

### `frontend/src/environments/development.environment.ts` file
### `frontend/src/environments/environment.development.ts` file

```typescript
export const environment = {
Expand Down
2 changes: 1 addition & 1 deletion GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ To maintain a pristine codebase, AI Agents **MUST** follow these rules:
10. **Seniority**: Act as a Senior Software Engineer with 10+ years of experience in software development.
11. **Code Review**: Always review the code before finishing execution, if it fails, fix it and run the pre-commit hook again.
12. **Security**: Always review the code for security vulnerabilities and fix them if found.
13. **Isolation**: Always work in isolation, do not modify files outside the scope of the task. Work with docker containers, do not run any gcloud commands locally nor modify any cloud resources.
13. **Isolation**: Always work in isolation, do not modify files outside the scope of the task. Work with docker containers, do not run any gcloud commands locally nor modify any cloud resources without permission.

---
121 changes: 121 additions & 0 deletions README_ENTRA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Google Cloud Creative Studio: Deployment & Entra ID Setup Guide

This guide provides step-by-step instructions for cloning, configuring, and deploying the Google Cloud Creative Studio Platform to Google Cloud Platform (GCP) with authentication backed by Microsoft Entra ID (formerly Azure Active Directory) via Workforce Identity Federation and IAP.

---

## 📋 Prerequisites

Before you begin, ensure you have the following installed and configured:
* **Git**: For cloning the repository.
* **Google Cloud CLI (`gcloud`)**: Authenticated to your GCP account.
* **Terraform**: Version 1.5.0 or later (if running manually, though the bootstrap script handles execution).
* **An active GCP Project** (referred to as `[PROJECT_NAME]` in this guide).
* **Owner permissions** on the GCP Project.
* **Administrator access** to a Microsoft Entra ID Tenant (to create App Registrations).

---

## 🛠️ Step 1: Clone the Repository

Clone the repository and checkout the latest branch containing the IAP and Entra integration changes.

1. Open your terminal.
2. Clone the repository:
```bash
git clone https://github.com/eric-lyons/gcc-creative-studio.git
cd gcc-creative-studio
```
3. Switch to the integration branch:
```bash
git checkout feature/iap-workforce-auth
```

---

## 🔑 Step 2: Configure Microsoft Entra ID (Azure AD)

You need to register the Creative Studio application in your Microsoft Entra Tenant to obtain the client credentials needed for authentication.

### 1. Create App Registration
1. Sign in to the [Microsoft Entra admin center](https://entra.microsoft.com/) as at least an Application Administrator.
2. Browse to **Identity** > **Applications** > **App registrations** and select **New registration**.
3. Enter a name for the application (e.g., `Creative Studio Dev`).
4. Under **Supported account types**, select **Accounts in this organizational directory only (Single tenant)**.
5. Under **Redirect URI**, select **Single-page application (SPA)** (for MSAL frontend login) and enter the URL where the app will be hosted:
* For local testing: `http://localhost:4200/`
* For deployed app: `https://[YOUR_DOMAIN_OR_IP]/` (or your custom domain).
* *Note: You can add multiple redirect URIs later.*
6. Select **Register**.

### 2. Collect Client and Tenant IDs
1. After registration, you will be redirected to the App's **Overview** page.
2. Copy the following values and save them:
* **Application (client) ID**
* **Directory (tenant) ID**

### 3. Generate Client Secret
1. In the left navigation panel, select **Certificates & secrets** > **Client secrets** > **New client secret**.
2. Add a description (e.g., `Creative Studio GCP Deployment`) and select an expiration period.
3. Select **Add**.
4. **CRITICAL**: Copy the **Value** of the secret immediately. It will be hidden permanently once you navigate away from this page.

### 4. Enable ID Token Issuance (for IAP / WIF)
1. Select **Authentication** in the left panel.
2. Under **Implicit grant and hybrid flows**, ensure **ID tokens (used for implicit and hybrid flows)** is **checked**.
3. Select **Save**.

---

## 🚀 Step 3: Deploy to Google Cloud Platform (GCP)

The project includes an automated `bootstrap.sh` script that handles the configuration of Terraform variables, GCP Secret Manager initialization, and deployment.

1. Initialize your Google Cloud application default credentials:
```bash
gcloud auth application-default login
```
2. Make the bootstrap script executable:
```bash
chmod +x bootstrap.sh
```
3. Run the bootstrap script:
```bash
./bootstrap.sh
```
4. Follow the interactive prompts:
* **GCP Project ID**: Enter `[PROJECT_NAME]`.
* **Environment**: Select `development`.
* **Authentication Choice**: Select **(2) Microsoft Entra ID**.
* **Entra Client ID**: Paste the *Application (client) ID* collected in Step 2.
* **Entra Tenant ID**: Paste the *Directory (tenant) ID* collected in Step 2.
* **Entra Client Secret**: Paste the *Client Secret Value* collected in Step 2.
* **Domain Name**: Enter your domain (e.g., `[YOUR_DOMAIN_OR_IP]` or your custom domain).
* **GCP Organization ID**: Enter your GCP Organization numerical ID (required for Workforce Pools).

The script will automatically update the `infra/environments/development/development.tfvars` file, create the necessary secrets in GCP Secret Manager, and trigger the Terraform execution to deploy all resources (Cloud Run, Cloud SQL, IAP, GCS, etc.).

---

## 🌐 Step 4: Add a Custom Domain

To configure a custom domain instead of using the default IP-based hostname:

### 1. Identify the Load Balancer IP
Once the Terraform deployment finishes successfully, it will output the external IP address of the Global Load Balancer created for IAP. You can also find it in the console:
1. Go to **Network Services** > **Load Balancing** in the GCP Console.
2. Select the load balancer created for your deployment (typically named `cstudio-lb-development` or similar).
3. Locate the Frontend IP address.

### 2. Configure DNS
1. Log in to your Domain Registrar (e.g., Google Domains, GoDaddy, Cloudflare).
2. Navigate to the DNS management panel for your custom domain.
3. Create an **A Record**:
* **Host/Name**: `@` (for root domain) or `studio` (for a subdomain like `studio.yourdomain.com`).
* **Value/Points to**: The Frontend IP address of the GCP Load Balancer identified above.
* **TTL**: Default (e.g., 3600 seconds).

### 3. Update the App Configurations
Once DNS propagates, you must update the application to recognize the new domain:
1. Re-run `./bootstrap.sh` and provide your new custom domain (e.g. `studio.yourdomain.com`) when prompted. This updates Terraform and regenerates the SSL certificate for the Load Balancer.
2. Update your Microsoft Entra App Registration (Step 2) to include `https://studio.yourdomain.com/` as an allowed **Redirect URI**.
164 changes: 164 additions & 0 deletions README_IAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Securing and Deploying with Identity-Aware Proxy (IAP) & Microsoft Entra ID

This guide explains how to secure and deploy the **Google Cloud Creative Studio Platform** in a Google Cloud project using **Identity-Aware Proxy (IAP)** federated with **Microsoft Entra ID (Azure AD)** via **Workforce Identity Federation (WIF)**.

---

## Architecture Overview
By securing the application with IAP and Workforce Identity Federation, you completely avoid having to provision or sync user identity accounts into Google Cloud.

1. An external user attempts to access the HTTPS Load Balancer domain.
2. IAP intercepts the request and checks for authentication.
3. If unauthenticated, IAP redirects the user to Google's Workforce Identity sign-in portal.
4. The sign-in portal redirects the user to your organization's Microsoft Entra ID sign-in page.
5. Upon successful Entra ID authentication, the user is redirected back to Google IAP and authorized based on IAM policy.

---

## Prerequisites
Before beginning the deployment, ensure you have the following:

### 1. Google Cloud Platform (GCP)
* A **GCP Organization** (Workforce Identity Pools cannot be created in standalone projects).
* Your GCP **Organization ID** (numeric). You can find this by running:
```bash
gcloud organizations list
```
* A target **GCP Project** inside that organization.
* The **Workforce Pool Admin** (`roles/iam.workforcePoolAdmin`) role granted to your GCP user account at the **Organization level**.

### 2. Microsoft Entra ID (Azure AD)
* An active Microsoft Entra tenant.
* Access to the Azure Portal with permissions to create **App Registrations**.

---

## Step-by-Step Setup Guide

### Step 1: Microsoft Entra ID App Registration
1. Log in to the [Azure Portal](https://portal.azure.com/).
2. Navigate to **Microsoft Entra ID** (or **Azure Active Directory**).
3. In the left navigation, select **App registrations** > **New registration**.
4. Configure the app registration:
* **Name**: e.g., `GCP Workforce Identity Client`
* **Supported account types**: Select "Accounts in this organizational directory only" (Single Tenant).
* **Redirect URI (optional)**: Select **Web** and add the following global Google sign-in callback URL:
```
https://auth.cloud.google/signin-callback/locations/global/workforcePools/cs-workforce-pool/providers/entra-provider
```
*(Note: If you change the Workforce Pool ID or Provider ID, update the path accordingly: `/workforcePools/<POOL_ID>/providers/<PROVIDER_ID>`).*

5. Click **Register**.
6. On the application Overview page, copy and save these values:
* **Application (client) ID**
* **Directory (tenant) ID**
7. Navigate to **Certificates & secrets** in the left menu.
8. Under the **Client secrets** tab, click **New client secret**.
9. Add a description, choose an expiration period, and click **Add**.
10. Copy and save the secret **Value** (do not copy the Secret ID). *Note: This value is only shown once upon creation, so save it immediately.*


---

### Step 2: Create a Google Workforce OAuth Client for IAP
Standard Google Accounts OAuth clients cannot be used with Workforce Identity Federation. Instead, you must create a dedicated Workforce Identity OAuth Client using the `gcloud` CLI.

1. Run the following command to create the global Workforce OAuth client (replace `YOUR_PROJECT_ID` with your GCP project ID):
```bash
gcloud iam oauth-clients create cs-wif-oauth-client \
--project=YOUR_PROJECT_ID \
--location=global \
--client-type="confidential-client" \
--display-name="Creative Studio IAP WIF Client" \
--allowed-grant-types="authorization-code-grant" \
--allowed-scopes="openid,email,https://www.googleapis.com/auth/cloud-platform" \
--allowed-redirect-uris="https://example.com/callback"

```
2. Describe the newly created client to retrieve the system-generated **Client ID**:
```bash
gcloud iam oauth-clients describe cs-wif-oauth-client \
--project=YOUR_PROJECT_ID \
--location=global
```
*Copy the **`clientId`** value from the output (it will look like a UUID, e.g., `ae1b3ac35-542f-4a97-b7ac-be4fb6160c2e`).*

3. Update the OAuth client's redirect URI to use its own generated Client ID redirect handler:
```bash
gcloud iam oauth-clients update cs-wif-oauth-client \
--project=YOUR_PROJECT_ID \
--location=global \
--allowed-redirect-uris="https://iap.googleapis.com/v1/oauth/clientIds/YOUR_GENERATED_CLIENT_ID:handleRedirect"
```
*(Replace `YOUR_GENERATED_CLIENT_ID` with the Client ID copied in the previous step).*

4. Generate the Client Secret for this Workforce client:
```bash
gcloud iam oauth-clients credentials create cs-wif-oauth-credential \
--oauth-client=cs-wif-oauth-client \
--project=YOUR_PROJECT_ID \
--location=global
```
5. Retrieve and save the generated **Client Secret**:
```bash
gcloud iam oauth-clients credentials describe cs-wif-oauth-credential \
--oauth-client=cs-wif-oauth-client \
--project=YOUR_PROJECT_ID \
--location=global
```
*Copy the **`clientSecret`** value from the output (it will look like a Google secret key starting with `GOCSPX-`).*


---

### Step 3: Populate Terraform Configuration (`dev-infra.tfvars`)
To enable WIF and IAP, configure these variables in your target environment's `.tfvars` file (e.g., `infra/environments/dev-infra/dev-infra.tfvars`):

```hcl
# --- IAP Credentials ---
iap_oauth2_client_id = "YOUR_GOOGLE_CLIENT_ID"
iap_oauth2_client_secret = "YOUR_GOOGLE_CLIENT_SECRET"
domain_name = "YOUR_DOMAIN_NAME" # (e.g., "creative.yourcompany.com" or "8.8.8.8.nip.io")

# --- Workforce Identity Federation (WIF) ---
org_id = "YOUR_GCP_ORGANIZATION_ID_NUMERIC"
entra_client_id = "YOUR_MICROSOFT_ENTRA_CLIENT_ID"
entra_tenant_id = "YOUR_MICROSOFT_ENTRA_TENANT_ID"
entra_client_secret = "YOUR_MICROSOFT_ENTRA_CLIENT_SECRET"

# --- Authorization Access Rules ---

# You can authorize individual Entra ID users, entire domains, or all users in the pool.
# Use wildcard '*' to allow any user authenticated via the Workforce pool to access the application:
iap_access_members = [
"principalSet://iam.googleapis.com/locations/global/workforcePools/cs-workforce-pool/*"
]
```

---

### Step 4: Deploy using Terraform
Initialize and apply the Terraform configuration inside your environment directory:
```bash
# Initialize Terraform
terraform init

# Apply the infrastructure configuration
terraform apply -var-file=dev-infra.tfvars
```
Terraform will automatically:
1. Create a Workforce Identity Pool (`cs-workforce-pool`).
2. Register Microsoft Entra ID as the OIDC provider inside the pool.
3. Configure the HTTP Load Balancer with Managed SSL Certificates.
4. Enable IAP on the Load Balancer's backend and associate it with the Workforce pool.
5. Create the IAM bindings granting access to the workforce principals.

---

### Step 5: Test and Access the App
1. Wait 5-10 minutes for your SSL certificates and Load Balancer to propagate globally.
2. Navigate to your domain in the browser (e.g., `https://YOUR_DOMAIN_NAME`).
3. You will be redirected to Google's Workforce Single Sign-On page.
4. Select your identity provider or log in. It will redirect you to Microsoft Entra's sign-in screen.
5. Enter your corporate email and password.
6. Once authenticated, Entra will redirect you back to Google IAP, and IAP will let you access Creative Studio!
10 changes: 4 additions & 6 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# syntax=docker/dockerfile:1.4
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -25,16 +26,13 @@ ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy

# Install the project's dependencies using the lockfile and settings
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project --no-dev
COPY uv.lock pyproject.toml /app/
RUN uv sync --locked --no-install-project --no-dev

# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev
RUN uv sync --locked --no-dev

# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
Expand Down
4 changes: 3 additions & 1 deletion backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
from src.system_settings.system_settings_controller import (
router as system_settings_router,
)
from src.auth.auth_controller import router as auth_router


def configure_cors(app):
Expand All @@ -84,7 +85,7 @@ def configure_cors(app):
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
allow_credentials=environment == "production",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Expand Down Expand Up @@ -185,3 +186,4 @@ def version():
app.include_router(workflows_executor_router)
app.include_router(workbench_router)
app.include_router(system_settings_router)
app.include_router(auth_router)
2 changes: 2 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ dependencies = [
"google-cloud-workflows>=1.19.0",
"google-api-python-client>=2.187.0",
"httpx>=0.27.0",
"pyjwt>=2.8.0",
"cryptography>=42.0.0",
]

[project.optional-dependencies]
Expand Down
Loading
Loading