Повідомлення каже, що OpenVPN не може завантажити вбудований сертифікат, а ім'я файлу, яке ви тримаєте в голові, стверджує протилежне. Те, що отримав парсер, важливіше за те, що містить файлова система, бо директива cert приймає два цілком різні типи значення. Одне — це шлях, який вона відкриває; інше — текст PEM, що прийшов усередині конфігурації. Доки ви не знаєте, яку форму отримав робочий клієнт, кожне виправлення — здогад.

Дві форми зберігання, одна директива

Директиви cert, key і ca приймають шлях або вбудований блок. Коли значення — шлях, OpenVPN відкриває цей файл і читає об'єкт з диска. Коли конфігурація містить блок, обмежений тегами cert, та сама директива натомість використовує вміст між цими тегами, і окремий файл не задіяний.

Обидві форми зрештою дають той самий тип об'єкта, тому робоче розгортання може переходити між ними без жодних інших змін. Профіль, що несе вбудований клієнтський сертифікат і закритий ключ, самодостатній, і його копіювання на іншу машину працює без копіювання каталогу сертифікатів.

Зворотне не є правильним. Покласти client.crt поруч із профілем, який вбудовує власні дані, нічого не змінює, бо ніщо в конфігурації не посилається на цей файл. Це найпоширеніша причина, чому файл, який явно існує, виглядає знехтуваним.

Як вбудований блок стає об'єктом

Вбудований вміст витягується з конфігурації та передається парсеру PEM як текст. Цей парсер очікує звичайних меж: рядка BEGIN, корисного навантаження base64 і відповідного рядка END. Якщо блок було обрізано невдалим копіюванням, обгорнуто в HTML сторінкою завантаження або відкрито в редакторі, який нормалізував дефіси, парсер зазнає невдачі на вмісті, що виглядає наявним.

<cert>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</cert>

Тому й формулювання помилки вводить в оману. Слово вбудований описує, куди подивився завантажувач, а не що він там знайшов. Файл, названий у конфігурації, і вбудований у неї об'єкт можуть дати ту саму скаргу, коли базові байти непридатні.

Перевірте, яку форму завантажений профіль справді використовує, а не який файл випадково відкрив ваш редактор:

grep -nE '^(ca|cert|key) |^<(ca|cert|key)>' client.ovpn

Як розв'язується посилання на шлях

Значення шляху відкривається відносно робочого каталогу клієнта, а не каталогу, що містить конфігурацію. Під systemd цей робочий каталог — те, що задає юніт, а інтерактивний запуск із вашої оболонки успадковує щось зовсім інше. Тому той самий файл конфігурації може працювати під час ручної перевірки й зазнавати невдачі як служба.

Відносні шляхи успадковують ту саму неоднозначність. Побачивши голе ім'я файлу, запитайте, яким є поточний каталог процесу в продакшені, замість того щоб припускати збіг із вашим терміналом.

Для сертифіката, що зберігається окремо, автономний розбір підтверджує об'єкт, перш ніж ви почнете налагоджувати щось вище нього:

openssl x509 -in client.crt -noout -subject -issuer -dates
openssl pkey -in client.key -noout -check

Ці команди доводять, що файли читабельні та структурно коректні. Вони не доводять, що партнер довіряє видавцю, що сертифікат ще в межах терміну дії або що ключ належить йому.

Що помилка парсера може і чого не може сказати

Збій розбору локалізує проблему на одному вході й одному етапі. Він не каже, яку з двох форм зберігання використав клієнт, і не каже, чи був би об'єкт прийнятий. Це окремі питання з окремими доказами.

Коли розбір успішний, наступний збій належить пізнішому етапу. Відмову в довірі, невідповідність призначення або невідповідність ключа повідомляє партнер або шар TLS, а не завантажувач. Повторна заміна того самого файлу не зрушить цю помилку.

Тримайте чутливу половину поза публічними звітами, поки ведете розслідування. Діліться назвами директив, текстом помилки та структурою блоку, прибравши матеріал ключа й будь-яке ідентифікувальне навантаження. Посібник openvpn(8) описує обидві форми файлових директив і поведінку робочого каталогу за ними.

Схожі статті