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

Options
XIII
XIII
Community Member
edited April 2022 in CLI

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

Comments

  • 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
    XIII
    Community Member
    edited April 2022
    Options

    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
    XIII
    Community Member
    Options

    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
    XIII
    Community Member
    Options

    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).

  • 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

  • sKCZWuLeiGrwVP
    sKCZWuLeiGrwVP
    Community Member
    Options

    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
    
  • Thanks for sharing @sKCZWuLeiGrwVP!

This discussion has been closed.