diff --git a/Makefile b/Makefile index ca43a2a0..d377bd1d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # It is designed to be the main entry point for developers. # Use .PHONY to declare targets that are not files, to avoid conflicts. -.PHONY: help install dev build integrate-export prepare-export deploy-launchpad deploy-launchpad-full deploy-app admin-install admin-dev admin-build admin-deploy-dev admin-deploy-staging configure-iap-launchpad list-iap-users remove-iap-user setup-labels export-issues create-issues-from-file install-git-hooks +.PHONY: help install dev build integrate-export prepare-export deploy-launchpad deploy-launchpad-full deploy-app admin-install admin-dev admin-build deploy-admin deploy-admin-full configure-iap-launchpad configure-iap-admin list-iap-users remove-iap-user setup-labels export-issues create-issues-from-file install-git-hooks # The default command to run if no target is specified (e.g., just 'make'). .DEFAULT_GOAL := help @@ -19,8 +19,13 @@ CR_LAUNCHPAD_SERVICE_NAME := internal-launchpad CR_LAUNCHPAD_REGION := us-central1 CR_LAUNCHPAD_IMAGE_URI := us-docker.pkg.dev/$(GCP_DEV_PROJECT_ID)/gcr-io/$(CR_LAUNCHPAD_SERVICE_NAME) +CR_ADMIN_SERVICE_NAME := admin-console +CR_ADMIN_REGION := us-central1 +CR_ADMIN_IMAGE_URI := us-docker.pkg.dev/$(GCP_PROJECT_ID)/gcr-io/$(CR_ADMIN_SERVICE_NAME) + # --- Environment Detection --- ENV ?= dev +SERVICE ?= launchpad # Default service for IAP commands: 'launchpad' or 'admin' # --- Conditional Variables by Environment --- ifeq ($(ENV),staging) @@ -33,6 +38,18 @@ else HOSTING_TARGET := app-dev endif +# --- Conditional Variables by Service for IAP commands --- +ifeq ($(SERVICE),admin) + IAP_SERVICE_NAME := $(CR_ADMIN_SERVICE_NAME) + IAP_SERVICE_REGION := $(CR_ADMIN_REGION) + IAP_PROJECT_ID := $(GCP_PROJECT_ID) # Admin console is env-specific +else + IAP_SERVICE_NAME := $(CR_LAUNCHPAD_SERVICE_NAME) + IAP_SERVICE_REGION := $(CR_LAUNCHPAD_REGION) + IAP_PROJECT_ID := $(GCP_DEV_PROJECT_ID) # Launchpad is dev-only +endif + + # Shows this help message. help: @echo "--------------------------------------------------" @@ -45,16 +62,13 @@ help: @echo " make build - Builds the web frontend for production." @echo "" @echo " --- DEPLOYMENT ---" - @echo " make deploy-launchpad - Deploys the internal launchpad to Cloud Run." - @echo " make deploy-launchpad-full - Deploys launchpad to Cloud Run & configures IAP." - @echo " make deploy-app [ENV=staging] - Builds and deploys the main web app (default: dev)." - @echo " make admin-deploy-dev - Builds and deploys the admin web app to the DEV environment (App Engine)." - @echo " make admin-deploy-staging - Builds and deploys the admin web app to the STAGING environment (App Engine)." + @echo " make deploy-launchpad-full - Deploys internal launchpad to Cloud Run (dev only) with IAP." + @echo " make deploy-admin-full [ENV=staging] - Deploys Admin Console to Cloud Run with IAP (default: dev)." + @echo " make deploy-app [ENV=staging] - Builds and deploys the main web app via Firebase Hosting (default: dev)." @echo "" - @echo " --- CLOUD IAP (for Cloud Run Launchpad) ---" - @echo " make configure-iap-launchpad - Adds users from iap-users.txt as IAP-secured Web App Users and grants IAP Service Account Cloud Run Invoker role." - @echo " make list-iap-users - Lists all users with IAP-secured Web App User role." - @echo " make remove-iap-user USER=user:email@example.com - Removes the IAP-secured Web App User role from a user." + @echo " --- CLOUD IAP MANAGEMENT ---" + @echo " make list-iap-users [SERVICE=admin] - Lists IAP users for a service (default: launchpad)." + @echo " make remove-iap-user USER=... [SERVICE=admin] - Removes an IAP user from a service." @echo "" @echo " --- PROJECT MANAGEMENT & TOOLS ---" @echo " make setup-labels - Creates/updates GitHub labels from labels.yml." @@ -125,19 +139,33 @@ admin-build: @echo "--> Building admin console for production..." @cd admin-web && VITE_APP_ENV=$(ENV) npm run build -admin-deploy-dev: admin-build - @echo "--> Deploying Admin Web App to DEV environment (App Engine)..." - @cd admin-web && gcloud app deploy app.dev.yaml --project=$(GCP_DEV_PROJECT_ID) +deploy-admin: admin-build + @echo "--> Building and deploying Admin Console to Cloud Run [$(ENV)]..." + @echo " - Step 1: Building container image..." + @cd admin-web && gcloud builds submit \ + --tag $(CR_ADMIN_IMAGE_URI) \ + --project=$(GCP_PROJECT_ID) + @echo " - Step 2: Deploying to Cloud Run..." + @gcloud run deploy $(CR_ADMIN_SERVICE_NAME) \ + --image $(CR_ADMIN_IMAGE_URI) \ + --platform managed \ + --region $(CR_ADMIN_REGION) \ + --no-allow-unauthenticated \ + --project=$(GCP_PROJECT_ID) + @echo " - Step 3: Enabling IAP on the service..." + @gcloud beta run services update $(CR_ADMIN_SERVICE_NAME) \ + --region=$(CR_ADMIN_REGION) \ + --project=$(GCP_PROJECT_ID) \ + --iap + @echo "--> ✅ Admin Console deployment to Cloud Run successful." + +deploy-admin-full: deploy-admin configure-iap-admin + @echo "✅ Admin Console deployed and IAP configured successfully!" -admin-deploy-staging: admin-build - @echo "--> Deploying Admin Web App to STAGING environment (App Engine)..." - @cd admin-web && gcloud app deploy app.staging.yaml --project=$(GCP_STAGING_PROJECT_ID) # --- Cloud IAP Configuration --- -# NOTE: These commands use the 'gcloud beta iap web' command set, which is the correct -# method for managing user access to an IAP-protected Cloud Run service. configure-iap-launchpad: - @echo "--> Configuring IAP users for Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)]..." + @echo "--> Configuring IAP for Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)]..." @echo " - Granting Cloud Run Invoker role to IAP Service Account..." @gcloud run services add-iam-policy-binding $(CR_LAUNCHPAD_SERVICE_NAME) \ --region=$(CR_LAUNCHPAD_REGION) \ @@ -158,46 +186,56 @@ configure-iap-launchpad: --role='roles/iap.httpsResourceAccessor' \ --quiet; \ done - @echo "✅ IAP user configuration complete." + @echo "✅ IAP configuration for Launchpad complete." + +configure-iap-admin: + @echo "--> Configuring IAP for Cloud Run service [$(CR_ADMIN_SERVICE_NAME)] in [$(ENV)]..." + @echo " - Granting Cloud Run Invoker role to IAP Service Account..." + @gcloud run services add-iam-policy-binding $(CR_ADMIN_SERVICE_NAME) \ + --region=$(CR_ADMIN_REGION) \ + --project=$(GCP_PROJECT_ID) \ + --member="serviceAccount:$(IAP_SERVICE_ACCOUNT)" \ + --role='roles/run.invoker' \ + --quiet + @echo " - Adding users from iap-users.txt..." + @cd admin-web && \ + grep -v '^#' iap-users.txt | grep -v '^$$' | while read -r member; do \ + echo " Adding $$member as IAP-secured Web App User..."; \ + gcloud beta iap web add-iam-policy-binding \ + --project=$(GCP_PROJECT_ID) \ + --resource-type=cloud-run \ + --service=$(CR_ADMIN_SERVICE_NAME) \ + --region=$(CR_ADMIN_REGION) \ + --member="$$member" \ + --role='roles/iap.httpsResourceAccessor' \ + --quiet; \ + done + @echo "✅ IAP configuration for Admin Console complete." list-iap-users: - @echo "--> Current IAP users for Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)]:" + @echo "--> Current IAP users for Cloud Run service [$(IAP_SERVICE_NAME)]:" @gcloud beta iap web get-iam-policy \ - --project=$(GCP_DEV_PROJECT_ID) \ + --project=$(IAP_PROJECT_ID) \ --resource-type=cloud-run \ - --service=$(CR_LAUNCHPAD_SERVICE_NAME) \ - --region=$(CR_LAUNCHPAD_REGION) + --service=$(IAP_SERVICE_NAME) \ + --region=$(IAP_SERVICE_REGION) remove-iap-user: @if [ -z "$(USER)" ]; then \ echo "❌ Error: Please specify USER=user:email@example.com"; \ exit 1; \ fi - @echo "--> Removing IAP access for $(USER) from Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)]..." + @echo "--> Removing IAP access for $(USER) from Cloud Run service [$(IAP_SERVICE_NAME)]..." @gcloud beta iap web remove-iam-policy-binding \ - --project=$(GCP_DEV_PROJECT_ID) \ + --project=$(IAP_PROJECT_ID) \ --resource-type=cloud-run \ - --service=$(CR_LAUNCHPAD_SERVICE_NAME) \ - --region=$(CR_LAUNCHPAD_REGION) \ + --service=$(IAP_SERVICE_NAME) \ + --region=$(IAP_SERVICE_REGION) \ --member="$(USER)" \ --role='roles/iap.httpsResourceAccessor' \ --quiet @echo "✅ User removed from IAP." -disable-iap-launchpad: - @echo "--> Disabling IAP and making Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)] public..." - @gcloud beta run services update $(CR_LAUNCHPAD_SERVICE_NAME) \ - --region=$(CR_LAUNCHPAD_REGION) \ - --project=$(GCP_DEV_PROJECT_ID) \ - --no-iap --quiet - @gcloud run services add-iam-policy-binding $(CR_LAUNCHPAD_SERVICE_NAME) \ - --region=$(CR_LAUNCHPAD_REGION) \ - --project=$(GCP_DEV_PROJECT_ID) \ - --member="allUsers" \ - --role='roles/run.invoker' \ - --quiet - @echo "✅ IAP disabled. The service is now public." - # --- Project Management --- setup-labels: @echo "--> Setting up GitHub labels..." diff --git a/admin-web/Dockerfile b/admin-web/Dockerfile new file mode 100644 index 00000000..2b46ff02 --- /dev/null +++ b/admin-web/Dockerfile @@ -0,0 +1,38 @@ +# STAGE 1: Build the React application +FROM node:20-alpine AS build + +WORKDIR /app + +# Copy package files and install dependencies +COPY package.json package-lock.json ./ +RUN npm install + +# Copy the rest of the application source code +COPY . . + +# Build the application for production +RUN npm run build + +# STAGE 2: Serve the static files with Nginx +FROM nginx:alpine + +# Copy the built files from the build stage +COPY --from=build /app/dist /usr/share/nginx/html + +# Copy our custom Nginx configuration +# This config is for a Single Page Application (SPA) and listens on port 8080 for Cloud Run +RUN echo 'server { + listen 8080; + server_name _; + root /usr/share/nginx/html; + index index.html; + location / { + try_files $uri $uri/ /index.html; + } +}' > /etc/nginx/conf.d/default.conf + +# Expose the port Nginx is listening on +EXPOSE 8080 + +# Command to run Nginx in the foreground +CMD ["nginx", "-g", "daemon off;"] diff --git a/admin-web/app.dev.yaml b/admin-web/app.dev.yaml deleted file mode 100644 index 93daa5fb..00000000 --- a/admin-web/app.dev.yaml +++ /dev/null @@ -1,13 +0,0 @@ -runtime: nodejs20 -service: admin-web-dev - -handlers: - # Servir les fichiers statiques (js, css, images, etc.) - - url: /(.*\.(js|css|svg|png|jpg|ico|txt))$ - static_files: dist/\1 - upload: dist/.*\.(js|css|svg|png|jpg|ico|txt)$ - - # Servir l'index.html pour toutes les autres routes (pour le routing côté client de React) - - url: /.* - static_files: dist/index.html - upload: dist/index.html \ No newline at end of file diff --git a/admin-web/app.staging.yaml b/admin-web/app.staging.yaml deleted file mode 100644 index 968c8c89..00000000 --- a/admin-web/app.staging.yaml +++ /dev/null @@ -1,13 +0,0 @@ -runtime: nodejs20 -service: admin-web-staging - -handlers: - # Servir les fichiers statiques (js, css, images, etc.) - - url: /(.*\.(js|css|svg|png|jpg|ico|txt))$ - static_files: dist/\1 - upload: dist/.*\.(js|css|svg|png|jpg|ico|txt)$ - - # Servir l'index.html pour toutes les autres routes (pour le routing côté client de React) - - url: /.* - static_files: dist/index.html - upload: dist/index.html \ No newline at end of file diff --git a/admin-web/iap-users.txt b/admin-web/iap-users.txt new file mode 100644 index 00000000..fa47fcfa --- /dev/null +++ b/admin-web/iap-users.txt @@ -0,0 +1,8 @@ +# List of authorized users for the Admin Console +# Format: one email per line, lines starting with # are comments +# +# IMPORTANT: These users must belong to the 'krowwithus.com' organization. +# This is a known limitation of enabling IAP directly on Cloud Run. +# See: https://docs.cloud.google.com/run/docs/securing/identity-aware-proxy-cloud-run#known_limitations + +user:admin@krowwithus.com diff --git a/firebase/internal-launchpad/iap-users.txt b/firebase/internal-launchpad/iap-users.txt index 50a03b87..4b166559 100644 --- a/firebase/internal-launchpad/iap-users.txt +++ b/firebase/internal-launchpad/iap-users.txt @@ -1,6 +1,9 @@ -# Liste des utilisateurs autorisés pour le Internal Launchpad -# Format: un email par ligne, les lignes commençant par # sont des commentaires +# List of authorized users for the Internal Launchpad +# Format: one email per line, lines starting with # are comments +# +# IMPORTANT: These users must belong to the 'krowwithus.com' organization. +# This is a known limitation of enabling IAP directly on Cloud Run. +# See: https://docs.cloud.google.com/run/docs/securing/identity-aware-proxy-cloud-run#known_limitations -user:boris@oloodi.com -# user:temporaire@oloodi.com # Décommenté pour donner accès temporaire -user:admin@krowwithus.com \ No newline at end of file +user:admin@krowwithus.com +# user:boris@oloodi.com # External users are not supported with this IAP method