-
-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: Enable reading env vars from files #4359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Enable reading env vars from files #4359
Conversation
|
Just a small heads-up: this will not go into v15 anymore, but rather v15.1, because I will start a release for v15 soon. |
|
I'll review when DMS v15 is released. Presently trying to tackle various docs PRs within that window until then. |
|
|
||
| if [[ -f "${file_path}" ]]; then | ||
| _log 'info' "Getting secret ${env_var} from ${file_path}" | ||
| export "${env_var}"="$(< "${file_path}")" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is export needed, what's the purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch! Exporting the variables is only needed if we need programs called by the startup script to read them. I expected that to be the case, I'll remove the export if that's not the case!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget the use for export when run within the same scripts, will it carry over to check-for-changes.sh? We seem to rely on getting our ENV from /etc/dms-settings for that (and setup CLI commands):
| source /etc/dms-settings |
One of the ENV we explicitly set is BIND_PW (LDAP):
| VARS[LDAP_BIND_PW]="${LDAP_BIND_PW:=}" |
So this PR would have BIND_PW__FILE set BIND_PW, writing the secret to /etc/dms-settings for anyone in the container to read.
Once the LDAP refactor PR is merged, a future change might have check-for-changes.sh support updating those config files, which would need access to the secret. However we'd not be writing all variations to /etc/dms-settings AFAIK, the feature would work with standard ENV, but not this __FILE variation in that case. Easy enough fix though to call this functionality when initializing check-for-changes.sh.
BIND_PW (technically LDAP_BIND_PW / DOVECOT_BIND_PW) and similar variations supported there.
test/tests/parallel/set3/container_configuration/env_vars_from_files.bats
Outdated
Show resolved
Hide resolved
polarathene
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My review feedback is mostly about the feature itself rather than implementation here (I'll leave that to @casperklein and @georglauterbach as they're both better versed with bash than I am).
One concern is the tests don't seem to be verifying the value read from file to ENV is correct.
- I have seen other projects implement file loaded ENV where a trailing
\nor similar was accidentally part of the assigned value. - EDIT: While the output to stdout in a shell would include white-space, assignment from the subshell seems to trim the trailing white-space 🤔 (so not affected by this caveat, but should probably still have a test for expected vs actual value)
Could we confirm what the expectation of this feature is security wise?
- Is it to avoid the container metadata about ENV the container was configured with? (
docker inspect <container-name> | jq -r .[].Config.Env/ Docker socket API query) Both operations should technically be privileged, but it's not uncommon to provide docker socket access to a container with more access than it needs (even just forlabelsmonitoring I think this would intersect the same API call forenvironment/env_fileon a container - confirmed) - Or is the concern with ENV visibility within the container from a non-root user/process? This information is presently publicly accessible at
/etc/dms-settings(although I don't think it needs to be644?), thus not a major improvement.
This PR would only be addressing the ENV metadata on the container from exposing secrets. If internal file access permissions is a concern that'll probably need to be tackled via a separate PR.
Reference
Linking my feedback from the FR issue:
- #3457 (comment) (FR approved for minor convenience, suggested to use filepath as ENV value instead of
__FILEsuffix, although the suffix is more useful when we don't have an explicit list) - #3457 (comment) (may leak to ENV + written copy to disk)
Verified:
- Both
/root/.bashrcand/etc/dms-settingsare written with644permissions, but/rootitself is700, thus non-root users can only access/etc/dms-settings. envwill have all ENV loaded from/etc/dms-settingswhen using abashshell specifically to trigger the.bashrc(docker exec -it bash, or ifshthen running a login shell viabash -lc 'env').- Running bash scripts via
bash(without-l) or relying on the standard shebang we use, neither will load in the ENV, hence why we source it from/etc/dms-settingsmanually when needed.
My earlier comments in the FR also expressed a bit of uncertainty to the value for this feature in DMS, discouraging it given the intention for security benefit seemed minimal?:
NOTE: In the original FR, I cited Compose secrets as not reliable. There has been recent activity to actually get proper secrets support in Docker Compose with file working with uid / gid / mode (still WIP, nothing landed yet), but that won't really help with the concerns raised for secrets exposure in DMS.
|
|
||
| if [[ -f "${file_path}" ]]; then | ||
| _log 'info' "Getting secret ${env_var} from ${file_path}" | ||
| export "${env_var}"="$(< "${file_path}")" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget the use for export when run within the same scripts, will it carry over to check-for-changes.sh? We seem to rely on getting our ENV from /etc/dms-settings for that (and setup CLI commands):
| source /etc/dms-settings |
One of the ENV we explicitly set is BIND_PW (LDAP):
| VARS[LDAP_BIND_PW]="${LDAP_BIND_PW:=}" |
So this PR would have BIND_PW__FILE set BIND_PW, writing the secret to /etc/dms-settings for anyone in the container to read.
Once the LDAP refactor PR is merged, a future change might have check-for-changes.sh support updating those config files, which would need access to the secret. However we'd not be writing all variations to /etc/dms-settings AFAIK, the feature would work with standard ENV, but not this __FILE variation in that case. Easy enough fix though to call this functionality when initializing check-for-changes.sh.
BIND_PW (technically LDAP_BIND_PW / DOVECOT_BIND_PW) and similar variations supported there.
|
I am not sure if I understand you correctly, but using |
Ok, but the Any ENV not stored in that file will not be usable by Just highlighting this as a potential caveat where subtle bugs may later appear. Anything within the container that can read This feature AFAIK is only to prevent secrets visibility from anyone with access to the Docker socket by sending a # Read the ENV associated to the running container:
docker inspect <container-name> | jq -r .[].Config.Env
# Shell into DMS as with an interactive TTY as root (implicitly starts a login shell `-l`):
# NOTE: Secrets would be visible in ENV loaded from `/etc/dms-settings` via `/root/.bashrc`
docker exec -it <container-name> bashI think this feature makes more sense when the secret is read temporarily into memory to use it, but due to how DMS is managing the secrets currently, this is to effectively only defend against a separately compromised container inspecting metadata through the Docker socket. I just want to clarify with the author (and any others interested in the feature) if that meets their actual expectations of implementing this feature, or if it falls short of the expected security benefit. If @aartoni still wants to proceed with that security benefit clarified, then they just need to ensure the PR has a test-case that verifies the target ENV has the expected value resolved by the |
|
@polarathene I'm willing to proceed. I'll get in touch in a few days in case I get stuck. |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
Hello @polarathene! I got stuck while trying to address this comment. It is not clear to me how to obtain the path for the copy of the configuration that I should be using in this case, here's what I have tried: TEST_TMP_CONFIG=$(_duplicate_config_for_container . 'env_vars_from_files') |
|
We have a variety of tests you can reference that do this :)
If you need to create files instead of Reference of tests manipulating configs from `TEST_TMP_CONFIG` (click to view)docker-mailserver/test/tests/parallel/set1/dovecot/dovecot_sieve.bats Lines 13 to 14 in ef66dd5
docker-mailserver/test/tests/parallel/set1/config_overrides.bats Lines 10 to 11 in ef66dd5
docker-mailserver/test/tests/parallel/set1/fetchmail.bats Lines 11 to 17 in ef66dd5
docker-mailserver/test/tests/parallel/set3/mta/lmtp_ip.bats Lines 19 to 29 in ef66dd5
docker-mailserver/test/tests/parallel/set3/mta/dsn.bats Lines 20 to 26 in ef66dd5
docker-mailserver/test/tests/parallel/set3/mta/smtp_delivery.bats Lines 44 to 48 in ef66dd5
docker-mailserver/test/tests/parallel/set3/scripts/setup_cli.bats Lines 12 to 14 in ef66dd5
docker-mailserver/test/tests/parallel/set3/scripts/replace_by_env_in_file.bats Lines 7 to 12 in ef66dd5
Extra notes
|
|
Thank you @polarathene for referencing the relevant code. I have implemented the tests the way you pointed out, I'd say that this is ready for the final review! |
Co-authored-by: Brennan Kinney <[email protected]>
Co-authored-by: Brennan Kinney <[email protected]>
test/tests/parallel/set3/container_configuration/env_vars_from_files.bats
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 Thanks for taking the time to contribute this feature! ❤️
Just waiting on @casperklein or @georglauterbach for their opinion on #4359 (comment) (there is also earlier review discussion for this too but for export at #4359 (comment))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the local -n approach outlined in my suggestion. I hope you agree with my idea :) Please double-check it, though :) Other than that: LGTM, nice addition 👍🏼
Co-authored-by: Georg Lauterbach <[email protected]>
|
I'm sorry @polarathene, I have unwillingly dismissed your review, can you please contribute back the comments so that I can approve them? Or simply push without my help if you prefer :) |
|
I'll review this on the weekend. |
test/tests/parallel/set3/container_configuration/env_vars_from_files.bats
Outdated
Show resolved
Hide resolved
test/tests/parallel/set3/container_configuration/env_vars_from_files.bats
Outdated
Show resolved
Hide resolved
|
Documentation preview for this PR is ready! 🎉 Built with commit: 9ef06e6 |
Description
Fixes #3457.
Allows setting any environment variable via the content of a file, this is especially useful to carry Docker secrets in. This fix takes inspiration from a few similar approaches, namely Bitnami container images (e.g., OpenLDAP) and Grafana.
I have marked this as a breaking change since it would change the behavior of setups providing
<VAR>__FILEenv vars where<VAR>is an existing configuration variable. However, you may consider that to be negligible.I've noticed a few Fail2ban tests breaking, but I'm not sure if that's due to my local setup or what. I've ignored them as they seemed unrelated.
Type of change
Checklist
docs/)CHANGELOG.md