Mulai ssh-agent saat login

262

Saya memiliki situs sebagai repo Git jarak jauh yang menarik dari Bitbucket.com menggunakan alias SSH. Saya dapat secara manual memulai ssh-agent di server saya tetapi saya harus melakukan ini setiap kali saya masuk melalui SSH.

Saya secara manual memulai ssh-agent:

eval ssh-agent $SHELL

Lalu saya menambahkan agen:

ssh-add ~/.ssh/bitbucket_id

Kemudian muncul ketika saya melakukannya:

ssh-add -l

Dan saya baik untuk pergi. Apakah ada cara untuk mengotomatisasi proses ini sehingga saya tidak harus melakukannya setiap kali saya masuk? Server menjalankan RedHat 6.2 (Santiago).

Pathsofdesign
sumber
2
Apa pun yang ingin Anda lakukan setiap kali masuk harus dalam profil. (Login terminal) atau .xinitrc (untuk login GUI).
Barmar
1
Ah! Saya menggunakan .bash_profile ... Apa perbedaan antara .profile dan .bash_profile?
Pathsofdesign
1
Tidak yakin mengapa Anda menjalankan perintah seperti itu di tempat pertama. ssh-agent <command>berjalan <command>sebagai subproses ssh-agent, jadi Anda memulai shell baru. Saya pikir kamu mau eval ssh-agent.
Barmar
9
.bash_profilekhusus untuk bash, .profilegenerik untuk semua shell POSIX. bashakan mencari yang pertama.bash_profile , lalu default ke .profile.
Barmar
5
Cara yang benar untuk menelurkan ssh-agentshell "standar" (kompatibel POSIX) adalah eval $(ssh-agent -s). Perhatikan juga bahwa Anda harus memastikan bahwa Anda benar-benar menyingkirkan agen ketika Anda logout, jadi sebaiknya Anda memasukkan setelah trap 'kill $SSH_AGENT_PID' EXITAnda .profilebaris yang memulai agen.
kostix

Jawaban:

368

Silakan baca artikel ini. Anda mungkin menemukan ini sangat berguna:

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

Kalau-kalau tautan di atas hilang suatu hari, saya menangkap bagian utama dari solusi di bawah:

Solusi ini dari Joseph M. Reagle melalui Daniel Starin:

Tambahkan yang berikut ini ke .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

Versi ini sangat bagus karena akan melihat apakah Anda sudah memulai ssh-agent dan, jika tidak dapat menemukannya, akan memulai dan menyimpan pengaturan sehingga mereka akan dapat digunakan saat berikutnya Anda memulai sebuah kulit.

Lakmus
sumber
8
Mesin restart tidak perlu. Anda bisa memuat ulang .bash_profilemenggunakan source ~/.bash_profiledalam sesi shell Anda saat ini. Mesin restart juga akan berfungsi karena itu akan memuat konfigurasi baru.
Litmus
11
Gunakan SSH_ENV="$HOME/.ssh/env"(yaitu tidak / lingkungan) Mengapa? sshd menggunakan ~ / .ssh / environment (lihat halaman manual: PermitUserEnvironment). Github juga merekomendasikan ini dalam solusi mereka - help.github.com/articles/…
Andrew Murphy
7
Skrip ini berfungsi untuk saya ketika saya meletakkannya di file ~ / .bashrc saya (bukan file ~ / .profile atau ~ / .bash_profile) saya. Pertama kali saya membuka konsol lokal yang meminta kata sandi, semuanya berfungsi sejak saat itu tanpa diminta lebih lanjut. Bersulang.
andrew pate
3
Menambahkan ssh-agentperintah mulai di .bashrc akan membuat scpperintah tidak berfungsi.
Dzanvu
5
Masih menyebalkan ... Anda harus melakukan ini setiap kali Anda masuk ... bahkan jika Anda tidak menggunakan ssh. Perlu mematikan ini setiap kali ssh dipanggil ... dan idealnya, Anda harus dapat mengonfigurasi host mana yang menyebabkan kunci mana yang dimuat.
Erik Aronesty
99

Di Arch Linux, berikut ini berfungsi dengan sangat baik (harus bekerja pada semua distro berbasis systemd):

Buat layanan pengguna systemd, dengan menempatkan yang berikut ke ~/.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

Setup shell memiliki variabel lingkungan untuk socket ( .bash_profile, .zshrc, ...):

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

Aktifkan layanan, sehingga akan dimulai secara otomatis saat masuk, dan mulai:

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

Tambahkan pengaturan konfigurasi berikut ke file konfigurasi ssh lokal Anda ~/.ssh/config(ini berfungsi sejak SSH 7.2):

AddKeysToAgent  yes

Ini akan menginstruksikan klien ssh untuk selalu menambahkan kunci ke agen yang sedang berjalan, jadi tidak perlu menambahkan ssh sebelumnya.

spheenik
sumber
3
Saya menemukan komentar ini ketika mencoba melakukan ini di Ubuntu. Tampaknya bermain jauh lebih baik dengan sistem bawaan daripada meretas sesuatu ke dalam skrip startup, setidaknya memberikan pengetahuan saya tentang bagaimana sistem seharusnya bekerja.
xiterion
Saya mencoba ini di Ubuntu 16.04 LTS. Sayangnya, setiap proses shell menginginkan ssh-agentproses individualnya . Mungkin saya kurang pengetahuan bahkan setelah membaca dokumen.
Daisuke Aramaki
Anda juga dapat menggunakan Type = sederhana . wiki.archlinux.org/index.php/…
Hans-J. Schmid
2
jadi apakah solusi ini pada dasarnya menginstal / mengkonfigurasi layanan systemd (tetapi hanya untuk pengguna)?
Trevor Boyd Smith
Ini tidak akan mengatur SSH_AGENT_PIDvariabel lingkungan, meskipun :(
MrMeszaros
73

Pertanyaan lama, tetapi saya menemukan situasi yang sama. Jangan berpikir jawaban di atas sepenuhnya mencapai apa yang dibutuhkan. Bagian yang hilang adalah keychain; instal jika belum.

sudo apt-get install keychain

Kemudian tambahkan baris berikut ke ~/.bashrc

eval $(keychain --eval id_rsa)

Ini akan memulai ssh-agentjika tidak berjalan, sambungkan ke sana jika sudah, muatssh-agent variabel lingkungan ke shell Anda, dan muat kunci ssh Anda.

Ubah id_rsake kunci pribadi mana saja yang ~/.sshingin Anda muat.

Referensi

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

xelber
sumber
gantungan kunci tidak berfungsi untuk saya sesuai dengan instruksi yang diberikan. Saya menambahkan .bash_profile dan ssh masih meminta kata sandi setiap waktu. saya mencobanya beberapa kali di shell yang sama. tidak ada dadu. akan kembali ke pendekatan ssh-agent dasar
javadba
Tambahkan eval keychain --eval id_[yourid file]ke .bashrc
xelber
4
Saya menghabiskan 20 menit meneliti solusi karena pemformatan komentar StackOverflow. Per komentar xelber di atas, solusi yang tepat adalah eval `keychain --eval id_[yourid file]`untuk .bashrc. Backticks diperlukan untuk mengevaluasi variabel lingkungan ke shell saat ini untuk akses ke ssh-agent yang sedang berjalan.
James
2
Ini adalah solusi yang benar dan sederhana. Jika Anda tidak ingin melihat log ketika perintah gantungan kunci dijalankan, Anda dapat menambahkan -qopsi untuk mode senyap. Info lebih lanjut tentang Keychain: funtoo.org/Keychain
Diki Ananta
4
Terima kasih, ini adalah solusi yang paling elegan.
greenspand
37

Solusi yang diterima memiliki kekurangan berikut:

  • rumit untuk dipertahankan;
  • itu mengevaluasi file penyimpanan yang dapat menyebabkan kesalahan atau pelanggaran keamanan;
  • itu mulai agen tetapi tidak menghentikannya yang hampir sama dengan meninggalkan kunci di pengapian.

Jika kunci Anda tidak perlu mengetik kata sandi, saya sarankan solusi berikut. Tambahkan berikut ini ke .bash_profile ujung Anda (edit daftar kunci dengan kebutuhan Anda):

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

Ini memiliki keuntungan sebagai berikut:

  • solusi yang jauh lebih sederhana;
  • sesi agen berakhir ketika sesi bash berakhir.

Ini memiliki kemungkinan kerugian:

  • interaktif ssh-addperintah hanya akan mempengaruhi satu sesi, yang sebenarnya merupakan masalah hanya dalam keadaan yang sangat tidak biasa;
  • tidak dapat digunakan jika mengetik kata sandi diperlukan;
  • shell yang dimulai menjadi non-login (yang tidak memengaruhi apa pun AFAIK).

Perhatikan bahwa beberapa ssh-agentproses bukanlah suatu kerugian, karena mereka tidak mengambil lebih banyak memori atau waktu CPU.

midenok
sumber
Saya punya kunci SSH di direktori di luar $ HOME di Windows 10, menggunakan Git Bash. Mengubah jalur ke RSA adalah semua yang perlu saya lakukan untuk membuatnya bekerja. TYVM!
kayleeFrye_onDeck
7
Saya berpendapat bahwa "Jika kunci Anda tidak perlu mengetik kata sandi" hampir sama dengan meninggalkan kunci dalam pengapian.
Bruno Bronosky
Setidaknya, itu ada di host Anda sendiri, bukan di suatu tempat di jaringan.
midenok
1
"Saya berpendapat bahwa" Jika kunci Anda tidak perlu mengetikkan kata sandi "hampir sama dengan meninggalkan kunci dalam pengapian." <- Jelaskan bagaimana caranya ?? Karena kunci jauh lebih fleksibel daripada kata sandi, jauh lebih mudah untuk dicabut (apa? Anda hanya menggunakan kunci untuk pengguna sudo dengan akses penuh? Tsk tsk). Beberapa set kunci untuk beberapa profil pengguna. Jika Anda ingin mengotomatiskan sesuatu (seperti penyebaran, atau pemeriksaan ujung ke ujung), semoga berhasil terus-menerus mengetikkan kata sandi selama "orkestrasi".
Scott Prive
2
Jangan lakukan itu. Kunci tanpa kata sandi adalah praktik yang buruk.
user48678
26

Tambahkan ini ke Anda ~/.bashrc, lalu keluar dan kembali untuk memberi efek.

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

Ini seharusnya hanya meminta kata sandi saat pertama kali Anda login setelah setiap reboot. Itu akan tetap menggunakan kembali sama ssh-agentselama itu tetap berjalan.

Collin Anderson
sumber
Apa yang akan kami gunakan jika kami memiliki beberapa kunci dan tidak diberi nama ~/.ssh/id_rsa? Tampaknya ssh-addbagian dari jawaban Anda mengharapkan nama file default untuk kunci tersebut.
Gabriel Staples
Ya. Saya percaya Anda bisa menambahkan nama file ke akhir baris terakhir jika diperlukan
Collin Anderson
Tetapi Anda masih tidak dapat mengotomatiskan skrip untuk melakukan hal-hal git misalnya tanpa memasukkan kata sandi secara manual? Bagaimana cara menghindarinya?
trainoasis
7

Jadi saya biasa menggunakan pendekatan yang dijelaskan di atas, tapi saya lebih suka agen mati ketika sesi bash terakhir saya berakhir. Ini sedikit lebih lama dari solusi lain, tetapi pendekatan yang saya sukai. Ide dasarnya adalah bahwa sesi bash pertama memulai ssh-agent. Kemudian setiap sesi bash tambahan memeriksa file konfigurasi ( ~/.ssh/.agent_env). Jika itu ada dan ada sesi berjalan maka sumber lingkungan dan buat hardlink ke file socket /tmp(perlu berada di sistem file yang sama dengan file socket asli). Saat sesi bash ditutup, masing-masing menghapus hardlinknya sendiri. Sesi terakhir untuk menutup akan menemukan bahwa hardlink memiliki 2 tautan (hardlink dan asli), penghapusan soket proses sendiri dan membunuh proses akan menghasilkan 0, meninggalkan lingkungan yang bersih setelah sesi bash terakhir ditutup.

# 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              
Mikha
sumber
jika kita menjalankan ini sebagai skrip BASH saat login dari shell lain (selain BASH), itu harus bekerja juga, kan?
hoijui
7

Hanya untuk menambahkan solusi lain: P, saya pergi dengan kombinasi solusi @spheenik dan @ 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

Bisa jadi sedikit lebih elegan tetapi sederhana dan mudah dibaca. Solusi ini:

  • memastikan AddKeysToAgent yes ada di konfigurasi ssh Anda sehingga kunci akan ditambahkan secara otomatis saat digunakan
  • tidak meminta Anda untuk memasukkan frasa sandi apa pun saat masuk (sekali lagi, kata sandi satu kali masuk terjadi saat digunakan pertama kali)
  • diam-diam memulai ssh-agent jika belum dimulai

Komentar diterima :)

Keego
sumber
1
Ini bekerja dengan baik untuk saya. Di Kubuntu saya memasukkannya ke dalam .profile.
Shai
1
Senang mengetahui AddKeysToAgent yespengaturannya. Terima kasih.
Collin Anderson
3

Saya menyelesaikannya dengan menambahkan ini ke / etc / profile - system wide (atau ke pengguna .profile lokal , atau _.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

Ini memulai ssh-agent baru jika tidak berjalan untuk pengguna saat ini, atau mengatur ulang parameter ssh-agent env jika menjalankan.

Katak
sumber
Terima kasih telah mengatakan bagaimana cara mengetahui apakah agen sudah berjalan!
Mike Maxwell
Bagaimana cara if pgrep -u $WHOAMI $SERVICE >/dev/nullkerjanya?
Josh Desmond
3

Pengguna shell ikan dapat menggunakan skrip ini untuk melakukan hal yang sama.

# 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
Daniel Gerber
sumber
2

Saya menggunakan alat ssh-ident untuk ini.

Dari halaman man- nya:

ssh-ident - Mulai dan gunakan ssh-agent dan muat identitas yang diperlukan.

PenciptaanTribe
sumber
1

Mencoba solusi pasangan dari banyak sumber tetapi semua sepertinya terlalu banyak kesulitan. Akhirnya saya menemukan yang paling mudah :)

Jika Anda belum terbiasa dengan zsh dan oh-my-zsh, lalu instal. Kau akan menyukainya :)

Kemudian edit .zshrc

vim ~/.zshrc

temukan pluginsbagian dan perbarui untuk digunakan ssh-agentseperti ini:

plugins=(ssh-agent git)

Dan itu saja! Anda akan memiliki ssh-agentdan menjalankan setiap kali Anda memulai shell Anda

Sharak
sumber
1

Saya sangat menyukai jawaban Anda. Itu membuat bekerja dari cygwin / linuxhost jauh lebih mudah. Saya menggabungkan fungsi awal dan akhir untuk membuatnya aman.

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
Knelis
sumber