github jdx/fnox v1.40.0
v1.40.0: Lua plugin providers, Kubernetes Secrets, and Windows daemon support

3 hours ago

fnox 1.40.0 adds custom providers written as Lua plugins, a read-only Kubernetes Secrets provider, 1Password Environments, file-backed plain providers and Bitwarden folder scoping. The daemon now runs on Windows. This release also fixes Azure service principal authentication, repeated hardware PIN prompts for age identities, and fnox set dropping piped values.

Added

  • Custom providers as Lua plugins (#968) by @jdx. You can now write a secrets backend that fnox doesn't support as a Lua 5.4 plugin and share it as a git repository. Declare the plugin under [plugins], then use it with type = "lua":
    [plugins]
    corp = "acme/fnox-plugin-corp#v1.2.0"   # git URL or owner/repo, optional #ref
    
    [providers.corp]
    type = "lua"
    plugin = "corp"                          # or a path such as ./plugins/corp.lua
    
    [secrets]
    DATABASE_URL = { provider = "corp", value = "prod/database-url" }
    • A plugin is a provider.lua that returns hooks. get is required. get_batch, put, encrypt and test are optional, and the hooks you define decide whether fnox set and fnox import can write to the provider. A provider's options table (string values, which can be secret references) is passed to the plugin as ctx.options. Plugins can use the fnox.http, fnox.json, fnox.cmd, fnox.log and fnox.base64 modules. fnox.auth_error(msg) triggers the provider's auth_command flow.
    • New commands: fnox plugin install, update, link, ls and uninstall, plus fnox provider add NAME lua --plugin ....
    • fnox installs a declared plugin the first time a provider uses it (git clone). Plugins go in $FNOX_DATA_DIR/plugins, which defaults to $XDG_DATA_HOME/fnox or ~/.local/share/fnox. Set FNOX_PLUGINS_DIR to use a different location. If a project declares a different source or ref than the installed one, fnox won't load the plugin until you run fnox plugin update <name>.
    • Plugins run with your user's permissions. Only install plugins from sources you trust, and pin a ref. See docs/providers/lua.md for details.
  • Kubernetes Secrets provider (#953) by @jdx. A read-only kubernetes provider reads existing Secrets through the Kubernetes API. It only makes named GET requests and never lists, watches or writes Secrets. A reference can be secret, secret/key or namespace/secret/key. The optional context, namespace, kubeconfig and prefix settings control where it looks, and the FNOX_K8S_CONTEXT environment variable can also select the context. Daemon caching is always disabled for this provider, even with daemon_cache = true.
    [providers.kubernetes]
    type = "kubernetes"
    context = "production"
    namespace = "payments"
    
    [secrets]
    DATABASE_URL = { provider = "kubernetes", value = "database/url" }
  • 1Password Environments (#955) by @jdx. The 1password provider can read variables from a 1Password Environment using environment://<environment-id>/<VARIABLE> references. You can mix these with vault item references in the same config. fnox reads each Environment once per provider instance, and a variable missing from the Environment is an error. This needs the beta op CLI with the op environment command.
  • Read values from a plaintext file with the plain provider (#954) by @joshbode. The new file and format settings make each secret's value a key to look up in that file. format can be env, shell, json, yaml or toml, and you must set it whenever file is set. A relative path resolves against the config file that declares the provider. The file is read-only, and a missing key counts as a missing secret, so default and if_missing still apply.
    [providers.dotenv]
    type = "plain"
    file = "secrets.env"
    format = "env"
    
    [secrets]
    API_TOKEN = { provider = "dotenv", value = "SERVICE_TOKEN" }
  • Bitwarden folder scoping (#965) by @andersonkrs. The new optional folder setting limits lookups to one Bitwarden folder. For nested folders, use the full path, such as folder = "MyApp/Production". This lets items with the same name exist in different folders. It works with both bw and rbw.
  • Azure managed identity (#964) by @jdx. azure-sm, azure-kms and azure-ac accept auth = "managed-identity", with an optional managed_identity_client_id for a user-assigned identity. fnox never tries managed identity on its own; you have to set auth.
  • Daemon on Windows (#974) by @jdx. On Windows, the daemon now uses a per-user named pipe where other platforms use a Unix socket, so Windows gets cached secrets too. Only the current user can access the pipe, and both the client and the daemon check the user on the other end. The wire protocol and the fnox-client API are unchanged.

Fixed

  • Azure service principal environment variables (#964) by @jdx. Azure providers authenticate as a service principal again when AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET are all set. Without them, fnox falls back to the az/azd login. For sovereign clouds, set AZURE_AUTHORITY_HOST. These variables can also be fnox secrets resolved by fnox exec.
  • Hardware PIN prompts for age identities (#978) by @andersonkrs and @jdx. With PIN-protected age identities (age-plugin-tpm --pin, age-plugin-yubikey), a value used by several providers made one command ask for the PIN up to three times. Now a successful decrypt is reused for the rest of the request, so you get one prompt per fnox get, exec or export, or per daemon request. Nothing is kept between requests, and a failed decrypt can be retried.
  • fnox set with piped stdin and metadata flags (#976) by @jdx. echo val | fnox set A -d "desc" (or with --default or --if-missing) said it worked but saved no value. fnox now stores the piped value along with the metadata. If stdin is empty, only the metadata is updated, as before.

Changed

  • fnox import parsing (#954) by @joshbode. fnox import now accepts the {secrets, metadata} document that fnox export --format json|yaml|toml produces. The env parser now follows Docker Compose dotenv rules for inline comments. For example, PORT=8080 # default now imports as 8080, where it used to keep the comment as part of the value. # without whitespace before it, as in ID=val#ue, and # inside quotes are still part of the value.

New Contributors

Full Changelog: v1.39.0...v1.40.0

💚 Sponsor fnox

fnox is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.

If fnox handles secrets or config for you or your team, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep fnox secure, free, and independent.

Don't miss a new fnox release

NewReleases is sending notifications on new releases.