ทำไมฉันต้องใช้ tty ในการเรียกใช้ sudo ถ้าฉันสามารถ sudo โดยไม่มีรหัสผ่าน


226

ผมได้กำหนดค่าsudoให้ทำงานโดยไม่มีรหัสผ่าน แต่เมื่อฉันพยายามผมยังได้รับข้อความแสดงข้อผิดพลาดssh 'sudo Foo'sudo: sorry, you must have a tty to run sudo

เหตุใดสิ่งนี้จึงเกิดขึ้นและฉันจะแก้ไขได้อย่างไร

คำตอบ:


290

อาจเป็นเพราะ/etc/sudoersไฟล์ของคุณ(หรือไฟล์ใด ๆ ที่รวมอยู่) มี:

Defaults requiretty

... ซึ่งทำให้sudoต้องมี TTY ระบบ Red Hat (RHEL, Fedora ... ) เป็นที่รู้จักกันว่าต้องการ TTY ในsudoersไฟล์เริ่มต้น ที่ไม่มีประโยชน์ด้านความปลอดภัยที่แท้จริงและสามารถลบออกได้อย่างปลอดภัย

Red Hat ยอมรับปัญหาแล้วและจะถูกลบออกในอนาคต

หากการเปลี่ยนการกำหนดค่าเซิร์ฟเวอร์ไม่ใช่ตัวเลือกเนื่องจากการแก้ไขปัญหาสำหรับการกำหนดค่าผิดพลาดนั้นคุณสามารถใช้ตัวเลือก-tหรือ-ttตัวเลือกที่จะsshสร้างเทอร์มินัลหลอกในระยะไกล แต่ระวังว่ามีจำนวนด้าน ผลกระทบ

-ttมีความหมายสำหรับการใช้งานแบบโต้ตอบ มันทำให้สถานีท้องถิ่นในrawโหมดเพื่อให้คุณโต้ตอบกับสถานีระยะไกล นั่นหมายความว่าถ้าsshI / O ไม่ใช่จาก / ถึงเทอร์มินัลนั่นจะมีผลข้างเคียง ยกตัวอย่างเช่นการป้อนข้อมูลทั้งหมดจะถูกสะท้อนกลับขั้วอักขระพิเศษ ( ^?, ^C, ^U) จะทำให้เกิดการประมวลผลพิเศษ; บนเอาต์พุตLFs จะถูกแปลงเป็นCRLFs ... (ดูคำตอบนี้เป็นเพราะเหตุใดไฟล์ไบนารีนี้จึงถูกเปลี่ยน?สำหรับรายละเอียดเพิ่มเติม

หากต้องการลดผลกระทบคุณสามารถเรียกใช้เป็น:

ssh -tt host 'stty raw -echo; sudo ...' < <(cat)

< <(cat)จะหลีกเลี่ยงการตั้งค่าของเครื่องท้องถิ่น (ถ้ามี) ในrawโหมด และเรากำลังใช้stty raw -echoเพื่อตั้งระเบียบวินัยบรรทัดของรีโมตเทอร์มินัลว่าผ่าน (อย่างมีประสิทธิภาพดังนั้นมันจะทำงานเหมือนไปป์ที่จะใช้แทนการหลอกเทอร์มินัลโดยไม่ต้องใช้-ttแม้ว่าจะใช้หลังจากคำสั่งนั้นเท่านั้น เพื่อหน่วงเวลาการส่งบางสิ่งบางอย่างสำหรับอินพุตจนกว่าจะเกิดขึ้น)

โปรดทราบว่าเนื่องจากเอาต์พุตของคำสั่งรีโมตจะไปที่เทอร์มินัลซึ่งจะยังคงส่งผลกระทบต่อการบัฟเฟอร์ (ซึ่งจะเป็นบรรทัดสำหรับแอพพลิเคชั่นจำนวนมาก) และประสิทธิภาพแบนด์วิดธ์นับตั้งแต่TCP_NODELAYเปิด นอกจากนี้ยังมี-tt, sshชุด IPQoS ไปเมื่อเทียบกับlowdelay throughputคุณสามารถแก้ไขทั้งสองอย่างด้วย:

ssh -o IPQoS=throughput -tt host 'stty raw -echo; sudo cmd | cat' < <(cat)

นอกจากนี้โปรดทราบว่าหมายถึงคำสั่งรีโมตไม่สามารถตรวจพบจุดสิ้นสุดไฟล์บน stdin และ stdout และ stderr ของคำสั่งรีโมตรวมเข้าด้วยกันเป็นสตรีมเดียว

ดังนั้นการทำงานที่ไม่ดีนัก

ถ้าคุณได้มีวิธีการที่จะวางไข่หลอกขั้วในพื้นที่ห่างไกล (เช่นกับexpect, zsh, socat, perl's IO::Pty... ) แล้วมันจะดีกว่าที่จะใช้ในการสร้างหลอกขั้วที่จะแนบsudoไป ( แต่ ไม่ได้สำหรับ I / O) และการใช้งานได้โดยไม่ต้องssh-t

ตัวอย่างเช่นกับexpect:

ssh host 'expect -c "spawn -noecho sh -c {
     exec sudo cmd >&4 2>&5 <&6 4>&- 5>&- 6<&-}
 exit [lindex [wait] 3]" 4>&1 5>&2 6<&0'

หรือด้วยscript(ที่นี่สมมติว่ามีการใช้งานจากutil-linux):

ssh host 'SHELL=/bin/sh script -qec "
              sudo cmd <&3 >&4 2>&5 3<&- 4>&- 5>&-
            " /dev/null 3<&0 4>&1 5>&2'

(สมมติว่า (สำหรับทั้งคู่) ว่าเชลล์ล็อกอินของผู้ใช้รีโมตนั้นเป็นแบบบอร์น)


30

โดยค่าเริ่มต้น SUDO ถูกกำหนดค่าให้ต้องใช้ TTY นั่นคือ SUDO คาดว่าจะเรียกใช้จากเปลือกเข้าสู่ระบบ คุณสามารถเอาชนะข้อกำหนดนี้ได้โดยเพิ่ม-tสวิตช์ไปยังการเรียกใช้ SSH ของคุณ:

ssh -t someserver sudo somecommand

การ-tจัดสรรกองกำลังของ pseudo-tty

หากคุณต้องการที่จะดำเนินการนี้ทั่วโลกปรับเปลี่ยนเพื่อระบุ/etc/sudoers !requirettyซึ่งสามารถทำได้ต่อผู้ใช้ต่อกลุ่มหรือระดับที่ครอบคลุมทั้งหมด


5
ไม่นั่นไม่ใช่ค่าเริ่มต้น มันเป็นเพียงการกระจายของ sudo ที่มีrequirettyอยู่ใน sudoers ที่เป็นค่าเริ่มต้น มันจะได้รับการแก้ไขในรุ่นที่ใหม่กว่า
Stéphane Chazelas

1
@StephaneChazelas +1 สำหรับให้ความกระจ่างแก่ฉันว่าส่วนใหญ่เป็นชนพื้นเมืองของ Red Hat และพี่น้องของมันและอีก ++ หากฉันสามารถรายงานข้อผิดพลาดในปัจจุบัน!
JRFerguson

18

ใช้-tแฟล็กsshเพื่อบังคับการจัดสรร tty

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$

เพิ่มวินาที-tในการบังคับจัดสรรเมื่อPseudo-terminal will not be allocated because stdin is not a terminal.
Samveen

11

ฉันพบปัญหานี้โดยใช้ Docker และ Centos 7 ฉันทำสิ่งต่อไปนี้:

yum install -y sudo

sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers

ฉันพบแฮ็คนี้ที่https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile


1
คำตอบนี้เหมาะสมที่สุดสำหรับฉันโดยใช้ Docker และ CentOS 7 เช่นกัน มันง่ายต่อการทำความเข้าใจรวมทั้งคัดลอก / วางง่าย!
DaShaun

1

ทางเลือกที่น่าสนใจคือการเรียกใช้ FreeIPA หรือ IdM เพื่อจัดการผู้ใช้ของคุณและกฎ sudoer จากส่วนกลาง จากนั้นคุณสามารถสร้างกฎ sudo และกำหนดตัวเลือก

! requiretty

ในกฎ คำสั่งจะทำงานตามที่คาดไว้ คุณจะได้รับประโยชน์จากการจัดการเซิร์ฟเวอร์และผู้ใช้ทั้งหมดจากการกำหนดค่าชุดเดียว


0

ฉันมีปัญหาเดียวกัน ในกรณีของฉันการแก้ปัญหาคือสองบรรทัด

myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"

คำอธิบาย:

  • วางคำสั่งที่คุณต้องการเรียกใช้ (รวมถึงคำสั่ง sudo) ลงในสคริปต์เช่น "ssh_test.sh"

  • อ่านสคริปต์ทั้งหมดเป็นตัวแปรที่เรียกว่า "myscript"

  • เรียกใช้ ssh ด้วยหนึ่ง -t และจัดหาตัวแปรแทนคำสั่ง

ก่อนหน้านี้ฉันพบปัญหาในการใช้ชุดค่าผสมของการอ่านจาก stdin และการใช้ heredocs


-1

ฉันพบคำถามนี้ขณะที่ Google และฉันพบข้อผิดพลาดนี้ด้วยเหตุผลที่แตกต่างอย่างสิ้นเชิง

การแก้ไขของฉันคือการหยุดเรียกเชลล์สคริปต์ปลายน้ำเป็นจากเชลล์สคริปต์พ่อแม่ของฉันเมื่อสคริปต์เชลล์แม่ได้แล้วเรียกว่ามีsudosudo

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