[systemd-devel] Environment-variable security?

Lennart Poettering lennart at poettering.net
Tue Nov 13 10:15:09 UTC 2018


On Mo, 12.11.18 14:49, David Parsley (parsley at linuxjedi.org) wrote:

> It's a fairly common practice to configure services and provide secrets
> with environment variables.

Passing secrets through env vars is marginally better than passing
them in via cmdline params, but still bad, bad, bad
practice. Seriously, don't do that.

Env vars suck for this. They are generally not considered secret, and
thus they leak everywhere, as programs generally don't assume them to
be. As one example: "systemctl show -p Environment …" will show to
unpriv users the env vars you pass to any service of your choice.

Moreover, env vars are by default inherited down the process tree, and
this means code that really shouldn't see them might end up seeing
them. The lifecycle of secrets needs to be tightly controlled, and as
limited as possible. Env vars are the opposite of that. They are
propagated agressively by default, even across security boundaries
(setuid/setgid!) and everything.

Seriously, don't do it that way. If you do it like that, then you are
building an insecure system.

There are other options available. The optimal way would be to stick
them in the kernel keyring. In the kernel keyring you get some
guarantees about lifecycle, access control, even paging that you
otherwise generally don't get. If the keyring doesn't work, then stick
them in a regular file in your $RUNTIME_DIRECTORY and make sure that
files has 0600 access mode or so. You can even set an env var to the
path of such a file if you really want to use the env vars for
something. But please, never stick passwords directly there.

Another option is to allocate a pipe(), write the password in there,
then pass over the reading side of the pipe to the process you
fork. It's not ideal since the fd would theoretically be propagated
further down the tree, but it does have nice properties in that you
can read the pw off the pipe only once, and then it's gone. It also
has the benefit over the file solution suggested above that it won't
leave artifacts in the fs by design.

> For instance, both Hubot (made by Github) and
> Gopherbot (made by me) can get their Slack token from an environment
> variable. In my case, github.com/lnxjedi/ansible-role-gopherbot stores the
> Slack bot token with "Environtment=GOPHER_SLACK_TOKEN=xxx" in the systemd
> unit file. I had hoped to keep this info to the robot user by marking the
> unit file world-inaccessible. I was dismayed to see the log warning about
> values being accessible via the API, though super glad that my unprivileged
> user couldn't fetch it with a simple systemctl cat gopherbot. I know very
> little about DBUS or any APIs for systemd, so wanted to ask - is there some
> means by which a non-privileged user can access the values provided with
> "Environment=..." lines? Can I disable this by disabling dbus-daemon on
> server systems?

Yes, the bus API is generally open for any clients. One way to access
it is "systemctl show -p Environment …", another is directly with busctl.

And no, you cannot reasonably disable this. It's the wrong place. It's
a swiss cheese.

Seriously, the right approach is not to pass these secrets in the env
vars in the first place, not then to try to play hide and seek to make
them hopefully not leak.

Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list