Allow using env vars to set config values #10205
Replies: 6 comments 2 replies
-
I would be prepared to contribute the code for this proposal, including the stretch goals. |
Beta Was this translation helpful? Give feedback.
-
This would be my proposed approach to implementing this. I would create an interface for a configuration value substitution provider, and one implementation which would substitute values from environment variables. I would create a generic processor for the syntaxes If there is no provider for This would create the bones for future |
Beta Was this translation helpful? Give feedback.
-
@marcbria, tagging you on this as our main docker/containerization agitator; I think you had made similar proposals. Could you cross-link those, and have a think about this proposal? |
Beta Was this translation helpful? Give feedback.
-
Thanks Jim. So happy to hear about undusting this. :-) I think best most relevant post about ENV vars in OJS is #7068: In the post Henrique suggest to "use the bullet-proof package vlucas/phpdotenv to handle the .env parsing and setting." Then the thread evolves to covers very interesting related topics (move from ini to yaml/toml, save config in DB, combine multiple config files, security concerns...) but made us take distance from the original proposal and it was never implemented. This final post from Nate is a good summary of the hierarchy we like to apply, that I'm sure will make Jim as happy as me: So, if I understood well, we have two proposals on the table:
I like Jim's idea (that offers one benefit that is removing used vars) but IMO, will be better using an existing library that let us release all the potential of the ENV files (aligned with the 12 factor) in a more standardized way. Related conversations: Probably @jonasraoni and @AndrewGearhart could be interested in this Discussion too? Update: The group made a great summary of the topics related and suggest config improvements but also suggest going with phpdotenv. |
Beta Was this translation helpful? Give feedback.
-
Hey, @marcbria ... thanks for pinging me. I appreciate many aspects of Jim's idea, but I have some reservations. While the As a side note, I fundamentally disagree that environment variables containing secrets are less secure than other secret storage mechanisms in a containerized environment, like writing values to disk or using an application's global variables. Deleting environment variables after reading them does offer some security benefits, but it's secondary since an attacker who compromises the application can access both the variables and settings. Proving one method or another would require implementation details to be argued, meaning these are functionally equivalent at face value. In many cases, I appreciate structured data config files (e.g., YAML over JSON because of comments), but setting OJS settings from the environment provides multiple avenues for configuration management, aligning with best practices for deployments. Without environment variables being available directly, a simple approach could be using In other words, I think that we gain all the versatility of Jim's proposal through a simpler approach: protect the config file and make it PHP operable. This leverages PHP's native environment variable handling, simplifies the codebase, and aligns with PHP practices that are standard in many other frameworks and applications. |
Beta Was this translation helpful? Give feedback.
-
Closing this in favour of #8015. |
Beta Was this translation helpful? Give feedback.
-
What
Create a syntax for config files — such as, ojs.config.inc.php — that allows setting a configuration value using an environment variable.
I propose the syntax be
{env:VAR_NAME}
1. This would substitute the value of the environment variable VAR_NAME, or the blank string if it is not set. The value from the environment variable undergoes trimming and type conversion, the same as configuration values not taken from an environment variable. The value of the environment variable does not undergo further substitution.The syntax is quiescent inside
'…'
and"…"
literal strings.The
{…}
in the syntax clearly delimits it, and theenv:
clearly marks it as a reference to an environment variable.The syntax is unlikely to have appeared organically in current configuration files. If it were it can continue to be used literally by turning the configuration value into a
'…'
or"…"
literal string.I propose this lands in version 3.5.0 as it is still a potentially breaking change.
Why
There are configuration values that cannot, or even must not, be built into a container image.
The pkpofficial/ojs docker image follows the standard practice of using environment variables in these cases. It achieves this via the ojs-variable command, which uses
sed
to substitute an environment variable into the configuration file.While this works, it hinders running containers with a read-only root filesystem, a security best practice.
How
I propose a change to readConfig in PKP\config\ConfigParser, which would add code before line 72 to match the syntax in
$value
and substitute the value of an environment variable. Line 72 would then use the result of that process.pkp-lib/classes/config/ConfigParser.php
Lines 68 to 78 in 65607cc
Here is an example of the proposed syntax in situ.
If the OJS_BASE_URL environment variable was
https://example.com/ojs
,Config::getVar("general", "base_url")
would return the stringhttps://example.com/ojs
.Stretch goals
Embedding
Allow the syntax to be embedded within other text. Allow multiple occurrences of the
{env:…}
syntax when constructing a value.If the SERVERNAME environment variable was
example.com
and BASEPATH wasojs
,Config::getVar("general", "base_url")
would return the stringhttps://example.com/ojs
. If BASEPATH was instead of unset or blank, the returned string would behttps://example.com/
.Default values
Extend the syntax to allow
{env:VAR_NAME:-VALUE}
. If VAR_NAME is unset or empty, VALUE is used instead. I took this syntax from POSIX shell parameter expansion. However, I propose VALUE be used literally. This precludes complex syntaxes like{env:VAR1:-{env:VAR2:-VALUE}}
.This is an example of the extended syntax in situ.
If OJS_DEBUG is unset or an empty value — via
OJS_DEBUG=
in a .env file, for example — show_stacktrace and display_errors would both have the boolean value false. If OJS_DEBUG is true or on, show_stacktrace and display_errors would both have the boolean value true. If OJS_DEBUG isX
both show_stacktrace and display_errors would have the stringX
, as is current behaviour.Delete after use
Extend the syntax to allow
{env:VAR_NAME:delete}
. Any environment variable referenced with this syntax is deleted from the environment after reading the whole of the configuration file.Some environment variables may contain secrets. An example of this might be the database password. Having secrets in environment variables risks the secrets being exposed should the environment become exposed. Being able to delete these environment variables help to mitigate this risk.
Future expansion
These are not part of this proposal, but are mentioned here because they were considered.
{file:PATH}
syntax that would set a configuration variable to the contents of the file at PATH. This would facilitate using docker compose secrets in configuration files.{config:SECTION:KEY}
syntax that would set a configuration variable based on prior configuration variable.Footnotes
I had considered the somewhat more common
${env:VAR_NAME}
syntax. But leaned towards something based on PHP's variable substitution syntax instead. ↩Beta Was this translation helpful? Give feedback.
All reactions