ฉันจะ SSH ไปยังเครื่อง A ผ่าน B ในคำสั่งเดียวได้อย่างไร


103

ฉันต้องการเข้าถึงคอมพิวเตอร์พูดว่าmachine Aซึ่งใช้เครือข่ายของมหาวิทยาลัย อย่างไรก็ตามคอมพิวเตอร์นี้สามารถเข้าถึงได้ผ่านเครือข่ายภายในของมหาวิทยาลัยเท่านั้นดังนั้นฉันจึงไม่สามารถใช้ SSH กับคอมพิวเตอร์เครื่องนี้ได้จากที่บ้านโดยตรง

นี่คือสิ่งที่ฉันทำตอนนี้:

  1. เข้าสู่เครื่องมหาวิทยาลัยอื่นพูดmachine B

    (เครื่อง B นี้สามารถเข้าถึงได้ผ่าน SSH จากคอมพิวเตอร์ที่บ้านของฉัน)

  2. ใช้ SSH บน B เพื่อเชื่อมต่อกับ A

มีวิธีทำเร็วกว่านี้ไหม ใช้คำสั่ง ssh เพียงคำเดียว


คำตอบ:


97

ใช่ใช้ProxyCommandในการกำหนดค่า SSH ของคุณ

สร้างไฟล์การกำหนดค่า SSH ในโฮมไดเร็กตอรี่ของคุณ (ยกเว้นว่าคุณต้องการสร้างทั้งระบบนี้) ~/.ssh/config:

Host unibroker          # Machine B definition (the broker)
Hostname 12.34.45.56    # Change this IP address to the address of the broker
User myusername         # Change this default user accordingly 
                        # (`user@unibroker` can overwrite it)

Host internalmachine    # Machine A definition (the target host)
ProxyCommand ssh -q unibroker nc -q0 hostname.or.IP.address.internal.machine 22

ตอนนี้คุณสามารถเข้าถึง Machine A ได้โดยตรงโดยใช้

ssh user@internalmachine

โปรดทราบว่าในตอนนี้คุณมีชื่อโฮสต์โฮสต์ SSH เดียวคุณสามารถใช้ชื่อนี้ในแอปพลิเคชันอื่นเช่นกัน เช่น:

  • SCP เพื่อคัดลอกไฟล์

    scp somefile user@internalmachine:~/
    
  • ในแอปพลิเคชัน GUI ของคุณ:

    ใช้sftp://user@internalmachine/เป็นที่ตั้งเพื่อเรียกดูบนเครื่อง

    ใช้ KDE (โลมา): ใช้ fish://user@internalmachine/

หมายเหตุ

เปลี่ยนhostname.or.IP.address.internal.machineและพอร์ต ( 22) เป็นเครื่องที่คุณต้องการเข้าถึงราวกับว่าคุณต้องการจากunibrokerเครื่อง

ทั้งนี้ขึ้นอยู่กับรุ่น netcat บนโฮสต์ unibroker -q0ตัวเลือกต้องถูกละเว้น เกี่ยวกับการรับรองความถูกต้อง; โดยทั่วไปคุณตั้งค่าการเชื่อมต่อ SSH สองรายการจากเวิร์กสเตชัน ซึ่งหมายความว่าทั้งโฮสต์ unibroker และ hostmachine ภายในจะได้รับการตรวจสอบ / รับรองความถูกต้องต่อกัน (สำหรับ keypair / รหัสผ่านและการตรวจสอบคีย์โฮสต์)

คำอธิบาย

วิธีการใช้งานProxyCommandและ 'netcat' นี้เป็นเพียงวิธีหนึ่งในการทำเช่นนั้น ฉันชอบสิ่งนี้เพราะลูกค้า SSH ของฉันพูดโดยตรงกับเครื่องเป้าหมายเพื่อให้ฉันสามารถตรวจสอบรหัสโฮสต์จากลูกค้าของฉันและฉันสามารถใช้การตรวจสอบกุญแจสาธารณะของฉันโดยไม่ต้องใช้คีย์อื่นในนายหน้า

แต่ละHostกำหนดการเริ่มต้นของส่วนโฮสต์ใหม่ Hostnameเป็นชื่อโฮสต์เป้าหมายหรือที่อยู่ IP ของโฮสต์นั้น คือสิ่งที่คุณจะให้เป็นส่วนหนึ่งของผู้ใช้ในUserssh user@hostname

ProxyCommandจะถูกใช้เป็นท่อไปยังเครื่องเป้าหมาย ด้วยการใช้ SSH ไปยังเครื่องแรกและตั้งค่า 'netcat' ( nc) ไปยังเป้าหมายโดยตรงจากตรงนั้นนี่เป็นเพียงข้อความธรรมดาที่ส่งต่อไปยังเครื่องภายในจากนายหน้าระหว่างนั้น -qตัวเลือกที่จะเงียบผลใด ๆ (เพียงความชอบส่วนบุคคล)

ให้แน่ใจว่าคุณได้ติดตั้ง netcat บนนายหน้า (มักจะใช้ได้โดยเริ่มต้นบน Ubuntu) - ทั้งnetcat-OpenBSDติดตั้ง netcat-openbsdหรือnetcat แบบดั้งเดิมติดตั้ง netcat ดั้งเดิม

โปรดทราบว่าคุณยังคงใช้ SSH พร้อมการเข้ารหัสสองครั้งที่นี่ ในขณะที่ช่อง netcat เป็นข้อความธรรมดาไคลเอ็นต์ SSH ของคุณบนพีซีของคุณจะตั้งค่าแชนเนลที่เข้ารหัสอีกเครื่องด้วยเครื่องเป้าหมายขั้นสุดท้าย


4
ฉันต้องลบตัวเลือก -q0 เนื่องจากเครื่องที่ฉันใช้ไม่รองรับ นอกจากนั้นทุกอย่างก็ใช้ได้ นี่คือเคล็ดลับที่ยอดเยี่ยม ขอบคุณมาก. :)
Gerry

ฉันพบปัญหาคำตอบของคุณทำงานได้ดีสำหรับฉันจาก terminal แต่ฉันไม่สามารถทำได้โดยใช้ gui sftp มันพูดว่า: ข้อความแสดงข้อผิดพลาดที่ไม่สามารถจัดการได้หมดเวลาขณะลงชื่อเข้าใช้
Vikash B

@VikashB เอาล่ะมันควรจะทำงานจริงๆ ลองสร้างคำถามใหม่เพื่อรับมือกับสถานการณ์เฉพาะของคุณ
gertvdijk

ฉันทำที่นี่เป็นคำถาม: askubuntu.com/questions/688567/…
Vikash B

1
เพื่อเติมเต็มคำที่ชาญฉลาดของ @gertvdijk มี wikibook ที่ยอดเยี่ยมเกี่ยวกับหัวข้อของssh proxies และ jump hostที่สามารถใช้เป็นข้อมูลอ้างอิงที่มีค่าได้
Travis Clarke

51

กระโดดในครั้งเดียว

ทางเลือกที่ชัดเจนสำหรับแนวทาง ProxyCommand ที่ฉันให้ไว้ในคำตอบอื่น ๆ ของฉันคือ 'กระโดด' โดยตรงไปยังเครื่องเป้าหมาย:

ssh -t user@machineB ssh user@machineA

หมายเหตุคำสั่ง-tบนsshคำสั่งแรก หากไม่มีมันก็จะล้มเหลว:

Pseudo-terminal will not be allocated because stdin is not a terminal.
ssh_askpass: exec(/usr/bin/ssh-askpass): No such file or directory
Permission denied, please try again.
[...]

มันจะบังคับให้ TTY จริงถูกจัดสรร

ข้อเสียคือตอนนี้การกำหนดค่าการตรวจสอบและการรับรองความถูกต้องทั้งหมดเกิดขึ้นที่ Machine B ซึ่งฉันไม่ชอบในสถานการณ์ของฉันด้วยเหตุผลด้านความปลอดภัย ฉันชอบ keypair ของฉันบนพีซีของฉันและรับรองความถูกต้องและตรวจสอบเครื่องเป้าหมายสุดท้ายจากพีซีของฉันเอง นอกจากนี้คุณสามารถใช้เชลล์แบบโต้ตอบสำหรับ SSH เท่านั้นดังนั้นสิ่งนี้จะไม่จัดการกับเครื่องมืออื่น ๆ เช่น SCP หรือใช้ตัวจัดการไฟล์ GUI ของคุณ

ด้วยเหตุผลทั้งหมดที่กล่าวมาฉันขอแนะนำวิธี ProxyCommandแต่สำหรับการเชื่อมต่ออย่างรวดเร็วสิ่งนี้ใช้ได้ผล


ทำไมไม่มีคำตอบเดียวกับทั้ง 'One Off' และโซลูชั่นถาวร?
เอียงอาย

5
@demure นั่นเป็นวิธีที่เว็บไซต์ StackExchange ทำงาน ... ดู: มารยาทที่เป็นทางการของการตอบคำถามสองครั้งคืออะไร? กล่าวว่า"เป็นการดีกว่าที่จะโพสต์คำตอบที่แตกต่างกันสองข้อแทนที่จะใส่ไว้ในคำตอบเดียว" . และฉันไม่คิดว่านี่จะเป็นทางออกเดียวกัน ถาวร / ชั่วคราวไม่ใช่สิ่งที่ทำให้วิธีการนี้แตกต่างกันในความคิดของฉัน
gertvdijk

คู่มืออื่น ๆ บอกว่าจะใช้นอกจากนี้สวิตช์ -A แต่ระบุว่าสิ่งนี้มีผลกระทบด้านความปลอดภัย คุณรู้หรือไม่ว่าการส่งต่อนั้นหมายถึงการเชื่อมต่อตัวแทนการรับรองความถูกต้องหรือไม่
Diagon

@ gertvdijk super ninja ที่นี่! คุณมีโซลูชันสองอันดับแรก ฉันไม่เคยเห็นแบบนั้นมาก่อน เด็ดสุด ๆ วิธีที่ดีกว่าการสร้างโซลูชันที่มีความยาวหนึ่งเมกะด้วยโซลูชัน N (ซึ่งเป็นสิ่งที่ฉันมักจะเห็น)
เทรเวอร์บอยด์สมิ ธ

สะดวกกว่าการตั้งค่าคอนฟิกซึ่งจะขัดขวาง ssh อื่น ๆ เช่นกัน
Nikhil Sahu

37

คุณสามารถใช้-Jตัวเลือกบรรทัดคำสั่ง:

ssh -J user@machineB user@machineA

จากman ssh:

-J [user@]host[:port]
     Connect to the target host by first making a ssh connection to
     the jump host and then establishing a TCP forwarding to the
     ultimate destination from there.  Multiple jump hops may be
     specified separated by comma characters.  This is a shortcut to
     specify a ProxyJump configuration directive.

เปิดตัวในOpenSSHเวอร์ชั่น 7.3 (เปิดตัวในเดือนสิงหาคม 2559) มันมีอยู่ใน Ubuntu 16.10 และใหม่กว่า


3
+1 เพราะวิธีนี้ใช้ได้แม้ว่าคุณจะต้องระบุไฟล์คีย์สำหรับ machineA
Grief

1
+1 นี่เป็นรุ่นที่ดีกว่าเมื่อเปรียบเทียบกับ ProxyCommand ของฉันหากตอบว่าโฮสต์ทั้งหมดของคุณกำลังใช้งาน OpenSSH เวอร์ชันล่าสุดเพียงพอ
gertvdijk

เซิร์ฟเวอร์ OpenSSH ควรติดตั้งในเครื่อง A และ B ในกรณีนี้หรือไม่? ฉันเข้าใจถูกมั้ย
Mikhail

17

ลองใช้ดู

Host <visible hostname alias>
        Controlmaster auto
        User <user>
        hostname <visible hostname>
        port <port>
        IdentityFile ~/.ssh/<id file>

Host <private LAN hostname alias>
     ProxyCommand ssh -q -W <private LAN hostname>:<private LAN port> <visible hostname alias>

ใน ~ / .ssh / config ของคุณและทำทุกอย่างในช็อตเดียวโดยใช้กุญแจที่อยู่บนคอมพิวเตอร์


1
นี่สะอาดกว่าการแนะนำ netcat ลงในส่วนผสม นอกจากนี้คีย์ SSH ส่วนตัวไม่จำเป็นต้องมีอยู่ในBเครื่องเช่นกัน
danemacmillan

1

นี่เป็นคำแนะนำที่มีประโยชน์มาก หลังจากเลอะเทอะไปหลายชั่วโมงฉันพบบันทึกนี้ & ยืนยันว่าได้ผลตรงตามเอกสาร ในการเชื่อมต่อผ่าน MachineA กับ MachineB จากเครื่องระยะไกล C:

เช่น: [xuser @ machineC ~] ssh -t MachineA ssh MachineB

"-t" มีความสำคัญ ssh ล้มเหลวหากไม่มีอยู่ คุณจะได้รับการแจ้งเตือนสองครั้งครั้งแรกสำหรับรหัสผ่านบน MachineA จากนั้นครั้งที่สองสำหรับ MachineB นอกจากนี้โปรดทราบว่าสิ่งนี้ถือว่าคุณมีผู้ใช้ "xuser" ที่กำหนดไว้ในทั้งสามเครื่อง หากไม่ใช่เพียงแค่ใช้ไวยากรณ์ ssh: "yuser @ MachineA ... " นอกจากนี้โปรดทราบว่าคุณสามารถใช้จุด IP ดิบแบบสี่จุดถ้าคุณต้องการ สิ่งนี้มีประโยชน์หากคุณกำลังเชื่อมโยงผ่านเครือข่ายท้องถิ่นที่ใช้ IP ที่ไม่ได้สัมผัสกับโลกนั่นคือ ไม่ได้อยู่ในไฟล์โฮสต์ในท้องถิ่นของคุณหรือ DNS ใด ๆ ในการรับไฟล์จาก MachineB ไปยัง remote machineC คุณสามารถ scp จาก MachineB ไปยัง MachineA แล้วจาก MachineA ไปยัง remote machineC (เช่นเครื่องระยะไกล C สามารถ ping MachineA แต่ไม่ใช่ MachineB.) Caveat: ฉันทดสอบด้วย Fedora และ WindowsXP, MachineA เป็นกล่อง XP ที่กำลังเรียกใช้ ICS (Internet Connection Sharing) ในขณะที่ MachineB และ remote machineC เป็นกล่อง Fedora-Linux คำแนะนำนี้แก้ไขปัญหาสำคัญสำหรับฉัน - เช่น จำกัด การเข้าถึงระยะไกลที่ถูกตรวจสอบไปยัง LAN ระยะไกลของไซต์ของฉัน โปรดทราบว่าเมื่อคุณ "ออกจากระบบ" จาก MachineB คุณควรเห็น "การเชื่อมต่อกับ xxx.xxx.xxx.xxx สองรายการ" ข้อความ


หากคุณตั้งค่าและกำหนดค่าการรับรองความถูกต้องของคีย์สาธารณะคุณไม่จำเป็นต้องกังวลเกี่ยวกับการป้อนรหัสผ่านของคุณ แต่-tก็ยังต้องการ
เฟลิเป้อัลวาเรซ

@FelipeAlvarez คุณยังต้องกังวลเกี่ยวกับการป้อนรหัสผ่านที่สองหากคุณไม่เชื่อถือเครื่อง B เพื่อให้มีการเข้าสู่ระบบโดยไม่มีรหัสผ่านเพื่อ A!
ไมเคิล

1

ProxyCommand เป็นโซลูชันแบบสะอาดสำหรับเคสเมื่อคุณอนุญาตการเข้าถึงเชลล์ในทั้งสองระบบ เราต้องการให้ผู้ใช้ระยะไกลเข้าถึงเครื่องภายใน (A) ผ่านทางโบรกเกอร์ (B) แต่ไม่อนุญาตให้ผู้ใช้เข้าถึงเชลล์ไปยัง B เพื่อความปลอดภัยที่ดีขึ้น สิ่งนี้ได้ผล:

แทนที่เชลล์ล็อกอิน

แทนที่ล็อกอินเชลล์ (ใช้chsh) สำหรับextuserบนโบรกเกอร์ด้วยสคริปต์ต่อไปนี้ (เก็บไว้ในไฟล์):

#!/bin/sh   # this is essential to avoid Exec format error
ssh internaluser@A

ไม่ได้ระบุว่ามีการตั้งรหัสผ่านใน extuser @ B สำหรับผู้ใช้ระยะไกลและใน internaluser @ A สำหรับ extuser @ B จากนั้นการดำเนินการคำสั่งต่อไปนี้จะนำผู้ใช้ระยะไกลไปยัง A โดยตรง

ssh extuser@B

เคล็ดลับ : สร้างการตั้งค่าที่จำเป็นโดยไม่ต้องใช้รหัสผ่าน login_keys ใน extuser @ B ก่อนเปลี่ยนเป็นเชลล์ล็อกอินแบบกำหนดเอง หลังจากการเปลี่ยนแปลงเนื่องจากบัญชีนี้ไม่สามารถเข้าถึงทุกคนผ่านเชลล์ sudoer @ B เท่านั้นที่สามารถทำการเปลี่ยนแปลงไฟล์ที่ได้รับอนุญาต _keys โดยการแก้ไขโดยตรง

sudo vi ~extuser/.ssh/authorized_keys
sudo touch ~extuser/.hushlogin

บรรทัดสุดท้ายคือการปิดกั้นการแสดงแบนเนอร์เข้าสู่ระบบจาก B ดังนั้นผู้ใช้ระยะไกลจึงสามารถเข้าถึง A. ได้อย่างโปร่งใส


วิธีการที่น่าสนใจมาก อย่างไรก็ตามข้อเสียเปรียบหลักของเรื่องนี้คือ: 1) การใช้งาน จำกัด เฉพาะการใช้งาน SSH มาตรฐาน (ไม่รองรับ SFTP / SCP) 2)ผู้ใช้ไม่สามารถเลือกโฮสต์เป้าหมายอื่นนอกเหนือจากโฮสต์เดี่ยว (เนื่องจากฮาร์ดโค้ดในเชลล์ล็อกอิน) 3)การตรวจสอบคีย์โฮสต์ไม่สามารถทำได้จากเวิร์กสเตชันไปยังโฮสต์เป้าหมายสุดท้าย (เนื่องจากการใช้ไบนารี SSH ของนายหน้า) . 4)กุญแจส่วนตัวสำหรับผู้ใช้ในการเข้าถึงโฮสต์เป้าหมายสุดท้ายกำลังอยู่ในนายหน้ามากกว่ากับผู้ใช้ สิ่งนี้อนุญาตให้มีการแอบอ้างเป็นผู้ใช้โดยผู้ดูแลระบบ (ซึ่งเป็นไปไม่ได้ตามปกติ)
gertvdijk

ทุกจุดเป็นจริงขอบคุณสำหรับการทำอย่างละเอียด อย่างไรก็ตามวัตถุประสงค์หลักคือเพื่อให้ผู้ใช้ที่เชื่อถือได้เข้าถึง ssh โดยไม่ต้องเข้าสู่ระบบ B เนื่องจากผู้ดูแลระบบเท่านั้นสามารถเพิ่มคีย์สาธารณะของผู้ใช้ที่เชื่อถือได้ใน B (ผ่าน sudo โดยไม่ต้องเข้าสู่ระบบ) นี่ก็หมายความว่าผู้ใช้มี ( ผู้ดูแลระบบ) เข้าถึงรหัสส่วนตัวของ extuser @ B (ไม่ใช่ผู้ใช้ที่เชื่อถือได้ภายนอก) และได้ตั้งค่าไว้ตั้งแต่แรก!
Sunthar

1

คุณหมายถึงคุณต้องมีจัมเปอร์หลายตัว :)

เมื่อเร็ว ๆ นี้ฉันพบปัญหานี้กับ jumper1 jumper2 และเครื่องสุดท้ายของฉันสำหรับโซลของฉัน

สคริปต์ท้องถิ่น:

#!/bin/bash
sshpass -p jumper1Passwd ssh -t jumper1@jumper1IP ./Y00.sh

จากนั้นในจัมเปอร์ที่ 1 (ซึ่งเป็นเราเตอร์ของฉัน) ฉันวางสคริปต์ชื่อ Y00.sh:

ssh -tt jumper2@jumper2 -i ~/.ssh/id_rsa sshpass -p finalPassWord ssh -tt final@final

คุณสามารถแทนที่สิ่งเหล่านี้ด้วย IP และรหัสผ่านของคุณโชคดี!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.