Ansible ไม่สามารถตรวจสอบความถูกต้องของ Sudo แม้ว่าจะผ่าน Sudo Pass ก็ตาม


9

ปัญหา

การใช้ Ansible build ที่เสถียรและใหม่ล่าสุดฉันมีปัญหาแปลก ๆ ที่ playbook ของฉันค้างบนเซิร์ฟเวอร์หนึ่งในช่วง "Gathering_Facts" แต่ทำงานได้ดีบนเซิร์ฟเวอร์อื่น ๆ ที่คล้ายคลึงกันเมื่อใช้ Sudo บนเซิร์ฟเวอร์ Ansible ฉันเรียกใช้ในฐานะผู้ใช้ของฉัน (ผู้ใช้ NIS) และใช้sudo (เป็น root) บนเซิร์ฟเวอร์ระยะไกลเพื่อทำการเปลี่ยนแปลง หากฉันลบ Sudo ออกจากการตั้งค่านี้ทุกอย่างก็ใช้ได้ดี

ติดตั้ง

รุ่นของซอฟต์แวร์

  • ระบบปฏิบัติการ : RHEL 6.4
  • รุ่น Ansible : ansible 1.8.2
  • รุ่น Sudo :
    Sudo เวอร์ชั่น 1.8.6p3
    ปลั๊กอินนโยบาย Sudoers เวอร์ชัน 1.8.6p3
    Sudoers ไฟล์ไวยากรณ์รุ่น 42
    Sudoers I / O plugin รุ่น 1.8.6p3
    
  • รุ่น SSH : OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 มีนาคม 2010

เซิร์ฟเวอร์แผนที่

                   -------- User1 @ Server1: sudo -H -S -p (ค้างที่ Gathering_Facts)
                  /
User1 @ Ansible ----
                  \
                   -------- User1 @ Server2: sudo -H -S -p (ทำงานได้ดี)

ผู้ใช้

  • User1: ผู้ใช้ NIS ที่สามารถเข้าถึงได้บนทั้ง Server1 และ Server2
  • root: ผู้ใช้รูทโลคัลสำหรับแต่ละเซิร์ฟเวอร์

กำหนดค่า Ansible

ส่วนที่เกี่ยวข้องของฉันansible.cfg

ansible.cfg

sudo           = true
sudo_user      = root
ask_sudo_pass  = True
ask_pass       = True
...
gathering = smart
....
# change this for alternative sudo implementations
sudo_exe = sudo

# what flags to pass to sudo
#sudo_flags = -H
...
# remote_user = ansible

นี่คือ playbook สำหรับทดสอบแบบง่าย ๆ เพื่อแตะไฟล์เปล่าแล้วลบออก จริง ๆ แล้วฉันแค่ต้องการทดสอบว่าฉันสามารถใช้ Ansible ให้ใช้ sudo บนเซิร์ฟเวอร์ระยะไกลได้อย่างถูกต้องหรือไม่ หาก playbook ทำงานได้ดีแสดงว่าฉันอยู่ในสภาพดี

TEST.yml

---
- hosts: Server1:Server2
  vars:
  - test_file: '/tmp/ansible_test_file.txt'
  sudo: yes
  tasks:
  - name: create empty file to test connectivity and sudo access
    file: dest={{ test_file }}
          state=touch
          owner=root group=root mode=0600
    notify:
    - clean
  handlers:
  - name: clean
    file: dest={{ test_file }}
          state=absent

การกำหนดค่า Sudo

/ etc / sudoers

Host_Alias SRV     = Server1, Server2
User_Alias SUPPORT = User1, User2, User3
SUPPORT SRV=(root) ALL

การกำหนดค่า sudo นี้ใช้ได้กับเซิร์ฟเวอร์ BOTH ไม่มีปัญหากับ sudo เอง

ฉันทำทุกอย่างได้อย่างไร

ง่ายมาก:

$ ansible-playbook test.yml
รหัสผ่าน SSH: 
รหัสผ่าน sudo [ค่าเริ่มต้นเป็นรหัสผ่าน SSH]:

เล่น [Server1: Server2] ******************************************** ** 

การรวบรวมข้อเท็จจริง ************************************************ *************** 
ตกลง: [Server2]
ล้มเหลว: [Server1] => {"ล้มเหลว": จริง, "แยกวิเคราะห์": false}

ขออภัยลองใหม่อีกครั้ง
[sudo ผ่าน ansible, คีย์ = mxxiqyvztlfnbctwixzmgvhwfdarumtq] รหัสผ่าน: 
sudo: พยายามรหัสผ่านไม่ถูกต้อง 1 ครั้ง


TASK: [สร้างไฟล์เปล่าเพื่อทดสอบการเชื่อมต่อและการเข้าถึง sudo] **************** 
เปลี่ยนแปลงแล้ว: [Server2]

แจ้งเตือน: [สะอาด] *********************************************** **************** 
เปลี่ยนแปลงแล้ว: [Server2]

เล่น RECAP ************************************************** ******************** 
           เพื่อลองอีกครั้งใช้: - เปิด @ / home / User1 / test.retry

เซิร์ฟเวอร์ 1: ok = 0 เปลี่ยนไป = 0 ไม่สามารถเข้าถึงได้ = 0 ล้มเหลว = 1   
Server2: ok = 3 มีการเปลี่ยนแปลง = 2 ไม่สามารถเข้าถึงได้ = 0 ล้มเหลว = 0

ล้มเหลวโดยไม่คำนึงว่าฉันป้อนรหัสผ่านทั้ง SSH / Sudo อย่างชัดเจนรวมทั้งโดยปริยาย (ให้ sudo pass default เป็น SSH)

บันทึกเซิร์ฟเวอร์ระยะไกล

เซิร์ฟเวอร์ 1 (ล้มเหลว)

/ var / log / การรักษาความปลอดภัย

31 ธันวาคม 15:21:10 Server1 sshd [27093]: รหัสผ่านที่ได้รับการยอมรับสำหรับ User1 จาก xxxx port 51446 ssh2
31 ธันวาคม 15:21:10 Server1 sshd [27093]: pam_unix (sshd: เซสชัน): เซสชันที่เปิดสำหรับผู้ใช้ User1 โดย (uid = 0)
31 ธันวาคม 15:21:11 Server1 sshd [27095]: คำขอระบบย่อยสำหรับ sftp
ธ.ค. 31 15:21:11 Server1 sudo: pam_unix (sudo: auth): การตรวจสอบล้มเหลว; logname = User1 uid = 187 euid = 0 tty = / dev / pts / 1 ruser = User1 rhost = ผู้ใช้ = User1
ธ.ค. 31 15:26:13 Server1 sudo: pam_unix (sudo: auth): การสนทนาล้มเหลว
ธ.ค. 31 15:26:13 Server1 sudo: pam_unix (sudo: auth): รับรองความถูกต้องไม่สามารถระบุรหัสผ่านสำหรับ [ผู้ใช้ 1]
Dec 31 15:26:13 Server1 sudo: User1: 1 พยายามรหัสผ่านไม่ถูกต้อง; TTY = pts / 1; PWD = / home / User1; USER = root; คำสั่ง = / bin / sh -c echo SUDO-SUCCESS-mxxiqyvztlfnbctwixzmgvhwfdarumtq; LANG = C LC_CTYPE = C / usr / bin / python /tmp/.ansible/tmp/ansible-tmp-1420039272.66-164754043073536/setup; rm -rf /tmp/.ansible/tmp/ansible-tmp-1420039272.66-164754043073536/> / dev / null 2> & 1
31 ธันวาคม 15:26:13 Server1 sshd [27093]: pam_unix (sshd: เซสชัน): เซสชันปิดสำหรับผู้ใช้ User1 

Server2 (ทำงานได้ดี)

/ var / log / การรักษาความปลอดภัย

31 ธันวาคม 15:21:12 Server2 sshd [31447]: รหัสผ่านที่ได้รับการยอมรับสำหรับ User1 จาก xxxx port 60346 ssh2
31 ธันวาคม 15:21:12 Server2 sshd [31447]: pam_unix (sshd: เซสชัน): เซสชันที่เปิดสำหรับผู้ใช้ User1 โดย (uid = 0)
ธ.ค. 31 15:21:12 Server2 sshd [31449]: คำขอระบบย่อยสำหรับ sftp
31 ธันวาคม 15:21:12 sudo Server2: ผู้ใช้ 1: TTY = pts / 2; PWD = / home / User1; USER = root; คำสั่ง = / bin / sh -c echo SUDO-SUCCESS-vjaypzeocvrdlqalxflgcrcoezhnbibs; LANG = C LC_CTYPE = C / usr / bin / python /tmp/.ansible/tmp/ansible-tmp-1420039272.68-243930711246149/setup; rm -rf /tmp/.ansible/tmp/ansible-tmp-1420039272.68-243930711246149/> / dev / null 2> & 1
31 ธันวาคม 15:21:14 Server2 sshd [31447]: pam_unix (sshd: เซสชัน): เซสชันปิดสำหรับผู้ใช้ User1 

เอาท์พุท STrace

นี่คือเอาต์พุตจาก strace เมื่อกำหนดเป้าหมายคำสั่ง ansible ของผู้ใช้รูท คำสั่ง:

while [[ -z $(ps -fu root|grep [a]nsible|awk '{print $2}') ]]; do
    continue
done
strace -vfp $(ps -fu root|grep [a]nsible|awk '{print $2}') -o /root/strace.out`

Server1

23650 เลือก (0, NULL, NULL, NULL, {1, 508055}) = 0 (หมดเวลา)
ซ็อกเก็ต 23650 (PF_NETLINK, SOCK_RAW, 9) = 10
23650 fcntl (10, F_SETFD, FD_CLOEXEC) = 0
23650 readlink ("/ proc / self / exe", "/ usr / bin / sudo", 4096) = 13
23650 sendto (10, "| \ 0 \ 0 \ 0L \ 4 \ 5 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0op = PAM: ของแท้" ... , 124, 0, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, 12) = 124
23650 โพล ([{fd = 10, เหตุการณ์ = POLLIN}], 1, 500) = 1 ([{fd = 10, revents = POLLIN}])
23650 recvfrom (10, "$ \ 0 \ 0 \ 0 \ 2 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0b \\\ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 | 0 \ 0 \ 0L \ 4 \ 5 \ 0 \ 1 \ 0 \ 0 \ 0 "... , 8988, MSG_PEEK | MSG_DONTWAIT, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, [12]) = 36
23650 recvfrom (10, "$ \ 0 \ 0 \ 0 \ 2 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0b \\\ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 | 0 \ 0 \ 0L \ 4 \ 5 \ 0 \ 1 \ 0 \ 0 \ 0 "... , 8988, MSG_DONTWAIT, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, [12]) = 36
23650 ปิด (10) = 0
23650 เขียน (2, "ขออภัยลองใหม่อีกครั้ง \ n", 18) = 18
23650 gettimeofday ({1420050850, 238344}, NULL) = 0
ซ็อกเก็ต 23650 (PF_FILE, SOCK_STREAM, 0) = 10
23650 เชื่อมต่อ (10, {sa_family = AF_FILE, path = "/ var / run / dbus / system_bus_socket"}, 33) = 0

Server2

6625 เลือก (8, [5 7], [], NULL, NULL) =? ERESTARTNOHAND (จะถูกเริ่มใหม่)
6625 --- SIGCHLD (ออกจากเด็กแล้ว) @ 0 (0) ---
6625 เขียน (8, "\ 21", 1) = 1
6625 rt_sigreturn (0x8) = -1 EINTR (การเรียกระบบขัดจังหวะ)
6625 เลือก (8, [5 7], [], NULL, NULL) = 1 (ใน [7])
6625 read (7, "\ 21", 1) = 1
6625 wait4 (6636, [{WIFEXITED & & WEXITSTATUS (s) == 0}], WNOHANG | WSTOPPED, NULL) = 6636
6625 rt_sigprocmask (SIG_BLOCK, NULL, [], 8) = 0
ซ็อกเก็ต 6625 (PF_NETLINK, SOCK_RAW, 9) = 6
6625 fcntl (6, F_SETFD, FD_CLOEXEC) = 0
6625 readlink ("/ proc / self / exe", "/ usr / bin / sudo", 4096) = 13
6625 sendto (6, "x \ 0 \ 0 \ 0R \ 4 \ 5 \ 0 \ 6 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0op = PAM: session_c" ... , 120, 0, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, 12) = 120
แบบสำรวจ 6625 รายการ ([{fd = 6, เหตุการณ์ = POLLIN}], 1, 500) = 1 ([{fd = 6, revents = POLLIN}])
6625 recvfrom (6, "$ \ 0 \ 0 \ 0 \ 2 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 330 \ 355 \ 377 \ 377 \ 377 \ 0 \ 0 \ 0x0 \ 0 \ 0 \ 0 \ 0 \ 0R \ 4 \ 5 \ 0 \ 6 \ 0 \ 0 \ 0 "... , 8988, MSG_PEEK | MSG_DONTWAIT, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, [12]) = 36
6625 recvfrom (6, "$ \ 0 \ 0 \ 0 \ 2 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 330 \ 355 \ 377 \ 377 \ 377 \ 0 \ 0 \ 0x0 \ 0 \ 0 \ 0 \ 0 \ 0R \ 4 \ 5 \ 0 \ 6 \ 0 \ 0 \ 0 "... , 8988, MSG_DONTWAIT, {sa_family = AF_NETLINK, pid = 0, กลุ่ม = 00000000}, [12]) = 36
6625 ปิด (6) = 0
6625 open ("/ etc / security / pam_env.conf", O_RDONLY) = 6
6625 fstat (6, {st_dev = makedev (253, 1), st_ino = 521434, st_mode = S_IFREG | 0644, st_nlink = 1, st_uid = 0, st_gid = 0, st_blksize = 4096, st_block = 8 = 2014/12 / 31-16: 10: 01, st_mtime = 2012/10 / 15-08: 23: 52, st_ctime = 2014/06 / 16-15: 45: 35}) = 0
6625 mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) = 0x7fbc3a59a000
6625 read (6, "# \ n # นี่คือการกำหนดค่า fi" ... , 4096) = 2980
6625 read (6, "", 4096) = 0
6625 ปิด (6) = 0
6625 munmap (0x7fbc3a59a000, 4096) = 0
6625 open ("/ etc / environment", O_RDONLY) = 6

เดาของฉัน

Server1 ไม่ได้รับรหัสผ่านอย่างถูกต้องหรือถาม / รอรหัสผ่านไม่ถูกต้อง สิ่งนี้ดูเหมือนว่าปัญหา Sudo หรือ Ansible (โดยลำพังพวกเขาทั้งคู่ทำงานได้ดี) แต่ Server1 ดูเหมือนจะไม่ได้รับข้อมูลรับรอง Server1 & 2 มีจุดประสงค์ที่แตกต่างกันดังนั้นจึงเป็นไปได้ว่าพวกเขามีการรับรองความถูกต้องหรือความแตกต่างของรุ่นแพ็คเกจ แต่ทั้งคู่ถูกสร้างจากที่เก็บเดียวกัน ดังนั้นพวกเขาไม่ควรแตกต่างกัน

PAM รับรองความถูกต้อง

ฉันคิดว่าบางทีระบบอาจมีการกำหนดค่า PAM ที่แตกต่างกันทำให้รหัสผ่านถูกจัดการแตกต่างกันเล็กน้อย ฉันเปรียบเทียบไฟล์ /etc/pam.d/ (โดยใช้md5sum [file]) และพวกมันเหมือนกันระหว่างสองระบบ

การทดสอบ

Sudo STDIN

ทดสอบปัญหาอื่นโดยที่ sudo ไม่อ่านรหัสผ่านจาก STDIN แต่ทำงานได้ดีบนเซิร์ฟเวอร์ทั้งสอง

ทดสอบ Sudo Ad-Hoc

-bash-4.1 $ ansible Server1 ไฟล์ - m "-a" ปลายทาง = / tmp / ansible_test.txt สถานะ = สัมผัส "-sK
รหัสผ่าน SSH: 
รหัสผ่าน sudo [ค่าเริ่มต้นเป็นรหัสผ่าน SSH]: 
เซิร์ฟเวอร์ 1 | ความสำเร็จ >> {
    "เปลี่ยน": จริง 
    "dest": "/tmp/ansible_test.txt", 
    "gid": 0, 
    "กลุ่ม": "รูท", 
    "โหมด": "0644", 
    "owner": "root", 
    "ขนาด": 0, 
    "state": "ไฟล์", 
    "uid": 0
}

ที่ประสบความสำเร็จ! แต่ทำไมล่ะ!

TL; DR

  1. Server1 ดูเหมือนว่าจะรอรหัสผ่าน sudo ในขณะที่ Server2 ทำงานได้ดี
  2. เรียกใช้ansible"ad-hoc" บน Server1 ทำงานได้ดี เรียกใช้เป็น playbook ล้มเหลว

คำถาม (s)

  • สิ่งใดที่อาจทำให้การกำหนดค่า Ansible Sudo ของฉันทำงานได้ดีบนเซิร์ฟเวอร์เครื่องหนึ่งและถูกปฏิเสธอีกเครื่องหนึ่ง
  • Ansible ทำรหัสผ่าน "pass" จากเครื่องโลคอลไปยังเครื่องรีโมตแตกต่างกันหรือไม่เมื่อเรียกใช้ ad-hoc กับ playbook? ฉันคิดว่าพวกเขาจะเหมือนกัน

ฉันคิดว่าสิ่งนี้กำลังใกล้เข้ามาเพียงแค่ส่งรายงานข้อผิดพลาดไปยังหน้า GitHub ล้วนๆจากข้อเท็จจริงที่ว่าการเข้าถึง sudo นั้นมีผลลัพธ์ที่แตกต่างกันไปขึ้นอยู่กับว่าฉันใช้โฆษณาเฉพาะกิจหรือไม่

คำตอบ:


4

สิ่งที่ฉันจะทำคือการใช้

strace -vfp `pidof sshd`

และดูว่ามันล้มเหลวที่ไหน

ตรวจสอบบัญชีด้วยเช่นกันอาจจะถูก จำกัด หรือบางอย่าง แต่การเดิมพันของฉันคือมีบางอย่างผิดปกติกับไฟล์ / etc / hosts ของคุณหรือมีการเปลี่ยนแปลงในกระบวนการ


ขอบคุณ lulian ฉันได้ใช้การแก้ไขกับคำถามไม่กี่ส่วนหนึ่งเป็นผลลัพธ์ STrace เห็นได้ชัดว่ามีความแตกต่างระหว่างสองเซิร์ฟเวอร์ในวิธีการดำเนินการหลังจากกระบวนการ ansible เริ่มทำงานบนเซิร์ฟเวอร์ระยะไกล การเรียกใช้ครั้งต่อไปและการจับการติดตามมีความสอดคล้องกัน
BrM13

ฉันคิดว่าคุณต้องการเพิ่มเติมจาก strace -vfp ทำด้วยตนเองในกระบวนการ sshd ด้านบนและติดตามผลลัพธ์ ฉันไม่คิดว่าหลังจากอ่านรหัสผ่านมันเป็นเพียงแค่ปิดช่องทางเช่นนั้นก่อนที่จะผ่าน PAM ฯลฯ ณ จุดนั้นโปรดดูที่ไฟล์ sshd_config และ hosts.deny .. ดูว่าคุณสามารถหาสิ่งที่มี
Iulian

ฉันเคยลองใช้คำแนะนำของคุณมาก่อน แต่ฉันต้องพลาดองค์ประกอบสำคัญในนั้น (ดังนั้นทำไมฉันเลือกที่จะดูกระบวนการที่เข้าใจได้ใน STrace เริ่มต้น) หลังจากไปอีกครั้งฉันพบตัวแปร {{password}} ที่ว่างเปล่าถูกส่งผ่านแทนที่จะเป็นรหัสผ่านจริง เลือกที่จะส่ง "คำตอบ" อีกต่างหากแยกกันในที่สุดคำตอบของคุณก็มาถึงฉันอย่างถูกต้อง
BrM13

4

ใช้ @lulian เป็นฐานที่มั่นในคำตอบนี้ปัญหาลงมาเพื่อโกงansible_sudo_pass:ที่กำหนดไว้ใน group_vars --ask-sudo-passซึ่งเอาชนะรหัสผ่านป้อนสำหรับ

ใช้ดังต่อไปนี้:

while [[ -z $(ps -eaf|grep 'sshd: [U]ser1@pts/1') ]]; do
    continue
done
strace -ff -vfp $(ps -eaf|grep 'sshd: [U]ser1@pts/1'|awk '{print $2}') -o /root/strace_sshd1_2.out

ฉันพบว่าwrite(4, "{{ password }}\n", 15)มันถูกส่งผ่านแทนที่จะใส่รหัสผ่าน หลังจากการค้นหาอย่างรวดเร็วฉันก็พบว่ามีการansible_sudo_passกำหนดไว้ใน group_vars ของฉันซึ่งแทนที่รหัสผ่านที่ฉันป้อน

ในฐานะที่เป็น FYI สำหรับคนอื่น ๆansible_sudo_pass:คำจำกัดความที่ดูเหมือนจะมีความสำคัญมากกว่า--ask-sudo-passซึ่งในตอนแรกดูเหมือนว่าจะต่อต้านได้ง่าย ในท้ายที่สุดนี่คือข้อผิดพลาดของผู้ใช้ แต่วิธีการของ @lulian ในการดีบั๊กการโต้ตอบของ SSH รวมถึงการค้นพบความสัมพันธ์ระหว่างansible_sudo_passและ--ask-sudo-passควรจะมีประโยชน์มากสำหรับคนอื่น ๆ (หวังว่า!)


1
ฉันจะยืนยันว่า Ansible ให้ความสำคัญกับตัวแปรที่กำหนดไฟล์ไว้เหนือตัวเลือกบรรทัดคำสั่งคือการตอบโต้และพฤติกรรมที่ไม่ดี อยากรู้อยากเห็นก็ไม่รับรู้ว่านี้เสียเมื่อคุณผ่านตัวเลือกและคุณอาจจะสามารถทำงานรอบนี้โดยผ่านตัวเลือกที่เหมาะสมกับ-e -e
Christopher Cashell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.