systemd, multiline variable in environmentfile , where new line is significant

Viewed 3864

I'm using systemd on debian jessie to control a service to which I'm feeding environment variables through the EnvironmentFile=/etc/default/myservice file

in this file I have a variable which is a public key

  JWT_PUB_KEY="-----BEGIN FOO BAR KEY-----
  MIIBgjAcBgoqhkiG9w0BDAEDMA4ECKZesfWLQOiDAgID6ASCAWBu7izm8N4V
  2puRO/Mdt+Y8ceywxiC0cE57nrbmvaTSvBwTg9b/xyd8YC6QK7lrhC9Njgp/
  ...
  -----END FOO BAR KEY-----"

putting it like that does not please systemd which report an error (though doing a source in bash of the same file works correctly)

the documentation of systemd report that you can have multiline variable by ending each file with a \ but that it concatenate each line (so my program receive the whole under one line, which is no more a valid public key)

Is there a known way to preserve the end of line ? without resorting to hack like putting \n which i them 'interpret' in my application code ?

4 Answers

The claim in the systemd.exec documentation that within the EnvironmentFile, “C escapes are supported, but not most control characters. "\t" and "\n" can be used to insert tabs and newlines within EnvironmentFile=.” is completely false. Instead, the allowed quotes and escapes are the same as in a POSIX shell. Like in sh, a multiline value surrounded by single or double quotes will turn into a multiline value in the environment; you don’t need \n and \t, which are meaningless in sh (without quotes, they are interpreted as n and t; within quotes, they are interpreted as \n and \t. They never become newline and tab).

And if you end a line with \ in double quotes or no quotes, then this is a line continuation, and the newline is discarded, just like in sh.

I opened PR 21908 to fix this documentation.

Thanks to @yonran that improved the documentation in his pull request: https://github.com/systemd/systemd/pull/21908

So the solution is quite easy, you just have to put the value between single quotes. Warning, this solution may only works in recent version of systemd (tested with version >= 250).

JWT_PUB_KEY='-----BEGIN FOO BAR KEY-----
MIIBgjAcBgoqhkiG9w0BDAEDMA4ECKZesfWLQOiDAgID6ASCAWBu7izm8N4V
2puRO/Mdt+Y8ceywxiC0cE57nrbmvaTSvBwTg9b/xyd8YC6QK7lrhC9Njgp/
...
-----END FOO BAR KEY-----'

If I understand correctly the updated documentation, this is the only solution to obtain new lines (0x0A aka \n characters) inside an environment variable. And this is clearly impossible to insert a new line by using the \n characters sequence inside the key value.

But after further tests, using double quotes also works (systemd does not complain, at least with systemd version 250).

Here my test files:

  • /etc/test-env.txt
JWT_PUB_KEY="-----BEGIN FOO BAR KEY-----
MIIBgjAcBgoqhkiG9w0BDAEDMA4ECKZesfWLQOiDAgID6ASCAWBu7izm8N4V
2puRO/Mdt+Y8ceywxiC0cE57nrbmvaTSvBwTg9b/xyd8YC6QK7lrhC9Njgp/
-----END FOO BAR KEY-----"
  • /etc/systemd/system/test-env.service
[Unit]
Description=Test env

[Service]
Type=simple
ExecStart=/usr/bin/test-dump-env.py JWT_PUB_KEY
EnvironmentFile=/etc/test-env.txt
  • /usr/bin/test-dump-env.py
#!/bin/env python3

import os, sys

s = os.environ.get(sys.argv[1])
h = ":".join("{:02x}".format(ord(c)) for c in s)

print(s)
print("***---***")
print(h)

To test it:

systemctl restart test-env.service; sleep 1; systemctl status -l test-env.service

So I do not understand why it failed in your case (You may be using a too old / broken version of systemd)

Related