This package is a backend to serve ATIP on App Engine. See architecture for details. It's a separate package from the ATIP frontend in the rest of this repo, and could logically be split into a separate git repo if useful.
This section is a WIP right now; only use the result for testing! Don't upload any non-public data yet.
Unless other specified, each command below should only take a few seconds to run.
Note the URLs won't work; you have to manually replace $PROJECT
.
- Install gcloud
- Hook up gcloud to your GCP account
- Pick a project ID (which'll also be used as the GCS bucket name) and set it as a shell variable:
PROJECT=atip-test-2
- Create it:
gcloud projects create $PROJECT
- Manually link the billing account: https://console.cloud.google.com/billing/linkedaccount?project=$PROJECT
- You may need to configure a billing account first for your GCP account
- Without this,
gcloud app --project=$PROJECT describe
gives a permissions error
- Set up App Engine:
gcloud app --project=$PROJECT create --region=europe-west
- Note there's only one GAE app per project, unlike most other GCP services
- And the region is immutable once you set it for the project!
Names and regions should match above.
gcloud storage --project=$PROJECT buckets create gs://$PROJECT --location=EUROPE-WEST2 --uniform-bucket-level-access
- Generate fake scheme data and upload it:
npm run generate-random-schemes && gsutil cp random_schemes.geojson gs://$PROJECT/private_layers/v1/
- Sync current public layers to GCS. This only works if you have S3 access (aka Dustin). Skip these otherwise, or download another way. This might take a few minutes, depending on your connection:
aws s3 sync s3://atip.uk/layers layers; gsutil -m cp -r ./layers gs://$PROJECT/
- Also copy private files (currently only from Ordnance Survey) into
gs://$PROJECT/private_layers/v1/
. These have to be generated by a developer; they can't be mirrored from S3, because our S3 bucket is only appropriate for public data. - Go to https://osdatahub.os.uk/projects/ATIP_scheme_browser (or enable the OS Maps API in a new project) and copy the API key. Also get a Bluesky APGB key. Create a file
api_keys.json
containing{"ordnance_survey": "the key", "bluesky": "the key"}
, and upload it to the GCS bucket atgs://$PROJECT/private_layers/api_keys.json
.
- Create
backend/app.yaml
by copying e.g.backend/app_public_dev.yaml
and setting the values according to your own project - Run
gcloud projects describe $PROJECT | grep projectNumber
and use the result to updatePROJECT_NUMBER
inbackend/app.yaml
- Set a env var for the vite resource base url, this depends if you're deploying to internal or public version. If public
BASE_URL=https://{env.}plan.activetravelengland.gov.uk
. If the internal version thenBASE_URL=https://$PROJECT.ew.r.appspot.com
. - Create the files to deploy:
VITE_RESOURCE_BASE="$BASE_URL/data" npm run build && cd backend && rm -rf dist && cp -R ../dist .
- Note we could make Cloud Build do this, but we'd have to get
wasm-pack
and other things set up there first - GH Actions will eventually trigger CI deployments for our test environment, and we've already done the work of configuring that build environment
- Note we could make Cloud Build do this, but we'd have to get
gcloud app --project=$PROJECT deploy --quiet
(takes a minute or two)- Try the result:
gcloud app browse --project=$PROJECT
or https://$PROJECT.ew.r.appspot.com/browse.html
Useful debugging:
- https://console.cloud.google.com/cloud-build/builds;region=europe-west1?project=$PROJECT
gcloud app --project=$PROJECT logs read
gcloud services --project=$PROJECT enable iap.googleapis.com
gcloud services --project=$PROJECT enable cloudresourcemanager.googleapis.com
- Go to https://console.cloud.google.com/apis/credentials/consent?project=$PROJECT and manually configure the oauth consent screen
- Choose "External" (unless everyone internal can be part of our cloud org?)
- Pick an app name, email
- No logo, app domains, authorized domains, scopes, or test users
- Go to https://console.cloud.google.com/security/iap?project=$PROJECT and enable IAP (it'll have an oauth misconfigured error)
Nobody should have access by default. To get the current auth list:
gcloud iap --project=$PROJECT web get-iam-policy --resource-type=app-engine
To add someone:
gcloud iap --project=$PROJECT web add-iam-policy-binding --resource-type=app-engine --member=user:foo@bar.com --role=roles/iap.httpsResourceAccessor
After changing this, there's seemingly a propagation delay of about a minute. You might also need to Ctrl+Shift+R or clear your browser cache.
For the test environment, we can automatically deploy App Engine for every push to the main
branch of the Github repo. One-time setup steps to create a service account with permission to deploy, and a service account JSON key:
gcloud services --project=$PROJECT enable appengine.googleapis.com
gcloud iam service-accounts --project=$PROJECT create gh-builder-service-account
# See https://github.com/google-github-actions/deploy-appengine for reference
for role in roles/appengine.appAdmin roles/storage.admin roles/cloudbuild.builds.editor roles/iam.serviceAccountUser; do
gcloud projects add-iam-policy-binding $PROJECT --member="serviceAccount:gh-builder-v2@$PROJECT.iam.gserviceaccount.com" --role=$role;
done
gcloud iam service-accounts keys create private_key --iam-account=gh-builder-v2@$PROJECT.iam.gserviceaccount.com
You then need to set the GCP_DEV_CREDENTIALS
secret in Github. Go to https://github.com/acteng/atip/settings/secrets/actions and create/edit it as needed. The contents are the private_key
file created by the last command, but you need to format it as a one-liner. If you have jq, you can just do
cat private_key | jq - c` and copy that.
Remove the private_key file after creating the Github secret, and make sure it's never made public
- Automated setup
- Terraform
- Oauth consent screen setup? https://issuetracker.google.com/issues/35907249?pli=1
- Automate IAP setup?
gcloud iap --project=$PROJECT web enable --resource-type=app-engine
needs some unknown oauth client ID/secret
- In the real project
- Publish the GAE app
- Optimize bucket location for serving
- Enable audit logs
- Go to https://console.cloud.google.com/iam-admin/audit?project=$PROJECT, "Cloud Identity-Aware Proxy API", enable all 3.
- Consider using the default storage bucket with GAE, even though we don't need/want write permissions
- Detect the logged-in user
- Set up GH actions CI with (only to a test project; we never want to do this for prod)
- Fix CORS errors that happen with IAP
Unblocked by this: - More basemaps - Load criticals and scheme data - Regional engagement contact list
- For completeness, other options to serve GCS files:
- ideally: some direct GCS URL that enforces the same IAP auth
- some LB in front of GCS, then glued to IAP
- make Express proxy the requests to GCS
- add the GAE service account as a storage.objectViewer on the bucket first
- insecure worst case: public bucket with an obfuscated URL
- signed URLs
- cookie based auth
- Consider using the GAE default bucket?