Does it make sense to add build-time secrets directly to a builder app?

I am very new to fly (literally started with it today, my lord it’s good).

I’m trying to set up a nice CD flow from GitHub. The official docs for this suggest this GitHub Actions workflow:

name: Fly Deploy
on: [push]
env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
  deploy:
      name: Deploy app
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v2
        - uses: superfly/flyctl-actions/setup-flyctl@master
        - run: flyctl deploy --remote-only

But I need DATABASE_URL to be available during build/deployment, as my Node app (Next.js) generates static pages based on info from the database.

It looks like one solution would be to add DATABASE_URL (the .internal one that Fly generated for me when I created my app and said “yes” to setting up a database) to my GitHub repo’s secrets, and then add --build-arg DATABASE_URL="${{ secrets.DATABASE_URL }}" to the flyctl command in the workflow above.

But it feels a tad clunky and I’m wondering if there’s a simpler approach I’m missing?

Another option that occurred to me is: just set the secret directly on the ‘builder app’ that Fly auto-created for building my app, i.e.

> flyctl secrets set -a fly-builder-tasty-moonlight-5678 DATABASE_URL="postgres://........."

This (if it works) feels a bit nicer and more secure than sharing the secret with GitHub so GitHub can provide the secret to fly.io.

But I’m not sure if the builder app is supposed to be considered ‘persistent’, i.e. is it sensible to assign it a secret? It was created for me automatically, I’m not sure if it might get randomly replaced with another builder app later. On the other hand, it does appear to be basically just an app, and it has a ‘secrets’ tab on the dashboard, so why not?

Alternatively, is there any more ‘official’ way to share secrets between an app and its builder?

Update: I tried it - it doesn’t actually work at all. Although I can set secrets on a builder, and even see it come up in the builder’s dashboard, the secret is not made available during build, even after manually restarting the builder.

Looks like I will have to use the other approach: share Fly’s secret internal DATABASE_URL with my GitHub as an “Actions Secret”, and pass it through from the Actions workflow with --build-arg DATABASE_URL="${{ secrets.DATABASE_URL }}". It just feels a bit convoluted though, and I don’t like the idea of sharing my fly.io database keys with a whole separate organisation just so that other organisation can send it back to Fly.

Interested to know if there’s a trick I’m missing, or if Fly are planning any more official way to share secrets with builders.

We have a similar need, +1 - sorry I don’t have another workaround in mind. (The secrets-on-builder idea was a clever one!)

Our example: Build pipeline pushes JS sourcemaps to Sentry upon release. This requires a SENTRY_API_KEY which is a secret.

Understanding not all customers may want all secrets exposed during build, perhaps some sort of per-secret option here?

[x] Expose this secret at build-time?

There’s the flyctl deploy -e <k=v> switch to overwrite envs, though, I’m unsure if it is available insider docker (during build). If it is, then that’s one possible avenue to inject DATABASE_URL at build-time and runtime.

Note though, flyctl overwrites all envs set via fly.toml rather than selectively override them: Is it possible to combine both env vars from CLI flags and fly.toml config?

flyctl release v0.0.333 supports passing build secrets on the command line. These have the caveat that you need to bust Docker build cache if the secret changes, but it may work for your use cases.

3 Likes