75089
今、作成したウェブアプリケーションを、 systemd の `.service`
ファイルでサービス化し、かつそのアプリケーション用のユーザーを作成し、そのユーザーにてサービス(サーバー)を実行しています。

この状態で、このアプリケーションユーザーでログインしていた際には、そこから自身のサービスの状態の更新を行えるようにしたくなりました。`sudo`
がこのユーザに付与されていれば、`sudo systemctl start/stop/etc... app.service`
を実行して、そのアプリのサービスの状態を更新できますが、アプリのユーザーに `sudo` はできれば付与したくありません。

# 質問

systemd のあるサービスを、特定のユーザーから実行された場合は、それが root でなくても `systemctl`
での状態更新を利用可能にしたいです。これは、実現する手段はあるのでしょうか?
CC BY-SA 4.0
2020-08-24T13:23:43.157
69831
2021-04-05T03:04:48.760
754
question
linux systemd
特定のユーザーのみ systemctl によるサービスの状態操作を許可したい
特定のユーザに特定のコマンドを許可するのがsudoだと思いますが、sudoを使いたくない場合は、実行ユーザをチェックし、特定ユーザならユーザをrooに変更し、systemctlを実行するプログラムを作成する必要があると思います。

【ソース:q.c】

```

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    #define UID (1000)
    int main(int argc, char *argv[])
    {
        int ret;
        if(getuid() != UID) {
            fprintf(stderr, "error uid not match(%d)\n", UID);
            return ret;
        }
        printf("getuid (%d)\n", getuid());
        ret = setuid(0);
        if(ret == -1) {
            fprintf(stderr, "setuid error(%s)\n", strerror(errno));
            return ret;
        }
        ret = system("/usr/sbin/service ssh stop");
        return ret;
    }
    
```

実行プログラムの所有者はrootユーザに変更し、setuid権限を付与する必要があります。

```

    clang q.c #or gcc q.c
    sudo chown root ./a.out
    sudo chmod u+s ./a.out
    
```
CC BY-SA 4.0
2020-08-24T15:16:27.463
69835
2020-08-24T23:26:43.257
2020-08-24T23:26:43.257
35558
35558
69831
answer
`sudo` を使う方法だと `systemctl` コマンドすべてを実行できてしまうので "特定サービスの操作だけ"
許可したい場合に不都合だから使いたくない…なんだろうと理解しました。

* * *

"systemctl user service"
で検索すればやりたいことに該当しそうなページがいくつかヒットしますが、そのうちの一つとして、`/etc/systemd/`
以下ではなく、実行させたいユーザーのホームディレクトリ以下にユニットファイルを`~/.config/systemd/user/*.service`
の形式で配置する方法があるようです。

**参考:**  
[systemdでユーザー固有のunitを動かす](https://kernhack.hatenablog.com/entry/2016/05/05/114633)

>
> systemdは~/.config/systemd/userにserviceファイルを置くことで、そのユーザー用のinit時の処理を動かすことができるんですね。基本的に使い方は通常と同じで、唯一違うのは
> --userをパラメータとして使用すること。
```

>     $ cat ~/.config/systemd/user/foobar.service
>     [Unit]
>     Description=User's service file
>  
>     [Service]
>     Type=oneshot
>     ExecStart=/usr/bin/touch /tmp/test.txt
>     RemainAfterExit=yes
>  
>     [Install]
>     WantedBy=default.target
>  
```

> このように実行します。
```

>     $ systemctl --user enable foobar
>  
```
CC BY-SA 4.0
2020-08-24T16:28:54.913
69837
2020-08-24T16:28:54.913
3060
69831
answer
あくまで一般論ですが、`アプリケーションユーザーでログイン` すること自体を無効化したほうが健全だと思います。

サービスを実行する専用のユーザはログインシェルを `/sbin/nologin` や `/usr/sbin/nologin`
にするなどしてログインを無効化して、許可された一般ユーザが sudo を通してサービスのコントロールを行う方がより良いと思います。

また、もしも専用ユーザのシェル操作が必要な場合は、`sudo -s -u ユーザID` で切り替えます。
CC BY-SA 4.0
2020-11-02T05:42:46.990
71657
2020-11-02T05:42:46.990
5008
69831
answer
`sudoers.d/app-user-systemctl` の中に、以下のように記載を行い、明示的にどのコマンドが sudo
可能かを列挙するのが、ちょうどよい設定方法なのではないか、と思うにいたりました。

```

    app-user ALL=(root) /bin/systemctl restart app-service, /bin/systemctl start app-service, /bin/systemctl stop app-service
    
```
CC BY-SA 4.0
2021-04-05T03:04:48.760
75089
2021-04-05T03:04:48.760
754
69831
answer