Bắt đầu ssh-agent khi đăng nhập


262

Tôi có một trang web dưới dạng repo Git từ xa lấy từ Bitbucket.com bằng bí danh SSH. Tôi có thể tự khởi động ssh-agent trên máy chủ của mình nhưng tôi phải làm điều này mỗi lần tôi đăng nhập qua SSH.

Tôi tự khởi động ssh-agent:

eval ssh-agent $SHELL

Sau đó tôi thêm tác nhân:

ssh-add ~/.ssh/bitbucket_id

Sau đó, nó xuất hiện khi tôi làm:

ssh-add -l

Và tôi tốt để đi. Có cách nào để tự động hóa quá trình này để tôi không phải làm điều đó mỗi khi tôi đăng nhập không? Máy chủ đang chạy RedHat 6.2 (Santiago).


2
Bất cứ điều gì bạn muốn làm mỗi khi bạn đăng nhập nên vào .profile (đăng nhập cuối) hoặc .xinitrc (đối với đăng nhập GUI).
Barmar

1
Ah! Tôi đã sử dụng .bash_profile ... Sự khác biệt giữa .profile và .bash_profile là gì?
Pathsofdesign

1
Không chắc chắn tại sao bạn đang chạy lệnh theo cách đó ngay từ đầu. ssh-agent <command>chạy <command>như một quy trình con ssh-agent, vì vậy bạn đang bắt đầu một trình bao mới. Tôi nghĩ bạn muốn eval ssh-agent.
Barmar

9
.bash_profilelà đặc trưng cho bash, .profilelà chung cho tất cả các vỏ POSIX. bashsẽ tìm đầu tiên .bash_profile, sau đó mặc định .profile.
Barmar

5
Cách chính xác để sinh ra ssh-agentvỏ "tiêu chuẩn" (tương thích POSIX) là eval $(ssh-agent -s). Cũng lưu ý rằng bạn phải chắc chắn rằng bạn đúng cách để loại bỏ các đại lý khi bạn đăng xuất, do đó, nó cũng nên đặt trap 'kill $SSH_AGENT_PID' EXITở của bạn .profilesau khi dòng mà bắt đầu các đại lý.
kostix

Câu trả lời:


368

Hãy đi qua bài viết này. Bạn có thể thấy điều này rất hữu ích:

http://mah.everybody.org/docs/ssh

Chỉ trong trường hợp liên kết trên biến mất một ngày nào đó, tôi đang nắm bắt phần chính của giải pháp bên dưới:

Giải pháp này của Joseph M. Reagle bằng cách của Daniel Starin:

Thêm cái này vào đây .bash_profile

SSH_ENV="$HOME/.ssh/agent-environment"

function start_agent {
    echo "Initialising new SSH agent..."
    /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
    echo succeeded
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    /usr/bin/ssh-add;
}

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
    . "${SSH_ENV}" > /dev/null
    #ps ${SSH_AGENT_PID} doesn't work under cywgin
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi

Phiên bản này đặc biệt hay vì nó sẽ biết nếu bạn đã khởi động ssh-agent và, nếu không tìm thấy, sẽ khởi động và lưu trữ các cài đặt để chúng có thể sử dụng được vào lần tới khi bạn khởi động vỏ.


8
Không cần khởi động lại máy. Bạn chỉ có thể tải lại .bash_profilebằng cách sử dụng source ~/.bash_profilephiên shell hiện tại của bạn. Khởi động lại máy cũng sẽ hoạt động vì dù sao nó cũng sẽ tải cấu hình mới.
Litmus

11
Sử dụng SSH_ENV="$HOME/.ssh/env"(tức là không / môi trường) Tại sao? sshd sử dụng ~ / .ssh / môi trường (xem trang man: PermitUserEn Môi trường). Github cũng đề xuất điều này trong giải pháp của họ - help.github.com/articles/ từ
Andrew Murphy

7
Kịch bản này hoạt động với tôi khi tôi đặt nó vào tệp ~ / .bashrc của tôi (không phải ~ / .profile hoặc ~ / .bash_profile). Lần đầu tiên tôi mở bảng điều khiển cục bộ, nó sẽ nhắc cụm mật khẩu, mọi thứ hoạt động từ thời điểm đó mà không cần nhắc thêm. Chúc mừng.
pate

3
Thêm ssh-agentlệnh start trong .bashrc sẽ khiến scplệnh không hoạt động.
Dzanvu 18/03/2015

5
Vẫn còn khó chịu ... bạn phải làm điều này mỗi khi bạn đăng nhập ... ngay cả khi bạn không sử dụng ssh. Cần tắt lửa mỗi khi ssh được gọi ... và lý tưởng nhất là bạn có thể định cấu hình máy chủ nào gây ra khóa nào để tải.
Erik Aronesty

98

Trên Arch Linux, các công việc sau đây thực sự tuyệt vời (nên hoạt động trên tất cả các bản phát hành dựa trên hệ thống):

Tạo một dịch vụ người dùng systemd, bằng cách đặt như sau ~/.config/systemd/user/ssh-agent.service:

[Unit]
Description=SSH key agent

[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK

[Install]
WantedBy=default.target

Thiết lập shell để có một biến môi trường cho socket ( .bash_profile, .zshrc, ...):

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"

Kích hoạt dịch vụ, vì vậy nó sẽ được khởi động tự động khi đăng nhập và khởi động nó:

systemctl --user enable ssh-agent
systemctl --user start ssh-agent

Thêm cài đặt cấu hình sau vào tệp cấu hình ssh cục bộ của bạn ~/.ssh/config(cách này hoạt động kể từ SSH 7.2):

AddKeysToAgent  yes

Điều này sẽ hướng dẫn máy khách ssh luôn thêm khóa vào một tác nhân đang chạy, do đó không cần phải thêm ssh trước đó.


3
Tôi đã tìm thấy nhận xét này trong khi cố gắng làm điều này trong Ubuntu. Nó dường như chơi độc đáo hơn nhiều với các hệ thống được tích hợp sẵn hơn là hack một cái gì đó vào các tập lệnh khởi động, ít nhất là cho tôi kiến ​​thức về cách hệ thống nên hoạt động.
tiêu chí

Tôi đã thử điều này trên Ubuntu 16.04 LTS. Thật không may, mọi quá trình shell muốn ssh-agentquá trình cá nhân của nó . Có lẽ tôi thiếu kiến ​​thức ngay cả sau khi đọc tài liệu.
Daisuke Aramaki

Bạn cũng có thể sử dụng Type = đơn giản . wiki.archlinux.org/index.php/ trộm
Hans-J. Schmid

2
Vì vậy, giải pháp này về cơ bản là cài đặt / cấu hình một dịch vụ systemd (nhưng chỉ dành cho người dùng)?
Trevor Boyd Smith

Điều này sẽ không đặt SSH_AGENT_PIDbiến môi trường, mặc dù :(
MrMeszaros

73

Câu hỏi cũ, nhưng tôi đã gặp một tình huống tương tự. Đừng nghĩ rằng câu trả lời trên hoàn toàn đạt được những gì cần thiết. Phần còn thiếu là keychain; cài đặt nó nếu nó chưa có.

sudo apt-get install keychain

Sau đó thêm dòng sau vào ~/.bashrc

eval $(keychain --eval id_rsa)

Điều này sẽ bắt đầu ssh-agentnếu nó không chạy, kết nối với nó nếu có, tảissh-agent biến môi trường vào vỏ của bạn và tải khóa ssh của bạn.

Thay đổi id_rsabất kỳ khóa riêng nào ~/.sshbạn muốn tải.

Tài liệu tham khảo

/unix/90853/how-can-i-run-ssh-add-automatically-without-password-prompt


móc khóa không hoạt động với tôi theo các hướng dẫn được đưa ra. Tôi đã thêm vào .bash_profile và ssh vẫn hỏi mật khẩu mỗi lần. tôi đã thử nó nhiều lần trong cùng một vỏ. không có con xúc xắc. quay trở lại cách tiếp cận ssh-agent cơ bản
javadba

Thêm eval keychain --eval id_[yourid file]vào .bashrc
xelber

4
Tôi đã dành 20 phút để nghiên cứu một giải pháp vì định dạng bình luận StackOverflow. Mỗi lần bình luận xelber của trên, giải pháp đúng là eval `keychain --eval id_[yourid file]`đến .bashrc. Backticks cần thiết để đánh giá các biến môi trường cho shell hiện tại để truy cập vào ssh-agent đang chạy.
James

2
Đây là giải pháp chính xác và đơn giản. Nếu bạn không muốn xem nhật ký khi lệnh móc khóa được thực thi, bạn có thể thêm -qtùy chọn cho chế độ im lặng. Thông tin thêm về Keychain: funtoo.org/Keychain
Diki Ananta

4
Thx, đây là giải pháp thanh lịch nhất.
g Greenspand

37

Các giải pháp được chấp nhận có nhược điểm sau:

  • nó là phức tạp để duy trì;
  • nó đánh giá tệp lưu trữ có thể dẫn đến lỗi hoặc vi phạm bảo mật;
  • nó khởi động tác nhân nhưng không dừng nó, tương đương với việc để chìa khóa trong đánh lửa.

Nếu khóa của bạn không yêu cầu nhập mật khẩu, tôi đề nghị giải pháp sau. Thêm phần sau vào .bash_profile phần cuối của bạn (chỉnh sửa danh sách chính theo nhu cầu của bạn):

exec ssh-agent $BASH -s 10<&0 << EOF
    ssh-add ~/.ssh/your_key1.rsa \
            ~/.ssh/your_key2.rsa &> /dev/null
    exec $BASH <&10-
EOF

Nó có những ưu điểm sau:

  • giải pháp đơn giản hơn nhiều;
  • phiên đại lý kết thúc khi phiên bash kết thúc.

Nó có những nhược điểm có thể xảy ra:

  • tương tác ssh-addlệnh sẽ chỉ ảnh hưởng đến một phiên, trong thực tế, đây chỉ là một vấn đề trong các trường hợp rất không điển hình;
  • không sử dụng được nếu gõ mật khẩu là bắt buộc;
  • shell bắt đầu trở thành không đăng nhập (không ảnh hưởng đến bất cứ điều gì AFAIK).

Lưu ý rằng một số ssh-agentquy trình không phải là bất lợi, vì chúng không chiếm nhiều thời gian bộ nhớ hoặc CPU.


Tôi đã có các khóa SSH trong một thư mục bên ngoài $ HOME trong Windows 10, sử dụng Git Bash. Thay đổi đường dẫn đến RSA là tất cả những gì tôi cần làm để thực hiện điều này. TYVM!
kayleeFrye_onDeck 18/03/2016

7
Tôi sẽ lập luận rằng "Nếu khóa của bạn không yêu cầu nhập mật khẩu" thì gần tương đương với việc để chìa khóa trong đánh lửa.
Bruno Bronosky

Ít nhất, nó là trên máy chủ của riêng bạn, không phải ở đâu đó trên mạng.
midenok

1
"Tôi sẽ lập luận rằng" Nếu khóa của bạn không yêu cầu nhập mật khẩu "thì gần tương đương với việc để chìa khóa trong đánh lửa." <- Giải thích làm thế nào ?? Bởi vì các khóa linh hoạt hơn nhiều so với mật khẩu, việc thu hồi dễ dàng hơn nhiều (cái gì? Bạn chỉ sử dụng các khóa cho người dùng sudo có quyền truy cập đầy đủ? Tsk tsk). Nhiều bộ khóa cho nhiều hồ sơ của người dùng. Nếu bạn muốn tự động hóa mọi thứ (như triển khai hoặc kết thúc kiểm tra) thì chúc may mắn liên tục nhập mật khẩu trong khi "phối hợp".
Scott Prive

2
Đừng làm vậy. Chìa khóa mật khẩu là một thực hành xấu.
dùng48678

26

Thêm cái này vào ~/.bashrc, sau đó đăng xuất và đăng nhập lại để có hiệu lực.

if [ ! -S ~/.ssh/ssh_auth_sock ]; then
  eval `ssh-agent`
  ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
ssh-add -l > /dev/null || ssh-add

Điều này chỉ nên nhắc mật khẩu lần đầu tiên bạn đăng nhập sau mỗi lần khởi động lại. Nó sẽ tiếp tục sử dụng lại ssh-agentmiễn là nó vẫn chạy.


Chúng ta sẽ sử dụng cái gì thay vào đó nếu chúng ta có nhiều khóa và chúng không được đặt tên ~/.ssh/id_rsa? Có vẻ như ssh-addmột phần câu trả lời của bạn mong đợi tên tệp mặc định cho các khóa.
Gabriel Staples

Vâng Tôi tin rằng bạn chỉ có thể thêm tên tệp vào cuối dòng cuối cùng nếu cần
Collin Anderson

Nhưng bạn vẫn không thể tự động hóa một tập lệnh để lấy công cụ git chẳng hạn mà không cần nhập mật khẩu thủ công? Làm thế nào để tránh điều đó?
đào tạo

7

Vì vậy, tôi đã từng sử dụng các cách tiếp cận được mô tả ở trên, nhưng tôi thích loại tác nhân chết hơn khi phiên bash cuối cùng của tôi kết thúc. Điều này dài hơn một chút so với các giải pháp khác, nhưng đó là cách tiếp cận ưa thích của tôi. Ý tưởng cơ bản là phiên bash đầu tiên khởi động tác nhân ssh. Sau đó, mỗi phiên bash bổ sung sẽ kiểm tra tệp cấu hình ( ~/.ssh/.agent_env). Nếu đó là có và có một phiên chạy, sau đó nguồn môi trường và tạo một liên kết cứng đến tệp ổ cắm trong /tmp(cần phải nằm trên cùng hệ thống tệp với tệp ổ cắm gốc). Khi các phiên bash đóng cửa, mỗi lần xóa liên kết cứng của chính nó. Phiên cuối cùng để đóng sẽ thấy rằng các liên kết cứng có 2 liên kết (liên kết cứng và ban đầu), loại bỏ ổ cắm riêng của quy trình và giết quá trình sẽ dẫn đến 0, để lại một môi trường sạch sau khi phiên bash cuối cùng đóng lại.

# Start ssh-agent to keep you logged in with keys, use `ssh-add` to log in
agent=`pgrep ssh-agent -u $USER` # get only your agents           
if [[ "$agent" == "" || ! -e ~/.ssh/.agent_env ]]; then
    # if no agents or environment file is missing create a new one
    # remove old agents / environment variable files
    kill $agent running
    rm ~/.ssh/.agent_env 

    # restart
    eval `ssh-agent` 
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ~/.ssh/.agent_env             
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ~/.ssh/.agent_env             
fi

# create our own hardlink to the socket (with random name)           
source ~/.ssh/.agent_env                                                    
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock                                        
ln -T $SSH_AUTH_SOCK $MYSOCK                                                
export SSH_AUTH_SOCK=$MYSOCK                                                

end_agent()                                                                     
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`                             
    if [[ "$nhard" -eq 2 ]]; then                                               
        rm ~/.ssh/.agent_env                                                    
        ssh-agent -k                                                            
    fi                                                                          
    rm $SSH_AUTH_SOCK                                                           
}                                                                               
trap end_agent EXIT                                                             
set +x              

Nếu chúng ta chạy tập lệnh này dưới dạng tập lệnh BASH khi đăng nhập bất kỳ trình bao nào khác (khác với BASH), thì nó cũng sẽ hoạt động, phải không?
hoijui

7

Chỉ cần thêm một giải pháp khác: P, tôi đã kết hợp các giải pháp của @spheenik và @ collin-anderson.

 # Ensure that we have an ssh config with AddKeysToAgent set to true
 if [ ! -f ~/.ssh/config ] || ! cat ~/.ssh/config | grep AddKeysToAgent | grep yes > /dev/null; then
     echo "AddKeysToAgent  yes" >> ~/.ssh/config
 fi
 # Ensure a ssh-agent is running so you only have to enter keys once
 if [ ! -S ~/.ssh/ssh_auth_sock ]; then
   eval `ssh-agent`
   ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
 fi
 export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock

Có thể thanh lịch hơn một chút nhưng nó đơn giản và dễ đọc. Giải pháp này:

  • đảm bảo AddKeysToAgent yestrong cấu hình ssh của bạn để các khóa sẽ được tự động thêm vào khi sử dụng
  • không nhắc bạn nhập bất kỳ cụm mật khẩu nào khi đăng nhập (một lần nữa, nhập cụm mật khẩu một lần xảy ra trong lần sử dụng đầu tiên)
  • âm thầm bắt đầu một tác nhân ssh nếu nó chưa bắt đầu một tác nhân

Bình luận hoan nghênh :)


1
Điều này làm việc hoàn hảo cho tôi. Trên Kubfox tôi đặt nó vào .profile.
Shai

1
Tốt để biết về các AddKeysToAgent yesthiết lập. Cảm ơn.
Collin Anderson

3

Tôi đã giải quyết nó bằng cách thêm phần này vào / etc / profile - toàn hệ thống (hoặc cho người dùng .profile cục bộ hoặc _.bash_profile_):

# SSH-AGENT 
#!/usr/bin/env bash
SERVICE='ssh-agent'
WHOAMI=`who am i |awk '{print $1}'`

if pgrep -u $WHOAMI $SERVICE >/dev/null
then
    echo $SERVICE running.
else
    echo $SERVICE not running.
    echo starting
    ssh-agent > ~/.ssh/agent_env
fi
. ~/.ssh/agent_env

Điều này khởi động một ssh-agent mới nếu không chạy cho người dùng hiện tại hoặc đặt lại tham số env ssh-agent nếu chạy.


Cảm ơn bạn đã nói làm thế nào để biết nếu các đại lý đã chạy!
Mike Maxwell

Làm thế nào để if pgrep -u $WHOAMI $SERVICE >/dev/nulllàm việc?
Josh Desmond

3

Người dùng vỏ cá có thể sử dụng tập lệnh này để làm điều tương tự.

# content has to be in .config/fish/config.fish
# if it does not exist, create the file
setenv SSH_ENV $HOME/.ssh/environment

function start_agent                                                                                                                                                                    
    echo "Initializing new SSH agent ..."
    ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV
    echo "succeeded"
    chmod 600 $SSH_ENV 
    . $SSH_ENV > /dev/null
    ssh-add
end

function test_identities                                                                                                                                                                
    ssh-add -l | grep "The agent has no identities" > /dev/null
    if [ $status -eq 0 ]
        ssh-add
        if [ $status -eq 2 ]
            start_agent
        end
    end
end

if [ -n "$SSH_AGENT_PID" ] 
    ps -ef | grep $SSH_AGENT_PID | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    end  
else
    if [ -f $SSH_ENV ]
        . $SSH_ENV > /dev/null
    end  
    ps -ef | grep $SSH_AGENT_PID | grep -v grep | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    else 
        start_agent
    end  
end

2

Tôi sử dụng công cụ nhận dạng ssh cho việc này.

Từ trang của anh ấy:

ssh-nhận dạng - Bắt đầu và sử dụng ssh-agent và tải danh tính khi cần thiết.


1

Đã thử giải pháp cặp đôi từ nhiều nguồn nhưng tất cả dường như quá nhiều rắc rối. Cuối cùng tôi cũng tìm được cái dễ nhất :)

Nếu bạn chưa quen với zshoh-my-zsh thì hãy cài đặt nó. Bạn sẽ thích nó :)

Sau đó chỉnh sửa .zshrc

vim ~/.zshrc

tìm pluginsphần và cập nhật nó để sử dụng ssh-agentnhư vậy:

plugins=(ssh-agent git)

Và đó là tất cả! Bạn sẽ có ssh-agentvà chạy mỗi khi bạn khởi động vỏ của bạn


1

Tôi thích câu trả lời của bạn rất nhiều. Nó làm cho công việc từ cygwin / linuxmáy chủ dễ dàng hơn nhiều. Tôi kết hợp các chức năng bắt đầu và kết thúc để làm cho nó an toàn.

SSH_ENV="$HOME/.ssh/.agent_env"

function start_agent {
    echo "Initialising new SSH agent..."

    eval `/usr/bin/ssh-agent`
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ${SSH_ENV}
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ${SSH_ENV}

    echo succeeded
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    /usr/bin/ssh-add;
}

# Source SSH settings, if applicable
if [ -f "${SSH_ENV}" ]; then
    . "${SSH_ENV}" > /dev/null
    #ps ${SSH_AGENT_PID} doesn't work under cywgin
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi

# create our own hardlink to the socket (with random name)
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock
ln -T $SSH_AUTH_SOCK $MYSOCK
export SSH_AUTH_SOCK=$MYSOCK

end_agent()
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`
    if [[ "$nhard" -eq 2 ]]; then
        rm ${SSH_ENV}
        /usr/bin/ssh-agent -k
    fi
    rm $SSH_AUTH_SOCK
}
trap end_agent EXIT
set +x
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.