Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • I use Pydantic Settings for this, would be nice to see a comparison to that. I do like the idea of keeping this in a configuration file.
  • Yeah Pydantic Settings is pretty nice
  • Two things:

    - Secrets don't belong in config https://secretspec.dev/blog/secrets-dont-belong-in-config/

    - You want to have flexibility of choosing between any secrets provider: https://secretspec.dev/blog/but-i-use-sops/

  • I'm working with .env and secrets and teamwide configs for the first time, trying to understand solutions from first principles.

    Are these valid observations so far?

    - .env is the simplest and oldest / most boring solution. Secrets are passed to teammates by DM?

    - .env.example seems like a nice home for documentation about secrets

    - but I'd rather avoid writing sensitive credentials at all -- instead, teams can use a cloud-based secrets manager and the project fetches secrets at runtime. Is this ever a hassle / any downsides? How standard is this practice these days? I hear this also helps updating secrets so you don't have to e.g. tell every teammate when you rotate a secret. Generally not a fan of introducing a network call and a saas dependency, tho

    - non-sensitive environment variables also need a home. I don't like the idea of cluttering the project with a .env.local or worse like .env.development.local

    - I hear lots of secrets and config management happens in container orchestration, but what if I barely have a container in the first place? I guess docker compose is one of the simplest tools at this layer?

    I guess I'm just looking for a safe, simple solution for a small team, and maybe the problem is that every team does things differently, and that many tools are marketed towards huge enterprise teams.

  • Varlock sounds like what you might be looking for. Free, open source, and very flexible toolkit to use however you like.
  • > - .env is the simplest and oldest / most boring solution. Secrets are passed to teammates by DM?

    I don't see a reason to ever pass them. Sensitive production values should never be accessible to everyone, and for development the team should be able to create them themselves.

    I usually keep very stupid values in .env.example, with the instructions to `cp .env.example .env`. In development it doesn't matter if the password is "password". In production the privileged admin sets up actual values.

    > - non-sensitive environment variables also need a home. I don't like the idea of cluttering the project with a .env.local or worse like .env.development.local

    `cp .env.example .env` and the application uses .env just like in production, only with dummy values.

  • This is why I love direnv (the tool) and just a simple .envrc (not .env). It has none of the problems posited in the OP's article. It assumes nothing, only that direnv manges loading up the .envrc into your shell.
  • I moved from direnv, asdf and Task combo to mise.

    Mise env vars management is much better. If you really need a script to generate env vars (like what you can do with direnv, there is a clean mechanism for that).

    If you need to do something when you enter the directory of a project, there is also a mechanism for that.

    Mise is really nice.

  • I see many .env files with unquoted values, like the first example in OP

       REDIS_URL=redis://localhost:6379
    
    and it triggers me big time. Always quoting shell variable values is so deeply ingrained from very painful experiences decades ago that it still causes a somatic flashback whenever I see it.

    This is what went wrong with .env

    Yes, I know

        docker --env-file 
    
    doesn't work with quotes but that's just docker being broken and why they fixed it in docker compose.

    Also see jt2290's comment:

    https://news.ycombinator.com/item?id=49171684

  • 92% of this text is detected as AI.

    It may be time for Hackernews to integrate a Pangram detector into the UI, similar to what substack is doing :)

    by chis
  • Why should HN pay for a questionable service when it already gets crowdsourced results for free?
  • I’m not saying whether I think you’re right or wrong, but AI text detectors don’t work and never will.
  • I suppose I'm spoiled by the Symfony framework which has a robust Secrets Component [0].

    It allows you to generate a public/private key for each environment: test, dev, and prod (by default). The 'prod' private key can't be committed to the repository. Once the cryptographic keys are generated, you can encrypt any secret you want, and the framework will automatically decrypt it and allow you to access it as an environment variable at runtime.

    The encrypted values for all environments are committed to the repository. For example, the file for the `$STRIPE_SECRET_KEY` environment variable for the 'dev' environment is a file that has these contents (shortened for readability):

        <?php // dev.STRIPE_SECRET_KEY.c33678
    
        return "\x1Dq\x11B6\x5B\xFE7\x9B\xA4\xFE...";
    
    This solves several problems:

    1. Keys for the 'dev' and 'test' environments can easily be shared with the team because their public and private keys values are committed to the repository. No more sharing secrets file over Slack or through some other mechanism.

    2. The private key for the 'prod' environment can be stored in a 3rd party vault so it can be made available to the production servers. You can also decrypt 'prod' secrets during deployment to reduce the decryption overhead for each request.

    3. At worst, agents would have access to the secrets in the 'test' and 'dev' environments only because they couldn't decrypt 'prod' values locally.

    4. It forces good practices to ensure you're not using the same secret value for production and non-production environments.

    It's made secret management so easy I don't even give it a second thought. Do other web frameworks support a system like this?

    [0] https://symfony.com/doc/current/configuration/secrets.html

  • I wish there was better support for something like `SECRET_CMD="..."` (ie: "run this command to get/refresh secrets"), but that's just baking arbitrary command execution into your development pipeline.

    Personally, I tend to have a `source ./source-me-auth` which does stuff like `DB_PASSWORD="$( pass show blah.com | head -1 )"`, but that still means I end up with secrets dangling around in my environment. The "source-me" file is safe to share, but my runtime environment is tainted (for good and bad...).

    I saw something w.r.t. the way open-claw handles things where you basically say `export DB_PASSWORD="REDACTED@SECRET_001"` and then it basically outbound filters network requests to hydrate that with `s/REDACTED@SECRET_001/$REAL_SECRET/g`, and I _really_ like that mechanism b/c it defers secret usage to runtime and keeps it physically "out" of the application itself.

    Basically, having `with $SECRETS -- some_app.sh --some params ...` wouldn't be terrible (conceptually).

  • Over at varlock (https://varlock.dev -- also free, open source), we agree that .env as we know it is full of problems. But instead of abandoning it, we evolved it. We replace your .env.example with a .env.schema - using decorator style comments to add schema info, and functions to load and compose values.

    A big difference between our tool and many other similar tools is that we combine the schema and value setting into one surface, with a way of merging many definitions together, much like cuelang - but in a way that feels more intuitive. It's extremely flexible, and can even do credential brokering for untrusted workloads.

    I've been enjoying the secretspec content lately, and watching it evolve :)

  • It's too bad they call background services "agents" now instead of daemons like they used to, because your slogan could be Secrets for daemons

    Varlock is clever. Sub string types for .envs pretty cool, why not

  • I'm sure there are many better alternatives to .env, but its ubiquity and support across various tools makes it super convenient.

    I'm using 1Password's .env integration[1] and although the UX is a bit clunky, I really like it. My API keys are secure, tools that ordinarily support .env just work and there's a team-sharing feature too (although I'm yet to use it). It's pretty neat.

    [1] https://www.1password.dev/environments

  • That's what we are using as well in our small team. `mise` for our non-sensitive values/ environment variables and then `fnox` (from the same author) to encrypt and manage the secrets. `mise` has a plugin for `fnox` that allows to automatically load the secrets in the context when running a mise task/command. This way, our secrets are never exposed, even during local development. Setting this up was effortless. Pretty happy about these tools.
  • Seconded. I've also had great luck with the same author's fnox secret manager, especially because you can tell it to fetch some secrets from the user's laptop's OS keychain, and some out of 1Password, and some out of AWS KMS, and some out of [probably your own favorite provider (https://fnox.jdx.dev/providers/overview)].
  • Hm, I haven't seen these issues personally. We only have one `.env` file and it's just for local secrets. Configuration emphatically does not go in `.env` and ideally is in docker compose and defined in code (we use Pydantic Settings).
  • Yeah, this is the way. I assumed that was fairly standard at this point.
  • This article reads like more of an ad than anything else.

    > Environment variables only deliver values

    Yes, the problem .env files try to solve is having "environment variables" be injectable from a file so that different applications can have different environment variables by default.

    > A string is not a schema

    Yes, input validation is an application concern. The application should know what these values represent / how to parse them and error if they're invalid.

    I could go on, but the article is all about trying to use a hammer as a screwdriver and complaining that the hammer doesnt work.

  • First couple sentences sounded like AI so I just stopped.
  • > Yes, the problem .env files try to solve is having "environment variables" be injectable from a file so that different applications can have different environment variables by default.

    This seems like a misunderstanding: The `.env` file should be `source`d into the current shell (environment). The application reads values using whatever mechanism it uses to read these values from the environment. Nothing should be “injected” into the application, i.e. the application should not read `.env` directly.

    (Not sure if you were just being loose with your terminology, trying to clarify.)