Cách tốt nhất để chạy dịch vụ Linux với tư cách người dùng khác


141

Các dịch vụ mặc định bắt đầu như rootlúc khởi động trên hộp RHEL của tôi. Nếu tôi nhớ lại một cách chính xác, điều tương tự cũng đúng với các bản phân phối Linux khác sử dụng các tập lệnh init /etc/init.d.

Bạn nghĩ gì là cách tốt nhất để thay vào đó các quy trình chạy như một người dùng (tĩnh) mà tôi chọn?

Phương pháp duy nhất tôi đã đến là sử dụng một cái gì đó như:

 su my_user -c 'daemon my_cmd &>/dev/null &'

Nhưng điều này có vẻ hơi không gọn gàng ...

Có một chút ma thuật nào đó được cung cấp một cơ chế dễ dàng để tự động bắt đầu các dịch vụ như những người dùng không phải root khác?

EDIT: Đáng lẽ tôi phải nói rằng các quy trình tôi bắt đầu trong trường hợp này là các tập lệnh Python hoặc chương trình Java. Tôi thà không viết một trình bao bọc riêng xung quanh chúng, vì vậy thật không may là tôi không thể gọi setuid () như Black gợi ý.


Python không cung cấp quyền truy cập vào nhóm các cuộc gọi hệ thống setuid ()? Đó dường như là một khiếm khuyết nghiêm trọng so với Perl.
Jonathan Leffler

12
Ồ, vâng, đúng vậy: os.setuid (uid). Mỗi ngày là một ngày học!
James Brady

Câu trả lời:


67

Trên Debian, chúng tôi sử dụng start-stop-daemontiện ích xử lý các tệp pid, thay đổi người dùng, đặt trình nền vào nền và nhiều hơn nữa.

Tôi không quen thuộc với RedHat, nhưng daemontiện ích mà bạn đang sử dụng (được định nghĩa trong /etc/init.d/functionsbtw.) Được đề cập ở mọi nơi tương đương với start-stop-daemon, vì vậy nó cũng có thể thay đổi uid của chương trình của bạn hoặc cách bạn làm nó đã là một trong những chính xác.

Nếu bạn nhìn quanh mạng, có một số hàm bao sẵn sàng mà bạn có thể sử dụng. Một số thậm chí có thể đã được đóng gói trong RedHat. Có một cái nhìn daemonize, ví dụ.


Các x-ref là thú vị. Tôi có chương trình daemonize của riêng tôi, rất giống nhau; không làm pidfile hoặc lockfile, không đặt umask. Tôi có một chương trình gốc SUID riêng để thiết lập các nhóm UID, GID, EUID, EGID và aux (được gọi là asroot). Tôi sử dụng 'asroot [opts] - env ​​-i [env] daemonize [opts] - lệnh [opts]'
Jonathan Leffler

(tiếp theo): chương trình env tiêu chuẩn POSIX không chấp nhận '-' giữa cài đặt môi trường và lệnh được thực thi (vô nghĩa, nhưng vì vậy).
Jonathan Leffler

4
Làm thế nào chức năng daemon từ /etc/init.d/fifts được sử dụng trong tập lệnh khởi động? Bạn có thể cho thấy một ví dụ, xin vui lòng.
Meglio

10
Trên Debian xem /etc/init.d/skeleton. Thêm các biến UID, GID và do_start()sử dụng:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham

Tôi nhận thấy daemon()được xác định trong /etc/rc.d/init.d/functioncả hai hộp RHEL & CentOS của tôi.
quickshiftin

53

Sau khi xem tất cả các đề xuất ở đây, tôi đã khám phá ra một vài điều mà tôi hy vọng sẽ hữu ích cho những người khác ở vị trí của mình:

  1. hop có quyền chỉ cho tôi quay lại /etc/init.d/functions: daemonchức năng đã cho phép bạn đặt người dùng thay thế:

    daemon --user=my_user my_cmd &>/dev/null &
    

    Điều này được thực hiện bằng cách gói lời gọi quy trình với runuser- nhiều hơn về điều này sau.

  2. Jonathan Leffler đã đúng: có setuid trong Python:

    import os
    os.setuid(501) # UID of my_user is 501
    

    Tuy nhiên, tôi vẫn không nghĩ rằng bạn có thể setuid từ bên trong JVM.

  3. Cả sucũng không runuser duyên dáng xử lý các trường hợp bạn yêu cầu để chạy một lệnh như là người dùng bạn đã là. Ví dụ:

    [my_user@my_host]$ id
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    [my_user@my_host]$ su my_user -c "id"
    Password: # don't want to be prompted!
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    

Để khắc phục hành vi đó surunuser, tôi đã thay đổi tập lệnh init của mình thành một cái gì đó như:

if [[ "$USER" == "my_user" ]]
then
    daemon my_cmd &>/dev/null &
else
    daemon --user=my_user my_cmd &>/dev/null &
fi

Cảm ơn tất cả vì sự giúp đỡ của bạn!


5
  • Một số daemon (ví dụ apache) tự làm điều này bằng cách gọi setuid ()
  • Bạn có thể sử dụng cờ setuid-file để chạy quy trình với tư cách người dùng khác.
  • Tất nhiên, giải pháp bạn đề cập là tốt.

Nếu bạn có ý định viết daemon của riêng mình, thì tôi khuyên bạn nên gọi setuid (). Bằng cách này, quá trình của bạn có thể

  1. Sử dụng các đặc quyền gốc của nó (ví dụ: mở tệp nhật ký, tạo tệp pid).
  2. Thả đặc quyền gốc của nó tại một điểm nhất định trong khi khởi động.

3

Chỉ cần thêm một số thứ khác để coi chừng:

  • Sudo trong một tập lệnh init.d là không tốt vì nó cần một tty ("sudo: xin lỗi, bạn phải có một tty để chạy sudo")
  • Nếu bạn đang tạo ứng dụng java, bạn có thể muốn xem xét Java Service Wrapper (cung cấp cơ chế để thiết lập id người dùng)
  • Một cách khác có thể là su --session-lệnh = [cmd] [user]

3

trên máy ảo CENTOS (Red Hat) cho máy chủ svn: được chỉnh sửa /etc/init.d/svnserver để thay đổi pid thành thứ gì đó mà svn có thể viết:

pidfile=${PIDFILE-/home/svn/run/svnserve.pid}

và thêm tùy chọn --user=svn:

daemon --pidfile=${pidfile} --user=svn $exec $args

Các pidfile ban đầu là /var/run/svnserve.pid. Trình nền không bắt đầu bởi vì chỉ có root mới có thể viết ở đó.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart

3
Điều này tạo ra một lỗ hổng leo thang đặc quyền. Giờ đây, người dùng svn có thể đặt các PID tùy ý vào tệp /home/svn/run/svnserve.pid sẽ bị giết thay vì quá trình svn bất cứ khi nào dịch vụ svn bị dừng hoặc khởi động lại.
rbu

2

Một số điều cần chú ý:

  • Như bạn đã đề cập, su sẽ nhắc nhập mật khẩu nếu bạn đã là người dùng mục tiêu
  • Tương tự, setuid (2) sẽ thất bại nếu bạn đã là người dùng mục tiêu (trên một số HĐH)
  • setuid (2) không cài đặt các đặc quyền hoặc điều khiển tài nguyên được xác định trong /etc/limits.conf (Linux) hoặc / etc / user_attr (Solaris)
  • Nếu bạn đi theo lộ trình setgid (2) / setuid (2), đừng quên gọi initgroups (3) - thêm về điều này tại đây

Tôi thường sử dụng / sbin / su để chuyển sang người dùng thích hợp trước khi bắt đầu trình nền.


2

Tại sao không thử những điều sau trong tập lệnh init:

setuid $USER application_name

Nó làm việc cho tôi.


3
Điều này không có sẵn trên tất cả các distro. Tôi đã thử trên RHEL 7:setuid: command not found
Cocowalla

0

Tôi cần chạy ứng dụng Spring .jar như một dịch vụ và tìm thấy một cách đơn giản để chạy ứng dụng này với tư cách là một người dùng cụ thể:

Tôi đã thay đổi chủ sở hữu và nhóm tệp jar của mình thành người dùng tôi muốn chạy. Sau đó, symlinked jar này trong init.d và bắt đầu dịch vụ.

Vì thế:

#chown myuser:myuser /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar

#ln -s /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar /etc/init.d/springApp

#service springApp start

#ps aux | grep java
myuser    9970  5.0  9.9 4071348 386132 ?      Sl   09:38   0:21 /bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.