Một script khởi chạy ứng dụng VPN của nhà cung cấp sẽ treo cho đến khi hết thời gian chờ, và nhật ký cho thấy ứng dụng đang yêu cầu một mã xác minh mà không ai gõ. Mật khẩu đã được gửi, nên kết luận hiển nhiên là mật khẩu sai. Không phải. Yêu cầu mã là một cuộc trò chuyện riêng trên một kênh riêng, và script của bạn chưa bao giờ mở nó.

Hãy làm năm kiểm tra dưới đây theo thứ tự. Dừng ở kiểm tra đầu tiên thất bại, vì mỗi bước sau đều giả định các bước trước đúng.

Kiểm tra 1: ứng dụng có đọc đầu vào chuẩn không?

Hãy thử trước khi viết bất kỳ tự động hóa nào: đẩy một bí mật giả vào ứng dụng qua đường ống và xem điều gì xảy ra. Nếu nó in lời nhắc rồi chờ, nghĩa là nó không đọc đường ống.

Nhiều ứng dụng mở trực tiếp thiết bị terminal, hoặc từ chối nhận bí mật từ một luồng không phải terminal, để một đường ống lạc không thể làm rò rỉ mật khẩu. OpenVPN là ngoại lệ được ghi trong tài liệu, vì --auth-user-pass nhận một đường dẫn tệp. Các ứng dụng của nhà cung cấp yêu cầu mã dùng một lần thường không có tùy chọn tương đương, và lời nhắc của chúng đang chờ một terminal mà script của bạn chưa bao giờ cung cấp.

Kiểm tra 2: tiến trình con có terminal không?

pty cấp một terminal cho tiến trình con, biến lời nhắc thành đầu ra đọc được mà bạn có thể trả lời theo thứ tự.

import pexpect

child = pexpect.spawn("openconnect vpn.example.net", encoding="utf-8", timeout=30)
child.expect("GROUP:")
child.sendline("staff")
child.expect("USERNAME:")
child.sendline("alice")
child.expect("PASSWORD:")
child.sendline(PASSWORD)
child.expect("Connected as", timeout=60)

Các chuỗi lời nhắc ở trên chỉ là ví dụ; hãy sao chép chính xác văn bản mà ứng dụng của bạn in ra, kể cả chữ hoa chữ thường và dấu câu. Mỗi kỳ vọng đều có thời gian chờ, và một tiến trình con đã đóng sẽ ném ngoại lệ thay vì trả về trạng thái, nên hãy bọc cả chuỗi và coi kết thúc tệp là thất bại. Để ý điều khối này không làm: tiến trình con chết cùng script, vì pty không phải cơ chế tách rời và disown là lệnh nội trú của shell, không với tới được tiến trình mà script của bạn tạo ra.

Kiểm tra 3: có đầu vào không tương tác được hỗ trợ không?

Việc cào màn hình hỏng mỗi khi ứng dụng nâng cấp, nên hãy tìm một tùy chọn có tài liệu trước.

Xem đầu ra trợ giúp để tìm tùy chọn token hoặc mã dùng một lần, và xem dịch vụ có chấp nhận mã được nối vào trường mật khẩu hay không. Ở nơi ứng dụng đọc tệp thông tin đăng nhập, hãy đưa cho nó tệp thay vì một lời nhắc:

openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")

Thay thế tiến trình cho ứng dụng một đường dẫn đọc được trên các hệ thống cung cấp /dev/fd. Bí mật vẫn là bí mật theo góc nhìn của ứng dụng, nên hãy giữ nó ngoài nhật ký, lịch sử shell và danh sách tiến trình. Nếu ứng dụng từ chối /dev/fd hoặc mở đường dẫn thông tin đăng nhập nhiều hơn một lần, hãy ghi một tệp thật với quyền hạn chế và xóa nó trong cùng script đó.

Kiểm tra 4: đường hầm có sống lâu hơn script không?

Mặc định đường hầm chết cùng tiến trình cha, đúng ngược lại với điều một script khởi động cần.

disown -h chỉ hữu ích khi bạn khởi chạy ứng dụng như một công việc của shell, vì nó sửa bảng công việc của shell đó và không với tới được tiến trình mà script của bạn khởi chạy qua pty. Trình quản lý dịch vụ là chỗ tốt hơn cho mọi thứ phải kết nối lại mà không cần giám sát, vì nó khởi động lại ứng dụng và ghi lại lý do nó chết. Dù thế nào, hãy chờ một mã mới sau mỗi lần kết nối lại: token dùng một lần bị tiêu hao ở lần xác thực thành công đầu tiên.

Để ý sudo làm gì với chuỗi này. Lời nhắc mật khẩu của sudo không phải lời nhắc của VPN, và trả lời nó bằng mật khẩu VPN là cách phổ biến nhất khiến một thứ tự kỳ vọng đúng đắn vẫn thất bại.

Kiểm tra 5: mã của một người có nên nằm trong script không?

Đây là kiểm tra mà người ta hay bỏ qua. Token thuộc về một người, còn đường hầm phải dựng lên theo lịch thuộc về cỗ máy.

Nếu một công việc phải kết nối lại mà không cần giám sát, hãy hỏi xem chứng chỉ máy hay tài khoản dịch vụ có thể thay thế đăng nhập tương tác không. Tự động hóa mã dùng một lần của ai đó biến yếu tố thứ hai thành một bí mật được lưu lại, đó là thay đổi chính sách chứ không phải tiện lợi khi viết script. Ở nơi dịch vụ hỗ trợ cả hai, hãy chọn thông tin đăng nhập khớp với cách công việc thực sự chạy. Hãy viết câu trả lời ra, vì người tiếp theo sẽ hỏi tại sao script lại giữ một token.

Một script chạy được trông như thế nào

Script in ra bước nó đã tới, không bao giờ in bí mật, và thoát với mã khác không khi bất kỳ kỳ vọng nào thất bại.

Hãy thử phá nó một cách có chủ đích: sai mật khẩu, sai nhóm, token hết hạn. Mỗi thất bại nên dừng ở một bước có tên thay vì treo. Sau đó chạy nó một lần với dịch vụ thật và kiểm tra đường hầm từ bên ngoài script, không phải từ bên trong.

Bài viết liên quan