Làm cách nào để tự động đặt chế độ đọc bash thành chế độ vi khi đăng nhập vào hệ thống?


9

Nhóm của tôi chịu trách nhiệm cho hàng ngàn máy Linux / Unix, do đó, tài khoản root được "chia sẻ" giữa các quản trị viên. Tôi thích chế độ vi, những người khác thích chế độ emacs.

Làm cách nào tôi có thể đặt chế độ đọc của bash thành chế độ vi khi đăng nhập SSH vào bất kỳ máy nào mà không buộc mọi người khác cũng sử dụng chế độ vi?

Về bản chất, tôi muốn có hiệu lực set -o visau khi đăng nhập mà không thực sự phải gõ nó mỗi lần và không ép buộc người khác (chế độ emacs gây khó chịu cho tôi, chế độ vi gây khó chịu cho họ).

Tôi biết điều này sẽ không thành vấn đề nếu mọi người sẽ sử dụng tài khoản của riêng họ với sudo để thực thi các lệnh đặc quyền, nhưng do hoàn cảnh nằm ngoài tầm kiểm soát của tôi, điều đáng buồn này không phải là một lựa chọn.


1
Điều đó không dễ dàng. Một cách là phân tích tệp nhật ký của sshd và xem khóa nào được sử dụng để đăng nhập. Tôi hy vọng giải pháp phía máy khách, ví dụ như một cách để chuyển cấu hình đường đọc cục bộ của tôi sang phía từ xa hoặc một cái gì đó tương tự, hoặc một số phép thuật OpenSSH đen tối âm thầm thực thi set -o vitrước khi cho tôi quyền kiểm soát vỏ.
Patrick

1
Có lẽ bạn có thể sử dụng tập lệnh Expect trên máy khách ssh vào máy chủ, gửi set -o vilệnh, sau đó chuyển sang chế độ tương tác.
Barmar

1
Ít nhất OpenSSH sshdthiết lập một số biến môi trường có thể giúp bạn xác định ai là người ở đầu bên kia. Ví dụ: SSH_CLIENTchứa địa chỉ IP kết nối (và cả cổng đi / đến của máy khách). Đấu tranh với điều này trong ~/.bashrccó thể cho phép bạn làm những việc chỉ dành cho bạn .
Sami Laine

1
Tiền thưởng cho biết bạn đang tìm kiếm một "giải pháp phía khách hàng" - đó là gì? ssh trên máy chủ Unix? Putty? Chim ruồi? Java SSH? Cygwin?
Jeff Schaller

1
Bạn đề cập đến hàng chục ngàn máy móc. Bạn có muốn bắt đầu từ một máy và đến các máy này không, hoặc bạn có muốn nhảy từ máy này sang máy khác sang máy mang chế độ vi với bạn không?
icarus

Câu trả lời:


3

Đây là một cách ngớ ngẩn để làm điều đó, nó thực sự chỉ hoạt động tốt với xác thực khóa công khai:

Đầu tiên, đảm bảo rằng máy cục bộ của bạn có nctrên đó.

Thứ hai, vẫn trên máy cục bộ của bạn, tạo một tập lệnh (tôi sẽ gọi nó connect-to-server) và đặt nó ở nơi bạn ${PATH}biết về *:

#!/bin/sh
# connect-to-server
ssh -q server-hostname "touch .yourname" </dev/null >/dev/null 2>&1
nc server-hostname 22

Tiếp theo, sửa đổi .bashrchệ thống từ xa để bao gồm một nơi nào đó:

# partial .bashrc
if [ -f "${HOME}/.yourname" ]; then
  rm "${HOME}/.yourname"
  set -o vi
fi

Cuối cùng, quay lại máy cục bộ của bạn, chỉnh sửa ~/.ssh/configđể thêm:

# partial ssh config
Host serverNickname
  Hostname server-hostname
  ProxyCommand connect-to-server

Nhược điểm của phương pháp này (và tại sao tôi gọi nó là ngớ ngẩn):

  • Nếu có một lệnh proxy thực sự cần thiết, nó trở nên phức tạp hơn.
  • Nếu người khác đăng nhập cùng lúc với bạn, có khả năng .yournametệp sẽ chưa bị xóa, trong trường hợp đó họ cũng nhận được set -o vi.
  • Quan trọng nhất, nếu bạn làm ssh serverNickname command, sau đó commandsẽ chạy, nhưng (vì .bashrckhông bao giờ có nguồn gốc) .yournametệp vẫn còn, vì vậy sẽ rất lịch sự khi có một bí danh thứ hai trong cấu hình ssh của bạn không sử dụng proxy giả.

Trong thực tế, nhược điểm duy nhất của phương pháp này là sshlệnh của bạn không cần phải đưa ra bất kỳ đối số bổ sung nào.


* Nếu bạn không muốn phải thay đổi bất cứ điều gì trên các hệ thống từ xa, đây là một proxy giả thay thế tạo tạm thời .bashrc:

#!/bin/sh
# connect-to-server
ssh -q server-hostname 'ln .bashrc .bashrc.real; cat .bashrc.real <(printf "set -o vi; ln -f .bashrc.real .bashrc\n") >.bashrc.yourname; ln -f .bashrc.yourname .bashrc' </dev/null >/dev/null 2>&1
nc server-hostname 22

Điều này có tất cả các nhược điểm tương tự của phương thức khác, vì vậy bạn vẫn muốn có một bí danh thứ hai trong sshcấu hình của mình mà không gọi proxy giả.


Rất sáng tạo. Cảm ơn vì đã góp ý. Tôi đã sử dụng ProxyCommand một cách rộng rãi (một số mạng / máy chủ yêu cầu 5+ bước nhảy để tiếp cận) và điều này sẽ nhanh chóng dẫn đến một cơn ác mộng cấu hình. Chỉnh sửa: Nhìn vào tất cả các câu trả lời tôi nghĩ rằng bạn đến gần nhất.
Patrick

4

Tôi muốn đi:

ssh server -t "bash --login -o vi"

nhưng nó là một quản trị viên, bạn có thể thử một cái gì đó sạch hơn. Ví dụ: bạn có thể sử dụng SendEnvtùy chọn ssh ở phía máy khách để truyền một biến cụ thể, sử dụng AcceptEnvtrong sshdcấu hình (phía máy chủ) để chấp nhận nó và dựa vào đó, sửa đổi .bashrctệp của root để điều chỉnh hành vi theo giá trị của biến.

Điều này ngụ ý thay đổi sshdcấu hình trên tất cả các máy chủ cũng như của chúng .bashrc. Không hẳn là một cách "độc lập" để làm, tuy nhiên ...


3

Đối với một giải pháp phía khách hàng dễ dàng:

alias connect='ssh -t root@server "bash -o vi"'

Điều này sẽ thất bại nếu các tập lệnh khởi tạo shell của root sử dụng set -o emacshoặc đặt EDITORthành rõ ràng emacs, hoặc nếu .initrctập tin của root gọi emacscác ràng buộc chính.

Phần còn lại của câu trả lời này liên quan đến các giải pháp phía máy chủ.


Điều này hoạt động khi bạn đang sshvào máy và sau đó sử dụng sudo -i:

Dành cho bạn /root/.bashrc:

if [[ -n "$SUDO_USER" ]] && [[ -f /root/.bashrc-"$SUDO_USER" ]]; then
  source /root/.bashrc-"$SUDO_USER"
fi

Điều này cho phép bạn có một bashrctệp cá nhân được gọi là /root/.bashrc-patricktrong đó bạn có thể làm bất cứ điều gì bạn thích, thích set -o vi.

Kết hợp điều này với một cách tiếp cận hơi ngây thơ để chọn tập tin RC đó tùy thuộc vào $SSH_CLIENT:

if [[ -n "$SUDO_USER" ]]; then
  person="$SUDO_USER"
elif [[ -n "$SSH_CLIENT" ]]; then

  case "$SSH_CLIENT" in
    192.168.216.100*)  person="joe" ;;
    192.168.216.120*)  person="patrick" ;;
    192.168.216.150*)  person="lindsey" ;;
  esac

fi

if [[ -n "$person" ]] && [[ -f /root/.bashrc-"$person" ]]; then
  source /root/.bashrc-"$person"
fi

Điều này rõ ràng chỉ hoạt động nếu bạn luôn kết nối từ cùng một địa chỉ IP ...

Một cách tiếp cận khác sử dụng trường nhận xét của khóa SSH cụ thể bạn đang sử dụng, hoạt động nếu bạn chuyển tiếp tác nhân SSH đến máy chủ:

ssh_comment="$( ssh-add -L | grep -f /root/.ssh/authorized_keys | awk '{ print $NF '} | head -n 1 )"

Thao tác này chọn trường nhận xét cho khóa mà bạn đã sử dụng để kết nối với máy chủ. Có head -n 1trong trường hợp bạn có một số khóa trong authorized_keystệp.

Sau đó, bạn có thể sử dụng $ssh_commentđể chọn một tệp RC vào nguồn, trực tiếp như với $SUDO_USERcách tiếp cận ở trên (trong đó nhận xét $ssh_commentcó thể cần phải trải qua một số dọn dẹp nếu đó là tên đường dẫn) hoặc thông qua một casetuyên bố như với $SSH_CLIENTcách tiếp cận.


Phù hợp SSH_CLIENTSUDO_USERlà những gì tôi sử dụng hiện tại, nhưng nó yêu cầu sửa đổi phía máy chủ và nó không đặc biệt đáng tin cậy. Tôi đã hy vọng cho một giải pháp phía khách hàng thuần túy. Cảm ơn bạn đã gợi ý mặc dù.
Patrick

3

Nếu bạn thực sự muốn làm điều đó mà không sửa đổi ở phía máy chủ, một trong hai:

1) Chạy một cái gì đó như

$ ssh user@host -t 'bash -l -o vi' 

Tôi không nghĩ rằng tài liệu này quá rõ ràng về điều đó, nhưng -o optionđược đề cập và dường như có hiệu quả.

2) Sử dụng mong đợi:

Các expectkịch bản:

$ cat bashsetup.expect
#!/usr/bin/expect -f 

set user [lindex $argv 0];
set host [lindex $argv 1];

spawn ssh -l $user $host
expect "$ "
send "set -o vi\n"
interact

Làm cho nó thực thi và chạy:

$ ./bashsetup.expect user testhost
spawn ssh -l user testhost
[motd, blahblah...]
user@testhost ~$ set -o vi
user@testhost ~$ 

Điều này giả định rằng bạn có thể đăng nhập mà không cần nhập mật khẩu (cho máy chủ từ xa hoặc cho các khóa của bạn), nếu không, tập lệnh mong đợi sẽ cần phải tính đến điều đó. Nhưng với rất nhiều máy bạn có khả năng đã có điều đó. Ngoài ra, tôi mong đợi một ký hiệu đô la và một khoảng trắng, chỉnh sửa nó theo lời nhắc của bạn: "# "có lẽ.

Mặc dù nếu một cái gì đó được in trước lời nhắc bao gồm các ký tự tương tự, bạn sẽ cần bao gồm một cái gì đó cụ thể hơn trong chuỗi dự kiến.

Ngoài ra, tập lệnh đó không hỗ trợ đưa ra các đối số bổ sung ssh. Nếu bạn định đưa ra một lệnh rõ ràng để chạy, có lẽ bạn không cần chế độ vi, nhưng nếu bạn cần nói đường hầm cổng, đó có thể là một vấn đề.


Nhưng trong mọi trường hợp, tôi thực sự nghĩ rằng điều này nên được giải quyết trên các hệ thống đích bằng các tài khoản riêng biệt ( sudohoặc chỉ đơn giản là UID 0 cũ). Cấu hình được cá nhân hóa cũng hữu ích cho nhiều trường hợp khác và nói chung, bạn có một loạt các tệp cấu hình và các biến môi trường mà bạn muốn đặt. (Xem xét rằng các quản trị viên có thể không đồng ý về giá trị của $EDITOR, hoặc nội dung của virchoặc bất cứ điều gì.)

Ngoài ra loại bỏ người dùng sẽ dễ dàng hơn với các tài khoản riêng biệt.

Bất kỳ cách nào để đồng bộ hóa các tệp trên tất cả các máy chủ cũng sẽ giải quyết vấn đề này một cách tầm thường bằng cách cho phép bạn đăng nhập bằng một cái gì đó như ssh -t user@host 'patricks_shell.sh'hoặc ssh -t user@host 'bash --rcfile patrick.rc'.


Tôi đã nghĩ đến việc sử dụng kỳ vọng, nhưng như bạn đã chỉ ra trong câu hỏi của mình, vấn đề đang khớp với một cái gì đó duy nhất để nhắc nhở bắt đầu interact. Nó không tồn tại, lời nhắc có thể khác nhau, cũng như các động cơ / đầu ra từ hồ sơ. Nhờ đề nghị mặc dù.
Patrick

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.