superfly / flyctl

Command line tools for fly.io services
https://fly.io
Apache License 2.0
1.41k stars 235 forks source link

Inject placeholder secrets/envs into build vars #778

Open michaeldwan opened 2 years ago

michaeldwan commented 2 years ago

Folks get tripped up when builds fail because a secret or env var available at runtime isn't available at build time. For example: https://community.fly.io/t/ruby-version-mismatch/3815/4?u=michael

It's almost always a library throwing an exception when a required env var is missing, like DATABASE_URL or SECRET_KEY_BASE. We're not going to bring real secrets/env in for obvious reasons, but maybe we can add placeholders for the current secrets and env. For example, for each secret and env var, make a build-arg with a value like <placeholder-env> or <placeholder-secret>. Dumb existence checks would "just work", and other errors would at least give some indication of what the problem is.

me-diru commented 2 years ago

Hey!

this looks like a decent task to get started on flyctl, may I work on this? thanks!

michaeldwan commented 2 years ago

@kurious-diru absolutely! We're happy to answer any questions as you go along.

me-diru commented 2 years ago

Hey, thanks for the reverting back

I am trying to set up flyctl locally, is there no way to build it from the source? to test the changes made

I am on ubuntu

rugwirobaker commented 2 years ago

make build will output a binary ./bin/flyctl

me-diru commented 2 years ago

I got few questions while going through the code and terminology to gain more context, it would be great if y'all can answer them

1) Does this happen only when the build is done via buildpacks? If so, it looks like the build args are passed as env in the build process here?

2) I created a draft PR, I think I am trying to add envs as build args during deployment, probably I am wrong.

Just wanted to confirm if I am going in the right direction here, thanks!

michaeldwan commented 2 years ago

Happy to help!

  1. This happens for both buildpacks and dockerfile builds. Both of them have a concept of a build-arg, which is like an env variable, except that build-args are available to the container at build-time and don't get saved to the image, while env vars do. We support build args via the fly.toml file and a --build-arg flag.
  2. You're on the right track. You need to fetch the list of secrets from the api (like we do in the flyctl secrets list command), then for each of those add a build arg with the secret name. Placeholders should probably go before we set args from flags and fly.toml.

Does that make sense? Feel free to ask more questions if it helps.

daniellaera commented 1 year ago

Any solutions here? I think I might have the same issue. I'm containeraizing a React app application with Dockerfile and Nginx and when I deploy from vscode with flyctl deploy, it seems to take in consideration the env variables stored in .env so the build for npm run build in the Dockerfile successfully uses the environment variables. But when I run it from the Github Action the variables are not injected. I've been searching a lot on that, a lot of Dockerfile posts with topics about ARG & ENV and flyctl command with cross-env arguments from github actions and Dockefile and some others but it doesn't work. WHat am I missing? Or the problem is just that the .env file is not committed since is in the .gitignore so in the Dockerfile from github action is not taken and so not injected?

Glyphack commented 1 year ago

Hey @michaeldwan

I'm happy to work on this issue. There's something I did not quite understand, is the accepted solution right now is to:

The current solution I'm using is to set dummy values in the Dockerfile then I don't need to provide the --build-arg to flyctl deploy anymore.

gabrielalmeida commented 1 year ago

michaeldwan:

We're not going to bring real secrets/env in for obvious reasons

rubys:

I definitely empathize with the problem you are dealing with and would like to help. I’m also aware of the damage that a wholesale leaking of secrets can cause. Over time I expect Fly’s auth token to become more fine-grained as to the amount of access an individual token can provide.

I see there's a bit of resistance from Flyers on interacting w/ secrets and the reasons are obviously valid concerns.

While placeholders may suffice to handle a couple of scenarios they may not be enough for a bunch of others and may even introduce unexpected surprising behavior (e.g., boolean-ish feature flag intended to be false but read by NodeJS as truthy due to the presence of <placeholder-secret> string).

OTOH, knowing that JS is not a first-class citizen as other languages/frameworks on Fly, I'm unsure if the expectations match across these other stacks.

TL;DR Placeholders may be subpar and using build-time secrets is painful.


I'm migrating away some Next.JS apps from Vercel to Fly.io and it's a bit painful to handle env vars (specially NEXTPUBLIC) because they're available only at runtime.

To get them to play right with Docker it's necessary to add them to a bunch of places:

Gets a bit painful when dealing with a bunch of values. Based on this table, .env files are the ideal choice because they will be used on the server and Next.JS will also expose NEXT_PUBLIC on the client, so it's a single file that is expected to mix sensitive values/tokens and configs and to always be .gitignore'd.


Some perspectives from how Vercel handles env vars that could be helpful here:

Your source code can read these values to change behavior during the Build Step or during Function execution.

All values are encrypted at rest and visible to any user that has access to the Project. It is safe to use both non-sensitive and sensitive data, such as tokens.

Allowing flyctl to at least export them would greatly smooth the process without exposing them on build-time unless needed by someone willing to script them. The recent addition of app-scoped deploy tokens would also probably play well with that.

As a side-note, Next.JS also allows to "set defaults" using .env[.environment] and .env.local to store sensitive data that can be used to handle this differently.

daniellaera commented 1 year ago

On my repos, I have a fully functional example with production build args for fly in a github action job https://github.com/daniellaera/supabase-react-auth/blob/main/.github/workflows/main.yml

redjonzaci commented 1 year ago

Hey @daniellaera, does that mean this works now?