Skip to main content
XIII
April 6, 2022
Question

How to inject a secret into the environment via a systemd service definition?

  • April 6, 2022
  • 7 replies
  • 3065 views

I want to inject a secret (password) into the environment for a systemd service, using either Environment= or EnvironmentFile=.

What I tried (and what failed):

1. Environment

Environment=password=$(op read op://Vault/Item/password)

However, since such service is not a script, the password will be set to this literal text; the command itself, not its result...

2. EnvironmentFile

As an override:


[Service]
ExecStartPre=op inject -i /etc/default/myservice.tpl -o /etc/default/myservice
ExecStartPost=rm /etc/default/myservice

with this additional line in etc/default/myservice.tpl:


password=op://Vault/Item/password

However, apparently the environment file is read before executing the ExecStartPre command...

Any tips on how I can inject the password into the environment for this service?


1Password Version: CLI 2.0.0
Extension Version: n/a
OS Version: Raspberry Pi OS Bullseye

7 replies

April 7, 2022

Hey @XIII, thanks for reaching out to us!

I think another solution here might be to pass the secret references as environment variables, and to use op run to prefix your ExecStart Command. I played a bit with this with the manual authentication process, hardcoding my session token, and managed to get something like this working:

[Service]
User=horia
Environment="OP_CONFIG_DIR=/home/horia/.config/op"
Environment="VAR=op://test-vault/docker/username"
Environment="OP_SESSION_<my_id>=<my_session_token>"
ExecStart=/usr/bin/op run --no-masking -- bash -c 'echo $VAR'

I assume this can be ported over to the biometric authentication process as well, but, in case you encounter any hurdles, let us know such that we can take another look, in more detail!

Best,
Horia

XIII
XIIIAuthor
April 7, 2022

That's exactly what I (already) did... (and that indeed works!)

However, this service's ExecStart is pretty complicated; I'd rather not overwrite that (since I manually have to copy the original one each time the author changes it).

XIII
XIIIAuthor
April 10, 2022

Turns out this does not work as good as I hoped, I always get these errors when I try to restart a service:


Apr 10 17:06:32 pi systemd[1]: my.service: Found left-over process 1944 (op) in control group while starting unit. Ignoring.
Apr 10 17:06:32 pi systemd[1]: This usually indicates unclean termination of a previous run, or service implementation deficiencies.

How to fix this?

XIII
XIIIAuthor
April 11, 2022

Might be because this service was using this (which is not recommended):


KillMode=process

Removed that line (to get the default mode control-group) and that seems to work better (so far).

May 19, 2022

I am glad you got this working. Is there anything else that we can help with, here?

Looking forward to hearing from you!

Best,
Horia

November 30, 2022

Hi @XIII ! Another option is to write the secret into a private temp file and read it from there into your app. This is secure because systemd creates private temp files in a separate application-specific namespace. In fact by some accounts it's even more secure than environment variables, which can be queried pretty easily from other processes!

My suggestion would look like:

[Service]
ExecStartPre=/path/to/op read op://Vault/Item/password >/tmp/item
ExecStart=/some/app # reads file /tmp/item contents into memory as password
PrivateTmp=yes # Enforces creating /tmp/* in private namespace for the service
Jack_P_1P
1Password Employee
November 30, 2022

Thanks for sharing @sKCZWuLeiGrwVP!