Làm cách nào để hạn chế người dùng SSH trong một nhóm lệnh được xác định trước sau khi đăng nhập?


85

Đây là một ý tưởng cho một bảo mật. Nhân viên của chúng tôi sẽ có quyền truy cập vào một số lệnh trên máy chủ linux nhưng không phải tất cả. Ví dụ, chúng sẽ có khả năng truy cập tệp nhật ký ( less logfile) hoặc bắt đầu các lệnh khác nhau ( shutdown.sh/ run.sh).

Thông tin lai lịch:

Tất cả nhân viên đều truy cập máy chủ bằng cùng một tên người dùng: Sản phẩm của chúng tôi chạy với quyền người dùng "bình thường", không cần "cài đặt". Chỉ cần giải nén nó trong dir người dùng của bạn và chạy nó. Chúng tôi quản lý một số máy chủ nơi ứng dụng của chúng tôi được "cài đặt". Trên mỗi máy đều có một người dùng johndoe. Nhân viên của chúng tôi đôi khi cần quyền truy cập vào ứng dụng trên dòng lệnh để truy cập và kiểm tra tệp nhật ký hoặc khởi động lại ứng dụng bằng tay. Chỉ một số người mới có toàn quyền truy cập dòng lệnh.

Chúng tôi đang sử dụng xác thực ppk trên máy chủ.

Sẽ thật tuyệt nếu nhân viên1 chỉ có thể truy cập vào logfile và nhân viên2 cũng có thể làm X, v.v.

Giải pháp: Là một giải pháp, tôi sẽ sử dụng commandtùy chọn như đã nêu trong câu trả lời được chấp nhận . Tôi sẽ tạo tập lệnh shell nhỏ của riêng mình, đây sẽ là tệp duy nhất có thể được thực thi cho một số nhân viên. Tập lệnh sẽ cung cấp một số lệnh có thể được thực thi, nhưng không có lệnh nào khác. Tôi sẽ sử dụng các tham số sau trong authorized_keystừ như đã nêu ở đây :

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host

Điều này là đủ bảo mật cho chúng tôi. Cảm ơn, cộng đồng!


Bảo mật dựa trên quyền ACL tiêu chuẩn của Linux là không đủ? Những tính năng bổ sung nào bạn cần?
James Brady,

22
Đó là một ý tưởng kinh khủng, Marcel.
Vinko Vrsalovic

13
@Vinko, @PEZ: Tôi đã thêm một số thông tin cơ bản. Thay vì nói "ý tưởng ngu ngốc", bạn có thể cung cấp các nhận xét có giá trị. Theo bạn thì ý tưởng tốt hơn là gì?
Marcel

8
Tôi vẫn không thấy bất kỳ lý do nào về việc nhiều người dùng chia sẻ cùng một tên người dùng.
Eldelshell,

3
"Kịch bản vỏ nhỏ của riêng tôi"? Nghe có vẻ khá nguy hiểm. Trừ khi bạn là một chuyên gia, có lẽ có nhiều cách để thoát khỏi nó để trở thành một cái vỏ đầy đủ. Tôi muốn tin tưởng một chương trình được viết tốt, gỡ lỗi và duy trì (một số chương trình đã được đề cập).
bortzmeyer

Câu trả lời:


68

Bạn cũng có thể hạn chế các khóa đối với các lệnh được phép (trong tệp ủy quyền_các phím).

Tức là người dùng sẽ không đăng nhập qua ssh và sau đó có một nhóm lệnh bị hạn chế mà chỉ được phép thực hiện các lệnh đó qua ssh (ví dụ: "ssh somehost bin / showlogfile")


Điều đó trông thú vị. Có thể xác định nhiều lệnh không?
Marcel

12
Bài viết này cung cấp cho bạn một số tùy chọn cho nhiều lệnh bằng cách sử dụng tệp allow_keys
Bash

@ rd834 ...: Cảm ơn nhiều. Tôi nghĩ rằng điều này đã cho tôi một giải pháp "tốt" ... (thêm vào câu hỏi). Tôi sẽ chấp nhận câu trả lời này là "đúng".
Marcel

11
Cuốn sách O'Reilly SSH có giải thích tuyệt vời về cách thực hiện điều này, bao gồm việc cho phép nhiều lệnh bằng cách thiết lập một tập lệnh nhìn vào biến môi trường SSH_ORIGINAL_COMMAND. oreilly.com/catalog/sshtdg/chapter/ch08.html
Alex Dupuy

5
câu trả lời serverfault này có một mẹo hay về cách cho phép nhiều lệnh bằng cách sử dụng biến SSH_ORIGINAL_COMMAND đã xuất.
MattBianco

32

sshtheo rshtruyền thống bằng cách sử dụng chương trình shell của người dùng từ tệp mật khẩu để thực hiện các lệnh.

Điều này có nghĩa là chúng ta có thể giải quyết vấn đề này mà không cần sshcấu hình theo bất kỳ cách nào.

Nếu bạn không muốn người dùng có thể có quyền truy cập shell, thì chỉ cần thay thế shell của người dùng đó bằng một tập lệnh. Nếu bạn nhìn vào, /etc/passwdbạn sẽ thấy rằng có một trường chỉ định trình thông dịch lệnh shell cho mỗi người dùng. Tập lệnh được sử dụng làm vỏ cho cả đăng nhập tương tác của chúng ssh user@host cũng như cho các lệnh ssh user@host command arg ....

Đây là một ví dụ. Tôi đã tạo một người dùng foocó trình bao là một tập lệnh. Tập lệnh in thông báo my arguments are:theo sau là các đối số của nó (mỗi đối số trên một dòng riêng biệt và trong dấu ngoặc nhọn) và kết thúc. Trong nhật ký trong trường hợp, không có đối số. Đây là những gì sẽ xảy ra:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.

Nếu người dùng cố gắng chạy một lệnh, nó sẽ giống như sau:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>

"Shell" của chúng ta nhận được một lệnh -cgọi kiểu, với toàn bộ lệnh là một đối số, giống như cách /bin/shsẽ nhận nó.

Vì vậy, như bạn có thể thấy, những gì chúng ta có thể làm bây giờ là phát triển tập lệnh thêm nữa để nó nhận ra trường hợp khi nó được gọi với một -cđối số, và sau đó phân tích cú pháp chuỗi (giả sử bằng cách so khớp mẫu). Những chuỗi được cho phép có thể được chuyển đến shell thực bằng cách gọi đệ quy /bin/bash -c <string>. Trường hợp từ chối có thể in thông báo lỗi và kết thúc (bao gồm cả trường hợp khi -cbị thiếu).

Bạn phải cẩn thận khi viết cái này. Tôi khuyên bạn chỉ nên viết các kết quả phù hợp tích cực chỉ cho phép những thứ rất cụ thể và không cho phép mọi thứ khác.

Lưu ý: nếu đúng như vậy root, bạn vẫn có thể đăng nhập vào tài khoản này bằng cách ghi đè shell trong sulệnh, như thế này su -s /bin/bash foo. (Vỏ thay thế của sự lựa chọn.) Non-root không thể làm điều này.

Đây là một tập lệnh ví dụ: hạn chế người dùng chỉ sử dụng sshđể gittruy cập vào các kho lưu trữ bên dưới /git.

#!/bin/sh

if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
  printf "interactive login not permitted\n"
  exit 1
fi

set -- $2

if [ $# != 2 ] ; then
  printf "wrong number of arguments\n"
  exit 1
fi

case "$1" in
  ( git-upload-pack | git-receive-pack )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    printf "access denied outside of /git\n"
    exit 1
    ;;
esac

if ! [ -e "$gitpath" ] ; then
   printf "that git repo doesn't exist\n"
   exit 1
fi

"$1" "$gitpath"

Tất nhiên, chúng tôi tin tưởng rằng các chương trình Git này git-upload-packgit-receive-packkhông có lỗ hổng hoặc cửa sập sẽ cho phép người dùng truy cập vào hệ thống.

Đó là điều vốn có trong loại kế hoạch hạn chế này. Người dùng được xác thực để thực thi mã trong một miền bảo mật nhất định và chúng tôi đang đưa ra một hạn chế để giới hạn miền đó ở một miền phụ. Ví dụ: nếu bạn cho phép người dùng chạy vimlệnh trên một tệp cụ thể để chỉnh sửa nó, người dùng chỉ có thể nhận được một trình bao :!sh[Enter].


6
Nghiêm túc mà nói, điều này RẤT NGUY HIỂM. Điều gì sẽ ngăn cản tôi thực hiện git-receive-pack '/git/';dd if=/dev/urandom of=/dev/sda?
Yeti

@Yeti Chúng ta có lỗ tiêm lệnh ở đây không? Điều đó cần được giải quyết. Ngoài ra, việc lạm dụng các mẫu tệp mà tôi đã gây ra trong tệp casenày có vẻ không đúng với tôi.
Kaz

1
Có, /bin/bash -c "$2"là không an toàn (tương tự như cách SQL injection hoạt động). Bạn có thể lọc chuỗi bằng "dấu ngoặc kép" như PHP. Nhưng cách dễ dàng để đảm bảo an toàn tuyệt đối là gọi một lệnh theo cách thủ công và sau đó chuyển các tham số trong dấu ngoặc kép. Bởi vì bảo mật của toàn bộ điều sau đó phụ thuộc vào lệnh đó là liên kết yếu nhất (khó xác minh hơn). Thú vị nhất khi xem câu trả lời của bạn có 22 lượt ủng hộ như thế nào, nhưng không ai nhận thấy điều này;) Bạn sẽ cập nhật câu trả lời của riêng mình chứ?
Yeti

1
@Yeti Có; Tôi vừa làm. Tôi đã thay thế tập lệnh bằng một tập lệnh phá vỡ đối số -c setvà sau đó chỉ lấy hai từ đầu tiên từ nó. Đầu tiên phải là một git-lệnh được phép và lệnh thứ hai phải là một đường dẫn được chuẩn hóa, được kiểm tra với tiền tố được phép và cũng được kiểm tra sự tồn tại. Bạn có thể nghĩ ra bất kỳ cách nào để phá vỡ điều này?
Kaz

1
Trừ khi ai đó tạo bí danh (hoặc ghi đè một lệnh) cho bất kỳ lệnh nào trong số các lệnh đã cho, thì không, dấu ngoặc kép Bash sẽ an toàn (và nếu không, thì đây là một lỗi trong Bash).
Yeti

15

Những gì bạn đang tìm kiếm được gọi là Restricted Shell . Bash cung cấp một chế độ trong đó người dùng chỉ có thể thực hiện các lệnh có trong thư mục chính của họ (và họ không thể di chuyển đến các thư mục khác), điều này có thể đủ tốt cho bạn.

Tôi thấy chủ đề này rất minh họa, nếu hơi lỗi thời.


1
Điều gì sẽ xảy ra nếu người dùng thực hiện "! / Bin / sh" hoặc một số như vậy từ dấu nhắc ít hơn?
PEZ,

3
@Ubersoldat: Hãy lớn lên và giảm bớt sự hung hăng trong tất cả các bài viết của bạn. Anh ấy đang hỏi liệu giới hạn chỉ áp dụng cho các quá trình bash hoặc con (và để trả lời câu hỏi của anh ấy, hóa ra là không).

Một vấn đề lớn với trình bao bị hạn chế là để bảo mật nó, bạn phải sử dụng .profile hoặc .bashrc để hạn chế PATH, vô hiệu hóa nội trang, v.v., nhưng những tệp đó chỉ được gọi cho các trình bao tương tác. Nếu người dùng sử dụng ssh để chạy lệnh từ xa thì họ không được gọi. Điều này cho phép người dùng có quyền truy cập ssh vào tài khoản có SHELL = / bin / rbash chỉ cần thực hiện một số việc như "ssh remotehost bash" để có được một shell không tương tác nhưng không bị giới hạn. Bạn cần các lệnh bắt buộc SSH như HD đã đề xuất, nhưng điều này có thể bảo vệ khỏi việc thoát shell khi PEZ yêu cầu (khi PATH bị khóa - nó bao gồm / bin: / usr / bin theo mặc định).
Alex Dupuy

2
Tôi rút lại điều đó, bash sẽ gọi .bashrc (không phải .profile) khi chạy không tương tác trong sshd; tuy nhiên, bạn phải đảm bảo rằng bạn đặt PATH rõ ràng và tắt nội trang và bí danh trong .bashrc - thay đổi thành thư mục con không có trong / trên PATH hoặc .ssh / hoặc .bashrc cũng là một ý kiến ​​hay. Có bất kỳ lệnh nào có thể ghi vào các tệp tùy ý sẽ tạo ra vấn đề - những điều này không phải lúc nào cũng rõ ràng, ví dụ: lệnh sed 'w' có thể được sử dụng để ghi đè .bashrc và thoát ra. Chroot jail sẽ luôn an toàn hơn nếu bạn có thể sử dụng nó và các lệnh bắt buộc ssh sẽ bị hạn chế hơn.
Alex Dupuy 11/11/11

4

Bạn nên có được `rssh ', trình bao bị hạn chế

Bạn có thể làm theo các hướng dẫn hạn chế được đề cập ở trên, tất cả chúng đều khá dễ hiểu và đơn giản để làm theo. Hiểu các thuật ngữ `` chroot jail '' và cách triển khai hiệu quả các cấu hình sshd / terminal, v.v.

Là hầu hết người dùng của bạn truy cập thiết bị đầu cuối của bạn thông qua sshd, bạn cũng có thể nên xem xét sshd_conifg, tệp cấu hình daemon SSH, để áp dụng một số hạn chế nhất định qua SSH. Hãy cẩn thận, tuy nhiên. Hiểu đúng những gì bạn cố gắng triển khai, vì sự phân chia của các cấu hình không chính xác có lẽ khá nghiêm trọng.


1
Lưu ý rằng pizzashack.org/rssh là một giải pháp tuyệt vời (có thể là tốt nhất) cho trường hợp đặc biệt mà bạn muốn cho phép scp / sftp / rdist / rsync / cvs (và không cần truy cập bất kỳ thứ gì bên ngoài chroot jail) - tuy nhiên , nó không giải quyết được câu hỏi chung của người đăng ban đầu, người muốn người dùng có thể xem các tệp nhật ký và chạy các tập lệnh chạy / tắt máy nhất định.
Alex Dupuy 11/11/11

2
rsshđã bị xóa khỏi Debian Buster. Tôi nghĩ độ hot mới là GNU vội vàng .
Thomas

1
@Thomas Tôi tin rằng rssh hiện không có nguyên nhân và có một vấn đề bảo mật đã biết: sourceforge.net/p/rssh/mailman/message/36519118
Max Barraclough

4

Tại sao bạn không viết trình bao đăng nhập của riêng mình? Nó sẽ khá đơn giản để sử dụng Bash cho việc này, nhưng bạn có thể sử dụng bất kỳ ngôn ngữ nào.

Ví dụ trong Bash

Sử dụng trình chỉnh sửa yêu thích của bạn để tạo tệp /root/rbash.sh(đây có thể là bất kỳ tên hoặc đường dẫn nào, nhưng phải là chown root:rootchmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit
        
    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'
    
    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection
        
        # For example, optionally you can log this command
        log COMMAND "echo $ln"
    
    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi

Tất cả những gì bạn phải làm là đặt tệp thực thi này làm trình bao đăng nhập của bạn. Ví dụ: chỉnh sửa /etc/passwdtệp của bạn và thay thế trình bao đăng nhập hiện tại của người dùng đó /bin/bashbằng /root/rbash.sh.

Đây chỉ là một ví dụ đơn giản, nhưng bạn có thể làm cho nó nâng cao như bạn muốn, ý tưởng là có. Hãy cẩn thận để không tự khóa mình bằng cách thay đổi trình bao đăng nhập của người dùng duy nhất và của riêng bạn. Và luôn kiểm tra các biểu tượng và lệnh kỳ lạ để xem liệu nó có thực sự an toàn hay không.

Bạn có thể thử nghiệm nó với: su -s /root/rbash.sh.

Hãy lưu ý , hãy đảm bảo khớp với toàn bộ lệnh và cẩn thận với các ký tự đại diện! Tốt hơn nên loại trừ các ký hiệu Bash như ;,& , &&, ||, $, và backticks để đảm bảo.

Tùy thuộc vào sự tự do mà bạn cung cấp cho người dùng, nó sẽ không an toàn hơn nhiều. Tôi nhận thấy rằng thường thì tôi chỉ cần tạo ra một người dùng chỉ có quyền truy cập vào một số lệnh liên quan và trong trường hợp đó, đây thực sự là giải pháp tốt hơn. Tuy nhiên, bạn có muốn trao thêm tự do không, một nhà tù và các quyền có thể phù hợp hơn. Sai lầm rất dễ mắc phải, và chỉ nhận ra khi đã quá muộn.


Tôi thực sự thích cách tiếp cận này. Bạn có bất kỳ ý tưởng nào về cách chúng tôi có thể xử lý các lệnh nhiều từ như "khởi động lại httpd dịch vụ" không?
Farzan

2
@Farzan Bạn có thể thực hiện các lệnh trong một biến, ví dụ ln="service httpd restart", với: ${ln[@]}. Hãy chắc chắn rằng hãy nghĩ đến các vấn đề bảo mật, một danh sách trắng chỉ dành cho các ký tự chữ và số và khoảng trắng sẽ hữu ích trong trường hợp như vậy. Nhưng bạn cũng có thể làm: if [[ "$ln" == "restart-httpd"];then service httpd restart;fivà làm việc với các lệnh đơn giản như vậy.
Yeti

/root/rbash.sh: Permission denied Tôi cũng đã thử chmod 777
Christian

@Christian, bạn đã thêm /root/rbash.shvào /etc/shellschưa? Nó phụ thuộc vào sự phân phối. Bạn cũng có thể thử tắt tạm thời selinuxvà kiểm tra thông báo nhật ký để tìm manh mối (xem dấu thời gian) trong các tệp trong /var/log.
Yeti

@yeti không, đã được giải thích để thêm vào / root :) Sẽ thử ngay bây giờ.
Christian


1

GNU Rush có thể là cách linh hoạt và an toàn nhất để thực hiện điều này:

GNU Rush là Lớp vỏ Người dùng Hạn chế, được thiết kế cho các trang web cung cấp quyền truy cập từ xa hạn chế vào tài nguyên của họ, chẳng hạn như kho lưu trữ svn hoặc git, scp, hoặc tương tự. Sử dụng tệp cấu hình phức tạp, GNU Rush cho phép bạn kiểm soát hoàn toàn các dòng lệnh mà người dùng thực thi, cũng như việc sử dụng tài nguyên hệ thống, chẳng hạn như bộ nhớ ảo, thời gian CPU, v.v.


0

Một cách khác để xem xét vấn đề này là sử dụng POSIX ACL, nó cần được hỗ trợ bởi hệ thống tệp của bạn, tuy nhiên bạn có thể điều chỉnh chi tiết tất cả các lệnh trong linux giống như cách bạn có cùng quyền kiểm soát trên Windows (chỉ cần không có giao diện người dùng đẹp hơn ). liên kết

Một điều khác cần xem xét là PolicyKit .

Bạn sẽ phải thực hiện kha khá googling để mọi thứ hoạt động vì đây chắc chắn không phải là thế mạnh của Linux hiện tại.


0

[Tiết lộ: Tôi đã viết sshdo được mô tả bên dưới]

Nếu bạn muốn đăng nhập tương tác thì thiết lập một trình bao bị hạn chế có lẽ là câu trả lời đúng. Nhưng nếu có một bộ lệnh thực tế mà bạn muốn cho phép (và không có gì khác) và các lệnh này được thực thi riêng lẻ thông qua ssh (ví dụ: ssh user @ host cmd arg blah blah), thì một lệnh chung điều khiển danh sách trắng cho ssh có thể là thứ bạn cần. Điều này rất hữu ích khi các lệnh được viết kịch bản bằng cách nào đó ở cuối máy khách và không yêu cầu người dùng thực sự nhập lệnh ssh.

Có một chương trình tên là sshdo để thực hiện việc này. Nó kiểm soát các lệnh nào có thể được thực hiện thông qua các kết nối ssh đến. Nó có sẵn để tải xuống tại:

http://raf.org/sshdo/ (đọc các trang hướng dẫn sử dụng tại đây) https://github.com/raforg/sshdo/

Nó có chế độ huấn luyện để cho phép tất cả các lệnh được thử và tùy chọn --tìm hiểu để tạo ra cấu hình cần thiết để cho phép các lệnh đã học vĩnh viễn. Sau đó, chế độ đào tạo có thể bị tắt và bất kỳ lệnh nào khác sẽ không được thực hiện.

Nó cũng có tùy chọn --unlearn để ngừng cho phép các lệnh không còn được sử dụng để duy trì đặc quyền ít nghiêm ngặt nhất khi các yêu cầu thay đổi theo thời gian.

Nó rất cầu kỳ về những gì nó cho phép. Nó sẽ không cho phép một lệnh có bất kỳ đối số nào. Chỉ có thể cho phép các lệnh shell hoàn chỉnh.

Nhưng nó hỗ trợ các mẫu đơn giản để biểu diễn các lệnh tương tự chỉ khác nhau về các chữ số xuất hiện trên dòng lệnh (ví dụ: số thứ tự hoặc dấu ngày / giờ).

Nó giống như một tường lửa hoặc điều khiển danh sách trắng cho các lệnh ssh.

Và nó hỗ trợ các lệnh khác nhau được phép cho những người dùng khác nhau.

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.