From 72af9063e0fc6f08f377ac407ba05c622ba87b93 Mon Sep 17 00:00:00 2001 From: Erik Taubeneck Date: Mon, 10 Jun 2024 10:40:10 -0700 Subject: [PATCH] Optional local auth (#34) * make user auth optional for local dev * grammer fixes in README * more grammer fixes in README * [failsafe] block demo user outside development if added to prod database by mistake * create dummy user on the fly in development mode, remove from seed.sql * clean up error handling for local auth bypass * readme typo * readme typo --- .gitignore | 2 +- README.md | 248 ++++++++++++++++++---------------------- server/.env.development | 13 +++ server/middleware.ts | 21 ++++ 4 files changed, 144 insertions(+), 140 deletions(-) create mode 100644 server/.env.development diff --git a/.gitignore b/.gitignore index fa86c33..ca32a63 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ IGNORE-ME* .draft # local env files -.env* +.env*.local # local certs local_dev/config/cert.pem diff --git a/README.md b/README.md index e69b077..f314637 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,100 @@ # DRAFT - Distributed Relay and Automation Facilitation Tool ![image of a draft beer tap](server/public/beer-tap.png) -draft is a project designed to help test [IPA](https://github.com/private-attribution/ipa) at scale. It contains 2 components: +draft is a project designed to help test [IPA](https://github.com/private-attribution/ipa) at scale. It contains two components: -1. draft-server: a web front end and service that starts queries an displays logs from the MPC helper servers -2. draft-sidecar: a sidecar back end API that runs next to the IPA binary on helper servers. This includes a CLI for setup and running. +1. draft-server: a web front end and service that starts queries and displays logs from the MPC helper servers. +2. draft-sidecar: a sidecar backend API that runs next to the IPA binary on helper servers. This includes a CLI for setup and running. -# Get started -## Local Dev +# Get started +## Deploying a Helper Party -### Running Locally +### Requirements -Make sure the repo is cloned and you're working in the root directory of the repo: +*Instructions for AWS Linux 2023* +1. Provision an EC2 instance. Download the provided `ssh_connect.pem` key and add it to `~/.ssh`. +2. Point a subdomain of a domain you control to the public IP address. +3. Add the host to your `~/.ssh/config` file: ``` -git clone https://github.com/eriktaubeneck/draft.git -cd draft +Host ipa + Hostname + User ec2-user + IdentityFile ~/.ssh/ssh_connect.pem ``` +4. Update the `draft/ansible/inventory.ini` file to only include a single host. (Unless you are running all 4 servers.) +5. Provision your machine: `ansible-playbook -i ansible/inventory.ini ansible/provision.yaml` + +To deploy new changes in draft, run: `ansible-playbook -i ansible/inventory.ini ansible/deploy.yaml` + +### Generating TLS certs with Let's Encrypt + +You will need a domain name and TLS certificates for the sidecar to properly run over HTTPS. The following instructions assume your domain is `example.com`, please replace with the domain you'd like to use. You will need to create two subdomains, `sidecar.example.com` and `helper.example.com`. (Note, you could also use a subdomain as your base domain, e.g., `test.example.com` with two subdomains of that: `sidecar.test.example.com` and `helper.test.example.com`.) + +1. Set up DNS records for `sidecar.example.com` and `helper.example.com` pointing to a server you control. +2. Make sure you've installed the requirements above, and are using the virtual environment. +3. Install `certbot`: `pip install certbot` +4. `sudo .venv/bin/certbot certonly --standalone -m cert-renewal@example.com -d "sidecar.example.com,helper.example.com"` + 1. Note that you must point directly to `.venv/bin/certbot` as `sudo` does not operate in the virtualenv. +5. Accept the [Let's Encrypt terms](https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf). -Assuming all requirements are installed, start prerequisites: +### Make Configuration + +For this stage, you'll need to know a few things about the other parties involved: +1. Their root domain +2. Their public keys +3. Everyone's *identity* (e.g., 0, 1, 2, 3) + + +Once you know these: +1. Make a config directory `mkdir config` +2. Copy the default network config: `cp local_dev/config/network.toml config/.` +3. Update that file. + 1. Replace `helper0.draft.test` and `sidecar0.draft.test` with the respective domains for party with identity=0. + 2. Repeat for identity= 1, 2, and 3. + 3. Replace respective certificates with their public keys. +4. Move your Let's Encrypt key and cert into place: `sudo ln -s /etc/letsencrypt/live/sidecar.example.com/fullchain.pem config/cert.pem` and `sudo ln -s /etc/letsencrypt/live/sidecar.example.com/privkey.pem key.pem` +5. Generate IPA-specific keys: + 1. Compile `ipa` with `cargo build --bin helper --features="web-app real-world-infra compact-gate stall-detection multi-threading" --no-default-features --release` + 2. Make the keys with `target/release/helper keygen --name localhost --tls-key h1.key --tls-cert h1.pem --mk-public-key h1_mk.pub --mk-private-key h1_mk.key` (replace h1 with for each helper) + 3. Add the public keys content into `network.toml` + 4. Add the public keys to `config/pub` (all helpers need all helper public keys). + 4. For each helper, put their private keys in `config`. + + +### Run draft ``` -colima start -supabase start --workdir server +draft start-helper-sidecar --identity --root_domain example.com --config_path config ``` -Start `draft` for local dev: +This will start the sidecar in the background. To confirm, visit `example.com/status`. + + +## Local Dev + +`draft` provides a fully functional local development setup to work on both the frontend web interface and the sidecar. + +### Running local development + +If `draft` and the other prerequisites are already installed, run: ``` draft start-local-dev ``` -### Requirements +You can follow the logs with: +``` +draft follow-local-dev-logs +``` + +And you can view the front end at [https://draft.test](https://draft.test). + + + +### Prerequisites Requirements: 1. Python 3.11 @@ -41,7 +102,12 @@ Requirements: 3. [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) 4. Docker -#### macOS install +#### macOS install prerequisites + +```brew install python3``` +```brew install node``` +```brew install supabase/tap/supabase``` +```brew install traefik``` **Docker** @@ -51,73 +117,39 @@ There are multiple options to run Docker locally. One such option is [colima](ht ``` brew install docker brew install colima -colima start ln -sf ~/.colima/docker.sock /var/run/docker.sock ``` The `ln` at the end is because Supabase requires interacting with the local Docker API. See [this Supabase issue](https://github.com/supabase/cli/issues/153) and [this colima issue.](https://github.com/abiosoft/colima/issues/144) This likely requires `sudo`. +### Installation -**Github App** +Make sure the repo is cloned, and you're working in the root directory of the repo: -The `draft` web front end uses Github for authentication. In order to login locally, you'll need to create a new application for development. Visit [https://github.com/settings/apps/new](https://github.com/settings/apps/new) to create a new Github app using the following parameters: -1. *name*: draft-local-dev (recommended, but not required) -2. *Homepage URL:* http://localhost:54321 -3. *Callback URL:* http://localhost:54321/auth/v1/callback -4. *Request user authorization (OAuth) during installation:* yes -5. *Webhook active:* false -6. *Permissions:* Read-only access to email address -7. *Where can this GitHub App be installed?:* Only on this account - -Once you have created the app, you'll need to create a file `server/.env` and add both the `CLIENT_ID` and a generated `CLIENT_SECRET`. - -``` -SUPABASE_AUTH_GITHUB_CLIENT_ID="" -SUPABASE_AUTH_GITHUB_SECRET="" ``` - - -**Supabase CLI** - -``` -brew install supabase/tap/supabase +git clone https://github.com/eriktaubeneck/draft.git +cd draft ``` -After installing, run +**Start colima and supabse:** ``` +colima start supabase start --workdir server ``` - -In the output, you'll find an `ANON_KEY`. Update the `server/.env` file one more time to include two new variables: +In the output, you'll find an `ANON_KEY`. Create the file `server/.env.development.local` and add: ``` -NEXT_PUBLIC_SUPABASE_URL="http://localhost:54321" NEXT_PUBLIC_SUPABASE_ANON_KEY="" -NEXT_PUBLIC_SITE_URL="https://draft.test" -SUPABASE_AUTH_GITHUB_CLIENT_ID="" -SUPABASE_AUTH_GITHUB_SECRET="" ``` -**Traefik** - -install traefik +**Add local draft.test domain to `/etc/hosts`:** ``` -brew install traefik +echo "#draft local domains\n127.0.0.1 draft.test\n127.0.0.1 sidecar0.draft.test\n127.0.0.1 sidecar1.draft.test\n127.0.0.1 sidecar2.draft.test\n127.0.0.1 sidecar3.draft.test" | sudo tee -a /etc/hosts ``` -update /etc/hosts with (requires sudo) - -``` -127.0.0.1 draft.test -127.0.0.1 sidecar0.draft.test -127.0.0.1 sidecar1.draft.test -127.0.0.1 sidecar2.draft.test -127.0.0.1 sidecar3.draft.test -``` - -make local certs +**make local certs** install mkcert with @@ -136,36 +168,19 @@ If you get a warning about the cert not being installed (i.e., it's the first ti mkcert -install ``` -**Run local dev** - -You're now ready to install, run, and develop on `draft`! - -To start the local development environment: - -``` -draft start-local-dev -``` - -(Make sure `draft` is installed, see next section.) - ### Install draft -If needed, clone this repo: -``` -git clone https://github.com/private-attribution/draft.git -cd draft -``` - -**Install `draft`** ``` -python -m virtualenv .venv +python -m venv .venv source .venv/bin/activate pip install --editable . ``` -### IPA specific certs +## Appendix -We check in self signed certs that are only for local development (and are not secure! They are in a public repo!) +### IPA-specific certs + +We check in self-signed certs that are only for local development (and are not secure! They are in a public repo!) They will periodically expire. You can regenerate them with a compiled helper binary: @@ -177,70 +192,25 @@ target/release/helper keygen --name helper3.draft.test --tls-key local_dev/confi The public content will also need to be pasted into `local_dev/config/network.toml` for each helper. -## Deployment - -### Requirements - -*Instructions for AWS Linux 2023* - -1. Provision an EC2 instance. Download the provided `ssh_connect.pem` key and add it to `~/.ssh`. -2. Point a subdomain of a domain you control to the public IP address. -3. Add the host to your `~/.ssh/config` file: -``` -Host ipa - Hostname - User ec2-user - IdentityFile ~/.ssh/ssh_connect.pem -``` -4. Update the `draft/ansible/inventory.ini` file to only include a single host. (Unless you are running all 4 servers.) -5. Provision your machine: `ansible-playbook -i ansible/inventory.ini ansible/provision.yaml` - -To deploy new changes in draft, run: `ansible-playbook -i ansible/inventory.ini ansible/deploy.yaml` - -### Generating TLS certs with Let's Encrypt - -You will need a domain name and TLS certificates for the sidecar to properly run over HTTPS. The following instructions assume your domain is `example.com`, please replace with the domain you'd like to use. You will need to create two sub-domains, `sidecar.example.com` and `helper.example.com`. (Note, you could also use a sub-domain as your base domain, e.g., `test.example.com` with two sub-domains of that: `sidecar.test.example.com` and `helper.test.example.com`.) - -1. Set up DNS records for `sidecar.example.com` and `helper.example.com` pointing to a server you control. -2. Make sure you've installed the requirements above, and are using the virtual environment. -3. Install `certbot`: `pip install certbot` -4. `sudo .venv/bin/certbot certonly --standalone -m cert-renewal@example.com -d "sidecar.example.com,helper.example.com"` - 1. Note that you must point directly to `.venv/bin/certbot` as `sudo` does not operate in the virtualenv. -5. Accept the [Let's Encrypt terms](https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf). - - -### Make Configuration - -For this stage, you'll need to know a few things about the other parties involved: -1. Their root domain -2. Their public keys -3. Everyone's *identity* (e.g., 0, 1, 2, 3) - - -One you know these: -1. Make a config directory `mkdir config` -2. Copy the default network config: `cp local_dev/config/network.toml config/.` -3. Update that file. - 1. Replace `helper0.draft.test` and `sidecar0.draft.test` with the respective domains for party with identity=0. - 2. Repeat for identity= 1, 2, and 3. - 3. Replace respective certificates with their public keys. -4. Move your Let's Encrypt key and cert into place: `sudo ln -s /etc/letsencrypt/live/sidecar.example.com/fullchain.pem config/cert.pem` and `sudo ln -s /etc/letsencrypt/live/sidecar.example.com/privkey.pem key.pem` -5. Generate IPA specific keys: - 1. Compile `ipa` with `cargo build --bin helper --features="web-app real-world-infra compact-gate stall-detection multi-threading" --no-default-features --release` - 2. Make the keys with `target/release/helper keygen --name localhost --tls-key h1.key --tls-cert h1.pem --mk-public-key h1_mk.pub --mk-private-key h1_mk.key` (replace h1 with for each helper) - 3. Add the public keys content into `network.toml` - 4. Add the public keys to `config/pub` (all helpers need all helper public keys). - 4. For each helper, put their private keys in `config`. +### Local Github Authentication +By default, local authentication is turned off (technically, you're automatically logged in as a demo user.) If you want to test Github authentication locally, you'll need to create a new application for development. Visit [https://github.com/settings/apps/new](https://github.com/settings/apps/new) to create a new Github app using the following parameters: +1. *name*: draft-local-dev (recommended, but not required) +2. *Homepage URL:* http://localhost:54321 +3. *Callback URL:* http://localhost:54321/auth/v1/callback +4. *Request user authorization (OAuth) during installation:* yes +5. *Webhook active:* false +6. *Permissions:* Read-only access to email address +7. *Where can this GitHub App be installed?:* Only on this account -### Run draft +Once you have created the app, you'll need to update `server/.env.development.local` to include both the `CLIENT_ID` and a generated `CLIENT_SECRET`, and set the `BYPASS_AUTH` flag. ``` -draft start-helper-sidecar --identity --root_domain example.com --config_path config +SUPABASE_AUTH_GITHUB_CLIENT_ID="" +SUPABASE_AUTH_GITHUB_SECRET="" +BYPASS_AUTH=false ``` -This will start the sidecar in the background. To confirm, visit `example.com/status`. - # Credit diff --git a/server/.env.development b/server/.env.development new file mode 100644 index 0000000..f4f24ee --- /dev/null +++ b/server/.env.development @@ -0,0 +1,13 @@ +# DO NOT ADD SECRETS TO THIS FILE. This is a good place for defaults. +# If you want to add secrets use `.env.development.local` instead. + +# for local dev, we turn off auth, unless specifically working on auth +BYPASS_AUTH=true +DUMMY_EMAIL="demo@draft.test" +DUMMY_PASSWORD="password" +SUPABASE_AUTH_GITHUB_CLIENT_ID="foo" +SUPABASE_AUTH_GITHUB_SECRET="bar" + +# default supabase variables +NEXT_PUBLIC_SUPABASE_URL="http://localhost:54321" +NEXT_PUBLIC_SITE_URL="https://draft.test" diff --git a/server/middleware.ts b/server/middleware.ts index 4fecfbd..ae4e880 100644 --- a/server/middleware.ts +++ b/server/middleware.ts @@ -54,6 +54,27 @@ export async function middleware(request: NextRequest) { }, ); + if (process.env.NODE_ENV === "development" && process.env.BYPASS_AUTH === "true") { + const dummyEmail: string = process.env.DUMMY_EMAIL!; + const dummyPassword:string = process.env.DUMMY_PASSWORD!; + const { data, error: signInError } = await supabase.auth.signInWithPassword({ + email: dummyEmail, + password: dummyPassword, + }) + + if (signInError) { + const { error: signUpError } = await supabase.auth.signUp({ + email: dummyEmail, + password: dummyPassword + }); + if (signUpError) { + console.error('Sign-in error:', signInError); + console.error('Sign-up error:', signUpError); + throw new Error('Failed to handle local development auth bypass.'); + } + } + return response + } const { data: { user }, } = await supabase.auth.getUser();