Вам не потрібен тимчасовий файл, щоб згенерувати ключ OpenVPN
Тримання матеріалу ключа в пам'яті обминає життєвий цикл файлу, а не витік. Тримайте потік виводу й потік помилок окремо, а потім ставтеся до ключа як до секрету.
Генерація ключа не потребує тимчасового файлу, і відмова від нього виправляє менше, ніж припускають більшість посібників. Він прибирає життєвий цикл файлу та гонитву за очищенням навколо нього. Він залишає недоторканою кожну можливість злити секрет згодом. Проблема коректності в цих скриптах зазвичай лежить в іншому місці, бо діагностика й матеріал ключа подорожують різними потоками.
Файл ніколи не був тією експозицією, про яку ви думали
Тимчасовий файл — конкретний ризик, коли він читабельний для всіх, коли переживає збій або коли після винятку пропускається крок очищення. Це реально, і це варто виправити. Вони також локальні, видимі й легко тестуються. Назвіть кожен із них у власному скрипті, перш ніж зробити висновок, що зміна була лише косметичною.
Тихіші ризики лежать нижче за потоком: ключ, надрукований під час налагодження, виняток, що серіалізує весь об'єкт результату, обробник збою, що пише дамп пам'яті, агрегатор журналів, що отримує шлях до файлу, а потім вміст. Уникнення тимчасового файлу не робить нічого для жодного з них, і віра в протилежне — це шлях, яким доброзичлива переробка залишає секрет більш відкритим, ніж раніше. Розглядайте зміну як одне покращення в черзі, а не як рішення.
Що клієнт пише, коли ім'я файлу не задано
Поточні версії клієнта надсилають згенерований ключ на стандартний вивід, коли команда ключа задана без шляху виводу. Саме ця задокументована поведінка робить підхід у пам'яті життєздатним і прибирає потребу в старому трюку скеровувати інструмент на шлях пристрою.
import subprocess
proc = subprocess.run(
["openvpn", "--genkey", "tls-crypt"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)
key_material = proc.stdout
Передавайте команду списком. Тут не потрібне розширення оболонки, а вмикання оболонки зробило б межу аргументів залежною від лапок, які ви не контролюєте. Використовуйте потрібний виконуваний файл за абсолютним шляхом, якщо скрипт може запускатися з іншим шляхом пошуку, ніж ви очікуєте.
Перевірка коду повернення не дає шляху успіху продовжитися після невдалого виклику. Без неї порожній рядок байтів може протекти далі й відмовити лише значно пізніше, у точці, де ключ використовується, а повідомлення про помилку вже зовсім не згадує генерацію.
Два потоки, два значення
Стандартний вивід несе ключ. Стандартна помилка несе все, що інструмент хоче вам сказати, зокрема попередження про конфігурацію, версію й тип ключа. Перенаправлення обох в один буфер — це та помилка, яка дає правдоподібний на вигляд ключ із вшитим посередині реченням.
Тримайте окремим і шлях відмови. Коли виклик не вдався, повідомте команду, що не спрацювала, і статус виходу, а потім свідомо вирішіть, чи безпечно показувати якусь частину стандартної помилки. Скидання всього об'єкта результату в журнал — звичне скорочення, і воно може понести ключ із собою.
Безпечне для двійкових даних читання важливе, якщо згодом ви хешуєте матеріал або порівнюєте його. Текстовий режим із несподіваним кодуванням може змінити байти, які ніколи не призначалися бути текстом, а змінений ключ не відрізнити від неправильного, доки не відмовить рукостискання.
Якщо ви все ж його зберігаєте, робіть це свідомо
Більшості розгортань зрештою потрібен ключ на диску, на шлюзі або в сховищі секретів. Запишіть його один раз, з обмежувальними правами від створення, а не пізнішим chmod, і зробіть запис атомарним, щоб частковий файл ніколи не став тим, який служба читає під час запуску. Перейменування зі шляху в тому самому каталозі для цього зазвичай достатньо. Вилучіть підготовчий шлях у гілці відмови, бо невдалий запис — це саме та копія, яку люди забувають.
Задайте режим файлу під час створення і тримайте режим каталогу теж обмежувальним. Уникайте будь-якого шляху під місцем, яке завдання резервного копіювання змітає не замислюючись, бо секрет у нічній резервній копії — це секрет у кожній копії цієї резервної копії. Ті самі міркування стосуються спільного тому, який можуть читати інші служби.
Спільний ключ — це не ідентичність
Генерація цього матеріалу не видає сертифікат, не реєструє клієнта і не встановлює, хто підключається. Спільний ключ захищає канал між сторонами, які вже довіряють одна одній; ідентичність і далі походить із сертифіката та будь-якої автентифікації перед ним.
Типи ключів теж не взаємозамінні. Симетричний ключ для однієї функції не є готовою заміною для іншої, а новіші випуски додають власні варіанти з різними файлами на кожному кінці. Генеруйте тип, який ваша конфігурація справді називає, а потім використовуйте його в ролі, яку цей тип визначає.
Перевіряйте результат справжнім підключенням, а не переглядом розміру файлу. Якщо рукостискання завершується і журнали не показують попереджень про ключ, шлях генерації правильний; якби ключ було обрізано об'єднаним потоком, з'єднання відмовило б так, що вказувало б на другу сторону, а не на скрипт.