Linux
- awk
- Цветной вывод в консоли
- Кракозябры в терминале
- OpenVPN in Docker container
- SSH Tunneling
- Memcached
- MongoDB
- SED
- iptables
- Wi-Fi через терминал
- Трекпад на thinkpad x240
- Домашняя система [configs]
- IPsec tunnel [ubuntu - ubuntu]
- deb-пакет
- LUKS Cryptsetup
- Postgresql
- Bash Tricks
- Сжатие/поворот jpeg
- LA
- VIM
- Два монитора
- CAPS -> ESC
- Bluetooth
- Firefox error: NS_ERROR_FILE_CORRUPTED
- DNS NetworkManager
- Сколько ресурсов "продано" на хостере
- Vagrant
- Vagrant
- Packer
- BIND9
- ssh tricks
- Bacula/Bareos
- linux tricks
- Docker and iptables
- Ferm
- openssl
- Процесс загрузки ядра Linux
- systemd/systemctl
- LVM
- network
- dvorak in console
- ini
- apt sources list
- MSSQL
- BASH
- OpenSSL
- LVS
- jq
- Certbot
- Linux hostname (как правильно изменить)
- Своя инфраструктура
- Reproxy
- Borg
- Borgmatic
- mdadm
- cloud-init
- Make
- CouchDB
awk
Статья на хабре от ruvds
Статья на сайте ibm
Синтаксис
~$ awk OPTIONS PROGRAM FILE
-
OPTIONS
- опции -
PROGRAM
- файл с программой на awk или строка с ней :'{print "Welcome to awk command tutorial"}'
-
FILE
- файл который нужно обработать
Опции (основные)
-
-F fs
— позволяет указать символ-разделитель для полей в записи, вот так можно указать его внутри скриптаFS=":"
-
-f file
— указывает имя файла, из которого нужно прочесть awk-скрипт -
-v var=value
— позволяет объявить переменную и задать её значение по умолчанию, которое будет использовать awk -
-mf N
— задаёт максимальное число полей для обработки в файле данных -
-mr N
— задаёт максимальный размер записи в файле данных -
-W keyword
— позволяет задать режим совместимости или уровень выдачи предупреждений awk
Применение
По умолчанию, каждое слово заносится в переменную с именем $<номер слова в строке>
, а через переменную $0
можно обратиться ко всей текущей строке, например $3
в текущей строке содержит значение каждое
(под словом подразумевается поле выделенное из строки с помощью разделителя (по умолчанию пробел или табуляция))
Скрипты выглядят следующим образом: (точкой с запятой нужно разделять строки если они записаны в одну строку, а если нет то достаточно переноса строки) (чтобы выполнить какие-то инструкции до или после начала обработки текста, нужно добавить перед блоком такого кода соответственно слово BEGIN или END)
BEGIN {
print "sosamba niga mazafaka"
}
{
text = " has a home directory at "
print $1 text $6
}
END {
print "konets sosamby"
}
Переменная $NF хранит последнее слово из строки
Переменные для обработки:
- FIELDWIDTHS — разделённый пробелами список чисел, определяющий точную ширину каждого поля данных с учётом разделителей полей
- FS — уже знакомая вам переменная, позволяющая задавать символ-разделитель полей
- RS — переменная, которая позволяет задавать символ-разделитель записей
- OFS — разделитель полей на выводе awk-скрипта
- ORS — разделитель записей на выводе awk-скрипта
Пременные окружающей среды:
- ARGC — количество аргументов командной строки
- ARGV — массив с аргументами командной строки
- ARGIND — индекс текущего обрабатываемого файла в массиве ARGV
- ENVIRON — ассоциативный массив с переменными окружения и их значениями
- ERRNO — код системной ошибки, которая может возникнуть при чтении или закрытии входных файлов
- FILENAME — имя входного файла с данными
- FNR — номер текущей записи в файле данных
- IGNORECASE — если эта переменная установлена в ненулевое значение, при обработке игнорируется регистр символов
- NF — общее число полей данных в текущей записи
- NR — общее число обработанных записей
Например можно узнавать внутри скрипта об указанных ключах и значениях в команде или о домашей директории
Условный оператор
Однострочный вариант
if (УСЛОВИЕ) ДЕЙСТВИЕ
Обычный (если нужно выполниь несколько строк кода, то их нужно объединить фигурными скобками)
if (УСЛОВИЕ)
{
ДЕЙСТВИЕ1
ДЕЙСТВИЕ2
}
Циклы
Можно использовать оператор break и continue
- while
while (УСЛОВИЕ)
{
ДЕЙСТВИЕ1
ДЕЙСТВИЕ2
}
- for -
for (ИНИЦИАЛИЗАЦИЯ_СЧЕТЧИКА; УСЛОВИЕ; ИНКРЕМЕНТАЦИЯ) # как в С-подобных языках
{
ДЕЙСТВИЕ1
ДЕЙСТВИЕ2
}
Фарматированный вывод printf
Вывод настраивается через спецификаторы в формате %[modifier]control-letter
Список спецификаторов:
- c - воспринимает переданное ему число как код ASCII-символа и выводит этот символ
- d - выводит десятичное целое число
- i - то же самое, что и d
- e - выводит число в экспоненциальной форме
- f - выводит число с плавающей запятой
- g - выводит число либо в экспоненциальной записи, либо в формате с плавающей запятой, в зависимости от того, как получается короче
- o - выводит восьмеричное представление числа
- s - выводит текстовую строку
Пример:
printf "The result is: %e\n", x
Встроенные функции
Ссылка на gnu.org на страницу с функциями
Пользовательские функции
function ИМЯ_ФУНКЦИИ()
{
ТЕЛО_ФУНКЦИИ
}
Цветной вывод в консоли
Escape-последовательность для указания цвета текста:
\x1b[...m
\x1b[ - начало
... - место для твоих параметров
m - конец
Коды и атрибуты перечисляются через ;
Пример:
[vandud@vps9104 ~]$ echo -e "\x1b[4;1;41;32mNigaMazafaka\nNigaMazafaka\x1b[0m"
атрибут | значение |
---|---|
0 | нормальный режим |
1 | жирный |
4 | подчеркнутый |
5 | мигающий |
7 | инвертированные цвета |
8 | невидимый |
код для фона | код для текста | цвет |
---|---|---|
40 | 30 | черный |
41 | 31 | красный |
42 | 32 | зеленый |
43 | 33 | желтый |
44 | 34 | синий |
45 | 35 | пурпурный |
46 | 36 | голубой |
47 | 37 | белый |
Последовательность \x1b[0m - Сбрасывает изменения к дефолтным
Кракозябры в терминале
Пример, который был получен выводом командой cat файлов из директории /bin:
for i in `ls -1 /bin`; do cat /bin/$i; done
Такое происходит из-за управляющих последовательностей (escape-последовательностей), которые были посланы в терминал.
https://www.opennet.ru/man.shtml?topic=console_codes&category=4&russian=0
При выводе какого-либо бинарного файла, символы в нем могут образовывать такие последовательности. Из-за этого терминал меняет свое поведение и начинает показывать кракозябры.
Это можно починить перезайдя в оболочку (так как эти последовательности применяют изменения только в рамках текущей сессии).
Либо если возможности перезайти нет, можно выполнить команду reset
, несмотря на то что в поле ввода команды будут кракозябры, эта команда выполнится и перезапустит оболочку (без перелогинивания).
Об этом написано тут http://www.linuxcookbook.ru/howto/Text-Terminal/Text-Terminal-14.html
OpenVPN in Docker container
https://habr.com/ru/post/354632/
Копируем следующие строчки в созданный docker-compose.yml
version: '2'
services:
openvpn:
cap_add:
- NET_ADMIN
image: kylemanna/openvpn
container_name: openvpn
ports:
- "1194:1194/udp"
restart: always
volumes:
- /home/vandud/docker/openvpn/config:/etc/openvpn
Далее
docker-compose run --rm openvpn ovpn_genconfig -u udp://vandud.ru
docker-compose run --rm openvpn ovpn_initpki
Enter New CA Passphrase: niga
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:vandudca
Потом дважды ввел пароль niga
[vandud@vps9104 openvpn]$ docker-compose up -d openvpn
Creating openvpn ... done
Создание серта
docker-compose run --rm openvpn easyrsa build-client-full vandud-phone nopass
Ввести пароль niga
docker-compose run --rm openvpn ovpn_getclient vandud-phone > certificate.ovpn
В получившемся файле только сертификаты и ключи, но нет параметров подключения
Нужно добавить в начало файла следующее
dev tun
proto udp
remote 51.255.215.177
port 1194
client
resolv-retry infinite
tls-client
key-direction 1
auth SHA1
cipher BF-CBC
persist-key
persist-tun
verb 3
Все работает
Чтобы добавить в автозагрузку с systemd
Надо в /etc/openvpn/client.conf положить конфиг (.ovpn)
И добавить в автозагрузку systemctl enable openvpn@client.service
Вот тут написано как делать
https://www.smarthomebeginner.com/configure-openvpn-to-autostart-linux/
Fri Mar 5 04:17:57 2021 write to TUN/TAP : Invalid argument (code=22)
Возникла такая ошибка (сыпется подряд и ничего не грузится)
Клиент - старый дебиан, Сервер - новый докер-контейнер
Решилась так
openvpn --config zabbix-server-1.8.22-web.ovpn --comp-lzo
SSH Tunneling
https://habr.com/ru/post/435546/
-
SSH Socks Proxy
Все очень просто.
Подключаемся по ssh к серверу или какому либо хосту (через который будем проксировать трафик) с добавлением ключа -D
и вместе с ним указываем порт.
~$ ssh connect@vandud.ru -D 8888
После этого нужно настроить подключение в приложении трафик которого нужно проксировать. Например firefox
В настройках подключения указываем localhost
и указанный ранне порт 8888
, все.
Готово, трафик со всех приложений идет по-старому, кроме настроенного приложения (firefox)
-
SSH Туннель (переадресация портов)
~$ ssh -L 8888:127.0.0.1:80 root@45.8.228.69
Эта команда создает защищенный туннель между локальным хостом и удаленным (но только между определенными портами).
То есть при подключении к порту 8888 на локальной машине, запрос идет на 80 порт удаленной машины (конкретно в этом примере). Вместо 127.0.0.1 можно указать какой либо другой адрес, и запрос будет идти на него (от имени удаленной машины)
На скриншоте это видно (на удаленной машине установлен nginx и при запросе на localhost:80 отдается страница wp)
Еще пример
Делаю вот такую команду
vandud@vandud-workstation:~$ ssh -L 8888:95.214.62.136:443 root@45.8.228.69
Она означает, что при подключении к localhost:8888 подключаться к 95.214.62.136:443 от имени 45.8.228.69. Это действительно работает.
Можно также указать локальный адрес
vandud@vandud-workstation:~$ ssh -4 -L 0.0.0.0:8888:95.214.62.136:443 root@45.8.228.69
Получается то же самое
vandud@vandud-workstation:~$ openssl s_client -connect 0.0.0.0:8888 | grep "subject"
Can't use SSL_get_servername
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = alexgyver.ru
verify return:1
subject=CN = alexgyver.ru
^C
Но не работает когда указываешь белые адреса (не локальные)
-
Обратный SSH Туннель
С помощью обратного ssh-туннеля можно получать доступ к мошине за NAT
В качестве примера, сделаю это с рабочим компьютером (он за NAT) и VPS сервером (с него буду подключаться к рабочему компу).
На рабочем компе делаю следующее
vandud@vandud-workstation:~$ ssh root@45.8.228.69 -R localhost:222:localhost:22 -N
root@45.8.228.69's password:
Конструкция -R localhost:222:localhost:22
означает, что при подключении на удаленной машине к localhost:222
подключаться к рабочему компьютеру на порт 22.
Ключ -N
указывает, что не нужно запускать оболочку (после такого подключения работать с машиной по ssh не получится, так как нет приглашения -> некуда вводить команды).
Далее нужно с VPS ввести следующую команду
root@vandud-main-server:~# ssh vandud@localhost -p 222
Ввести пароль и все. Таким образом можно подключаться по ssh к рабочему компьютеру с удаленной VPS
-
SSHFS (дотестить и написать тут)(пункт 16 в статье на хабре)
Memcached
Запущенный memcached
root@vandud:/etc# systemctl status memcached
● memcached.service - memcached daemon
Loaded: loaded (/lib/systemd/system/memcached.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2019-11-12 10:46:25 UTC; 9min ago
Docs: man:memcached(1)
Main PID: 9066 (memcached)
Tasks: 10 (limit: 1073)
CGroup: /system.slice/memcached.service
└─9066 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 -P /var/run/memcached/memcached.pid
Nov 12 10:46:25 vandud systemd[1]: Started memcached daemon.
Конфиг memcached'a
root@vandud:/etc# grep -vE '^#|^$' memcached.conf
-d
logfile /var/log/memcached.log
-m 64
-p 11211
-u memcache
-l 127.0.0.1
-P /var/run/memcached/memcached.pid
Как видно, он берет данные из конфига и запускает с ними себя.
Для работы с memcached нужно подключиться к сервису на порт на котором он запущен (например через nc
, можно также через telnet
)
Запись данных
root@vandud:~# echo -e 'add TEST 0 0 3\r\n101\r' | nc localhost 11211
STORED
^C
root@vandud:~# echo -e 'get TEST\r' | nc localhost 11211
VALUE TEST 0 3
101
END
Пример запроса
echo -e 'add KEY 0 0 5\r\nVALUE\r' | nc localhost 11211
В нем указано, что нужно создать ключ KEY который имеет
- флаг 0 (флаги существуют и их можно использовать на свое усмотрение)
- неограниченное время жизни (второй ноль означает пока не уберут этот ключ вручную)
- длину 5 байт
- значение VALUE равное 5 байт
Также нужно обратить внимание, что memcached сначала проверяет корректность данных (например указано что будет 5 байт данных, а передано 6, такой запрос завершится с ошибкой данных), а потом пытается их засунуть в ключ (то есть потом уже он смотрит на существование запрашиваемого ключа (на случай запроса к несуществующему ключу))
Замена значений
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
VALUE KEY 0 5
TESTS
END
^C
root@vandud:~# echo -e 'set KEY 0 0 3\r\nkey\r' | nc localhost 11211
STORED
^C
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
VALUE KEY 0 3
key
END
Удаление ключа со значением
root@vandud:~# echo -e 'delete KEY\r' | nc localhost 11211
DELETED
^C
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
END
^C
Инкремен\Декремент (только если значение ключа числовое, иначе ошибка)
root@vandud:~# echo -e 'set KEY 0 0 3\r\n333\r' | nc localhost 11211
STORED
^C
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
VALUE KEY 0 3
333
END
^C
root@vandud:~# echo -e 'incr KEY 333\r' | nc localhost 11211
666
^C
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
VALUE KEY 0 3
666
END
^C
root@vandud:~# echo -e 'decr KEY 111\r' | nc localhost 11211
555
^C
root@vandud:~# echo -e 'get KEY\r' | nc localhost 11211
VALUE KEY 0 3
555
END
MongoDB
В качестве идентификатора используется поле _id
(именно с подчеркиванием)
Для того чтобы войти в MongoShell, нужно ввести команду mongo
, также можно сразу указать имя базы mongo mydb
(это заменяет команду use mydb
)
Для того чтобы импортировать свою базу нужно выполнить следующую команду
~# mongoimport -v --file=zips.json
2019-11-12T16:05:10.757+0000 no collection specified
2019-11-12T16:05:10.758+0000 using filename 'zips' as collection
2019-11-12T16:05:10.760+0000 filesize: 3182409 bytes
2019-11-12T16:05:10.761+0000 using fields:
2019-11-12T16:05:10.781+0000 connected to: localhost
2019-11-12T16:05:10.782+0000 ns: test.zips
2019-11-12T16:05:10.782+0000 connected to node type: standalone
2019-11-12T16:05:10.784+0000 using write concern: w='1', j=false, fsync=false, wtimeout=0
2019-11-12T16:05:10.784+0000 using write concern: w='1', j=false, fsync=false, wtimeout=0
2019-11-12T16:05:11.758+0000 imported 29353 documents
Посмотреть список коллекций в базе
> use test
switched to db test
> show collections
zips
>
Поиск по базе
> db.zips.find({'_id': '01001'})
{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
>
Показать все документы в базе
> db.zips.find({})
{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
{ "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51565, 42.377017 ], "pop" : 36963, "state" : "MA" }
{ "_id" : "01005", "city" : "BARRE", "loc" : [ -72.108354, 42.409698 ], "pop" : 4546, "state" : "MA" }
{ "_id" : "01007", "city" : "BELCHERTOWN", "loc" : [ -72.410953, 42.275103 ], "pop" : 10579, "state" : "MA" }
{ "_id" : "01008", "city" : "BLANDFORD", "loc" : [ -72.936114, 42.182949 ], "pop" : 1240, "state" : "MA" }
{ "_id" : "01010", "city" : "BRIMFIELD", "loc" : [ -72.188455, 42.116543 ], "pop" : 3706, "state" : "MA" }
{ "_id" : "01011", "city" : "CHESTER", "loc" : [ -72.988761, 42.279421 ], "pop" : 1688, "state" : "MA" }
{ "_id" : "01012", "city" : "CHESTERFIELD", "loc" : [ -72.833309, 42.38167 ], "pop" : 177, "state" : "MA" }
{ "_id" : "01013", "city" : "CHICOPEE", "loc" : [ -72.607962, 42.162046 ], "pop" : 23396, "state" : "MA" }
{ "_id" : "01020", "city" : "CHICOPEE", "loc" : [ -72.576142, 42.176443 ], "pop" : 31495, "state" : "MA" }
{ "_id" : "01022", "city" : "WESTOVER AFB", "loc" : [ -72.558657, 42.196672 ], "pop" : 1764, "state" : "MA" }
{ "_id" : "01026", "city" : "CUMMINGTON", "loc" : [ -72.905767, 42.435296 ], "pop" : 1484, "state" : "MA" }
{ "_id" : "01027", "city" : "MOUNT TOM", "loc" : [ -72.679921, 42.264319 ], "pop" : 16864, "state" : "MA" }
{ "_id" : "01028", "city" : "EAST LONGMEADOW", "loc" : [ -72.505565, 42.067203 ], "pop" : 13367, "state" : "MA" }
{ "_id" : "01030", "city" : "FEEDING HILLS", "loc" : [ -72.675077, 42.07182 ], "pop" : 11985, "state" : "MA" }
{ "_id" : "01031", "city" : "GILBERTVILLE", "loc" : [ -72.198585, 42.332194 ], "pop" : 2385, "state" : "MA" }
{ "_id" : "01032", "city" : "GOSHEN", "loc" : [ -72.844092, 42.466234 ], "pop" : 122, "state" : "MA" }
{ "_id" : "01033", "city" : "GRANBY", "loc" : [ -72.520001, 42.255704 ], "pop" : 5526, "state" : "MA" }
{ "_id" : "01034", "city" : "TOLLAND", "loc" : [ -72.908793, 42.070234 ], "pop" : 1652, "state" : "MA" }
{ "_id" : "01035", "city" : "HADLEY", "loc" : [ -72.571499, 42.36062 ], "pop" : 4231, "state" : "MA" }
Type "it" for more
>
Показывает порциями, чтобы показать еще нужно набрать it
Поиск документов по условиям через И
> db.zips.find({'city':'GOSHEN','state':'MA'})
{ "_id" : "01032", "city" : "GOSHEN", "loc" : [ -72.844092, 42.466234 ], "pop" : 122, "state" : "MA" }
>
Через ИЛИ
> db.zips.find({$or: [{'city':'GOSHEN'},{'state':'MA'}]})
{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
{ "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51565, 42.377017 ], "pop" : 36963, "state" : "MA" }
{ "_id" : "01005", "city" : "BARRE", "loc" : [ -72.108354, 42.409698 ], "pop" : 4546, "state" : "MA" }
{ "_id" : "01007", "city" : "BELCHERTOWN", "loc" : [ -72.410953, 42.275103 ], "pop" : 10579, "state" : "MA" }
{ "_id" : "01008", "city" : "BLANDFORD", "loc" : [ -72.936114, 42.182949 ], "pop" : 1240, "state" : "MA" }
{ "_id" : "01010", "city" : "BRIMFIELD", "loc" : [ -72.188455, 42.116543 ], "pop" : 3706, "state" : "MA" }
{ "_id" : "01011", "city" : "CHESTER", "loc" : [ -72.988761, 42.279421 ], "pop" : 1688, "state" : "MA" }
{ "_id" : "01012", "city" : "CHESTERFIELD", "loc" : [ -72.833309, 42.38167 ], "pop" : 177, "state" : "MA" }
{ "_id" : "01013", "city" : "CHICOPEE", "loc" : [ -72.607962, 42.162046 ], "pop" : 23396, "state" : "MA" }
{ "_id" : "01020", "city" : "CHICOPEE", "loc" : [ -72.576142, 42.176443 ], "pop" : 31495, "state" : "MA" }
{ "_id" : "01022", "city" : "WESTOVER AFB", "loc" : [ -72.558657, 42.196672 ], "pop" : 1764, "state" : "MA" }
{ "_id" : "01026", "city" : "CUMMINGTON", "loc" : [ -72.905767, 42.435296 ], "pop" : 1484, "state" : "MA" }
{ "_id" : "01027", "city" : "MOUNT TOM", "loc" : [ -72.679921, 42.264319 ], "pop" : 16864, "state" : "MA" }
{ "_id" : "01028", "city" : "EAST LONGMEADOW", "loc" : [ -72.505565, 42.067203 ], "pop" : 13367, "state" : "MA" }
{ "_id" : "01030", "city" : "FEEDING HILLS", "loc" : [ -72.675077, 42.07182 ], "pop" : 11985, "state" : "MA" }
{ "_id" : "01031", "city" : "GILBERTVILLE", "loc" : [ -72.198585, 42.332194 ], "pop" : 2385, "state" : "MA" }
{ "_id" : "01032", "city" : "GOSHEN", "loc" : [ -72.844092, 42.466234 ], "pop" : 122, "state" : "MA" }
{ "_id" : "01033", "city" : "GRANBY", "loc" : [ -72.520001, 42.255704 ], "pop" : 5526, "state" : "MA" }
{ "_id" : "01034", "city" : "TOLLAND", "loc" : [ -72.908793, 42.070234 ], "pop" : 1652, "state" : "MA" }
{ "_id" : "01035", "city" : "HADLEY", "loc" : [ -72.571499, 42.36062 ], "pop" : 4231, "state" : "MA" }
Type "it" for more
>
То есть используется оператор $or
, далее в квадратных скобках идет список значений в фигурных скобках
Поиск документов, где одно поле равно либо одному значению либо другому
> db.zips.find({'city':{$in:['AGAWAM','CUSHMAN']}})
{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
{ "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51565, 42.377017 ], "pop" : 36963, "state" : "MA" }
{ "_id" : "72526", "city" : "CUSHMAN", "loc" : [ -91.776455, 35.869663 ], "pop" : 336, "state" : "AR" }
>
Проецирование (что отображать, а что нет (при поиске))
Отобразить только айди и город
> db.zips.find({'city':{$in:['AGAWAM','CUSHMAN']}},{'_id':1,'city':1})
{ "_id" : "01001", "city" : "AGAWAM" }
{ "_id" : "01002", "city" : "CUSHMAN" }
{ "_id" : "72526", "city" : "CUSHMAN" }
>
При этом если указать только city
> db.zips.find({'city':{$in:['AGAWAM','CUSHMAN']}},{'city':1})
{ "_id" : "01001", "city" : "AGAWAM" }
{ "_id" : "01002", "city" : "CUSHMAN" }
{ "_id" : "72526", "city" : "CUSHMAN" }
>
То id все равно отображается (поэтому можно указать "не отображать id")
> db.zips.find({'city':{$in:['AGAWAM','CUSHMAN']}},{'city':1,'_id':0})
{ "city" : "AGAWAM" }
{ "city" : "CUSHMAN" }
{ "city" : "CUSHMAN" }
>
Но это сработает только с id, потому что это особое поле, например следующий запрос будет с ошибкой (потому что при проецировании поля должны иметь одинаковые значения (1 или 0))
> db.zips.find({'city':{$in:['AGAWAM','CUSHMAN']}},{'city':1,'pop':0})
Error: error: {
"ok" : 0,
"errmsg" : "Projection cannot have a mix of inclusion and exclusion.",
"code" : 2,
"codeName" : "BadValue"
}
>
Сортировка
> db.zips.find().sort({'_id':-1})
{ "_id" : "99950", "city" : "KETCHIKAN", "loc" : [ -133.18479, 55.942471 ], "pop" : 422, "state" : "AK" }
{ "_id" : "99929", "city" : "WRANGELL", "loc" : [ -132.352918, 56.433524 ], "pop" : 2573, "state" : "AK" }
{ "_id" : "99927", "city" : "POINT BAKER", "loc" : [ -133.376372, 56.307858 ], "pop" : 426, "state" : "AK" }
{ "_id" : "99926", "city" : "METLAKATLA", "loc" : [ -131.579001, 55.121491 ], "pop" : 1469, "state" : "AK" }
{ "_id" : "99925", "city" : "KLAWOCK", "loc" : [ -133.055503, 55.552611 ], "pop" : 851, "state" : "AK" }
{ "_id" : "99923", "city" : "HYDER", "loc" : [ -130.124915, 55.925867 ], "pop" : 116, "state" : "AK" }
{ "_id" : "99922", "city" : "HYDABURG", "loc" : [ -132.633175, 55.137406 ], "pop" : 891, "state" : "AK" }
{ "_id" : "99921", "city" : "CRAIG", "loc" : [ -133.117081, 55.47317 ], "pop" : 1398, "state" : "AK" }
{ "_id" : "99919", "city" : "THORNE BAY", "loc" : [ -132.513815, 55.66086 ], "pop" : 744, "state" : "AK" }
{ "_id" : "99901", "city" : "KETCHIKAN", "loc" : [ -131.683175, 55.372028 ], "pop" : 13886, "state" : "AK" }
{ "_id" : "99840", "city" : "SKAGWAY", "loc" : [ -135.301794, 59.468471 ], "pop" : 692, "state" : "AK" }
{ "_id" : "99835", "city" : "SITKA", "loc" : [ -135.316569, 57.051436 ], "pop" : 8638, "state" : "AK" }
{ "_id" : "99833", "city" : "PETERSBURG", "loc" : [ -133.160683, 56.827134 ], "pop" : 4253, "state" : "AK" }
{ "_id" : "99829", "city" : "HOONAH", "loc" : [ -135.558435, 58.032237 ], "pop" : 1670, "state" : "AK" }
{ "_id" : "99827", "city" : "HAINES", "loc" : [ -135.542032, 59.251886 ], "pop" : 2246, "state" : "AK" }
{ "_id" : "99826", "city" : "GUSTAVUS", "loc" : [ -135.761542, 58.42835 ], "pop" : 258, "state" : "AK" }
{ "_id" : "99824", "city" : "DOUGLAS", "loc" : [ -134.395041, 58.275597 ], "pop" : 1802, "state" : "AK" }
{ "_id" : "99820", "city" : "ANGOON", "loc" : [ -134.371052, 57.569832 ], "pop" : 1002, "state" : "AK" }
{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" }
{ "_id" : "99789", "city" : "NUIQSUT", "loc" : [ -150.997119, 70.192737 ], "pop" : 354, "state" : "AK" }
Type "it" for more
>
У функции sort
указывается поле по которому нужно сортировать, и указывается как сортировать (возрастание\убывание)(1-1 соотв.)
Подсчитать количество документов в выборке
> db.zips.find().sort({'_id':-1}).count()
29353
>
Также есть функции skip(N)
и limit(N)
, для того чтобы пропустить первые N документов и вывести только N первых документов в выборке
Вставить значение
> db.zips.insertOne({
... 'field1':'val1',
... 'field2':'val2'
... })
{
"acknowledged" : true,
"insertedId" : ObjectId("5dcae56343b4da469bb68a61")
}
> db.zips.find({'field1':'val1'})
{ "_id" : ObjectId("5dcae56343b4da469bb68a61"), "field1" : "val1", "field2" : "val2" }
>
Замена значения
> db.zips.find({'_id':'01001'},{'state':1})
{ "_id" : "01001", "state" : "niga" }
> db.zips.updateOne({'_id':'01001'},{$set: {'state':'mazafaka'}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.zips.find({'_id':'01001'},{'state':1})
{ "_id" : "01001", "state" : "mazafaka" }
>
Удаление документа
> db.zips.remove({'_id':'01001'})
WriteResult({ "nRemoved" : 1 })
> db.zips.find({'_id':'01001'})
>
Информация о базе (размеры и пр.)
> db.stats()
{
"db" : "test",
"collections" : 1,
"views" : 0,
"objects" : 29353,
"avgObjSize" : 94.50815930228596,
"dataSize" : 2774098,
"storageSize" : 1724416,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 364544,
"fsUsedSize" : 1849679872,
"fsTotalSize" : 15426048000,
"ok" : 1
}
SED
i.dudin@idudin-vb:~/Documents$ echo "test test niga mazafaka" | sed 's/test/azaza/'
azaza test niga mazafaka
i.dudin@idudin-vb:~/Documents$ echo "test test niga mazafaka" | sed 's/test/azaza/g'
azaza azaza niga mazafaka
Если применять команду к файлу (а не к stdin), то содержимое файла не изменяется (он просто берет текст из файла на обработку и результат выводит)
Чтобы выполнить несколько инструкций нужно использовать ключ -e
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
test
niga
niga
mazafaka
i.dudin@idudin-vb:~/Documents$ sed -e 's/test/niga/g; s/mazafaka/niga/g' test
niga1
niga
niga
niga
niga
niga
niga
Ключ -f
нужен для указания файла со скриптом
Кроме флага g
у команды замены (s
) есть и другие флаги, например можно указывать номер вхождения которое нужно заменить или записать вывод в файл (sed 's/test/new test/w filename' text
)
Можно указывать диапазоны обрабатываемых строк
Во второй строке (если в ней есть вхождение) сделать замену
i.dudin@idudin-vb:~/Documents$ sed '3s/niga/1/' test
test1
niga
mazafaka
test
niga
niga
mazafaka
Начиная с 5 и до конца сделать замену
i.dudin@idudin-vb:~/Documents$ sed '5,$s/niga/1/' test
test1
niga
mazafaka
test
1
1
mazafaka
Первое значение не может быть больше второго при указании диапазона, также при указании диапазона не работает флаг g
Поиск подходящей строки по фильтру
Перед командой замены указывается фильтр
Пример: (если в строке встречается test1, то в этой строке заменить первое вхождение mazafaka на 000) (работает со всеми подходящими по фильтр строками)
i.dudin@idudin-vb:~/Documents$ cat newtest
test1 niga test1 mazafaka test1
niga niga niga mazafaka niga
mazafaka niga mazafaka mazafaka mazafaka
test1 niga test mazafaka test
niga niga niga mazafaka niga
niga niga niga mazafaka niga
mazafaka niga mazafaka mazafaka mazafaka
i.dudin@idudin-vb:~/Documents$ sed '/test1/s/mazafaka/000/' newtest
test1 niga test1 000 test1
niga niga niga mazafaka niga
mazafaka niga mazafaka mazafaka mazafaka
test1 niga test 000 test
niga niga niga mazafaka niga
niga niga niga mazafaka niga
mazafaka niga mazafaka mazafaka mazafaka
i.dudin@idudin-vb:~/Documents$
Чтобы удалить строку (строки) можно использовать команду d
(нужно указывать номер удаляемой строки, если не указать то будут удалены все строки)
i.dudin@idudin-vb:~/Documents$ sed '1d' test
niga
mazafaka
test
niga
niga
mazafaka
i.dudin@idudin-vb:~/Documents$ sed '1,5d' test
niga
mazafaka
Можно удалять по фильтру
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
test
niga
niga
mazafaka
i.dudin@idudin-vb:~/Documents$ sed '/mazafaka/d' test
test1
niga
test
niga
niga
Можно указать диапазон строк по фильтру (указывается два фильтра через запятую и будут удалены все строки между этими фильтрами)
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
test22
niga
niga
mazafaka
test
test22
niga
mazafaka
aseohtu
aeou
aoeustnh
i.dudin@idudin-vb:~/Documents$ sed '/test22/,/test22/d' test
test1
niga
mazafaka
niga
mazafaka
aseohtu
aeou
aoeustnh
Ключ -i
позволяет записать изменения в исходный файл (а не выводить на экран)
Чтобы вставить строку в поток можно использовать команду i
или a
(по умолчанию она вставит текст после или до каждой входящей строки (см. пример))
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
niga
mazafaka
aseohtu
aeou
aoeustnh
i.dudin@idudin-vb:~/Documents$ sed -e 'i0000000' test
0000000
test1
0000000
niga
0000000
mazafaka
0000000
niga
0000000
mazafaka
0000000
aseohtu
0000000
aeou
0000000
aoeustnh
0000000
Вставить строку до указанной
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
i.dudin@idudin-vb:~/Documents$ sed -e '2i\00000' test
test1
00000
niga
mazafaka
Вставить строку перед строкой по фильтру
i.dudin@idudin-vb:~/Documents$ cat test
test1
niga
mazafaka
i.dudin@idudin-vb:~/Documents$ sed -e '/niga/i\00000' test
test1
00000
niga
mazafaka
Вставить в множество файлов (в начало или конец) определенную строку
i.dudin@idudin-vb:~/Documents$ ls
1 100 12 14 16 18 2 21 23 25 27 29 30 32 34 36 38 4 41 43 45 47 49 50 52 54 56 58 6 61 63 65 67 69 70 72 74 76 78 8 81 83 85 87 89 90 92 94 96 98
10 11 13 15 17 19 20 22 24 26 28 3 31 33 35 37 39 40 42 44 46 48 5 51 53 55 57 59 60 62 64 66 68 7 71 73 75 77 79 80 82 84 86 88 9 91 93 95 97 99
i.dudin@idudin-vb:~/Documents$ cat 1
testovaya stroka
1
$i
1
i.dudin@idudin-vb:~/Documents$ for var in `ls -1`; do sed -ie '$a'"$var nigerskaya stroka" $var; done
i.dudin@idudin-vb:~/Documents$ cat 1
testovaya stroka
1
$i
1
1 nigerskaya stroka
i.dudin@idudin-vb:~/Documents$
Заменить целую строку можно через команду c
(так же как с командой d
, если не указывать конкретные строки для обработки, заменит все входящие строки)
i.dudin@idudin-vb:~/Documents$ cat 11
testovaya stroka
11
$i
11
11 nigerskaya stroka
i.dudin@idudin-vb:~/Documents$ sed -e 'c\test test test' 11
test test test
test test test
test test test
test test test
test test test
i.dudin@idudin-vb:~/Documents$
Номер строки указывается перед командой
i.dudin@idudin-vb:~/Documents$ sed -ie '2c\test test test' 11
i.dudin@idudin-vb:~/Documents$ cat 11
testovaya stroka
test test test
$i
11
11 nigerskaya stroka
Можно воспользоваться фильтром для замены только в нужных строках
i.dudin@idudin-vb:~/Documents$ cat 11
testovaya stroka
test test test
$i
11
11 nigerskaya stroka
i.dudin@idudin-vb:~/Documents$ sed -ie '/11/c\test test test' 11
i.dudin@idudin-vb:~/Documents$ cat 11
testovaya stroka
test test test
$i
test test test
test test test
i.dudin@idudin-vb:~/Documents$
Замена символов
i.dudin@idudin-vb:~/Documents$ sed -ie 'y/e/1/' 11
i.dudin@idudin-vb:~/Documents$ cat 11
t1stovaya stroka
t1st t1st t1st
$i
t1st t1st t1st
t1st t1st t1st
Команда =
показывает номер строки перед строкой
Ключ -n
запрещает вывод потока (выводит только обработанные строки)
i.dudin@idudin-vb:~/Documents$ sed -ne '3p' 11
$i
iptables
Тоже хорошая статья (более короткая)
https://wiki.archlinux.org/index.php/Iptables_(Русский)
Большая и подробная статья на русском
Чтобы посмотреть текущие правила
iptables -nvL
Что бы сохранить правила в отдельный файл — используйте:
iptables-save > /root/iptables_bkp
Что бы восстановить из него:
iptables-restore < /root/iptables_bkp
Привилегированные порты - порты для использования которых нужно иметь права суперпользователя
Это порты с 0 по 1023
[vandud@desktop ~]$ nc -l -p 88
Error: Couldn't setup listening socket (err=-3) # не разрешило слушать привилегированный порт
[vandud@desktop ~]$ nc -l -p 1088 # прекрасно повисло на прослушивание порта
^C
При добавления правил нужно понимать что после рестарта они пропадут. Поэтому нужно сохранять их в /etc/iptables/iptables.rules
docker,ferm,iptables
При использовании ferm совместно с docker возникает проблема. Докер создает правила на ходу (при создании контейнеров), а ферм про них ничего не знает
Для решения этой проблемы можно использовать ferment (github.com/diefans/ferment)
Лучше использовать ferment-ng, так как в новых версия докера правила создаются иначе
Он ставится через pip и умеет генерировать ферм конфиг для докера
Достаточно в конец ferm.conf дописать
@include '/usr/local/bin/ferment docker config|';
Tables, chains, rules
Каждое правило состоит из критерия (набора условий), действия и счетчика пакетов попавших под это правило. Правило применяется к пакетам подходящим под все условия (критерия)
Каждая таблица служит конкретной цели. Таблицы составляют набор цепочек, которые содержат список правил, организованных в определенном порядке
Цепочки - это упорядоченные последовательности правил (их можно разделить на базовые и пользовательские)
Базовые цепочки создаются по-умолчанию, пользовательские цепочки создаются пользователем)
Принято, что имена базовых цепочек пишутся в верхнем регистре, а имена пользовательских в нижнем
Таблица - это совокупность базовых и пользовательских цепочек, объединенных общим фунуциональным назначением. Имена таблиц пишутся в нижнем регистре
Таблицы:
- raw - пакет проходит таблицу raw до передачи системе определения состояний (может использоваться для маркировки пакетов)
- mangle - содержит правила модификации ip-пакетов и разные специальные преобразования
- nat - подмена адреса отправителя или получателя, проброс портов, итд
- filter - основная таблица, используется по-умолчанию если название таблицы не указано. Используется для фильтрации пакетов
- security - используется для контроля доступа (SELinux)
Таблицы состоят из цепочек правил (правила в цепочках расположены в определенном порядке)
Например таблица по умолчанию filter содержит 3 встроенные цепочки:
- INPUT
- OUTPUT
- FORWARD
А таблица nat содержит:
- PREROUTING (для DNAT)
- POSTROUTING (для SNAT)
- OUTPUT
5 базовых цепочек:
- PREROUTING - для изначальной обработки входящих пакетов
- INPUT - для входящих пакетов, адресованных непосредственно локальному компьютеру
- FORWARD - для проходящих (маршрутизируемых) пакетов
- OUTPUT - для пакетов создаваемых локальным компьютером
- POSTROUTING - для окончательной обработки исходящих пакетов
Также можно создавать собственных цепочки
У всех цепочек есть стандартное правило (политика). Оно применяется к пакету, когда он прошел все остальные правила. То есть политика - это правило по умолчанию
Критерий (условие)
Критерий это логическое условие, которое определяет, соответствует ли пакет этому правилу. В одном правиле может быть несколько критериев (они неявно объединяются логическим AND). Если критерий не указан, то предполагается что правило действует для всех пакетов
Критерий можно инвертировать знаком !
перед ним (логическое НЕ)
Восклицательный знак нужно ставить перед названием критерия, а не между названием критерия и его значением (так стало в новых версиях):--option ! this
- is deprecated! --option this
- is actual
Универсальные критерии
Универсальные критерии применимы к пакетам независимо от протокола транспортного уровня и они не требуют подключения модулей через ключ -m
-
-p
- протокол (tcp, udp, icmp, all, etc). Также протокол можно указать числом или названием из /etc/protocols. После указания протола можно использовать специфичные для него критерии, например--sport
,--dport
или--icmp-type
-
-s
- адрес отправителя. Можно указывать как имя, так и адрес (адрес можно указывать с маской в классическом формате или в CIDR). Можно указать более одного адреса разделяя их запятой (для каждого адреса будет созданно отдельное правило)
Стоит понять что команда с множеством адресов перобразуется в несколько команд с одним адресом, поэтому например добавление правил в конец цепочки добавит правила в порядке перечисления адресов, а вставка в начало цепочки добавит правила в порядке обратном порядку перечисления адресов
При использовании доменов нужно знать что они резолвятся в адреса единожды - при создании правила. Если в будущем адрес домена изменится, то на правило это не повлияет, в правиле останется старый адресiptables -I FORWARD -s deimos.vandud.ru -j DROP # команда (используется таблица forward из-за докера) DROP all -- 185.211.247.85 0.0.0.0/0 # итоговое правило которое работает
А вот если попробовать добавить правило для несуществующего хоста, то возникнет ошибка
root@mars:~# iptables -I FORWARD -s deimos.vandaoeuud.ru -j DROP iptables v1.8.2 (nf_tables): host/network `deimos.vandaoeuud.ru' not found Try `iptables -h' or 'iptables --help' for more information.
-
-d
- то же что и-s
только destination addressИнтересный момент: если использовать одновременно и
-d
и-s
, и в обоих критериях по несколько адресов, то в итоге будет созданно d*s правил. То есть все возможные комбинации -
-i
- входящий интерфейс. В конце имени интерфейса можно поставить+
, тогда под него будут подходить все интерфейсы, имена которых начинаются на слово до плюса. Данный критерий можно использовать в цепочках PREROUTING, INPUT и FORWARD -
-o
- исходящий интерфейс. То же что и-i
, но для цепочек FORWARD, OUTPUT и POSTROUTING
Критерии специфичные для протоколов
TCP
-
--sport
- source-port -
--dport
- destination-port
Можно указывать как диапазон - --sport 1:20
-
--tcp-flags
- позволяет отфильтровать пакеты по установленным в них tcp-флагам. Синтаксис:--tcp-flags маска установленные-флаги
- маска это список флагов на которые смотрим, а установленные-флаги это те флаги, которые установлены на пакете (установленные флаги это подмножество маски, но не наоборот). Те флаги, которые не перечислены в маске - могут быть как установлены, так и нет, на них мы не смотрим вообще
А вот подмножество флагов маска - установленные-флаги должно быть в неустановленном состоянии -
--syn
- позволяет отлавливать SYN-пакеты -
--tcp-option
- проверка наличия какого-либо tcp-параметра
UDP
-
--sport
,--dport
- аналогично соотв. критериям из tcp
IPv4
-
-f
- позволяет отлавливать фрагменты пакетов начиная со второго -
addrtype
- позволяет проверить тип адреса источника и/или назначения с точки зрения подсистемы маршрутизации сетевого стека ядра (UNICAST, LOCAL, UNREACHABLE, etc.)-
--src-type
,--dst-type
- пренадлежит ли src/dst адрес указанному типу
-
-
ecn
- разные проверки ECN -
ttl
- проверка поля TTL, можно сравнивать TTL пакета с каким-то значением
ICMP
-
--icmp-type
- проверка типа icmp-пакета (допустимые типы можно посмотреть командойiptables -p icmp -h
)
Критерии состояния соединения - ConnTrack
В netfilter также есть механизм определения состояний. Он позволяет определить какому состоянию пренадлежит пакет
ConnTrack позволяет делать stateful-фильтрацию
Для протоколов в которых есть понятие "соединение" (tcp), conntrack активно его использует, тесно взаимодействуя с базовой сетевой подсистемой ядра Linux. А в тех протоколах где соединений нет (udp) он вводит его искусственно
У conntrack есть разные модули, которые помогают ему анализировать пакеты и понимать разные факты о них. Например протокол FTP использует два соединения, conntrack это понимает и, проанализировав пакеты управляющего соединения, знает куда будет устанавливаться передающее
С помощью утилит conntrack
и iptstate
можно наблюдать таблицы состояний соединений
Примерно то же самое что и conntrack
показывает cat /proc/net/nf_conntrack
Типы состояний (критерий --ctstate
):
- NEW - новое соединение
- ESTABLISHED - уже установленное соединение
- RELATED - дополнительное к уже существующему соединению
- INVALID - пакет должен принадлежать уже сущ. соединению, но такого соединения не зарегистрировано. Обычно такие пакеты дропают
- UNTRACKED - пакет для которого было отключено отслеживание состояния (в таблице raw)
- DNAT, SNAT - пакет был изменен подменой адреса
Типы статусов (критерий --ctstatus
):
- EXPECTED - ожидаемое соединение (например передающее соединение в FTP, conntrack проанализировал предыдущие пакеты и понял что скоро будет новое соединение)
- CONFIRMED - подтвержденное соединение (что бы это не значило)
- SEEN_REPLY - соединение по которому поступил ответ, то есть имеет место передача в обоих направлениях
- ASSURED - полностью уставноленное соединение, этот статус присваивается после определенного колчества переданных данных. После присвоения этого статуса увеличивается conntrack timeout
- NONE - нет статуса
Существует также понятие «связанных соединений». Например, когда в ответ на UDP-пакет с нашего хоста удаленный хост отвечает ICMP-пакетом icmp-port-unreachable, формально этот ответ является отдельным соединением, так как использует совсем другой протокол. netfilter отслеживает подобные ситуации и присваивает таким соединениям статус «связанных» (RELATED), позволяя корректно пропускать их через фильтры фаервола.
Красными ромбами обозначен момент передачи пакета в механизм определения состояния
Синими кругами обозначены точки маршрутизации: направлен пакет локальному хосту или это проходящий пакет. На какой сетевой интерфейс нужно направить исходящий пакет, итд
На схеме видно что и входящие и исходящие пакеты первым делом попадают в таблицу raw
Эта таблица предназначена для выполнения действий с пакетами до их обработки системой conntrack
В ней невозможно использовать критерии связанные с conntrack'ом (т.к. до него очередь еще не дошла)
Критерий conntrack предоставляет:
-
--ctstate
- позволяет выбрать состояние пакета
Например:iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-
--ctstatus
- опеределение статуса соединения -
--ctproto
- протокол транспортного уровня. Аналогично критерию-p
-
--ctdir
- направление пакета-
ORIGINAL
- от инициатора к отвечающему -
REPLY
- ответ инициатору
-
-
--ctorigsrc
,--ctorigdst
,--ctreplsrc
,--ctrepldst
+ 4 таких же критерия, но с приставкойport
справа - позволяют определять адреса/порты источника/назначения в разных направлениях -
--ctexpire
- позволяет указать оставшееся до таймаута время жизни соединения (принимает минимально оставшееся время, но также можно указать и диапазон). Важно помнить что таймауты для разных протоколов (и даже на разных стадиях одного протокола) - разные
Дополнительные критерии
Дополнительные критерии можно подгружать с помощью параметра -m
. Можно подгружать сразу несколько модулей в одной команде (в одном правиле), но нельзя смешивать параметры (критерии) этих модулей, после каждого модуля строго его параметры
Также допустимо использовать отрицание для каждого критерия (параметра) в отдельности:
-m conntrack ! --ctstate NEW
Справку по модулю можно получить так:
iptables -m название_критерия -h
Список критериев:
-
multiport
- позволяет указать несколько (до 15) портовiptables -A DOCKER-USER -p tcp -m multiport --dports 80,81,82,83,84,85,86 -j ACCEPT
ACCEPT tcp -- anywhere anywhere multiport dports http,81,82,83,84,85,86
Также этот критерий имеет параметр--ports
, который объединяет sport и dport -
iprange
- позволяет указать диапазон адресов не являющихся подсетью -
mark
- позволяет выделять пакеты по маркировке -
connmark
- то же что и mark но для соединений -
limit
- позволяет ограничить количество пакетов в единицу времени -
hashlimit
- то же что и limit но позволяет применять одно правило для групп хостов, подсетей -
connlimit
- позволяет ограничивать количество одновременно открытых соединений с каждого IP-адреса -
connbytes
- позволяет ограничивать количество переданных байт или пакетов -
quota
- позволяет задать квоту в байтах для данного конкретного правилаChain INPUT (policy DROP 13166 packets, 684K bytes) pkts bytes target prot opt in out source destination 3 171 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:33 quota: 200 bytes 9 780 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:33
-
length
- ограничение по размеру пакета (размер пакета протокола сетевого уровня (IP, IPv6) за вычетом размера заголовков сетевого уровня) -
recent
- мощный критерий, умеет много всего относительно запоминания информации о проходящих через него пакетах и принятия решения на основе собранных знаний. С помощью него можно строить крутые вещи -
u32
- супер штука для глубокого анализа трафика. Для него нужно писать программы на местном языке
Если действия не указано, то правило будет работать как счетчик
Путь пакета по цепочкам и таблицам
Схема прохождения пакета:
Чуть более удобная схема:
Как видно, пакет вначале проходит по цепочкам PREROUTING в трех таблицах (raw, mangle, nat)
Важно понимать, что это три разные цепочки (с одинаковым именем) в трех разных таблицах
Далее, пройдя по трем цепочкам, пакет уходит в цепочки INPUT или FORWARD, таблиц mangle и filter
И т.д.
Не важно с какого интерфейса был получен пакет. В каждом случае он обрабатывается одинакого и проходит одинаковый путь по таблицами и цепочкам
Действие над пакетом указывается через ключ -j
или --jump
. В него передается либо стандартное действие, либо действие расширения, либо переход на пользовательскую цепочку
Примеры стандартных действий:
- ACCEPT
- DROP
- QUEUE
- RETURN
Примеры действий расширений:
- REJECT
- LOG
Если выбрано стандартное действие, то участь пакета ясна (он допускается, отбрасывается, итд)
Если выбран переход на пользовательскую цепочку, то пакет проходит по всем правилам пользовательской цепочки и если ни одно правило из нее не подошло ему, то он возвращается на следующее после перехода правило (см. картинку)
А действия расширений могут вести себя и как переход на пользовательскую цепочку, и как стандартное действие (зависит от расширения)
Более правильными словами: действия расширений могут быть терминальными (как стандартные действия) или нетерминальными (как пользовательские цепочки)
Более подробно про расширения man iptables-extensions
Пользовательские цепочки не могут иметь политику. А также важно, что пакет попадает в пользовательскую цепочку из стандартной. И если ни одно правило из стандартной цепочки не подошло, по пакет просто возвращается в стандартную цепочку как показано на схеме выше
Также важно, если пакет отброшен действием DROP, то он отброшен окончательно. Но если пакет принят действием ACCEPT, то он принят на уровне этой таблицы и цепочки в ней. Он просто продолжает свой путь по следующим цепочкам (как указано на общей схеме)
Комментарии
Можно добавлять комментарии к правилам
Это делается через модуль comment
и его параметр --comment
(max-len 256 символов)
Пример:
iptables -A DOCKER-USER -p tcp --dport 77 -j DROP -m comment --comment "supper comment"
Результат:
Chain DOCKER-USER (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere
DROP tcp -- anywhere anywhere tcp dpt:77 /* supper comment */
Основные действия
Работа с цепочками
-
iptables -N chain
- New chain
-
-F
- Flush chain -
-L [chain-name]
- List all rules -
-Z
- Zero the packet and byte counters in all chains
-
-P
- Set Policy for built-in chain
-
-X
- Delete user-defined chain. There must be no references to the chain -
-E
- Rename user-chain
Работа с правилами
-
-I chain-name [rulenum]
- вставить правило в начало или в указанную позицию (при вставке в указанную позицию, уже существующее на этой позиции правило сдвигается вниз) -
-R chain-name rulenum
- заменить правило с указанным номером -
-A
- добавить в конец -
-C
- проверить что такое правило уже есть -
-D
- удалить правило по описанию или по номеру
Действие (target)
-
ACCEPT – принять пакет, и передать следующей цепочке (или приложению, или передать для дальнейшего роутинга)
-
DNAT — (Destination Network Address Translation) используется для преобразования адреса места назначения в IP заголовке пакета; если пакет подпадает под критерий правила, выполняющего DNAT, то этот пакет, и все последующие пакеты из этого же потока, будут подвергнуты преобразованию адреса назначения и переданы на требуемое устройство, хост или сеть; действие DNAT может выполняться только в цепочках PREROUTING и OUTPUT таблицы nat, и во вложенных под-цепочках
важно запомнить, что вложенные подцепочки, реализующие DNAT не должны вызываться из других цепочек, кроме PREROUTING и OUTPUT
-
DROP – просто «сбрасывает» пакет и IPTABLES «забывает» о его существовании; «сброшенные» пакеты прекращают свое движение полностью, т.е. они не передаются в другие таблицы, как это происходит в случае с действием ACCEPT
-
LOG — действие, которое служит для журналирования отдельных пакетов и событий; в журнал могут заноситься заголовки IP пакетов и другая полезная информация; информация из журнала может быть затем прочитана с помощью dmesg или syslogd, либо с помощью других программ; обратите ваше внимание так же на цель ULOG, которое позволяет выполнять запись информации не в системный журнал, а в базу данных MySQL и т.п.
-
MARK — используется для установки меток для определенных пакетов; это действие может выполняться только в пределах таблицы mangle; установка меток обычно используется для нужд маршрутизации пакетов по различным маршрутам, для ограничения трафика и т.п.; «метка» пакета существует только в период времени пока пакет не покинул брандмауэр, т.е. метка не передается по сети
-
MASQUERADE — в основе своей представляет то же самое, что и SNAT только не имеет ключа
--to-source
; причина тому то, что маскарадинг может работать, например, с dialup подключением или DHCP, т.е. в тех случаях, когда IP адрес присваивается устройству динамически; если у вас имеется динамическое подключение, то нужно использовать маскарадинг, если же у вас статическое IP подключение, то лучше будет использование SNAT -
MIRROR — может использоваться вами только для экспериментов и в демонстрационных целях, поскольку это действие может привести к «зацикливанию» пакета и в результате к «Отказу от обслуживания»; в результате действия MIRROR в пакете, поля source и destination меняются местами и пакет отправляется в сеть; допускается использовать только в цепочках INPUT, FORWARD и PREROUTING, и в цепочках, вызываемых из этих трех
-
QUEUE – ставит пакет в очередь на обработку пользовательскому процессу; оно может быть использовано для нужд учета, проксирования или дополнительной фильтрации пакетов
-
REDIRECT — выполняет перенаправление пакетов и потоков на другой порт той же самой машины; можно пакеты, поступающие на HTTP порт перенаправить на порт HTTP-proxy; удобен для выполнения «прозрачного» проксирования (transparent proxy), когда машины в локальной сети даже не подозревают о существовании прокси; может использоваться только в цепочках PREROUTING и OUTPUT таблицы nat
-
REJECT — используется, как правило, в тех же самых ситуациях, что и DROP, но в отличие от DROP, команда REJECT выдает сообщение об ошибке на хост, передавший пакет
-
RETURN — прекращает движение пакета по текущей цепочке правил и производит возврат следующему правилу в вызывающей (предыдущей) цепочке, если текущая цепочка была вложенной, или, если текущая цепочка лежит на самом верхнем уровне (например INPUT), то к пакету будет применена политика по-умолчанию; обычно, в качестве политики по-умолчанию назначают действия ACCEPT или DROP
-
SNAT — используется для преобразования сетевых адресов (Source Network Address Translation), т.е. изменение исходящего IP адреса в IP в заголовке пакета; SNAT допускается выполнять только в таблице nat, в цепочке POSTROUTING; если первый пакет в соединении подвергся преобразованию исходящего адреса, то все последующие пакеты, из этого же соединения, будут преобразованы автоматически и не пойдут через эту цепочку правил
-
TOS — используется для установки битов в поле Type of Service IP заголовка; поле TOS содержит 8 бит, которые используются для маршрутизации пакетов; важно помнить, что данное поле может обрабатываться различными маршрутизаторами с целью выбора маршрута движения пакета; в отличие от MARK, сохраняет свое значение при движении по сети, а поэтому может использоваться для маршрутизации пакета; лучше всего использовать это поле для своих нужд только в пределах WAN или LAN
-
TTL — используется для изменения содержимого поля Time To Live в IP заголовоке
-
ULOG — система журналирования пакетов, которая заменяет традиционное действие LOG, базирующееся на системном журнале; при использовании этого действия, пакет, через сокеты netlink, передается специальному демону который может выполнять очень детальное журналирование в различных форматах (обычный текстовый файл, база данных MySQL и пр.), может формировать отчёты в CSV, XML, Netfilter’s LOG, Netfilter’s conntrack; подробнее смотрите на домашней странице проекта
Wi-Fi через терминал
В этой статье рассматривается еще один способ подключения к wi-fi (wpasupplicant)
Через утилиту nmcli (скорее всего нет по умолчанию)
Найти нужную wi-fi сеть и информацию о ней
Можно использовать утилиту nmcli
nmcli device wifi
Ключевое слово wifi означает тип девайса (можно увидеть в выводе команды nmcli device
)
В выводе список wi-fi точек со следующими полями (пример вывода):
IN-USE SSID MODE CHAN RATE SIGNAL BARS SECURITY
iFree Infra 52 270 Mbit/s 100 ▂▄▆█ WPA1 WPA2 802.1X
Поле BARS это (насколько я понял) просто график поля SIGNAL, а значение в поле SIGNAL указано в процентах.
Подключиться к выбранной точке
Используя ту же утилиту nmcli
nmcli device wifi connect WiFi-Name password Password
После выполнения этой команды даже не нужно вызывать dhclient
для получения параметров dhcp (они настраиваются автоматически)
Утилита iwctl/iwd
https://ctlos.github.io/wiki/packages/iwd/
Поднимаем беспроводной интерфейс (если не поднят)
[vandud@thinkpad ~]$ sudo ip link set wlp3s0 up
Подключение
iwctl station wlan0 scan
iwctl station wlan0 get-networks
iwctl station wlan0 connect COSMOPOLITAN
После команды connect будет запрошен пароль от точки доступа.
Далее нужно получить ip-адрес. Для этого достаточно выполнить команду dhclient
Для автоподключения к wi-fi нужно добавить сервис iwd в автозагрузку:
systemctl enable iwd
И добавить в файл /var/lib/iwd/NETWORK.psk такую директиву:
[Settings]
AutoConnect=true
Этот файл уже будет содержать пароль от этой сети (создается после первого подключения)
Для автоматического получения ip-адреса нужно добавить в /etc/iwd/main.conf вот такое:
[General]
EnableNetworkConfiguration=true
Теперь при перезагрузке сервер будет автоматически подключаться к wi-fi
(это нужно для автонастройки ip, по умолчанию dhclient не запускается)
Если указанный выше метод не сработал для dhcp, то можно сделать так:
cat /etc/systemd/network/20-dhcp.network
[Match]
Name=enp*
[Network]
DHCP=ipv4
И нужно сделать reload/enable/start для systemd-networkd.service
Трекпад на thinkpad x240
Сначала нужно установить драйвер
# pacman -S xf86-input-synaptics
Далее нужно изменить параметры загрузки ядра. Происходит тайм-аут по бездействию устройства (трекпоинт или трекпад). Нужно добавить в /etc/default/grub следующие параметры
GRUB_CMDLINE_LINUX_DEFAULT="[уже присутствующие параметры] i8042.nomux=1 i8042.noloop=1 i8042.notimeout=1 i8042.reset=1"
Далее
sudo update-grub
И рестарт системы (чтобы она загрузилась уже с новыми параметрами)
После этих действий у меня стало работать (но вскоре проблема вернулась)
Документация про параметры ядра (искать по i8042)
Вот еще
https://www.linux.org.ru/forum/desktop/9066459
В итоге видимо проблема не на таком низком уровне как я подумал ранее.
Файл /etc/X11/xorg.conf.d/30-touchpad.conf привел к следующему виду:
Section "InputDevice"
Identifier "TouchPad"
Driver "synaptics"
EndSection
Перезагрузил ноут и команда synclient -l стала показывать вывод переменных драйвера synaptics (ранее драйвер не был задействован (возможно в этом была проблема))
Через драйвер synaptics можно настроить все (я был шокирован когда увидел количество различных параметров)
Утилита synclient позволяет менять настройки на лету (без перезагрузки X)
Чтобы настроить клики мыши по тапам (там по тачпаду) нужно выполнить следующую команду
synclient TapButton1=1 TapButton2=3 TapButton3=2
Эти клики можно настроить через утилиту synclient, либо указать в ранее упомянутом конфиге xorg.conf.d
Section "InputDevice"
Identifier "touchpad"
Driver "synaptics"
Option "TapButton1" "1"
Option "TapButton2" "3"
Option "TapButton3" "2"
EndSection
Домашняя система [configs]
Список файлов и директорий, которые нужно бэкапировать:
- ~/.mozilla/*
- ~/.bash_aliases
- ~/.i3/config
Язык (раскладка + переключение)
Вот такая команда работает корректно, пока не определился куда именно ее поместить, в данный момент она находится в ~/.i3/config
exec setxkbmap -layout us,ru -variant dvorak, -option grp:win_space_toggle
exec - для выполнения через конфиг i3 (если надумаю разместить в каком-нибудь bash конфиге, то она не нужна)
Firefox
Директория с конфигами ~/.mozilla/firefox
, проще копировать целую ~/.mozilla
При первом запуске, firefox создает в домашней папке эту директорию с дефолтными конфигами. Перед копированием своего конфига, старую директорию нужно удалить.
После копирования своей ~/.mozilla
, firefox запускается сразу с нужными настройками, то есть кроме копирования конфигов, больше ничего делать не нужно.
С помощью плагина Firefox color создал тему. Плагин может сразу применять новую тему на лету, а также позволяет сохранить тему как архив.
Вся тема состоит из двух файлов:
- json-манифест
- Картинка (используется для фона)
├── images
│ └── bg-039-717a66ba4d455686088c80f391cb3264.svg
├── manifest.json
manifest.json:
{
"manifest_version": 2,
"version": "1.0",
"name": "vandud-firefox-theme-manjaro-i3",
"theme": {
"images": {
"additional_backgrounds": [
"images/bg-039-717a66ba4d455686088c80f391cb3264.svg"
]
},
"properties": {
"additional_backgrounds_alignment": [
"top"
],
"additional_backgrounds_tiling": [
"repeat"
]
},
"colors": {
"toolbar": "rgb(39, 65, 81)",
"toolbar_text": "rgb(100, 152, 154)",
"frame": "rgb(37, 57, 69)",
"tab_background_text": "rgb(100, 152, 154)",
"toolbar_field": "rgba(0, 0, 0, 0.2)",
"toolbar_field_text": "rgb(100, 152, 154)",
"tab_line": "rgb(28, 171, 176)",
"popup": "rgb(49, 67, 78)",
"popup_text": "rgb(100, 152, 154)",
"tab_loading": "rgb(28, 171, 176)"
}
}
bg-039-717a66ba4d455686088c80f391cb3264.svg:
<svg width="144" height="96" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" opacity=".3"><path fill-opacity=".1" d="M0 9h180v24H0z"/><path fill-opacity=".2" d="M0-15h180V9H0zm0 96h180v24H0z"/><path fill-opacity=".1" d="M0 0h24v96H0zm48 0h24v96H48zm48 0h24v96H96z"/><path fill-opacity=".1" d="M0 57h180v24H0z"/><path fill-opacity=".2" d="M0 33h180v24H0z"/></g></svg>
Так и не понял как ее установить отдельно
Bash
Все конфиги раскиданы по хомяку
-
~/.bash_aliases
Для работы .bash_aliases, нужно чтобы в .bashrc (или .bash_profile), было прописано следующее:
[[ -f ~/.bash_aliases ]] && . ~/.bash_aliases
Иногда подобная запись уже есть где-либо (в том же .bashrc или где-то еще), но например в manjaro такой записи нет.
i3wm
IPsec tunnel [ubuntu - ubuntu]
https://www.gypthecat.com/ipsec-vpn-host-to-host-on-ubuntu-14-04-with-strongswan
По этой статье все заработало
deb-пакет
Вообще это просто архив типа ar (с сигнатурой !<arch>.
[точка это на самом деле 0a
- \n])
Буду разбирать на основе zabbix_1.8.22_amd64.deb
Состоит из трех частей:
-
debian-binary - текстовый файл содержащий версию deb
Вот такой командой выделил из основного файла только текстовый файл debian-binary
root@test-slave:/tmp/test# dd if=zabbix_1.8.22-1_amd64.deb of=debian-binary skip=68 count=4 iflag=skip_bytes,count_bytes
Его содержимое
root@test-slave:/tmp/test# xxd debian-binary
0000000: 322e 300a 2.0.
Как видно он содержит 2.0 (0a
это \n)
-
control.tar.gz - содержит информацию о deb-пакете и скрипты установки
Выделил из основного файла так
root@test-slave:/tmp/test# dd if=zabbix_1.8.22-1_amd64.deb of=control.tar.gz skip=132 count=299 iflag=skip_bytes,count_bytes
Распаковка
root@test-slave:/tmp/test/control# tar -xzvf control.tar.gz
./
./control
./conffiles
Control содержит следующее
root@test-slave:/tmp/test/control# cat control
Package: zabbix
Priority: extra
Section: checkinstall
Installed-Size: 916
Maintainer: root@test-slave
Architecture: amd64
Version: 1.8.22-1
Provides: zabbix
Description: Zabbix Agent
Conffiles в моем случае был пустым
-
data.tar.xz - содержит файлы для установки
Выделил из основного файла так
dd if=zabbix_1.8.22-1_amd64.deb of=data.tar.xz skip=476 iflag=skip_bytes
Распаковал архив, получилось следующее
root@test-slave:/tmp/test/data# tree .
.
├── data.tar.xz
└── usr
├── local
│ ├── bin
│ │ ├── zabbix_get
│ │ └── zabbix_sender
│ ├── sbin
│ │ ├── zabbix_agent
│ │ └── zabbix_agentd
│ └── share
│ └── man
│ ├── man1
│ │ ├── zabbix_get.1.gz
│ │ └── zabbix_sender.1.gz
│ └── man8
│ └── zabbix_agentd.8.gz
└── share
└── doc
└── zabbix
├── AUTHORS
├── COPYING
├── CREDITS
├── ChangeLog
├── INSTALL
├── NEWS
└── README
В архиве лежат файлы с абсолютными путями, поэтому они просто разархивируются относительно корня и все.
LUKS Cryptsetup
https://wiki.debian.org/ru/Crypt
Подключить диск
cryptsetup luksOpen /dev/sda2 sda2_crypt
Примонтиовать куда надо
mount /dev/mapper/sda2_crypt /mnt/data
Отмотировать
umount /mnt
Отлючить диск
cryptsetup luksClose sdb1_crypt
Для автомонтирования сделал так
В /etc/crypttab
sdb1_crypt /dev/sdb1 none luks
В /etc/fstab
/dev/mapper/sdb1_crypt /mnt/hdd_1tb ext4 defaults 0 0
При загрузке системы будет спрашиваться пароль от диска
Postgresql
https://postgrespro.ru/docs/postgresql/9.5/install-short
Установка
apt install postgresql-9.5
После установки бинарники постгреса хранятся тут: /usr/lib/postgresql/9.5/bin
Создание директории в которой будут храниться базы
mkdir -p /usr/local/pgsql/data
Можно выбрать любую иную директорию
Назначение соответствующих прав на эту директорию:
chown -R postgres:postgres /usr/local/pgsql/data
Создание нового кластера базы данных в созданной директории
sudo -u postgres /usr/lib/postgresql/9.5/bin/initdb -D /usr/local/pgsql/data/
Запуск постгреса
sudo -u postgres /usr/lib/postgresql/9.5/bin/pg_ctl -D /usr/local/pgsql/data/ -l /var/log/postgresql/postgresql-9.5-main.log start
Создание базы
sudo -u postgres /usr/lib/postgresql/9.5/bin/createdb zabbix
Подключение к консоли постгреса
sudo -u postgres psql
psql (9.5.19)
Type "help" for help.
postgres=#
Дамп большой базы по сети
При дампе большой базы может возникнуть проблема с нехваткой места для файла дампа на сервере с базой. Тогда можно дампить сразу на удаленное хранилище.
Можно на сервере с базой запустить вот такую команду (ее можно сделать еще проще, но в моем случае были вынужденные усложнения)
root@cm-db-pgsql-01x:/home/i.dudin_pro# pg_dump -U postgres notify -Fc -E UTF-8 | bzip2 | ssh i.dudin_pro@bk02.g02.i-free.ru -i /home/i.dudin_pro/.ssh/id_rsa "bunzip2 > /var/backups-remote/cm-db-pgsql-01x_UPEADM-9992/notify.2020-06-07.dump"; echo $?
Bash Tricks
Убрать префикс из имен файлов
Например есть куча файлов у которых в названии есть перфикс
В моем случае префикс это _frem_iptables.txt
...
vendors-highscoring-01x.g01.i-free.ru_frem_iptables.txt
vendors-msgpro-filterws-01.g01.i-free.ru_frem_iptables.txt
vendors-web-backend-01x.g01.i-free.ru_frem_iptables.txt
voiceassistant-vas01.aws-eu-west-1.i-free.ru_frem_iptables.txt
vrs02.g01.i-free.ru_frem_iptables.txt
web-backend-01x.g01.i-free.ru_frem_iptables.txt
web-backend-01y.g01.i-free.ru_frem_iptables.txt
web-backend-02x.g01.i-free.ru_frem_iptables.txt
web-backend-02y.g01.i-free.ru_frem_iptables.txt
web-srv2.pro.i-free.ru_frem_iptables.txt
web-srv3.pro.i-free.ru_frem_iptables.txt
wf-vas01.g01.i-free.ru_frem_iptables.txt
zabbix-proxy.l5.i-free.local_frem_iptables.txt
...
Делаю вот так:
for name in `ls -1`; do mv $name ${name%_frem_iptables.txt}; done
-
${var#pattern}
- удаляет наименьшую строку с левой стороны, которая соответствует шаблону -
${var##pattern}
- удаляет наибольшую строку с левой стороны, которая соответствует шаблону -
${var%pattern}
- удаляет наименьшую строку с правой стороны, которая соответствует шаблону -
${var%%pattern}
- удаляет наибольшую строку с правой стороны, которая соответствует шаблону
Более подробно это описано в части "Parameter Expansion" в man bash
sshpass и как выполнить команду через sudo
SSHPass
for servername in `cat /tmp/servernames-for-ferm-reload`; do sshpass -p'ПАРОЛЬ' ssh -tt i.dudin_pro@${servername} 'echo ПАРОЛЬ | sudo -S -s /bin/bash -c "/etc/init
.d/ferm reload"';echo $servername; done
<<<
В баше есть перенаправления потоков, и среди них есть штука их трех стрелок
Она добавляет перенос строки в конец переданного ей (но это не точно)
[vandud@desktop ~]$ cat < "zhopa"
bash: zhopa: No such file or directory
[vandud@desktop ~]$ cat << "zhopa"
> ^C
[vandud@desktop ~]$ cat <<< "zhopa"
zhopa
[vandud@desktop ~]$
Это можно использовать в командах которые ждут ввода пользователя
Например openssl s_client
после вывода ожидает от пользователя "Q" и только после этого завершается
[vandud@desktop ~]$ openssl s_client -connect smsservisy.ru:443 2>/dev/null | openssl x509 -noout -subject
subject=OU = Domain Control Validated, OU = Gandi Standard Wildcard SSL, CN = *.i-free.com
Q # ввел руками и нажал enter
А если передать туда "Q" через <<<
, то работает само
[vandud@desktop ~]$ openssl s_client -connect smsservisy.ru:443 2>/dev/null <<< "Q" | openssl x509 -noout -subject
subject=OU = Domain Control Validated, OU = Gandi Standard Wildcard SSL, CN = *.i-free.com
[vandud@desktop ~]$
А еще в случае с openssl можно сделать так:
echo | openssl s_client aoseuhosaetuaoue
Сжатие/поворот jpeg
Сжатие
Утилита jpegoptim
Пример использования
[vandud@thinkpad Downloads]$ jpegoptim --size=250K IMG_0892.jpg
IMG_0892.jpg 3421x1460 24bit N Exif IPTC ICC JFIF [OK] 1060271 --> 253677 bytes (76.07%), optimized.
Размер можно не указывать, тогда будет оптимизация без потерь качества, но сжатие совсем не значительное (около 1-2 процентов).
Поворот
Утилита convert
convert [input-options] input-file [output-options] output-file
Пример:
convert IMG_0191.jpg -rotate -90 IMG_0191r.jpg
Крутит по часовой стрелке
heic -> jpg
$ heif-convert IMG_0583.heic recomendations.jpg
LA
https://firstvds.ru/technology/nagruzka-na-server-opredelenie-prichin
В выводе top есть строка CPU:
- us (user) - Использование процессора пользовательским процессами
- sy (system) - Использование процессора системным процессами
- ni (nice) - Использование процессора процессами с измененным приоритетом с помощью команды nice
- id (idle) - Простой процессора. Можно сказать, что это свободные ресурсы
- wa (IO-wait) - Говорит о простое, связанным с вводом/выводом
- hi (hardware interrupts) - Показывает сколько процессорного времени было потрачено на обслуживание аппаратного прерывания
- si (software interrupts) - Показывает сколько процессорного времени было потрачено на обслуживание софтверного прерывания
- st (stolen by the hypervisor) - Показывает сколько процессорного времени было «украдено» гипервизором
Командой atop -l -c -d1 можно посмотреть кто грузит диск
VIM
Как установить плагин в vim
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
Эта команда добавит менеджер плагинов.
Далее в .vimrc добавляем плагины вот так:
set nu
set expandtab
set tabstop=2
set incsearch
syntax on
call plug#begin('~/.vim/plugged')
Plug 'stephpy/vim-yaml'
Plug 'preservim/nerdtree'
Plug 'morhetz/gruvbox'
call plug#end()
colorscheme gruvbox
set background=dark
map <C-n> :NERDTreeToggle<CR>
Строки с call нужны обязательно, между ними и указываются плагины.
И в конце чтобы новые плагины установились нужно:
- Подгрузить конфиг файл
:source %
или:source PATH_TO_vimrc
(если конфиг был изменен вимом же только что), либо перезайти в вим. - Выполнить
:PluginInstall
Два монитора
xrandr --auto --output DP2 --mode 1366x768 --left-of eDP1
Внешний справа:
xrandr --output eDP1 --auto --pos 0x312 --output DP2 --auto --pos 1366x0
Внешний сверху:
xrandr --output eDP1 --auto --pos 0x1080 --output DP2 --auto --pos -276x0
CAPS -> ESC
setxkbmap -option "caps:swapescape"
Что это было перманентным, можно засунуть в .bashrc
Bluetooth
Запустите интерактивную команду bluetoothctl
. После этого можно ввести help
для получения списка доступных команд:
- Включите питание контроллера, введя
power on
. По умолчанию оно отключено. - Введите
devices
, чтобы увидеть MAC-адрес устройства для сопряжения. - Войдите в режим обнаружения устройств при помощи команды
scan on
, если нужного вам устройства нет в списке. - Включите агент при помощи
agent on
. - Введите
pair MAC-адрес
, чтобы осуществить сопряжение (работает автодополнение по tab). - При использовании устройства без PIN, возможно, потребуется подтверждение, прежде чем оно сможет успешно переподключиться. Для этого введите
trust MAC-адрес
. - Наконец, используйте
connect MAC-адрес
для установки соединения.
# bluetoothctl
[bluetooth]# agent KeyboardOnly
[bluetooth]# default-agent
[bluetooth]# power on
[bluetooth]# scan on
[bluetooth]# pair 00:12:34:56:78:90
[bluetooth]# connect 00:12:34:56:78:90
[bluetooth]# trust 00:12:34:56:78:90
Чтобы устройство было активно после перезагрузки, необходимо включить автовключение bluetooth:
/etc/bluetooth/main.conf
[Policy]
AutoEnable=true
Firefox error: NS_ERROR_FILE_CORRUPTED
С такой ошибкой сайт не загружается корректно (не подгружается часть страницы). Я выполнил в консоли браузера такое:
localStorage.clear()
sessionStorage.clear()
И стало работать как надо.
DNS NetworkManager
По умолчанию NetworkManager сам настраивает DNS и у него есть конфиги где можно указать как именно ему это нужно делать.
Но мне было проще отключить автонастройку и делать это через /etc/resolv.conf
Для этого нужно в /etc/NetworkManager/NetworkManager.conf внести:
[main]
dns=none
И все, теперь после перезагрузки NM не будет затирать мои изменения в resolv.conf
Сколько ресурсов "продано" на хостере
Виртуализация qemu/kvm. Команда ниже посчитает проданные ядра.
SUM=0;for i in `sudo grep vcpu /etc/libvirt/qemu/autostart/* | grep -o ">[[:digit:]]<" | grep -o "[[:digit:]]"`; do let SUM+=$i; done; echo $SUM
Vagrant
Инициализация
Чтобы инициализировать виртуалку, нужно ввести команду:
vagrant init ubuntu/xenial64
Она создаст файл Vagrantfile в текущей дериктории. В этом файле содержится конфигурация (на ruby). А также после этой команды будет скачан образ указанной системы с серверов vagrant
Примерно по такому пути находится скачанный образ виртуалки: /home/vandud/.vagrant.d/boxes/ubuntu-VAGRANTSLASH-xenial64/20200617.0.0/virtualbox
Вот тут можно выбрать подходящий образ
В конфиге можно редактировать параметры виртуалки (добавить памяти и прочее)
Старт выполняется командой vagrant up
Для подключения к виртуалке нужно использовать команду vagrant ssh
(виртуалка слушает порт для ssh на хостовой машине, но там по-умолчанию доступ только по ключу, который есть у vagrant'a)
Традиционно в вагранте пользователь по-умолчанию - vagrant (пароль такой же как имя)
Директория из которой запускалась виртуалка (в которой лежит Vagrantfile) прокидывается в виртуалку по пути /vagrant (доступ и на чтение и на запись, поэтому нужно быть аккуратным)
[vandud@desktop vagrant]$ touch testfile
[vandud@desktop vagrant]$ vagrant ssh
vagrant@ubuntu-xenial:~$ cd /vagrant/
vagrant@ubuntu-xenial:/vagrant$ ll
total 60
drwxr-xr-x 1 vagrant vagrant 4096 Jun 23 15:01 ./
drwxr-xr-x 24 root root 4096 Jun 23 14:53 ../
-rw-r--r-- 1 vagrant vagrant 0 Jun 23 15:01 testfile
-rw------- 1 vagrant vagrant 42191 Jun 23 14:53 ubuntu-xenial-16.04-cloudimg-console.log
drwxr-xr-x 1 vagrant vagrant 4096 Jun 23 14:32 .vagrant/
-rw-r--r-- 1 vagrant vagrant 3010 Jun 23 15:01 Vagrantfile
Команды управления
- Перезагрузка (выключение и включение, а не просто обновление конфига) -
vagrant reload
- Выключение/приостановка -
vagrant halt/suspend
- Пробуждение приостановленной ВМ -
vagrant resume
- Удаление виртуалки (конф. файлы останутся нетронутыми) -
vagrant destroy
- Чтобы удалить и файлы ВМ нужно добавить ключи -f -
vagrant destroy -f
- Состояние окружения (а также проверка сиснтаксиса Vagrantfile) -
vagrant status
- Подключение -
vagrant ssh
- Конфиг ssh -
vagrant ssh-config
- Управление боксами -
vagrant box
:
$ vagrant box list
ubuntu/xenial64 (virtualbox, 20200617.0.0)
Приватный ключ для подклюлчения по ssh находится примерно по такому пути: /home/vandud/Documents/vagrant/.vagrant/machines/default/virtualbox/private_key
Плагины
vagrant scp
Плагины устанавливаются так (устанавливаю vagrant-scp):
$ vagrant plugin install vagrant-scp
Installing the 'vagrant-scp' plugin. This can take a few minutes...
Fetching vagrant-scp-0.5.7.gem
Installed the plugin 'vagrant-scp (0.5.7)'!
Работа vagrant scp:
$ vagrant scp testfile default:/tmp/testfile
load pubkey "/home/vandud/Documents/vagrant/.vagrant/machines/default/virtualbox/private_key": invalid format
Warning: Permanently added '[127.0.0.1]:2222' (ECDSA) to the list of known hosts.
testfile 100% 0 0.0KB/s 00:00
Информацию о боксе (имя или id) можно получить из $ vagrant global-status
vagrant sahara
vagrant sandbox (sahara-plugin):
Этот плагин позволяет делать снапшоты. Пример использования:
- Включаем режим песочницы -
vagrant sandbox on
- Что-то делаем -
vagrant ssh
- Коммитим изменения или откатываемся -
vagrant sandbox commit/rollback
- Выключаем песочницу -
vagrant sandbox off
(если выйти из песочницы с незакоммиченными изменениями, то они закоммитятся)
Provisioning (подготовка)
Для провижининга (подготовки) можно использовать встроенные средства, или такие системы как ansible/puppet
На примере ansible:
- Редактируем Vagrantfile. Нужно дописать в конец следующее:
config.vm.provision "ansible" do |ansible| ansible.playbook = "playbook.yaml" end
- Далее создаем playbook.yaml, например такой:
$ cat playbook.yaml --- - hosts: all become: yes tasks: - name: test task apt: name: hollywood state: present update_cache: yes
- И запускаем провижининг с помощью команды
vagrant provision
:$ vagrant provision ==> default: Running provisioner: ansible... default: Running ansible-playbook... PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [default] TASK [test task] *************************************************************** changed: [default] PLAY RECAP ********************************************************************* default : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Прокидывание директорий
В Vagrantfile нужно дописать следующее:
config.vm.synced_folder "src/", "/tmp/src/"
Эта настройка указывает откуда и куда примонтировать директорию
Далее нужно сделать reload и настройка применится
Результат (сверху команда watch tree
на виртуалке):
Прокидывание портов
config.vm.network "forwarded_port", guest: 80, host: 8080
Vagrant
CLI
-
vagrant box
-
box add ADDRESS - добавить бокс (образ) на компьютер. Может принимать в качестве адреса:
- Короткое имя бокса из публичного каталога Vagrant или http url до него
- Url до бокса (видимо если он хостится где-то кроме публичного каталога)
- box list - список установленных боксов
-
box outdated - есть ли обновления для используемых боксов. С ключом
--global
проверит наличие обновлений для всех боксов, а не только для используемых - box prune - удаляет устаревшие боксы. Есть параметры для указания провайдера, имени или принудительного удаления даже если бокс запущен и тд.
- box remove NAME - удалить бокс. Можно указать версию или провайдера
-
box repackage NAME PROVIDER VERSION - переупаковка бокса. Версию, имя и провайдера нужно указывать как в выводе
vagrant box list
-
box update - обновить бокс. Обновляет то, что покаывает
vagrant box outdated
-
box add ADDRESS - добавить бокс (образ) на компьютер. Может принимать в качестве адреса:
-
vagrant cloud
-
cloud auth
- auth login - вход в Vagrant cloud
- auth logout - выход
- auth whoami [TOKEN] - проверить под кем залогинен или проверка токена
-
cloud box
- box create NAME - создать бокс в Vagrant cloud
- box delete NAME - удалить бокс в Vagrant cloud (безвозвратно)
- box show NAME - показать информацию о боксе
- box update NAME OPTION - обновить бокс
-
cloud provider
- provider create NAME PROVIDER VERSION [URL] - создать сущность в Vagrant cloud
- provider delete NAME PROVIDER VERSION - удалить провайдер
- provider update NAME PROVIDER VERSION [URL] - обновить уже созданный провайдер для бокса в Vagrant cloud
-
cloud auth
Packer
https://www.packer.io/docs
https://rtfm.co.ua/packer-vvedenie-primery/
Терминология
- Артефакт - результат одиночной сборки. Обычно это id'шники или файлы для воссоздания ВМ
- Сборка - одиночная задача, которая произведет образ для одной из платформ
- Сборщик - компонент packer'а, который позволяет создать образ
- Post-processor - компонент packer'а, который берет результат работы сборщика или другого пост-обработчика и обрабатывает его для получения новых артефактов
- Provisioner - устанавливает и конфигурирует ПО на запущенной машине
- Шаблоны - json-файлы в которых определяется сборка образа и конфигурирование компонентов packer'а. Packer позволяет читать шаблон и создавать множество образов машин параллельно
CLI
Packer имеет очень человеко-читаемый вывод. Но он также имеет и машино-читаемый режим.
Его можно включить флагом -machine-readable
для любой команды и не важно в каком порядке, команда флаг
или флаг команда
, главное чтобы он присутствовал.
-
packer build - на основе шаблона генерирует набор артефактов. Разные сборки, опреленные в шаблоне, запускаются параллельно
-
packer console - позволяет проверить как накладываются передаваемые переменные на шаблон
Переменные (уже определенные или пустые) можно вызывать так:{{user `aws_access_key`}} # Этот шаблон заменится на значение переменной определенное пользователем в секции __variables__ в темплейте
Также в console можно загонять разный текст через пайплайн и получать на выходе то как он выглядел бы при обработке
-
packer fix - позволяет исправить шаблон в соответствии с новой версией packer'а (если после обновления packer'а шаблон перестал работать)
-
packer inspect - позволяет получить описание содержимого темплейта без погружения в json. Пример:
$ packer inspect main.json Optional variables and their defaults: aws_access_key = aws_secret_key = Builders: amazon-ebs Provisioners: <No provisioners>
-
packer validate - валидирует шаблон и выводит допущенные в шаблоне ошибки
Шаблоны
Шаблоны это json-файлы которые конфигурируют разные компоненты packer'а и описывают создание одного или более образов ВМ
Компоненты шаблона:
- builders - единственный обязательный элемент шаблона. Список из одного или более объектов, которые описывают сборщиков
- description - строка с описанием того что делает шаблон
- min_packer_version - минимальная версия packer'а для этого шаблона
- post-processors - список объектов, которые описывают разные шаги постобработки при сборке образа
- provisioners - описывает какие средства провижининга будут задействованы для установки и конфигурации ПО при сборке образа
- variables - набор key:value строк, которые описывают переменные
-
sensitive-variables - то же что и
variables
, но эти переменные не пишутся в лог и stdout
Так как JSON не предоставляет комментарии, то чтобы оставить комментарий в шаблоне packer нужно добавить корневой элемент, имя которого начинается с подчеркивания. Пример:
{ "_super-comment": "My cool comment", "variables": { "aws_access_key": "", "aws_secret_key": "" ...
Только такие элементы могут быть комментариями. Другие будут вызывать ошибки при валидации
builders
Билдер (сборщик) - это объект, который определяет параметры сборки
Выглядит так:
{
"builders": [
{
"type": "amazon-ebs",
"access_key": "...",
"secret_key": "...",
// еще куча разных аттрибутов
}
]
}
Поле type является обязательным и по умолчанию является именем по которому можно обратиться к билдеру. Имя используется в выводе при сборке, чтобы было видно что сейчас происходит. Если просто типа билдера не достаточно, то можно и явно указать имя билдера через аттрибут name
communicators
Коммуникаторы это механизм используемый packer'ом для загрузки файлов, запуска скриптов и прочего провижининга запущенной машины. Каждый билд ассоциируется с каким-то коммуникатором для связи, обычно это SSH. Коммуникатор конфигурируется в секции builders и может быть трех видов (это значения ключа communicator):
- none - коммуникатор отключен. В таком случае провижининг не возможен
- ssh - будет установлено ssh соединение с машиной (по умолчанию)
- winrm - WinRM
Аттрибут pause_before_connecting позволяет указать паузу перед подключением к собранной машине. На самом деле это время ожидания перед повторным подключением после первого (тестового) успешного подключения.
template engine
В шаблонах используются следующие постановления:
- Все связанное с шаблонизацией происходит в двойных фигурных скобках
{{ }}
(без пробелов между скобкой и словом как в jinja) - Функции вызываются в двойных фигурных скобках
- Переменные префиксируются точкой и начинаются с большой буквы
Функции
Имеется множество разных функций, которые могут быть использованы в шаблоне
post-processors
Секция пост-процессинга в шаблоне определяет какие дополнительные действия должны сделаны билдерами при сборке образа. Например сжатие образа или загрузка его куда-либо
Каждый описанный пост-процессор будет выполнен для каждого описанного билдера. То есть при двух билдерах и одном пост-процессоре, пост-процессор будет выполнен дважды (по одному разу для каждого билдера)
Есть три варианта описания пост-процессора: простой, детализированный и последовательный. Можно представлять, что простой и детализированный варианты это ссылки на последовательный вариант
- Просто это просто строка с именем пост-процессора
{ "post-processors": ["compress"] }
- Детализированный похож на определение билдера или провижинера. Это объект с разными аттрибутами
{ "post-processors": [ { "type": "compress", "format": "tar.gz" } ] }
- Последовательный еще более подробный
Чтобы сохранять промежуточные артефакты во время пост-процессинга нужно указать true
в аттрибуте keep_input_artifact
для нужного пост-проссинга
Провижининг
{
"provisioners": [
// ... one or more provisioner definitions here
]
}
Провизоры будут запускаться для каждой сборки в том порядке в котором они определены в шаблоне
В определение провизора должен содержаться аттрибут type
, оно определяет имя используемого провизора. У разных провизоров разные обязательные поля, например провизор shell
требует аттрибута shell
Можно использовать аттрибуты only
или except
в объекте провизора, чтобы избрать нужные билды. Они принимают в себя список имен билдов (не типов билдеров, нужно указать билдам имена и использовать их тут)
Наравне с обычными провизорами, можно указать провижининг для обработки ошибок обычного провизора. Он сработает при возникновении ошибки в работе провизора
Можно делать переопределения в провизорах. Это может быть нужно когда мы хотим чтобы создаваемые машины отличались
{
"type": "shell",
"script": "script.sh",
"override": {
"vmware-iso": {
"execute_command": "echo 'password' | sudo -S bash {{.Path}}"
}
}
}
Иногда нужно делать паузу при сборке. Например когда ваш скрипт в провизоре делает ребут, тогда нужно подождать некоторое время перед запуском следующего провизора
Это можно сделать с помощью аттрибута pause_before
, он указывается в провизоре который идет после перезагрузки и принимает время в секундах
max_retries
- определяет количество повторных попыток после первой неудачной
timeout
- это таймаут на выполнение провизора прежде чем он будет считаться зафейленым
Пользовательские переменные
Переменные позволяют шаблонам быть параметризированными и не хранить в шаблонах секретные данные (например токены)
Переменные объявляются в секции variables, а также могут быть переданны через файл или флаг -var
Если переменная будет передваться как аргумент, то лучше ее объявить пустой в шаблоне. Тогда будет понятно, что эта переменная будет заменена
Например тут мы сразу видим какие переменные нам нужно передать аргументами
{
"variables": {
"aws_access_key": "",
"aws_secret_key": ""
},
"builders": [
{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}"
// ...
}
]
}
Устанавливать переменные можно из файла или через командную строку
Через командную строку это делается через ключ -var
которому передается строка в формате "var_name=var_value". Ключи -var
может быть передан сколько угодна раз (в зависимости от того как много у вас переменных). Переменные из командной строки переопределяют любые ранее заданные переменные
Чтобы определить переменные в отдельном файле, нужно в нем описать объект variables из шаблона:
{
"aws_access_key": "foo",
"aws_secret_key": "bar"
}
Переменные из файла с переменными указанного в конце переопределят предыдущие
То же и с комбинированием-var-file
и-var
, то что указано позже - важнее. Не важно файл это или параметр команды
Существует секция sensitive-variables
, в ней можно указывать чувствительные переменные, которые не должны быть видно в журналах и прочих местах (например это токены)
{
"variables": {
"my_secret": "{{env `MY_SECRET`}}",
"not_a_secret": "plaintext",
"foo": "bar"
},
"sensitive-variables": ["my_secret", "foo"],
}
На работу приложения это никак не влияет, влияет только на вывод и журналы
Коммуникаторы
Коммуникаторы это механизм для загрузки файлов, выполнения скриптов и прочих действий в созданной машине. Коммуникаторы конфигурируются в секции builders
Поддерживаются три вида коммуникаторов:
- none - никакой
- ssh - ssh (по умолчанию)
- winrm - winrm
Иногда ssh может быть не сконфигурирован в дефолтном образе, тогда нужно использовать файл preseed или kickstart для предконфигурирования
SSH коммуникотор имеет огромное количество опций, которые можно посмотреть здесь https://www.packer.io/docs/communicators/ssh
Builders
Билдеры отвечают за создание машины и генерацию образа из нее для различных платформ. Packer может работать с различными билдерами по умолчанию и может быть расширен для добавления новых билдеров
По умолчанию в packer доступно огромное количество билдеров для огромного количества платформ. Опишу здесь лишь то что интересно мне:
docker
Docker билдер собирает образы для докера. Он стартует докер контейнер, запускает провижининг внутри этого контейнера и экспортирует контейнер в образ
Провижининг в этом случае происходит без использования Dockerfile, это происходит так же как если бы вы настраивали железный или виртуальный сервер
Для работы docker-builder'а требуется docker engine
Обязательные опции:
- commit/discard/export_path - закоммитить контейнер/отменить/экспортировать в указанный tar файл (одновременно может быть указано только одно из трех)
- image - базовый образ для контенера (из которого он будет запущен)
Также есть еще миллион опциональных параметров
https://www.packer.io/docs/builders/docker
Packer умеет добавлять к образу различную информацию (тэги, и прочее) и импортировать его сразу в репозиторий образов
file
file-builder - то не настоящий билдер, он просто создает артефакты из файла и может быть использован для отладки пост-процессоров без длительного ожидания
null
Это тоже не настоящий билдер. Он просто настраивает ssh-подключение и запускает провижининг. Полезно для дебагинга провизоров так как занимает мало времени
Vagrant
Обязательные:
- source_path - URL или имя используемого vagrant-бокса (имя на vagrant-cloud, имя на другом хранилище, имя локального файла). Если используется .box имя (url или локальный файл), то нужно также указать box_name опцию
-
global_id - айдишник уже существующего в системе бокса (посмотреть айдишники можно командой
vagrant global-status
)
Две эти ^ опции - взаимоисключающие, возможна только одна из них
Остальные опции:
-
output_dir - папка в которую будет помещен бокс и прочее. Это нужно для избежания коллизий (чтобы файлы не смешивались). Если не указывать, то папка будет создана все-равно
output-BUILDERNAME
- box_name - нужно при использовании source_path
- provider - нужно при использовании source_path, указывает на используемый провайдер (virtualbox, docker, etc)
- checksum - чексумма .box файла
-
checksum_type - тип указываемой выше чексуммы. Без этого поля чексумма не может быть проверена. Поддерживаемые значения:
- none
- md5
- sha1
- sha256
- sha512
Рекомендуется проверять чексумму, потому что большие файлы могут быть легко повреждены при загрузке
- template - путь до темплейта с vagrantfile'ом. Используется шаблонизация на языке Go
-
skip_add - не вызывать
vagrant add
для добавления бокса в локальное окружение -
teardown_method - что сделать с боксом после сборки, возможные значения:
- halt <- default
- suspend
- destroy
- box_version - версия
-
add_cacert - эквивалент
vagrant box add --cacert
-
add_capath - эквивалент
vagrant box add --capath
-
add_cert - эквивалент
vagrant box add --cert
-
add_clean - эквивалент
vagrant box add --clean
-
add_force - эквивалент
vagrant box add --force
-
add_insecure - эквивалент
vagrant box add --insecure
-
output_vagrantfile - эквивалент
vagrant package --vagrantfile
-
package_include - эквивалент
vagrant package --include
Эквиваленты можно посмотреть здесь https://www.vagrantup.com/docs/cli/box.html#box-add
- skip_package - пакер не будет упаковывать бокс в .box-файл
virtualbox
VirtualBox builder может создавать ВМ и экспортировать их в OVA/OVF формат
- virtualbox-iso - начинает с iso, создает новую ВМ, устанавливает и провижинит ПО и экспортирует машину в образ
- virtualbox-ovf - импортирует существующий OVF/OVA файл, запускает провизоры поверх этой ВМ и экспортирует машину для создания образа
- virtualbox-vm - поверх существующей ВМ запускает провижининг и может сделать снапшот или экспортировать машину
provisioners
Провизоры это встроенное и стороннее ПО для конфигурирования и установки машины после загрузки
Обычно они устанавливают пакеты, патчат ядро, создают юзеров, загружают код приложений
ansible-local
В машину будет закинут плейбук и запущен ансибл в локальном режиме (то есть виртуалка сама себя сконфигурирует [без ssh])
{
"type": "ansible-local",
"playbook_file": "local.yml"
}
ansible-remote
{
"type": "ansible",
"playbook_file": "./playbook.yml"
}
file
В машину будет загружен файл
Для загрузки файла будет использовать пользователь для провижининга (обычно это не рут), поэтому рекомендуется загрузить таким образом файл куда-нибудь, а потом уже с помощью модуля shell делать с ним что надо (установить права, положить в нужно место и тд)
{
"type": "file",
"source": "app.tar.gz",
"destination": "/tmp/app.tar.gz"
}
shell
{
"type": "shell",
"inline": ["echo foo"]
}
Вместо инлайн можно указывать скрипты (которые там уже лежат)
post-proccessors
Пост-процессоры запускаются после сборки и провижининга
Могут загружать собранный образ куда-то (в облако), сжимать, или что угодно еще
BIND9
BIND - Berkeley Internet Name Daemon
bind имеет утилиты для проверки конфига и зоны:
named-checkconf
named-checkzone
rndc - утилита для управления биндом (remote name daemon control)
Зонный трансфер - один из механизмов репликации баз DNS между серверами. Бывает полным (AXFR) и инкрементальным (IXFR)
Трансфер происходит по TCP в отличие от обычных DNS-запросов
Результат работы команды
dig
выводится в формате зонного файла
Настройки корневой зоны всегда доступны по адресу ftp://ftp.internic.net/domain/named.root
Комментарии в зонном файле вводятся с помощью ;
В зонном файле можно указать переменные ORIGIN и TTL и не указывать для каждой записи TTL и ORIGIN (ориджин можно итак не указывать, но имея переменную это выглядит более очевидно)
$ORIGIN testzone.vandud.ru.
$TTL 3600
@ IN SOA (
phobos.vandud.ru.
dns-admin.dns
2020082011
7200
1200
64800
3600
)
@ IN NS phobos.vandud.ru.
web IN TXT "sosamba; nstshsnthst pidor"
test1 IN CNAME test2
test2 IN CNAME test1
Glue records
- Glue records или добавочная запись - это А-запись, в которой хранится IP-адрес, присвоенный домену или поддомену
Итак, есть существующая зона minsk.by. Мы подаем заявку на делегирование домена 3-го уровня nestor.minsk.by. В качестве неймсерверов будут выступать хосты с именами ns1.nestor.minsk.by и ns2.nestor.minsk.by. Чтобы все заработало, администратор зоны minsk.by должен прописать у себя примерно следующее:
$ORIGIN = minsk.by
nestor IN NS ns1.nestor
nestor IN NS ns2.nestor
ns1.nestor IN A 194.226.121.90
ns2.nestor IN A 194.158.200.188
Последние две записи и есть glue records, без которых запросы будут зацикливаться
Личный пример
root@phobos:/var/named/zones# cat testzone.vandud.ru
...
testns 3600 IN NS testns.testzone.vandud.ru.
testns 3600 IN A 185.176.25.117 <- без этой записи BIND не заведется
И на вот такой запрос получаем ответ:
$ dig ns testns.testzone.vandud.ru @phobos.vandud.ru.
...
;; QUESTION SECTION:
;testns.testzone.vandud.ru. IN NS
;; AUTHORITY SECTION:
testns.testzone.vandud.ru. 3600 IN NS testns.testzone.vandud.ru.
;; ADDITIONAL SECTION:
testns.testzone.vandud.ru. 3600 IN A 185.176.25.117
Как видно, на запрос в котором запрашивается только NS, сервер также подсовывает нам и additional records, в которых указан адрес сервера из NS записи, потому что иначе его получить нельзя
Простой конфиг
# cat /etc/bind/named.conf <- положение этого файла зависит от того как собран bind
# (может быть /etc/named.conf, а может быть /etc/bind/named.conf;
# посмотреть как он собран можно через named -V
options {
directory "/var/named";
};
zone testzone.vandud.ru. { <- имя зоны за которую отвечает файл из директивы file
type master;
file "zones/testzone.vandud.ru";
};
В /var/named/zones/testzone.vandud.ru имена могут быть абсолютными (с точкой на конце) или относительными, тогда к ним будет добавляться зона
Примеры:
-
web.testzone.vandud.ru.
- абсолютный -
web
- относительный -
@
- пустое относительное имя (то есть сама зона)
Чтобы запись SOA была более читаемой (ведь она очень длинная) можно разбить ее на несколько строк
Для этого нужно использовать круглые скобки@ 3600 IN SOA ( phobos.vandud.ru. dns-admin.dns 2020082002 7200 1200 64800 3600 ) @ 3600 IN NS phobos.vandud.ru. web 3600 IN A 8.8.8.8
Вторичный DNS-сервер
# cat /etc/bind/named.conf
options {directory "/var/named";};
zone testzone.vandud.ru. {
type slave;
file "zones/testzone.vandud.ru";
masters { 185.176.25.117; }; <- хз почему, но домен указать нельзя
};
Далее запускаем сервер убедившись что все окей с правами на директории и видим что файл зоны подгрузился в /var/named/zones/testzone.vandud.ru
При настройке вторичного сервера нужно учитывать права на файлы и директории в системе. Нужно чтобы процессу named была доступна запись в указанные в конфигах директории, чтобы он мог записывать туда скачанные с первичного сервера зоны
Также можно использовать setuid/setgid для дополнительной безопасности
Кэширующий DNS-сервер
Базовый конфиг кэширующего сервера
options {
directory "/var/named/zones";
forwarders { 1.1.1.1; };
allow-query { any; };
allow-query-cache { any; };
};
Или
zone "." {
type hint;
file "/etc/bind/db.root"; # <- путь к файлу с рут-зоной (с адресами корневых)
# а так же в этом варианте требуются некоторые настройки в options (мне лень искать и писать)
};
Работает)
$ dig a mail.ru @deimos.vandud.ru +short
217.69.139.202
94.100.180.201
94.100.180.200
217.69.139.200
rndc
Управление сервером BIND 9 производится с помощью специальной утилиты rndc
, которая соединяется с сервером (по умолчанию - TCP порт 953) и использует специальный протокол для передачи ему команд
Файл /etc/rndc.conf имеет тот же синтаксис что и /etc/named.conf и содержит в себе настройки подключения к BIND (адрес, порт, пароль, алгоритм, etc)
Имеет следующие команды:
- reload - перезагрузить файл настройки и зоны
- reload зона [класс [вид]] - перезагрузить зону
- refresh зона [класс [вид]] - запланировать немедленное обновление зоны
- reconfig - перезагрузить файл настройки и новые зоны
- stats - записать статистику в конец файла named.stats
- querylog - включить/выключить журнализацию запросов
- dumpdb - сбросить базу данных в файл named_dump.db
- stop - сохранить изменения в файлы зон и остановить сервер
- halt - остановить сервер без сохранения изменений
- trace - увеличить уровень отладки на 1
- trace уровень - установить уровень отладки
- notrace - отключить отладку
- flush - сбросить весь кеш
- flush вид - сбросить кеш для указанного вида
- status - показать состояние сервера
- restart - перезапустить сервер; не реализовано (?)
ssh tricks
Когда виснет ssh после потери коннекта
Когда при потере соединения ssh-клиент зависает (и замораживает терминал) нужно ввести в замороженном терминале ~.
то есть нажать shift+` . после этих символов ssh-клиент завершится несмотря на свои внутренние таймауты
Как узнать кто из админов сейчас на сервере
Админы заходят на сервера сразу как root, поэтому не очень легко понять кто конкретно сейчас работает на сервере
Можно сделать следующим образом:
Смотрим на вывод команды w
:
i.dudin_pro@db13y:~$ w
22:43:12 up 5:12, 2 users, load average: 0.38, 0.71, 1.25
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 172.27.249.190 21:44 59.00s 0.31s 0.31s -bash
i.dudin_ pts/1 172.27.0.22 22:27 0.00s 0.43s 0.01s sshd: i.dudin_pro [priv]
Видим там ip-адрес
Ищем этот ip в auth.log:
i.dudin_pro@db13y:~$ sudo grep '172.27.249.190' /var/log/auth.log
Mar 16 21:44:18 db13y sshd[24290]: Accepted publickey for root from 172.27.249.190 port 59107 ssh2: RSA 5c:88:17:2b:e8:62:ad:c5:cc:32:c4:f2:e0:0e:bb:db
Mar 16 22:47:46 db13y sudo: i.dudin_pro : TTY=pts/1 ; PWD=/home/i.dudin_pro ; USER=root ; COMMAND=/bin/grep 172.27.249.190 /var/log/auth.log
Видим там отпечаток ключа с которым подключался админ
Дальше можно выполнить вот такую штуку. Она выдаст отпечатки на основе ключей (отпечатки будут в том порядке, в котором они указаны в authorized_keys):
i.dudin_pro@db13y:~$ sudo cat /root/.ssh/authorized_keys | xargs -I% bash -c 'ssh-keygen -l -f /dev/stdin <<<"%"'
4096 26:c0:4f:97:c9:15:7a:38:9c:52:2c:97:b2:18:5d:24 /dev/stdin (RSA)
4096 89:87:b1:92:ca:d3:f3:4c:c1:ec:f3:f0:43:6f:ad:e6 /dev/stdin (RSA)
4096 d3:96:ca:42:95:1d:ab:4c:c4:c9:6b:01:09:96:79:5e /dev/stdin (RSA)
4096 82:2b:49:a7:c1:72:06:4e:1f:21:c2:f6:3c:ae:f0:f6 /dev/stdin (RSA)
4096 c4:11:53:10:2e:e0:d3:6a:b7:5e:0f:48:10:6b:fc:28 /dev/stdin (RSA)
4096 8e:df:71:3a:39:cd:ca:41:23:5c:96:87:aa:66:f7:a8 /dev/stdin (RSA)
4096 38:05:c0:7d:ea:78:d1:79:1c:71:f8:51:bb:6b:57:a6 /dev/stdin (RSA)
2048 5c:88:17:2b:e8:62:ad:c5:cc:32:c4:f2:e0:0e:bb:db /dev/stdin (RSA)
В полученном списке находим подходящий отпечаток (в нашем случае это самый последний ключ):
i.dudin_pro@db13y:~$ sudo cat /root/.ssh/authorized_keys | tail -n1
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJ************************************************************************ZV4hkYxqdXrjzwB8IMLegLc/CQjSbGAzcafbHE9iOs1 root_a.seliverstov
Теперь нам известно кто именно сейчас ломает сервер
Bacula/Bareos
https://workaround.org/bacula-cheatsheet/
Общее
Бэкапы бывают:
- Полные - содержат самодостаточный набор данных для восстановления на определенный момент времени
- Дифференциальные - содержат в себе изменения с момента последнего полного бэкапа. Восстановление осуществляется из полного и дифференциального
- Инкрементальные - содержат изменения с последнего полного или инкрементального бэкапа. Восстанавление осуществляется из полного и всех инкрементальных
Компоненты
Bacula состоит из трех основных компонентов и базы данных (для хранения метаданных бэкапов)
-
file daemon - ставится на хостах подлежащих бэкапированию. По команде от директора шлет данные storage daemon'у, или восстанавливает из бэкапа
-
storage daemon - управляет хранилищем бэкапов. По команде может дать инфу о имеющихся бэкапах или аллоцировать место для новых данных. Принимает данные от файл демона и сохраняет ее на диски
-
director - управляющий демон. Хранит инфу о том когда и что бэкапить, отдает нужных хостам нужные команды для бэкапирования
-
catalog - директор хранит в базе данных инфу об имеющихся бэкапах, задания, клиентах, статусах и пр.
-
console - интерфейс для работы с директором (можно подключаться к удаленным директорам)
-
у bareos есть и web ui, через него можно смотреть текущее положение дел
Сокращенно называются fd, sd - file daemon, storage daemon
Различия BareOS/Bacula
Изначально была бакула, но со временем она перестала быть крутой и появился bareos
The situation between Bareos and Bacula is very similar to the situation of Nextcloud and OwnCloud. Bacula have open source free Community version and Enterprise paid version. In 2012 then Bacula Enterprise version was still open source but since 2012 its not. Some features from free Community version has been CUT/MOVED into Bacula Enterprise version only. People sent patches for Bacula Community edition but they were not merged for YEARS, so some developers got sick a tired of that situation and they created a fork named Bareos
Job
Job levels
Level | Description |
---|---|
Backup | Levels |
F | Full backup: Every files |
I | Incremental: Files modified since last backup |
D | Differential: Files modified since last full backup |
S | Since: Not used |
f | Virtual full backup |
Verification levels | |
C | Verify from Catalog |
V | Verify: Init database |
O | Verify volume to Catalog entries |
d | Verify disk attributes to Catalog |
A | Verify data on volume |
Others | |
B | Base level job |
-- | None: for Restore and Admin |
Job types
Type | Description |
---|---|
B | Backup Job |
V | Verify Job |
R | Restore Job |
D | Admin job |
C | Copy of a Job |
c | Copy Job |
M | A previous backup job that was migrated |
g | Migration Job |
A | Archive Job |
S | Scan Job |
U | Console program |
I | Internal system “job” |
Job status
Status | Description |
---|---|
A | Job canceled by user |
B | Job blocked |
C | Job created but not yet running |
D | Verify differences |
E | Job terminated in error |
F | Job waiting on File daemon |
I | Incomplete Job |
L | Committing data (last despool) |
M | Job waiting for Mount |
R | Job running |
S | Job waiting on the Storage daemon |
T | Job terminated normally |
W | Job terminated normally with warnings |
a | SD despooling attributes |
c | Waiting for Client resource |
d | Waiting for maximum jobs |
e | Non-fatal error |
f | Fatal error |
i | Doing batch insert file records |
j | Waiting for job resource |
l | Doing data despooling |
m | Waiting for new media |
p | Waiting for higher priority jobs to finish |
q | Queued waiting for device |
s | Waiting for storage resource |
t | Waiting for start time |
Установка
По официальной документации bareos'a он ставится не сложно (есть затыки, но они преодолимы)
bconsole
Для управления директором используется bconsole
$ bconsole
*status
Status available for:
1: Director
2: Storage
3: Client
4: Scheduler
5: All
Select daemon type for status (1-5): 1
bareos-dir Version: 19.2.7 (16 April 2020) Linux-3.10.0-1062.18.1.el7.x86_64 debian Debian GNU/Linux 10 (buster)
Daemon started 01-Sep-20 01:35. Jobs: run=4, running=0 db:postgresql, bareos.org build binary
Scheduled Jobs:
Level Type Pri Scheduled Name Volume
===================================================================================
Incremental Backup 10 03-Sep-20 21:00 backup-bareos-fd Incremental-0002
Full Backup 11 03-Sep-20 21:10 BackupCatalog Incremental-0002
====
Running Jobs:
Console connected at 03-Sep-20 01:33
No Jobs running.
====
Terminated Jobs:
JobId Level Files Bytes Status Finished Name
====================================================================
1 Full 319 124.0 M OK 01-Sep-20 21:00 backup-bareos-fd
2 Full 59 11.87 K OK -- with warnings 01-Sep-20 21:10 BackupCatalog
3 Incr 0 0 OK 02-Sep-20 21:00 backup-bareos-fd
4 Full 59 11.87 K OK -- with warnings 02-Sep-20 21:10 BackupCatalog
Client Initiated Connections (waiting for jobs):
Connect time Protocol Authenticated Name
====================================================================================================
====
*
Команда help
в bconsole покажет доступные команды
Восстановление
Для восстановления вводим команду restore
в bconsole
Это интерактивная команда (как и почти все остальные), она будет предлагать пункты на выбор
Восстановленные из бэкапа данные по умолчанию будут расположены в /tmp/bareos-restores
linux tricks
Восстановление дефолтного файла из пакета
(рассматривается debian)
В случае когда удалил или изменил что-то и хочешь вернуть к дефолтному виду, можно сделать так:
- Смотрим/ищем что за файл и из какого именно пакета
root@mars:~# dpkg -S RestoreFiles.conf
bareos-director: /usr/lib/bareos/defaultconfigs/bareos-dir.d/job/RestoreFiles.conf
- Видим точное имя пакета
bareos-director
- Скачиваем этот пакет
root@mars:~# apt download bareos-director
- Превращаем deb в tar
root@mars:~# dpkg --fsys-tarfile bareos-director_19.2.7-2_amd64.deb > bareos.tar
- Все) Теперь у нас есть tar со всеми файлами
Docker and iptables
При использовании докера нужно быть внимательным с правилами
Докер создает правила и цепочки в таблице nat, поэтому какие-либо запрещающие правила в цепочке INPUT таблицы filter не сработают
Кейс:
Поднят контейнер с nginx и проброшен порт 80
- Пакет приходит в nat PREROUTING где указано
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Это правило отправляет в цепочку DOCKER любой пакет который назначен машине, адрес которой назначен нашей машине. Т.е. все что назначено нам - В цепочке DOCKER есть следующее правило
DNAT tcp -- anywhere anywhere tcp dpt:http to:172.17.0.3:80
То есть все что приходит на наш 80 порт нужно отправлять на 80 порт контейнера - Далее, т.к. это транзитный пакет, он уходит в filter FORWARD и спустя некоторый путь попадает в следующее правило
ACCEPT tcp -- anywhere 172.17.0.3 tcp dpt:http
- Ну и по всей видимости попадает в контейнер (я не разобрался на 100% как именно он туда попадает)
В общем filter INPUT не сработает
Ferm
Название
ferm - парсер файерволл-правил для линукс
Синтаксис
ferm options inputfile
Описание
ferm это фронтенд для iptables. Он читает правила из структурированного конфигурационного файла и вызывает iptables(8) для вставки их в запущенное ядро.
Задача ferm'а сделать файерволл-правила более простыми для написания и чтения. Он пытается сократить утомительную задачу записи правил, так что это позволяет файерволл-администратору тратить больше времени на разработку хороших правил чем на надлежащую имплементацию обычных правил.
Для достижения этого, ferm использует простой, но мощный язык конфигурирования, в котором доступны переменные, функции, массивы и блоки. Он также позволяет тебе инклудить другие файлы, разрешая этим создавать библиотеки часто используемых структур и функций.
ferm произносится как "firm", и означает "For Easy Rule Making".
Предупреждение
Этот мануал не стремится научить тебя тому как работает файерволл и как писать хорошие правила. На эту тему уже есть достаточно документации.
Вступление
Начнем с простого примера:
chain INPUT {
proto tcp ACCEPT;
}
Здесь добавляется правило во встроенную цепочку INPUT, которое сопоставляет и принимает все TCP пакеты. Хорошо, давайте усложним его:
chain (INPUT OUTPUT) {
proto (udp tcp) ACCEPT;
}
Здесь будет вставлено 4 правила, а именно 2 правила в цепочку INPUT и 2 в OUTPUT. Правила будут принимать UDP и TCP пакеты.
Обычно ты бы напечатал так:
iptables -A INPUT -p tcp -j ACCEPT
iptables -A OUTPUT -p tcp -j ACCEPT
iptables -A INPUT -p udp -j ACCEPT
iptables -A OUTPUT -p udp -j ACCEPT
Заметил насколько меньше нам нужно печатать чтобы сделать это? :-)
В основном это все что нужно делать, однако, ты можешь сделать его более сложным. Что-то похожее на:
chain INPUT {
policy ACCEPT;
daddr 10.0.0.0/8 proto tcp dport ! ftp jump mychain sport :1023 TOS 4 settos 8 mark 2;
daddr 10.0.0.0/8 proto tcp dport ftp REJECT;
}
Моя мысль здесь в том, что тебе нужно писать хорошие правила, оставлять их читаемыми для тебя и других и не превращать их в бардак.
Наличие результирующих правил здесь для справки, помогло бы читателю. Также ты можешь заинклудить вложенную версию для большей читабельности.
Попробуй использовать комментарии, чтобы показать что ты делаешь:
# this line enables transparent http-proxying for the internal network:
proto tcp if eth0 daddr ! 192.168.0.0/255.255.255.0
dport http REDIRECT to-ports 3128;
Потом сам скажешь спасибо!
chain INPUT {
policy ACCEPT;
interface (eth0 ppp0) {
# deny access to notorious hackers, return here if no match
# was found to resume normal firewalling
jump badguys;
protocol tcp jump fw_tcp;
protocol udp jump fw_udp;
}
}
Чем больше вложенность, тем лучше это выглядит. Убедись что твоя последовательность верна, ведь ты бы не хотел сделать такое:
chain FORWARD {
proto ! udp DROP;
proto tcp dport ftp ACCEPT;
}
потому что второе правило никогда не сработает. Лучший путь это сперва определить все что разрешено, а затем запретить все остальное. Смотри на примеры, чтобы было больше "хороших снимков". Многие люди делают что-то похожее на это:
proto tcp {
dport (
ssh http ftp
) ACCEPT;
dport 1024:65535 ! syn ACCEPT;
DROP;
}
Структура конфигурационного файла
Структура корректного файерволл-файла похожа на упрощенный C-код. Лишь несколько синтаксических символов используются в конфигурационных файлах ferm. Кроме этих специальных символов, ferm использует 'keys' и 'values', думай об этом как об опциях и параметрах или как о переменных и значениях.
С этими словами ты опишешь свойства своего файерволла. Каждый файерволл состоит из двух вещей: Первое, проверка подходит ли сетевой трафик под конкретные условия, и второе, что делать с этим трафиком.
Ты можешь описать условия которые будут валидны для kernel interface program которую ты используешь, скорее всего это iptables(8). Например, в iptables, если ты попытаешься сопоставить TCP пакеты, ты бы написал:
iptables --protocol tcp
В ferm это превращается в:
protocol tcp;
Просто набранное это, не сделает ничего, тебе нужно сказать ferm'у (на самом деле нужно сказать iptables(8) и ядру), что делать с трафиком который совпадает с этим условием:
iptables --protocol tcp -j ACCEPT
Или, в переводе ferm'a:
protocol tcp ACCEPT;
Символ ; есть на конце каждого ferm-правила. Ferm игнорирует переносы строк, значит пример выше идентичен следующему:
protocol tcp
ACCEPT;
Далее список специальных символов:
;
Этот символ заканчивает правило. Разделяя точкой с запятой, ты можешь писать множество правил в одну строку, хоть это и уменьшает читабельность:
protocol tcp ACCEPT; protocol udp DROP;
{}
Символ вложенности определяет 'блок' правил.
Фигурные скобки содержат некоторое количество вложенных правил. Все совпадения до блока переносятся к ним.
Закрывающая фигурная скобка завершает набор правил. Тебе не нужно писать ';' после нее потому что это будет пустым правилом.
Пример:
chain INPUT proto icmp {
icmp-type echo-request ACCEPT;
DROP;
}
Этот блок показывает два правила внутри блока, они оба будут объединены с чем-либо перед этим блоком и ты получишь два правила:
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp -j DROP
Здесь может быть множество уровней вложенности:
chain INPUT {
proto icmp {
icmp-type echo-request ACCEPT;
DROP;
}
daddr 172.16.0.0/12 REJECT;
}
Заметь что на правило 'REJECT' не влияет 'proto icmp', однако там нет ';' после закрывающей фигурной скобки. В переводе на iptables:
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp -j DROP
iptables -A INPUT -d 172.16.0.0/12 -j REJECT
$
Раскрытие переменной. Заменяет '$FOO' на значение переменной. Смотри в секцию VARIABLES для деталей.
&
Вызов функции. Смотри секцию FUNCTIONS для деталей.
()
Символ массива. Используя круглые скобки ты можешь определить 'список' значений которые должны быть применены к ключу слева от него.
Пример:
protocol ( tcp udp icmp )
результатом этого будут три правила:
... -p tcp ...
... -p udp ...
... -p icmp ...
Только значения могут буть 'засписочены', поэтому ты не сможешь сделать что-то похожее на это:
proto tcp ( ACCEPT LOG );
но ты можешь сделать так:
chain (INPUT OUTPUT FORWARD) proto (icmp udp tcp) DROP;
(что приведет к девяти правилам!)
Значения разделяются пробелами. Массив одновременно лево- и право-ассоциативный, в отличие от блока вложенности, который может быть только лево-ассоциативным.
#
Символ комментария. Все что следует за этим символом до конца строки - игнорируется.
`command`
Выполнить команду в shell и вставить вывод процесса. Смотри секцию backticks для деталей.
'string'
Закавыченная строка, которая может содержать пробелы, знаки доллара и т.д.
LOG log-prefix ' hey, this is my log prefix!';
"string"
Закавыченная строка (см. выше), но вызовы переменных через знак доллара остаются вычислимыми:
DNAT to "$myhost:$myport";
Ключевые слова
В предыдущей секции мы уже представили некоторые базовые ключевые слова, такие как "chain", "protocol" и "ACCEPT". Давайте исследуем их природу.
Здесь три вида ключевых слов:
- location ключевые слова определяют где будет создано правило. Например: "table", "chain".
-
match ключевые слова сопоставляют все проходящие пакеты на соответствие условию. Текущее правило будет без эффекта если одно (или больше) сопоставление по критерию не пройдет. Пример: "proto", "daddr".
За множеством критериев следует параметр: "proto tcp", "daddr 172.16.0.0./12". -
target ключевые слова указывают что делать с пакетом. Пример: "ACCEPT", "REJECT", "jump".
Многие цели описываются большим количеством ключевых слов для описания деталей: "REJECT reject-with icmp-net-unreachable".
Каждое правило состоит из location и target, плюс некоторое количество matches:
table filter # location
proto tcp dport (http https) # match
ACCEPT; # target
Строго говоря, существует четвертый вид ключевых слов ferm (которые управляют внутренним поведением ferm), но они будут объяснены позже.
Параметры
Множество ключевых слов используют параметры. Они могут быть определены как константы, вызовы переменных или списки (массивы):
proto udp
saddr $TRUSTED_HOSTS;
proto tcp dport (http https ssh);
LOG log-prefix "funky wardriver alert: ";
Некоторые из них могут быть инвертированы (списки не могут):
proto !esp;
proto udp dport !domain;
Ключевые слова, которые не принимают параметров отрицаются префиксом '!':
proto tcp !syn;
Читай iptables(8) чтобы увидеть где может быть использован !.
Базовые ключевые слова
location keywords
-
domain [ip|ip6] - Устанавливает домен. "ip" значит "IPv4" (iptables) а "ip6" для поддержки IPv6, используя "ip6tables". Если ключевое слово не указано, будет использоваться значение из опции --domain или если и она не указана, то будет выбрано "ip", т.е. IPv4.
-
table [filter|nat|mangle] - Определяет в какую таблицу netfilter будет вставлено это правило: "filter" (default), "nat" или "mangle".
-
chain [chain-name] - Определяет в какую цепочку netfilter (в текущей таблице) это правило будет вставлено. Обычно в зависимости от таблицы предопределенны следующие имена цепочек "INPUT", "OUTPUT", "FORWARD", "PREROUTING", "POSTROUTING". Смотри документацию к netfilter для справки.
Если указать здесь имя несуществующей цепочки, то ferm добавит правило в кастомную цепочку м таким именем.
-
policy [ACCEPT|DROP|...] - Определяет политику по умолчанию для текущей цепочки (только встроенные значения). Может быть одной из встроенных целей (ACCEPT, DROP, REJECT, ...). Пакет которому не подойдет ни одно правило в цепочке, будет обработан указанной политикой.
Чтобы избежать двусмысленности, всегда указывайте политики всех предопределенных цепочек явно.
-
@subchain ["CHAIN-NAME"]{...} - Работает как обычный блок (без @subchain), за исключением того, что ferm перемещает правила внутри фигурных скобок в новую пользовательскую цепочку. Иия для этой цепочки будет выбрано автоматически ferm'ом.
В множестве случаев это быстрее чем просто блок, потому что ядро может пропускать большие блоки правил когда предварительное условие ложно. Представь следующий пример:
table filter chain INPUT { saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; } }
Здесь будет сгенерировано 20 правил. Когда приходит пакет который не проходит saddr сопоставление, он тем не менее проверится через все 20 правил. С @subchain эта проверка пройдет единожды, как результат быстрая фильтрация и меньшая нагрузка на CPU:
table filter chain INPUT { saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) @subchain { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; } }
Опционально можно задать имя для подцепочки:
saddr (1.2.3.4 2.3.4.5 3.4.5.6) @subchain "foobar" { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; }
Именем может быть любая закавыченная строковая константа или развернутое ferm выражение, такое как @cat("interface_", $iface) или @substr($var,0,20).
Ты можешь добиться такого же результата явно описывая кастомные цепочки, но ты можешь почувствовать, что использование @subchain требует меньше ввода.
-
@gotosubchain ["CHAIN-NAME"]{...} - Работает как @subchain за искллючением того что вместот использования jump target используется goto target. Разницу между этими двумя таргетами смотри ниже.
-
@preserve - Сохранять существующие правила в текущей цепочке:
chain (foo bar) @preserve;
С этой опцией ferm загружает предыдущий набор правил используя iptables-save, выделяет все "preserved" цепочки и вставляет их в итоговый вывод.
"Preserved" цепочки не должны изменяться ferm'ом: ни правила, ни политики.
Basic iptables match keywords
-
interface [interface-name] - Определяет имя интерфейса твоей внешней сетевой карты, как eth0 или dialup ppp1, или какого-либо другого девайса имя которого ты хочешь сопоставлять с проходящими пакетами. Это эквивалентно
-i
в iptables(8). - outerface [interface-name] - То же что и interface, только пакеты сопоставляются с исходящим интерфейсом, как в iptables(8).
-
protocol [protocol-name|protocol-number] - Сейчас ядро поддерживает TCP, UDP и ICMP или их соответствующие номера.
Вместо protocol ты можешь также использовать сокращение proto. -
saddr|daddr [address-spec] - Совпадение указанного адреса в адресе отправителя (saddr) или в адресе получателя (daddr).
Пример:saddr 192.168.0.0/24 ACCEPT; # (identical to the next one:) saddr 192.168.0.0/255.255.255.0 ACCEPT; daddr my.domain.com ACCEPT;
-
fragment - Определяет что только фрагмент IP пакета будет заматчен. Когда пакеты больше чем максимальный размер с которым может справиться твоя система (это называется Maximum Transmission Unit или MTU), то они делятся на части и отправляются один за одним как одиночные пакеты. Смотри ifconfig(8) если хочешь узнать MTU своей системы (обычно по умолчанию это 1500 bytes).
Фрагменты часто используются в DOS аттаках потому что нет пути поиска происхождения фрмагмента пакета. -
sport|dport [port-spec] - Срабатывает на пакеты на указанный TCP или UDP порт. "sport" срабатывает на исходящий порт и "dport" срабатывает на конечный порт.
Эта проверка может быть использована только после указания "protocol tcp" или "protocol udp", потому что только в этих двух протоколах на данный момент есть порты.
И несколько примеров валидных портов/диапазонов:dport 80 ACCEPT; dport http ACCEPT; dport ssh:http ACCEPT; dport 0:1023 ACCEPT; # equivalent to :1023 dport 1023:65535 ACCEPT;
- syn - Указывает что SYN флаг, который используется для создания новых TCP соединений, должен быть в TCP пакете. Так ты можешь идентифицировать входящие соединения и принимать решение разрешать их или нет. Пакеты не имеющие такого флага обычно из уже существующих соединений, поэтому считается достаточно безопасным пропускать их.
-
module [module-name] - Загружает какой-либо iptables модуль. Множество модулей предоставляет много критериев. Мы вернемся к этому позже.
Вместо module ты можешь также использовать сокращение mod
Basic target keywords
- jump [custom-chain-name] - Перейти к кастомной цепочке. Если в кастомной цепочке нет походящего правила, netfilter вернется к следующему правилу в предыдущей цепочке.
- goto [custom-chain-name] - Перейти к кастомной цепочке. Не похоже на jump, RETURN не будет продолжать обработку в этой цепочке, вместо этого продолжит в цепочке которая вызвала эту цепочку через jump.
- ACCEPT - Допустить заматченный пакет.
- DROP - Откинуть заматченный пакет без дальнейших уведомлений.
-
REJECT - Реджектить заматченные пакеты, то есть отправлять ICMP пакеты отправителю, в которых по умолчанию port-unreachable. Ты можешь определить иной ICMP тип.
Вводи "iptables -j REJECT -h" для справки.REJECT; # default to icmp-port-unreachable REJECT reject-with icmp-net-unreachable;
- RETURN - Закончить в текущей цепочке и вернуться к вызвавшей цепочке (если "jump [custom-chain-name]" использован)
- NOP - Нет действий для всех.
ADDITIONAL KEYWORDS
Netfilter модульный. Модули погут предоставлять дополнительные критерии. Список модулей netfilter постоянно растет, а ferm пытается сохранить поддержку их всех.
iptables match modules
-
account - Учитывать трафик для всех хостов в определенной сети. Это один из модулей поиска совпадений, который уже ведет себя как цель, поэтому в основном тебе придется использовать цель NOP.
mod account aname mynetwork aaddr 192.168.1.0/24 ashort NOP;
-
addrtype - Проверка типа адреса; любой: исходящй адрес или адрес назначения.
Набери "iptables -m addrtype -h" для справки.mod addrtype src-type BROADCAST; mod addrtype dst-type LOCAL;
-
ah - Проверка SPI заголовка в AH пакете.
Дополнительные аргументы для IPv6:mod ah ahspi 0x101; mod ah ahspi ! 0x200:0x2ff;
mod ah ahlen 32 ACCEPT; mod ah ahlen !32 ACCEPT; mod ah ahres ACCEPT;
-
bpf - Матчинг с использованием Linux Socket Filter.
mod bpf bytecode "4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0";
-
cgroup - Матчинг с использованием cgroupsv2 hierarchy или устаревшего net_cls cgroup.
Путь относителен корня cgroupsv2 hierarchy и сравнивается с начальной частью пути процесса в иерархии.mod cgroup path ! example/path ACCEPT;
Соответствует значениюmod cgroup cgroup 10:10 DROP; mod cgroup cgroup 1048592 DROP;
net_cls.classid
установленному на процесс старым net_cls cgroup. Этот класс может быть определен как шестнадцатеричная major:minor пара (см. tc(8)), или как десятичное число, эти два правила эквивалентны. -
comment - Добавляет комментарий к правилу, не больше 256 символов, комментарий не имеет эффекта на пакет. Отметь что это не то же что и ferm комментарии ('#'), этот будет показан в "iptables -L".
"mod comment" можно не писать, ferm добавить автоматически.mod comment comment "This is my comment." ACCEPT;
-
condition - Срабатывает если значение в /proc/net/ipt_condition/NAME равно 1 (путь для ip6 /proc/net/ip6t_condition/NAME).
mod condition condition (abc def) ACCEPT; mod condition condition !foo ACCEPT;
-
connbytes - Сопоставляет как много байт или пакетов было передано соединением до текущего момента, или среднее bytes per packet.
Валидные значения для connbytes-dir: original, reply, both; для connbytes-mode: packets, bytes, avgpkt.mod connbytes connbytes 65536: connbytes-dir both connbytes-mode bytes ACCEPT; mod connbytes connbytes !1024:2048 connbytes-dir reply connbytes-mode packets ACCEPT;
-
connlabel - Модуль для проверки или добавления connlabel к соединению.
mod connlabel label "name"; mod connlabel label "name" set;
-
connlimit - Позволяет тебе ограничивать количество параллельных TCP соединений к серверу по клиентскому IP адресу (или блоку адресов).
mod connlimit connlimit-above 4 REJECT; mod connlimit connlimit-above !4 ACCEPT; mod connlimit connlimit-above 4 connlimit-mask 24 REJECT; mod connlimit connlimit-upto 4 connlimit-saddr REJECT; mod connlimit connlimit-above 4 connlimit-daddr REJECT;
-
connmark - Проверка метки связанной с этим соединением, установленной CONNMARK'ом.
mod connmark mark 64; mod connmark mark 6/7;
-
conntrack - Проверка информации от механизма определения состояния соединения.
Введи "iptables -m conntrack -h" для справки.mod conntrack ctstate (ESTABLISHED RELATED); mod conntrack ctproto tcp; mod conntrack ctorigsrc 192.168.0.2; mod conntrack ctorigdst 1.2.3.0/24; mod conntrack ctorigsrcport 67; mod conntrack ctorigdstport 22; mod conntrack ctreplsrc 2.3.4.5; mod conntrack ctrepldst ! 3.4.5.6; mod conntrack ctstatus ASSURED; mod conntrack ctexpire 60; mod conntrack ctexpire 180:240;
-
cpu - Сопоставление CPU обрабатывающего это соединение.
mod cpu cpu 0;
-
dccp - Проверка атрибутов специфичных для DCCP (Datagram Congestion Control Protocol). Этот модуль автоматически подгружается когда ты используешь "protocol dccp".
proto dccp sport 1234 dport 2345 ACCEPT; proto dccp dccp-types (SYNCACK ACK) ACCEPT; proto dccp dccp-types !REQUEST DROP; proto dccp dccp-option 2 ACCEPT;
-
dscp - Сопоставление 6-битного DSCP поля с TOS полем.
mod dscp dscp 11; mod dscp dscp-class AF41;
-
dst - Сравнение параметров в заголовке Destination Options (IPv6).
mod dst dst-len 10; mod dst dst-opts (type1 type2 ...);
-
ecn - Сравнение ECN битов IPv4 TCP заголовков.
Набери "iptables -m ecn -h" для подробной информации.mod ecn ecn-tcp-cwr; mod ecn ecn-tcp-ece; mod ecn ecn-ip-ect 2;
-
esp - Сравнение SPI заголовка в ESP пакете.
mod esp espspi 0x101; mod esp espspi ! 0x200:0x2ff;
-
eui64 - "Этот модуль матчит EUI-64 часть автонастраиваемого IPv6 адреса без сохранения состояния. Он сравнивает EUI-64 полученный из MAC адреса в Ethernet фрейме с наименьшими 64 битами исходящего IPv6 адреса. Но "Universal/Local" биты не сравниваются. Этот модуль не проверяет другие фреймы канального уровня, а только валидные в PREROUTING, INPUT и FORWARD цепочках."
mod eui64 ACCEPT;
-
fuzzy - "Этот модуль матчит пакеты которые входят в ограничение скорости основываясь на FLC."
mod fuzzy lower-limit 10 upper-limit 20 ACCEPT;
-
geoip - Матчит пакеты основываясь на их геопозиции. (Нужно установить GeoDB.)
mod geoip src-cc "CN,VN,KR,BH,BR,AR,TR,IN,HK" REJECT; mod geoip dst-cc "DE,FR,CH,AT" ACCEPT;
-
hbh - Матчит заголовок параметров Hop-by-Hop (ip6).
mod hbh hbh-len 8 ACCEPT; mod hbh hbh-len !8 ACCEPT; mod hbh hbh-opts (1:4 2:8) ACCEPT;
-
hl - Матчит поле Hop Limit (ip6).
mod hl hl-eq (8 10) ACCEPT; mod hl hl-eq !5 ACCEPT; mod hl hl-gt 15 ACCEPT; mod hl hl-lt 2 ACCEPT;
-
helper - Проверяет какой именно conntrack хелпер затрекал это соединение. Порт может быть указан через "-portnr".
mod helper helper irc ACCEPT; mod helper helper ftp-21 ACCEPT;
-
icmp - Проверяет специфичные для ICMP аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol icmp".
Эта опция может быть использована в ip6 домене, несмотря на то что в ip6tables она называется icmpv6.proto icmp icmp-type echo-request ACCEPT;
Используй "iptables -p icmp-h
" чтобы получить список валидных ICMP типов. -
iprange - Матчит диапазон IPv4 адресов.
mod iprange src-range 192.168.2.0-192.168.3.255; mod iprange dst-range ! 192.168.6.0-192.168.6.255;
-
ipv4options - Проверяет в IPv4 заголовках такие опции как source routing, record route, timestamp and router-alert.
mod ipv4options ssrr ACCEPT; mod ipv4options lsrr ACCEPT; mod ipv4options no-srr ACCEPT; mod ipv4options !rr ACCEPT; mod ipv4options !ts ACCEPT; mod ipv4options !ra ACCEPT; mod ipv4options !any-opt ACCEPT;
-
ip6header - Матчит заголовки расширений IPv6 (ip6).
mod ipv6header header !(hop frag) ACCEPT; mod ipv6header header (auth dst) ACCEPT;
-
hashlimit - Похоже на 'mod limit', но добавляет способность добавления per-destination или per-port ограничений управляемых через hash таблицу.
Возможные значения для hashlimit-mode: dstip dstport srcip srcport (или список нескольких из этих значений).mod hashlimit hashlimit 10/minute hashlimit-burst 30/minute hashlimit-mode dstip hashlimit-name foobar ACCEPT;
Здесь больше возможных настроек, набери "iptables -m hashlimit -h" для просмотра документации. -
ipvs - Сравнивает свойства IPVS подключения.
mod ipvs ipvs ACCEPT; # packet belongs to an IPVS connection mod ipvs vproto tcp ACCEPT; # VIP protocol to match; by number or name, e.g. "tcp mod ipvs vaddr 1.2.3.4/24 ACCEPT; # VIP address to match mod ipvs vport http ACCEPT; # VIP port to match mod ipvs vdir ORIGINAL ACCEPT; # flow direction of packet mod ipvs vmethod GATE ACCEPT; # IPVS forwarding method used mod ipvs vportctl 80; # VIP port of the controlling connection to match
-
length - Проверяет длину пакета.
mod length length 128; # exactly 128 bytes mod length length 512:768; # range mod length length ! 256; # negated
-
limit - Ограничивает скорость пакетов.
Введи "iptables -m limit -h" для справки.mod limit limit 1/second; mod limit limit 15/minute limit-burst 10;
-
mac - Сравнивает исходящий MAC адрес.
mod mac mac-source 01:23:45:67:89;
-
mark - Матчит пакеты основываясь на отметках netfilter mark. Здесь может быть 32 битное целое число между 0 и 4294967295.
mod mark mark 42;
-
mh - Матчит заголовки мобильности (ip6).
proto mh mh-type binding-update ACCEPT;
-
multiport - Матчит по набору исходящих или конечных портов (только UDP и TCP).
Это правило имеет большое преимущество над "dport" и "sport": оно генерирует только одно правило для вплоть до 15 портов вместо одного правила на каждый порт.mod multiport source-ports (https ftp); mod multiport destination-ports (mysql domain);
Как сокращение ты можешь использовать "sports" и "dports" (без "mod multiport"):sports (https ftp); dports (mysql domain);
-
nth - Матчит каждый n-ный пакет.
Введи "iptables -m nth -h" для справки.mod nth every 3; mod nth counter 5 every 2; mod nth start 2 every 3; mod nth start 5 packet 2 every 6;
-
osf - Матчит пакеты в зависимости от ОС отправителя.
Введи "iptables -m osf -h" для справки.mod osf genre Linux; mod osf ! genre FreeBSD ttl 1 log 1;
-
owner - Проверяет информацию о создателе пакета, а именно user id, group id, process id, session id и command name.
("cmd-owner", "pid-owner" and "sid-owner" требуют специальных патчей для ядра, которые не включены в обычную поставку ядра Linux)mod owner uid-owner 0; mod owner gid-owner 1000; mod owner pid-owner 5432; mod owner sid-owner 6543; mod owner cmd-owner "sendmail";
-
physdev - Матчит пакеты по девайсу с/на которые пакет пришел/ушел. Это полезно для bridge-интерфейсов.
mod physdev physdev-in ppp1; mod physdev physdev-out eth2; mod physdev physdev-is-in; mod physdev physdev-is-out; mod physdev physdev-is-bridged;
-
pkttype - Проверяет тип пакета канального уровня.
mod pkttype pkt-type unicast; mod pkttype pkt-type broadcast; mod pkttype pkt-type multicast;
-
policy - Проверяет IPsec политику которая была применена к пакету.
Заметь что ключевое слово proto также используется как сокращенная версия для protocol (встроенные match module). Ты можешь исправить этот конфликт используя всегда длинное ключевое слово protocol.mod policy dir out pol ipsec ACCEPT; mod policy strict reqid 23 spi 0x10 proto ah ACCEPT; mod policy mode tunnel tunnel-src 192.168.1.2 ACCEPT; mod policy mode tunnel tunnel-dst 192.168.2.1 ACCEPT; mod policy strict next reqid 24 spi 0x11 ACCEPT;
-
psd - Детектит TCP/UDP скан портов.
mod psd psd-weight-threshold 21 psd-delay-threshold 300 psd-lo-ports-weight 3 psd-hi-ports-weight 1 DROP;
-
quota - Реализует сетевые квоты уменьшая счетчик байтов с каждым пакетом.
mod quota quota 65536 ACCEPT;
-
random - Матчит случайный процент всех пакетов.
mod random average 70;
-
realm - Матчит области маршрутизации. Полезно в окружениях использующих BGP.
mod realm realm 3;
-
recent - Временно отмечат исходящие IP адреса.
Этот модуль имеет конструкционный недостаток: несмотря на то что он реализован как match module, он имеет target-like поведение когда используется ключевое слово "set".mod recent set; mod recent rcheck seconds 60; mod recent set rsource name "badguy"; mod recent set rdest; mod recent rcheck rsource name "badguy" seconds 60; mod recent update seconds 120 hitcount 3 rttl; mod recent mask 255.255.255.0 reap;
http://snowman.net/projects/ipt_recent/ -
rpfilter - Проверяет, что ответ на пакет будет отправлен через тот же интерфейс, с которого он прибыл. Пакеты из loopback интерфейса всегда ограничиваются.
Этот модуль является предпочтительным способом выполнения фильтрации обратного пути для IPv6 и мощной альтернативой проверкам, контролируемым через sysctl net.ipv4.conf.*.rp_filter.mod rpfilter proto tcp loose RETURN; mod rpfilter validmark accept-local RETURN; mod rpfilter invert DROP;
-
rt - Матчит IPv6 роутинг заголовки (ip6).
mod rt rt-type 2 rt-len 20 ACCEPT; mod rt rt-type !2 rt-len !20 ACCEPT; mod rt rt-segsleft 2:3 ACCEPT; mod rt rt-segsleft !4:5 ACCEPT; mod rt rt-0-res rt-0-addrs (::1 ::2) rt-0-not-strict ACCEPT;
-
sctp - Проверят специфичные для SCTP (Stream Control Transmission Protocol) аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol sctp".
Используй "iptables -p sctpproto sctp sport 1234 dport 2345 ACCEPT; proto sctp chunk-types only DATA:Be ACCEPT; proto sctp chunk-types any (INIT INIT_ACK) ACCEPT; proto sctp chunk-types !all (HEARTBEAT) ACCEPT;
-h
" чтобы показать список валидных типов. -
set - Сравнивает исходящий или конечный IP/Port/MAC с указанным набором.
Смотри http://ipset.netfilter.org/ для большей информации.mod set set badguys src DROP;
-
state - Проверяет состояние соединения.
Введи "iptables -m state -h" для справки.mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT;
-
statistic - Преемник nth и random, на данный момент недокументирован в iptables(8) man page.
mod statistic mode random probability 0.8 ACCEPT; mod statistic mode nth every 5 packet 0 DROP;
-
string - Сравнивает строку.
mod string string "foo bar" ACCEPT; mod string algo kmp from 64 to 128 hex-string "deadbeef" ACCEPT;
-
tcp - Проверяет специфичные для TCP аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol tcp".
Набери "iptables -p tcp -h" для справки.proto tcp sport 1234; proto tcp dport 2345; proto tcp tcp-flags (SYN ACK) SYN; proto tcp tcp-flags ! (SYN ACK) SYN; proto tcp tcp-flags ALL (RST ACK); proto tcp syn; proto tcp tcp-option 2; proto tcp mss 512;
-
tcpmss - Проверяет поле TCP MSS в SYN или SYN/ACK пакетах.
mod tcpmss mss 123 ACCEPT; mod tcpmss mss 234:567 ACCEPT;
-
time - Сравнивает время поступления пакета с указанными диапазонами.
Набери "iptables -m time -h" для справки.mod time timestart 12:00; mod time timestop 13:30; mod time timestart 22:00 timestop 07:00 contiguous; mod time days (Mon Wed Fri); mod time datestart 2005:01:01; mod time datestart 2005:01:01:23:59:59; mod time datestop 2005:04:01; mod time monthday (30 31); mod time weekdays (Wed Thu); mod time timestart 12:00; mod time timestart 12:00 kerneltz;
-
tos - Матчит пакеты по указанному TOS значению.
Набери "iptables -m tos -h" для справки.mod tos tos Minimize-Cost ACCEPT; mod tos tos !Normal-Service ACCEPT;
-
ttl - Матчит по TTL (time to live) полю в IP заголовке.
mod ttl ttl-eq 12; # ttl equals mod ttl ttl-gt 10; # ttl greater than mod ttl ttl-lt 16; # ttl less than
-
u32 - Сравнивает сырые данные из пакета. Ты можешь указать больше чем один фильтр через список; они не развернутся в множество правил.
mod u32 u32 '6&0xFF=1' ACCEPT; mod u32 u32 ('27&0x8f=7' '31=0x527c4833') DROP;
- unclean - Матчит пакеты которые выглядят как бесформенные или необычные. Эта проверка не имеет дополнительных параметров.
iptables target modules
Следующие дополнительные цели доступны в ferm, при условии что ты включил их в своем ядре:
-
CHECKSUM - Считает чек-сумму пакета.
CHECKSUM checksum-fill;
-
CLASSIFY - Устанавливат CBQ класс.
CLASSIFY set-class 3:50;
-
CLUSTERIP - Конфигурирует простой кластер нод которые делят определенный IP и MAC адрес. Соединение статически доставляется между нодами.
CLUSTERIP new hashmode sourceip clustermac 00:12:34:45:67:89 total-nodes 4 local-node 2 hash-init 12345;
-
CONNMARK - Устанавливает netfilter отметки связанные с этим соединением.
CONNMARK set-xmark 42/0xff; CONNMARK set-mark 42; CONNMARK save-mark; CONNMARK restore-mark; CONNMARK save-mark nfmask 0xff ctmask 0xff; CONNMARK save-mark mask 0x7fff; CONNMARK restore-mark mask 0x8000; CONNMARK and-mark 0x7; CONNMARK or-mark 0x4; CONNMARK xor-mark 0x7; CONNMARK and-mark 0x7;
-
CONNSECMARK - Этот модуль копирует маркировки безопасности из пакета на соединение (если не помечено), и из соединения возвращает пакеты (также, только если не помечены). Обычно используется в связи с SECMARK, он доступен только для таблицы mangle.
CONNSECMARK save; CONNSECMARK restore;
-
DNAT to [ip-address|ip-range|ip-port-range] - Изменяет адрес назначения пакета.
DNAT to 10.0.0.4; DNAT to 10.0.0.4:80; DNAT to 10.0.0.4:1024-2048; DNAT to 10.0.1.1-10.0.1.20;
-
DNPT - Предоставляет IPv6-to-IPv6 Трансляцию Сетевых Префиксов без сохранения состояния назначения.
DNPT src-pfx 2001:42::/16 dst-pfx 2002:42::/16;
-
ECN - Позволяет выборочно работать вокруг известных черных дыр ECN. Доступно только в таблице mangle.
ECN ecn-tcp-remove;
-
HL - Изменяет поле IPv6 Hop Limit (ip6/mangle).
HL hl-set 5; HL hl-dec 2; HL hl-inc 1;
-
HMARK - Как MARK, т.е. устанавливает fwmark, но метка вычисляется из селектора пакетов хэширования по выбору.
HMARK hmark-tuple "src" hmark-mod "1" hmark-offset "1" hmark-src-prefix 192.168.1.0/24 hmark-dst-prefix 192.168.2.0/24 hmark-sport-mask 0x1234 hmark-dport-mask 0x2345 hmark-spi-mask 0xdeadbeef hmark-proto-mask 0x42 hmark-rnd 0xcoffee;
-
IDLETIMER - Может быть использовано для идентификации когда интерфейс проставивает в определенный период времени.
IDLETIMER timeout 60 label "foo";
-
IPV4OPTSSTRIP - Очищает все IP опции с пакета. Модуль не имеет опций.
IPV4OPTSSTRIP;
-
JOOL - Передает пакеты для стэйтфул NAT64 трансляции через JOOL. JOOL должен быть установлен в системе и модуль ядра jool дожен быть загружен.
JOOL instance "foo";
-
JOOL_SIIT - Передает пакеты для стэйтлес IP/ICMP трансляции (SIIT) через JOOL. JOOL должен быть установлен в системе и модуль ядра jool_siit дожен быть загружен.
JOOL_SIIT instance "foo";
-
LED - Создает LED-триггер который может быть приаттачен к панели индикаторов, чтобы мигать или светить ими когда определенные пакеты проходят через систему.
LED led-trigger-id "foo" led-delay 100 led-always-blink;
-
LOG - Логирует пакеты которые матчатся этим правилом в kernel log. Будь осторожен с лог флудингом. Отметь что это "non-terminating target", т.е. обход по правилам будет продолжен.
LOG log-level warning log-prefix "Look at this: "; LOG log-tcp-sequence log-tcp-options; LOG log-ip-options;
-
MARK - Устанавливает netfilter маркировку для пакета (32 битное целое число между 0 и 4294967295):
MARK set-mark 42; MARK set-xmark 7/3; MARK and-mark 31; MARK or-mark 1; MARK xor-mark 12;
-
MASQUERADE - Маскарадит заматченные пакеты. Опционально за ним следует порт или диапазон портов для iptables. Указывается как "123", "123-456" или "123:456". Параметр с диапазоном портов определяет через какие локальные порты должно проходить замаскараженое соединение.
MASQUERADE; MASQUERADE to-ports 1234:2345; MASQUERADE to-ports 1234:2345 random;
-
MIRROR - Экспериментально/демонстрационная цель, которая меняет местами получателя и отправителя в IP заголовках.
MIRROR;
-
NETMAP - Мапит целую сеть на другую сеть в nat таблице.
NETMAP to 192.168.2.0/24;
-
NOTRACK - Отключает conntrack для всех пакетов которые матчатся этим правилом.
proto tcp dport (135:139 445) NOTRACK;
-
RATEEST
RATEEST rateest-name "foo" rateest-interval 60s rateest-ewmalog 100; proto tcp dport (135:139 445) NOTRACK;
-
NFLOG - Логирует пакеты по netlink; это наследник ULOG'a.
NFLOG nflog-group 5 nflog-prefix "Look at this: "; NFLOG nflog-range 256; NFLOG nflog-threshold 10;
-
NFQUEUE - Очерединг, требует поддержку ядром nfnetlink_queue.
proto tcp dport ftp NFQUEUE queue-num 20;
-
QUEUE - Очерединг, предок NFQUEUE. Все пакеты уходят в очередь 0.
proto tcp dport ftp QUEUE;
-
REDIRECT to-ports [ports] - Прозрачное проксирование: изменяет IP назначения пакета на свой.
proto tcp dport http REDIRECT to-ports 3128; proto tcp dport http REDIRECT to-ports 3128 random;
-
SAME - Похоже на SNAT, но клиент мапится на один и тот же исходящий IP для всех его подключений.
SAME to 1.2.3.4-1.2.3.7; SAME to 1.2.3.8-1.2.3.15 nodst; SAME to 1.2.3.16-1.2.3.31 random;
-
SECMARK - Используется для маркирования пакета для подсистемы безопасности такой как SELinux. Это работает только в таблице mangle.
SECMARK selctx "system_u:object_r:httpd_packet_t:s0";
-
SET [add-set|del-set] [setname] [flag(s)] - Добавляет IP в специальный список. См. http://ipset.netfilter.org/
proto icmp icmp-type echo-request SET add-set badguys src; SET add-set "foo" timeout 60 exist;
-
SNAT to [ip-address|ip-range|ip-port-range] - Изменяет исходящий адрес пакета.
SNAT to 1.2.3.4; SNAT to 1.2.3.4:20000-30000; SNAT to 1.2.3.4 random;
-
SNPT - Предоставляет IPv6-to-IPv6 трансляцию исходящих сетевых префиксов без сохранения состояния.
SNPT src-pfx 2001:42::/16 dst-pfx 2002:42::/16;
-
SYNPROXY - Проксирование тройного рукопожатия в TCP: пусть файерволл обрабатывает тройное рукопожатие TCP и устанавливает соединение с сокетом сервера единожды для тех клиентов которые прошли стадию рукопожатия.
SYNPROXY wscale 7 mss 1460 timestamp sack-perm
-
TCPMSS - Подменяет MSS значение в TCP SYN пакетах.
TCPMSS set-mss 1400; TCPMSS clamp-mss-to-pmtu;
-
TCPOPTSTRIP - Лишает TCP пакет его TCP опций.
TCPOPTSTRIP strip-options (option1 option2 ...);
-
TOS set-tos [value] - Устанавлиет TCP Type Of Service в указанное значение. Это будет использоваться любым планировщиком трафика, который захочет, в основном вашей собственной Linux-машиной, но, возможно, и больше. Оригинальные TOS-биты очищаются и перезаписываются.
Введи "iptables -j TOS -h" для справки.TOS set-tos Maximize-Throughput; TOS and-tos 7; TOS or-tos 1; TOS xor-tos 4;
-
TTL - Изменяет заголовок TTL.
TTL ttl-set 16; TTL ttl-dec 1; # decrease by 1 TTL ttl-inc 4; # increase by 4
-
ULOG - Логирует пакеты пользовательской программой.
ULOG ulog-nlgroup 5 ulog-prefix "Look at this: "; ULOG ulog-cprange 256; ULOG ulog-qthreshold 10;
ДРУГИЕ ДОМЕНЫ
Начиная с версии 2.0, ferm поддерживает не только ip и ip6, но также arp (ARP таблицы) и eb (ethernet bridging таблицы). Эти концепции аналогичны iptables.
Ключевые слова arptables
- source-ip, destination-ip - Матчат исходящие или конечные IPv4 адреса. Похоже на saddr и daddr в ip домене.
- source-mac, destination-mac - Матчат исходящие или конечные MAC адреса.
- interface, outerface - Входной или выходной интерфейс.
-
h-length - Аппаратная длина пакета.
chain INPUT h-length 64 ACCEPT;
-
opcode - Код операции, для справки смотри iptables(8).
opcode 9 ACCEPT;
-
h-type - Аппаратный тип.
h-type 1 ACCEPT;
-
proto-type - Тип протокола.
proto-type 0x800 ACCEPT;
- Mangling - Ключевые слова mangle-ip-s, mangle-ip-d, mangle-mac-s, mangle-mac-d, mangle-target могут быть использованы для изменения ARP. См. iptables(8) для справки.
Ключевые слова ebtables
- proto - Матчит протокол которым создан этот фрейм, например IPv4 или PPP. Для просмотра списка, см. /etc/ethertypes.
- interface, outerface - Физический входной или выходной интерфейс.
- logical-in, logical-out - Логический bridge интерфейс.
- saddr, daddr - Матчит исходный или конечный MAC адрес.
- Match modules - Поддерживаются следующие модули: 802.3, arp, ip, mark_m, pkttype, stp, vlan, log.
-
Target extensions - Поддерживаются следующие расширения: arpreply, dnat, mark, redirect, snat.
Пожалуйста отметь что здесь происходит конфликт между --mark из mark_m модуля и -j mark. Поскольку они оба сработают по ключевому слову mark, то мы решили эту проблему написанием имени цели в вернем регистре. Как и в других доменах. Следующий пример перезаписывает маркировку 1 на 2:mark 1 MARK 2;
ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ
Переменные
В сложных файервольных файлах полезно использовать переменные, например чтобы дать сетевому интерфейсу осмысленное имя.
Чтобы указать переменную, напиши:
@def $DEV_INTERNET = eth0;
@def $PORTS = (http ftp);
@def $MORE_PORTS = ($PORTS 8080);
В настоящем ferm коде, переменные используются как параметры:
chain INPUT interface $DEV_INTERNET proto tcp dport $MORE_PORTS ACCEPT;
Заметь, что переменные могуть использоваться только в параметрах ("192.168.1.1", "http"); они не могут содержать ключевых слов как "proto" или "interface".
Переменные действительны только в текущем блоке:
@def $DEV_INTERNET = eth1;
chain INPUT {
proto tcp {
@def $DEV_INTERNET = ppp0;
interface $DEV_INTERNET dport http ACCEPT;
}
interface $DEV_INTERNET DROP;
}
будет перобразован в:
chain INPUT {
proto tcp {
interface ppp0 dport http ACCEPT;
}
interface eth1 DROP;
}
"def $DEV_INTERNET = ppp0" валидно только в блоке "proto tcp"; родительский блок остается с "set $DEV_INTERNET = eth1".
Подключаемые файлы с описанными переменными остаются доступными в вызвавшем блоке. Это полезно когда ты инклудишь файлы в которых описаны только переменные.
Автоматические переменные
Некоторые переменные устанавливаются ferm'ом изнутри. Ferm скрипты могут использовать их просто как любые другие переменные.
- $FILENAME - Имя конфигурационного файла относительно директории откуда был запущен ferm.
- $FILEBNAME - Базовое имя конфигурационного файла.
- $DIRNAME - Директория конфигурационного файла.
- $DOMAIN - Текущий домен. Один из ip, ip6, arp, eb.
- $TABLE - Текущая netfilter таблица.
- $CHAIN - Текущая netfilter цепочка.
-
$LINE - Строка текущего скрипта. Это может быть использовано например так:
@def &log($msg) = { LOG log-prefix "rule=$msg:$LINE "; } . . . &log("log message");
Функции
Функции похожи на переменные, за исключением того что они могут принимать параметры и они предоставляют ferm'у команды а не значения.
@def &FOO() = proto (tcp udp) dport domain;
&FOO() ACCEPT;
@def &TCP_TUNNEL($port, $dest) = {
table filter chain FORWARD interface ppp0 proto tcp dport $port daddr $dest outerface eth0 ACCEPT;
table nat chain PREROUTING interface ppp0 proto tcp dport $port daddr 1.2.3.4 DNAT to $dest;
}
&TCP_TUNNEL(http, 192.168.1.33);
&TCP_TUNNEL(ftp, 192.168.1.30);
&TCP_TUNNEL((ssh smtp), 192.168.1.2);
Вызов функции, который содержит блок (как '{...}') должен быть последней командой в ferm правиле, например за ним должна следовать ';'. '$FOO()' не содержит блок и поэтому ты можешь написать 'ACCEPT' после ее вызова. Для обхода этого ты можешь реорганизовать ключевые слова:
@def &IPSEC() = { proto (esp ah); proto udp dport 500; }
chain INPUT ACCEPT &IPSEC();
Апострофы
С апострофами ты можешь использовать вывод внешних команд:
@def $DNSSERVERS = `grep nameserver /etc/resolv.conf | awk '{print $2}'`;
chain INPUT proto tcp saddr $DNSSERVERS ACCEPT;
Команды выполняются в shell (/bin/sh), просто как апострофы в Perl. Ferm не разворачивает никакие переменные в них.
Затем вывод помечается и сохраняется как ferm список (массив). Строки начинающиеся с '#' игнорируются; другие строки могут содержать любое количество значений разделенных пробелом.
Включения
Ключевое слово @include позволяет тебе включать внешние файлы:
@include 'vars.ferm';
Имя файла относительно к вызывающему файлу, например выражение выше включает /etc/ferm/vars.ferm когда включение происходит из /etc/ferm/ferm.conf.
Переменные и функции описанные во включенном файле остаются доступными в вызвавшем файле.
include работает в блоках:
chain INPUT {
@include 'input.ferm';
}
Если ты укажешь директорию (с '/' на конце), все файлы из этой директории будут включены в алфавитном порядке:
@include 'ferm.d/';
Функция @glob может быть использована для разворачивания вайлдкардов:
@include @glob('*.include');
С пайп-символом на конце, ferm выполняет shell команду и парсит вывод:
@include "/root/generate_ferm_rules.sh $HOSTNAME|"
ferm прервется если код возврата не 0.
Условия
Ключевое слово @if предоставляет условное выражение:
@if $condition DROP;
Значение расценивается как true также как в Perl: ноль, пустой список, пустая строка это ложь, все остальное это истина. Примеры для истинных значений:
(a b); 1; 'foo'; (0 0)
Примеры для ложных значений:
(); 0; '0'; ''
Также здесь есть @else:
@if $condition DROP; @else REJECT;
Учитывай точку с запятой перед @else.
Можно использовать фигурные скобки перед @if и @else:
@if $condition {
MARK set-mark 2;
RETURN;
} @else {
MARK set-mark 3;
}
С закрывающейся фигурной скобкой также завершается команда, поэтому точка с запятой здесь не нужна.
Здесь нет @elsif, используй вместо этого @else @if.
Пример:
@def $have_ipv6 = `test -f /proc/net/ip6_tables_names && echo 1 || echo`;
@if $have_ipv6 {
domain ip6 {
# ....
}
}
Хуки
Для запуска кастомных команд ты можешь устанавливать хуки:
@hook pre "echo 0 >/proc/sys/net/ipv4/conf/eth0/forwarding";
@hook post "echo 1 >/proc/sys/net/ipv4/conf/eth0/forwarding";
@hook flush "echo 0 >/proc/sys/net/ipv4/conf/eth0/forwarding";
Описанные команды выполняются используя shell. "pre" значит запустить команду до применения файерволл правил, а "post" значит запустить команду после. "flush" хук запускается после того как ferm зафлашит файерволл правила (опция --flush). Ты можешь установить любое количество хуков.
Встроенные функции
Здесь некоторые встроенные функции, которые ты можешь найти полезными.
@defined($name), @defined(&name)
Тестирует определена ли функция или переменная.
@def $a = 'foo';
@if @defined($a) good;
@if @not(@defined($a)) bad;
@if @defined(&funcname) good;
@eq(a,b)
Тестирует два значения на равенство. Например:
@if @eq($DOMAIN, ip6) DROP;
@ne(a,b)
Похоже на @eq, оно тестирует на неравенство.
@not(x)
Инвертирует логическое значение.
@resolve((hostname1 hostname2 ...), [type])
Обычно, хостнэймы резолвятся iptables'ом. Чтобы позволить ferm'у резолвить хостнэймы, используй функцию @resolve:
saddr @resolve(my.host.foo) proto tcp dport ssh ACCEPT;
saddr @resolve((another.host.foo third.host.foo)) proto tcp dport openvpn ACCEPT;
daddr @resolve(ipv6.google.com, AAAA) proto tcp dport http ACCEPT;
Отметь двойные скобки на второй строке: внутренняя пара создает список, в внешняя как разделитель параметров функции.
Второй параметр опционален и определяет тип DNS записи. По умолчанию это "A" для домена ip и "AAAA" для домена ip6.
Будь аккуратен с зарезолвленными хостнэймами в конфигурации файерволла. DNS запросы могут блокировать конфигурирование файерволла на долгое время, оставляя машину уязвимой, или они могут фэйлиться.
@cat(a, b, ...)
Конкатенирует все параметры в одну строку.
@join(separator, a, b, ...)
Объединяет все параметры в одну строку разделяя указанным разделителем.
@substr(expression, offset, length)
Извлекает подстроку из выражения и возвращает ее. Первый символ имеет отступ 0. Если OFFSET отрицательный, то отсчитывается настолько же далеко от конца строки.
@length(expression)
Возвращает длину выражения в символах.
@basename(path)
Возвращает базовое имя файла для указанного пути (File::Spec::splitpath).
@dirname(path)
Возвращает имя последней директории для указанного пути, предполагая что последний компонент это имя файла (File::Spec::splitpath).
@glob(path)
Разворачивает shell wildcard'ы в указанных путях (предполагается что они относительны к текущему скрипту). Возвращает список заматченных файлов. Эта функция полезна как параметр для @include.
@ipfilter(list)
Отфильтровывает IP адреса которые, очевидно, не подходят под текущий домен. Это полезно для создания общих переменных и правил для IPv4 и IPv6:
@def $TRUSTED_HOSTS = (192.168.0.40 2001:abcd:ef::40);
domain (ip ip6) chain INPUT {
saddr @ipfilter($TRUSTED_HOSTS) proto tcp dport ssh ACCEPT;
}
РЕЦЕПТЫ
Директория ./examples/ содержит многочисленные ferm конфигурации, которые могут быть использованы для начала в новом файерволле. Эта секция содержит много примеров, рецептов и трюков.
Легкий проброс портов
Ferm функции делают рутинные задачи быстрыми и легкими:
@def &FORWARD_TCP($proto, $port, $dest) = {
table filter chain FORWARD interface $DEV_WORLD outerface $DEV_DMZ daddr $dest proto $proto dport $port ACCEPT;
table nat chain PREROUTING interface $DEV_WORLD daddr $HOST_STATIC proto $proto dport $port DNAT to $dest;
}
&FORWARD_TCP(tcp, http, 192.168.1.2);
&FORWARD_TCP(tcp, smtp, 192.168.1.3);
&FORWARD_TCP((tcp udp), domain, 192.168.1.4);
Удаленный ferm
Если удаленная машина не способна запустить ferm по каким-то причинам (может быть не имеется Perl), то ты можешь редактировать конфигурационный файл ferm на другом компьютере и дать ferm'у сгенерировать shell скрипт.
Пример для OpenWRT:
ferm --remote --shell mywrt/ferm.conf >mywrt/firewall.user
chmod +x mywrt/firewall.user
scp mywrt/firewall.user mywrt.local.net:/etc/
ssh mywrt.local.net /etc/firewall.user
ОПЦИИ
- --noexec - Не выполнят iptables(8) команды, а пропускать их. С помощью этого ты можешь парсить свои данные, используй --lines для отображения вывода.
- --flush - Очистить файерволл правила и установить политики всех цепочек в ACCEPT. ferm'у потребуется конфигурационный файл чтобы понять какие домены и таблицы пострадают.
- --lines - Отображать строки которые были сгенерированы из правил. Они будут показаны перед тем как будут исполнены, поэтому если ты получишь сообщение об ошибке из iptables(8) итд, то ты сможешь увидеть какое правило вызвало ошибку.
- --interactive - Применять правила и спрашивать подтверждение у пользователя. Отменяет предыдущий набор правил если не было пользовательского ответа в течение 30 секунд (см. ---timeout). Это полезно для удаленного администрирования файерволла: ты можешь тестировать правила без страха заблокировать себе доступ.
- --timeout S - Если используется --interactive, то делает откат если в течение указанного количества секунд не было валидного пользовательского ответа. По умолчанию 30.
- --help - Показывает краткий список доступных опций.
- --version - Показывает номер версии программы.
-
--fast - Включает быстрый режим: ferm генерирует iptables-save(8) файл и устанавливает его через iptables-restore(8). Это намного быстрее, потому что по умолчанию ferm вызывает iptables(8) по одному разу на каждое правило.
Быстрый режим включен по умолчанию начиная с ferm 2.0, и эта опция задепрекейчена. - --slow - Отключает быстрый режим, т.е. запускает iptables(8) для каждого правила и не использует iptables-restore(8).
- --shell - Генерирует shell скрипт, который вызывает iptables-restore(8) и печатает. Заключает в себе --fast и --lines.
- --remote - Генерирует правила для удаленной машины. Подразумевает --noexec и --lines. Может быть скомбинирован с --shell.
- --domain {ip|ip6} - Обрабатывает только указанный домен и выбирает его как домен по умолчанию для правил где он не определен. Вывод ferm может быть пустым если домен не сконфигурирован во входном файле.
- --def '$name=value' - Переопределяет переменные определенные в конфигрурационном файле.
СМОТРИ ТАКЖЕ
iptables(8)
ТРЕБОВАНИЯ
Операционная система
Linux 2.4 или новее, с поддержкой netfilter и всеми модулями которые используются твоими скриптами
Программное обеспечение
iptables и perl 5.6
БАГИ
Баги? Какие еще баги?
Если ты нашел баг, пожалуйста уведоми об этом на GitHub: https://github.com/MaxKellermann/ferm/issues
КОПИРАЙТ
Copyright 2001-2017 Max Kellermann max.kellermann@gmail.com, Auke Kok sofar@foo-projects.org and various other contributors.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
АВТОР
Max Kellermann max.kellermann@gmail.com, Auke Kok sofar@foo-projects.org
openssl
Проверить соответствие Root.crt - User.crt
openssl verify -CAfile root.crt user.crt
Проверить соответствие user.crt - user.key
openssl x509 -noout -modulus -in certificate_name.crt | openssl md5
openssl rsa -noout -modulus -in certificate_name.key | openssl md5
Процесс загрузки ядра Linux
systemd/systemctl
Команда systemctl
без параметров или с подкомандой list-units
выведет список запущенных юнитов
Вывод выглядит такboot.mount loaded active mounted /boot
-
UNIT -
boot.mount
- Название юнита и его тип -
LOAD -
loaded
- Состояние юнита, загружен или нет -
ACTIVE -
active
- Обобщенный статус -
SUB -
mounted
- Текущий статус -
DESCRIPTION -
/boot
- Описание
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
JOB = Pending job for the unit.
Параметр --failed
покажет список юнитов, запуск которых не удался
root@mars:~# systemctl --failed
0 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
Файлы юнитов находятся в /usr/lib/systemd/system/
и /etc/systemd/system/
(последний каталог имеет приоритет). Команда systemctl list-unit-files
покажет список установленных юнитов
Юнитами могут быть сервисы, точки монтирования, устройства или сокеты
Обычно при использовании systemctl
нужно указывать полное имя файла юнита (вметсе с суффиксом типа - sshd.socket
). Но есть сокращения:
- Если суффикс не указан, то предполагается что это сервис
- Точки монтирования автоматически преобразуются в
mount
(напр./home
->home.mount
) - Имена устройств автоматически преобразуются в
device
(напр./dev/sda2
->dev-sda2.device
)
Некоторые юниты содержат в названии символ
@
-название@строка.service
Это значит что они являются экземплярами юнита-шаблона. Имя юнита шаблона не содержит частистрока
-название@.service
строка
- это идентификатор экземпляра
-
systemctl help ntp.service
- показать man для юнита -
systemctl status ntp.service
- статус юнита -
systemctl is-enabled ntp.service
- добавлен ли в автозагрузку -
systemctl start/stop/restart/reload/enable/disable ntp.servec
- и так понятно -
systemctl daemon-reload
- systemd при запуске загружает файлы юнитов с файловой системы в память, при изменении файла юнита, systemd изменения не увидит. Эта команда заставит systemd перечитать все юниты заново (и мягко перезапустит их)
systemctl mask/unmask ntp.service
- маскирует юнит. Это делает невозможным его запуск
root@mars:/etc/systemd/system# systemctl mask ntp.service
Created symlink /etc/systemd/system/ntp.service → /dev/null.
root@mars:/etc/systemd/system# systemctl stop ntp.service
root@mars:/etc/systemd/system# systemctl start ntp.service
Failed to start ntp.service: Unit ntp.service is masked.
Файлы юнитов загружаются из разных мест, и чтобы увидеть эти места можно выполнить такую команду
root@mars:/etc/systemd# systemctl show --property=UnitPath
UnitPath=/etc/systemd/system.control /run/systemd/system.control /run/systemd/transient /etc/systemd/system /run/systemd/system /run/systemd/generator /lib/systemd/system /run/systemd/generator.late
-
/usr/lib/systemd/system/
- юниты, предоставляемые пакетами при их установке -
/etc/systemd/system/
- юниты, устанавливаемые системным администратором
В файлах юнитов допустимы комментарии. Но каждый комментарий на отдельной строке. Комментарий начинается с решетки
Юнит файлы пакетов редактировать напрямую не стоит. Это вызовет проблемы с пакетным менеджером. Есть два пути редактирования юнит файла пакета (см. документацию)
Файлы из /etc/systemd/system/
переопределяют /usr/lib/systemd/system
А для того чтобы новый файл подтянулся, нужно выполнить systemctl reenable UNIT
Это можно сделать через утилиту systemctl edit --full UNIT
Она либо откроет файл из /etc/...
, либо скопирует файл из /usr/lib/...
в /etc/...
и после редактирования автоматически перезагрузит все что нужно
Но этот метод может вызвать проблемы с пакетным менеджером
Также можно переопределять юнит файлы через drop-in файлы. Нужно создать каталог /etc/systemd/system/UNIT.d/
и в нем создать .conf файлы (описываются так же как и юнит-файлы). systemd будет применять эти файлы поверх оригинального
Это делает команда systemctl edit UNIT
(без флага --full
)
Чтобы отменить изменения сделанные через
edit
нужно выполнитьsystemctl revert UNIT
Для просмотра юнитов можно использовать systemctl cat ntp.service
systemd-delta
- позволяет увидеть какие есть оверрайды для каких юнитов
root@mars:/etc/systemd# systemd-delta
[OVERRIDDEN] /etc/systemd/system/ntp.service → /usr/lib/systemd/system/ntp.service
Files /usr/lib/systemd/system/ntp.service and /etc/systemd/system/ntp.service are identical
[EXTENDED] /usr/lib/systemd/system/rc-local.service → /usr/lib/systemd/system/rc-local.service.d/debian.conf
[EXTENDED] /usr/lib/systemd/system/systemd-resolved.service → /usr/lib/systemd/system/systemd-resolved.service.d/resolvconf.conf
[EXTENDED] /usr/lib/systemd/system/systemd-timesyncd.service → /usr/lib/systemd/system/systemd-timesyncd.service.d/disable-with-time-daemon.conf
4 overridden configuration files found.
Цели ( target ) используются для группировки юнитов по зависимостям в качестве точек синхронизации (как уровни запуска)
Показать все текущие цели можно такой командой
systemctl list-units --type=target
Уровни запуска, имеющие определённое значение в sysvinit (0, 1, 3, 5 и 6), один в один соответствуют конкретным целям systemd
Уровнень запуска SysV | Цель systemd | Примечания |
---|---|---|
0 | runlevel0.target, poweroff.target | Выключение системы |
1, s, single | runlevel1.target, rescue.target | Однопользовательский уровень запуска |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | Уровни запуска, определенные пользователем/специфичные для узла. По умолчанию соответствует уровню запуска 3 |
3 | runlevel3.target, multi-user.target | Многопользовательский режим без графики. Пользователи, как правило, входят в систему при помощи множества консолей или через сеть |
5 | runlevel5.target, graphical.target | Многопользовательский режим с графикой. Обычно эквивалентен запуску всех служб на уровне 3 и графического менеджера входа в систему |
6 | runlevel6.target, reboot.target | Перезагрузка |
emergency | emergency.target | Аварийная оболочка |
Переключаться между режимами можно так
systemctl isolate default.target
systemctl isolate rescue.target
systemctl isolate emergency.target
systemctl default
systemctl rescue
systemctl emergency
systemctl reboot
systemctl poweroff
Создаёте новый юнит-цель с названием
/etc/systemd/system/цель
, который берет за основу один из существующих уровней запуска (взгляните, например, на/usr/lib/systemd/system/graphical.target
), создаёте каталог/etc/systemd/system/цель.wants
, а после этого — символические ссылки на те службы из каталога/usr/lib/systemd/system/
, которые вы хотите включить при загрузке
Зависимости, о которых сказано выше, можно добавлять с помощью команд
systemctl add-wants <target-unit-name> <requirement-name>
systemctl add-requires <target-unit-name> <requirement-name>
Изменить текущую цель можно командой systemctl isolate UNIT.target
Это не повлияет на последующие загрузки (только на текущую)
Стандартная цель это default.target
Узнать текущую цель можно так
# systemctl get-default
graphical.target
А указать цель можно через systemctl set-default UNIT
Также это можно указать через параметры ядра
systemd.mount - отвечает за монтирование разделов и ФС из файла /etc/fstab
systemd-tmpfiles позволяет управлять временными файлами и каталогами (пример: samba предполагает что существует каталог /run/samba с нужными правами доступа)
systemctl preset <unit-name>
Восстановит параметры автозагрузки по умолчанию, т. е. если изначально юнит не загружался автоматически, а это было изменено администратором, то юнит будет извлечён из автозагрузки
Бывает так что юнит файл находится вне путей стандартного авто-поиска юнитов
В этом случае можно слинковать этот файл в нужно место
systemctl preset <unit-name>
Эта команда создаст ссылку в на файл в нужной папке
systemctl revert <unit-name>
Восстановит юнит-файл к изначальному состоянию. Сотрет drop-in юниты, отменит результаты команд edit
, set-property
, mask
С помощью systemctl show-environment
можно увидеть переменные окружения которые доступны всем запускаемым юнитам
Устанавливать переменные можно через set-environment
systemctl set-environment MY_VAR=test
А удалять через unset-environment
systemctl unset-environment MY_VAR
LVM
https://www.dmosk.ru/instruktions.php?object=lvm
Base
Существует проблема правильного разбиения дисков на разделы. В какой-то момент во время работы системы одни разделы остаются свободными, а другие забиваются под завязку. Эту проблему решает LVM
LVM - Logical Volume Manager
Позволяет делать снапшоты, легко добавлять новые физические диски, позволяет уменьшать и расширять тома без размонтирования
Работа с томати организована на трех уровнях:
- Физический том (PV) - физический диск и раздел на диске
- Группа томов (VG) - объединение физических томов
- Логический том (LV) - раздел группы томов
PV и LV делятся на экстенды PE и LE (физические и логический экстенд соответственно)
Создание разделов
- Помечаем нужные диски как PV
root@osboxes:~# pvcreate /dev/sdb /dev/sdc
Physical volume "/dev/sdb" successfully created.
Physical volume "/dev/sdc" successfully created.
- Проверяем командой
pvdisplay
- Создаем из этих дисков VG
root@osboxes:~# vgcreate vg01 /dev/sdb /dev/sdc Volume group "vg01" successfully created
- Проверяем командой
vgdisplay
- Создаем логический раздел
root@osboxes:~# lvcreate -L 2.19G vg01
Rounding up size to full physical extent 2.19 GiB
Logical volume "lvol0" created.
- Проверяем командой
lvdisplay
В выводе будет путь до разделаLV Path /dev/vg01/lvol0
- Создаем ФС
mkfs.ext4 vg01/lvol0
- Монтируем
mount /dev/vg01/lvol0 /mnt
- Готово
lsblk
sdb 8:16 0 1G 0 disk
└─vg01-lvol0 254:0 0 2.2G 0 lvm /mnt
sdc 8:32 0 1.2G 0 disk
└─vg01-lvol0 254:0 0 2.2G 0 lvm /mnt
df -h /mnt
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg01-lvol0 2.1G 150M 1.9G 8% /mnt
Командой pvs
можно получить краткую информацию о lvm дисках
pvs
PV VG Fmt Attr PSize PFree
/dev/sdb vg01 lvm2 a-- 1.03g 8.00m
/dev/sdc vg01 lvm2 a-- <1.17g 0
pvdisplay
покажет информацию о дисках в развернутом виде
vgs
покажет информацию о группах
vgs
VG #PV #LV #SN Attr VSize VFree
vg01 2 1 0 wz--n- <2.20g 8.00m
vgdisplay
- более подробно
lvs
покажет информацию о логических томах (подробный вывод в lvdisplay
)
lvmdiskscan
покажет lvm диски
Расширить логический диск за счет свободного места в волюм группе можно так
root@osboxes:~# vgs
VG #PV #LV #SN Attr VSize VFree
vg01 2 1 0 wz--n- <2.20g 8.00m
root@osboxes:~# lvextend -l +100%FREE /dev/vg01/lvol0
Size of logical volume vg01/lvol0 changed from 2.19 GiB (561 extents) to <2.20 GiB (563 extents).
Logical volume vg01/lvol0 successfully resized.
root@osboxes:~# vgs
VG #PV #LV #SN Attr VSize VFree
vg01 2 1 0 wz--n- <2.20g 0
Расширить группу томов за счет нового диска
vgextend vg01 /dev/sdd
Для уменьшения логического тома требуется его отмонтировать
network
For up interface on boot and DHCP configuring you need edit /etc/network/interfaces
auto eth0
iface eth0 inet dhcp
For static configuration
auto eth0
iface eth0 inet static
address 192.168.1.254
netmask 255.255.255.0
network 192.168.1.0
broadcast 192.168.1.255
gateway 192.168.1.1
After editing conf files you need restart network service
sudo /etc/init.d/networking restart
dvorak in console
Чтобы сработала команда loadkeys dvorak
нужно чтобы был установлен пакет console-data
ini
Комментарии
Обозначаются точкой с запятой ;
От точки с запятой до конца строки
Идентификаторы
Могут содержать в себе a-z, A-Z, 0-9, _, ~, -, ., :, $, space
, начинаются с a-z, A-Z, . , $, :
Регистр важен
Секции
Это часть конфига обозначенная идентификатором
Секция обозначается заголовком в квадратных скобках
Пример
[Defaults]
Одна секция заканчивается там где начинается другая секция
Секция не может быть разделена на несколько частей, каждый идентификатор секции может встречаться в конфиге лишь однажды (в рамках одного файла)
Секция может быть пустой (т.е. содержать в себе 0+ опций)
Опции
Опция это пара идентификатор=значение
в какой-либо секции
Пробелы в начале или конце идентификатора или значения нужно экранировать
Пробелы между словами в идентификаторе или значении экранировать не надо
Значение может быть представлено одним или несколькими элементами разделенными запятой ,
или двоеточием :
. Если в значении присутствуют оба разделителя, то будет выбрана запятая (у нее приоритет выше)
Элемент
Элемент это текст стоящий в паре с идентификатором опции
Текст элемента может быть связан с другим элементом (даже в разных секциях)
- Ссылки форматируются так:
${section#option}
- Слинкованные элементы обрабатываются в следующем порядке:
- Сначала вставляется текст указанного элемента
- Обрабатываются спецсимволы и команды из вставленного текста (это может влиять на результат)
- Ссылка не будет обработана как ссылка если перед долларом стоит бэкслэш
\
Типы данных
Элемент может быть определенного типа
-
boolean
-
False
0
f
n
off
no
disabled
-
True
1
t
y
on
yes
enabled
-
False
-
signed и unsigned - 64 битное по умолчанию десятичное число со знаком и без
- Шестнадцатиричное префиксируется -
0x
- Восьмиричное -
0
- Бинарное -
0b
- Шестнадцатиричное префиксируется -
- float - 64 битное с плавающей точкой
- enum - значение из предопределенного сета значений
-
string - может содержать разные символы кроме
,
,:
,;
, они должны быть заэкранированы через\
Примеры
[Section 1]
; comment
Option 1 = value 1 ; option 'Option 1' has value 'value 1'
oPtion 1 = \ value 2\ \ \ ; option 'oPtion 1' has value ' value 2 ', 'oPtion 1' and 'Option 1' are different
[$Section::subsection] ; no subsection, only valid identifier of section
Option 2=value 1:value 2:value 3 ; option 'Option 2' is list of 'value 1', 'value 2' and 'value 3'
Option 3 =value 1, ${Section 1#Option 1} ; option 'Option 3' is list of 'value 1' and 'value 1'
Option 4= v1,${$Section::subsection#Option 3},v2 ; option 'Option 4' is list of 'v1', 'value 1', 'value 1', 'v2'
Option 5= v1, v2:v3 ; option 'Option 5' is list of 'v1' a 'v2:v3'
[Numbers]
num = -1285
num_bin = 0b01101001
num_hex = 0x12ae,0xAc2B
num_oct = 01754
float1 = -124.45667356
float2 = +4.1234565E+45
float3 = 412.34565e45
float4 = -1.1245864E-6
[Other]
bool1 = 1
bool2 = on
bool3=f
apt sources list
https://wiki.debian.org/ru/SourcesList
/etc/apt/sources.list - apt использует этот файл в качестве хранилища источников пакетов
Строки в этом файле выглядят примерно так
deb http://mirror.yandex.ru/debian buster main contrib
deb-src http://mirror.yandex.ru/debian buster main contrib
deb http://security.debian.org/debian-security buster/updates main contrib
deb-src http://security.debian.org/debian-security buster/updates main contrib
Первое слово в каждой строке это тип архивов в этом репозитории
- deb - значит что в репе содержатся deb-пакеты
- deb-src - в репе содержатся исходники
Дальше идет ссылка на репозиторий
За ссылкой идет псевдоним релиза (jessie, stretch, buster, sid), либо класс релиза (stable, oldstable, testing, unstable)
Потом идут компоненты
- main - dfsg-совместимые
- contrib - сами по себе dfsg-совместимые, но имеют зависимости не из main
- non-free - dfsg-несовместимые
Бывают репы из тора, apt умеет работать и с ними
MSSQL
Как подключиться к mssql с linux
# Сперва поднял туннель со своей машины до mssql базы через сервер с репликатором (чтобы как будто мы с репликатора ходим)
root@c58882dda0d8:~# ssh -4 -L localhost:1234:srv-pro-db07.i-free.pro:1433 i.dudin_pro@vas73.g01.i-free.ru -N &
[1] 1818
# Проверяем что все слушается
root@c58882dda0d8:~# ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 128 127.0.0.1:1234 *:* users:(("ssh",pid=1818,fd=4))
# Подключаемся
root@c58882dda0d8:~# sqlcmd -S tcp:127.0.0.1,1234 -d DB2DB_Replicator -U db2db_agent_msg3_interactive -P PASSWORD
1> :setvar SQLCMDMAXVARTYPEWIDTH 30
2> select top 10 id, name, rule_id from filter_log;
3> go
id name rule_id
-------------------- ------------------------------ -----------
1930921024 DBInboundFilter 308
1930921025 DBOutboundFilter 80643
1930921026 DBInboundFilter 81028
1930921027 DBOutboundFilter 79961
1930921028 DBOutboundFilter 79961
1930921029 DBOutboundFilter 79961
1930921030 DBInboundFilter 79858
1930921031 DBInboundFilter 79858
1930921032 DBOutboundFilter 80799
1930921033 DBOutboundFilter 79859
(10 rows affected)
BASH
Заметки из книги "BASH. Карманный справочник системного администратора"
bash-huyash
Команды оболочки bash можно выполнять с терминала, из файла (когда первым аргументом передано имя файла) или можно подавать баш скрипты на вход команде bash:
macbook:~ vandud$ echo "echo govno" | bash
govno
macbook:~ vandud$ echo "echo govno" | bash -s
govno
Ключ -i
запустит оболочку и покажет приглашение:
macbook:~ vandud$ bash -i
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
bash-3.2$ echo "echo 'mocha i govno'" | bash -s
mocha i govno
bash-3.2$
Исходные оболочки читают содержимое файлов /etc/profile и -/.profile, а обычные оболочки - содержимое переменной окружения $ENV, если она установлена
Исходная оболочка это та которая служит для входа в систему
--init-file
/--rcfile
- переопределить ~/.bashrc
-
$0
- имя сценария -
$1
- первый аргумент -
$N
- N-ный аргумент
macbook:test vandud$ cat test
echo "govno"
macbook:test vandud$ ls -l test
-rw-r--r-- 1 vandud wheel 13 Feb 19 07:22 test
macbook:test vandud$ ./test
-bash: ./test: Permission denied
macbook:test vandud$ bash test
govno
Код завершения команды доступен в переменной $?
Внутренние команды оболочки передают этот код непосредственно оболочке, а внешние команды передают его операционной системе
Значение кода завершения может находиться в диапазоне от 0 до 255
Инит файлы читаются в следующем порядке
- /etc/profile
- Первый найденный из ~/.bash_profile, ~/.bash_login или ~/.profile
- ~/.bashrc читается неисходными оболочками, но не читается если оболочка запущена как sh или с параметром --posix (в этих двух случаях читается $ENV)
При выходе из интерактивной оболочки выполняется ~/.bash_logout (при наличии)
Интересный момент про ссылки
macbook:test vandud$ cat test
echo $0
macbook:test vandud$ ls -lh
total 8
-rwxr--r-- 1 vandud wheel 8B Feb 19 10:22 test
lrwxr-xr-x 1 vandud wheel 4B Feb 19 10:22 test2 -> test
macbook:test vandud$ ./test
./test
macbook:test vandud$ ./test2
./test2
Существует сокращение для получения хомяка пользователя
vandud@macbook test % grep logd /etc/passwd
_logd:*:272:272:Log Daemon:/var/db/diagnostics:/usr/bin/false
vandud@macbook test % echo ~_logd
/var/db/diagnostics
Немного про глоббинг
Базовые штуки
- * - любое кол-во любых символов
- ? - один любой символ
- [a-zA-Z0-9] - один любой символ из перечисленных
- ~ - хомяк
- ~username - хомяк username'a
- ~+ - текущая дира (аналогично pwd)
- ~- - предыдущая дира
Для этих нужно чтоб был включен параметр extglob (в bash он ставится через shopt -s extglob
, в zsh через setopt)
- ?(pattern) - 0-1 вхождений паттерна
- *(pattern) - 0+ вхождений
- +(pattern) - 1+ вхождений
- @(pattern) - точное совпадение с одним паттерном
- !(pattern) - все что точно не шаблон
Шаблонов может быть много, тогда их нужно разделять пайпом
Классы символов (для них тоже требуется extglob)
Указываются в [[:<class>:]]
- alnum - буквоцифры
- alpha - буквы
- ascii - ASCII
- blank - пробелы и табы
- cntrl - управляющие символы
- digit - десятичные цифры
- graph - непробельные
- lower - строчные
- upper - прописные
- print - печатаемые
- punct - знаки препинания
- space - пробелы
- word - то же что и alnum
- xdigit - шестнадцатиричные
Скрипты читаются построчно
Каждая строка сначала читается, потом проверяется на синтаксис, а потом уже выполняется
Поэтому, например, нельзя определить алиас и вызвать его в одной строке
Нужно учитывать аналогичные примеру операции
Подстановки (выше) и раскрытие скобок отличаются
При раскрытии скобок образуется текст, который не обязательно должен совпадать с уже существующими файлами
Есть два варианта раскрытия скобок
vandud@macbook test % echo head{A,B,C}tail
headAtail headBtail headCtail
vandud@macbook test % echo head{A..C}tail
headAtail headBtail headCtail
vandud@macbook test % echo head{1..5..2}tail
head1tail head3tail head5tail
В числовом выражении предел start может предваряться нулями
vandud@macbook test % echo head{001..5..2}tail
head001tail head003tail head005tail
vandud@macbook test % echo head{01..005..2}tail
head01tail head03tail head05tail
По длине числа start будут выровняны раскрытые числа
vandud@macbook test % echo {0..10..5}
0 5 10
vandud@macbook test % echo {00..10..5}
00 05 10
vandud@macbook test % echo {000..10..5}
000 005 010
vandud@macbook test % echo {0000..10..5}
0000 0005 0010
Скобки могут быть вложенными
vandud@macbook test % echo {a,b,{1..4}}
a b 1 2 3 4
vandud@macbook test % echo {a..b..{1..4}}
{a..b..1} {a..b..2} {a..b..3} {a..b..4}
vandud@macbook test % echo {a..b..{1..5..2}}
{a..b..1} {a..b..3} {a..b..5}
Скобки должны быть без кавычек, иначе баш не распарсит
Подстановки команд будут проигнорированы при раскрытии скобок (но у меня в zsh работает, в баше не смог)
vandud@macbook test % echo {1..10..$(echo 3)}
1 4 7 10
vandud@macbook test % echo {1..10..`echo 3`}
1 4 7 10
vandud@macbook test % echo hi{DD,BB,CC,AA}bitch
hiDDbitch hiBBbitch hiCCbitch hiAAbitch
vandud@macbook test % ls LKz{QQ,Qt}e0f
LKzQQe0f LKzQte0f
В качестве элемента внутри скобок может быть и пустота
vandud@macbook test % ls zhopa*
zhopa
vandud@macbook test % mv zhopa{,_s_gavnoy}
vandud@macbook test % ls zhopa*
zhopa_s_gavnoy
Управляющие последовательности распознаются и интерпретируются в след. контекстах
- $'...'
- аргументы в
echo -e
иprintf%b
В кавычках отменяется спец. значение символов, например скобок, стрелок, итд
Внутри двойных кавычек действует доллар и тик
- $ - для подстановки переменных, комманд или арифметики
- ` - для подстановки комманд
Внутри одинарных кавычек все становится обычным текстом
\ - используется для экранирования
- cmd & - в фоне
- { cmd ; cmd ; } - в текущей оболочке
- ( cmd ; cmd ; ) - в подоболочке
- cmd | cmd - пайп
- cmd `cmd` - подстановка (без вложенности)
- cmd $(cmd) - подстановка (возможна вложенность)
- cmd $((cmd)) - арифметика
- cmd1 && cmd2 - выполнить cmd2 только если cmd1 выполнился успешно
- cmd || cmd - выполнить cmd2 если cmd1 сломался
- !cmd - инвертировать код ответа
cmd < filename
vandud@macbook test % cat zhopa_s_gavnoy | cat
asonetuhaoesntuhsanoethustaoehustnaoehusnaeohus
vandud@macbook test % cat < zhopa_s_gavnoy
asonetuhaoesntuhsanoethustaoehustnaoehusnaeohus
vandud@macbook test % cat zhopa_s_gavnoy | grep -o 'aso'
aso
vandud@macbook test % grep -o 'aso' < zhopa_s_gavnoy
aso
То же самое что и выше, только данные берутся не из файла а из текста
cmd << text
vandud@macbook test % cat <<< "niga mazafaka bitch"
niga mazafaka bitch
vandud@macbook test % echo "niga mazafaka bitch" | cat
niga mazafaka bitch
cmd << EOF
vandud@macbook test % cat << ZHOPA | grep -i niga
pipe heredoc> niga1
pipe heredoc> niiga2
pipe heredoc> zhopa
pipe heredoc> ZHOPA
niga1
>| - позволяет перезаписать файл даже если включен параметр noclobber
bash-3.2$ set -o | grep clobber
noclobber off
bash-3.2$ cat test
govno
bash-3.2$ echo "zhopa" > test
bash-3.2$ cat test
zhopa
bash-3.2$ set -o noclobber
bash-3.2$ set -o | grep clobber
noclobber on
bash-3.2$ cat test
zhopa
bash-3.2$ echo "govno" > test
bash: test: cannot overwrite existing file
bash-3.2$ cat test
zhopa
bash-3.2$ echo "govno" >| test # SUCCESS
bash-3.2$ cat test
govno
bash-3.2$
О параметрах
У оболочки есть разные параметры
Один из них упоминался ранее (extglob)
Для просмотра и установки этих параметров можно использовать команду set или shopt
Существует сразу две команды потому что set (и параметры с которыми можно взаимодействовать через него) унаследовался вместе с bourne-style (от sh), а shopt появился в bash. Поэтому некоторые параметры могут быть не видны в одном и видны в другом
Посмотреть текущее состояние можно так
set -o
shopt
Активировать так
set -o noclobber # enable
set +o noclobber # disable
shopt -s extglob # enable
shopt -u extglob # disable
-
cdspell - исправляет опечатки
bash-3.2$ shopt -s cdspell bash-3.2$ ls -lh total 0 drwxr-xr-x 2 vandud wheel 64B Feb 22 18:30 aoeu bash-3.2$ cd aoue aoeu bash-3.2$ pwd /tmp/test/aoeu
-
autocd - по дефолту баш выполняет указанный файл, а эта опция позволяет переходить по переданному пути если передана папка а не файл
root@phobos:/tmp# shopt -s autocd root@phobos:/tmp# /etc cd -- /etc root@phobos:/etc# shopt -u autocd root@phobos:/etc# /etc -bash: /etc: Is a directory
-
histverify - при вводе
!!
не будет выполнять сразуbash-3.2$ shopt -s histverify bash-3.2$ echo "test" test bash-3.2$ sudo !! bash-3.2$ sudo echo "test" ^C # ВОТ bash-3.2$ shopt -u histverify bash-3.2$ echo "test" test bash-3.2$ sudo !! # А ТУТ СРАЗУ ПРИМЕНИЛО sudo echo "test" Password:
Параметров всяких целая куча, тут парочку показал для примера
Перенаправление вывода по дескриптору
- stdoud направить в файл с дескриптором n
cmd >&n
- (stdout + то что cmd пишет в файл с дескриптором m) направить в файл с дескриптором n
cmd m>&n
- закрыть stdout
cmd >&-
Пробел между стрелкой и ФД не нужен
stderr в stdout
root@mars:/var/tmp/test# nginx 2>&1 | tee nginx.out
root@mars:/var/tmp/test# nginx |& tee nginx.out
bash doc
http://www.gnu.org/software/bash/manual/bash.html
1 Introduction
1.1 Что такое Bash
Bash это шелл, или командный интерпретатор для операционных систем GNU. Имя является акронимом от 'Bourne-Again SHell', игрой слов на Стивена Борна, автора прямого предка текущего Unix шелла - sh, который появился в Седьмом Издании Bell Labs Research версии Unix.
Bash хорошо совместим с sh и объединяет в себе полезные фишки из Korn shell ksh и C shell csh. Он направлен на то чтобы быть совместимой имплементацией 'IEEE POSIX Shell and Tools' которая является частью спецификации POSIX. Он предлагает улучшения функционала поверх sh сразу для интерактивности и использования в программировании.
Операционные системы GNU предоставляют другие шеллы, включая csh, Bash является шеллом по умолчанию. Как и другое ПО GNU, Bash полностью портабельный. На данный момент он запускается на почти каждом Unix'e и нескольких других ОС - существуют порты для MS-DOS, OS/2 и Windows которые поддерживаются независимыми разработчиками.
1.2 Что такое Шелл
В основе, шелл это макропроцессор который выполняет команды. Термин макропроцессор обозначает функциональность при которой текст и символы расширяются до больших выражений.
Unix шелл одновременно и интерпретатор команд и язык программирования. Как интерпретатор команд шелл предоставляет пользовательский интерфейс к богатому набору GNU утилит. Как язык программирования он позволяет комбинировать эти утилиты. Можно создавать файлы с командами и делать их командами. Эти новые команды могут иметь такой же статус как и системные команды в таких директориях как /bin, позволяя пользователям или группам создавать кастомные условия для автоматизации их повседневных задач.
Шеллы могут использоваться интерактивно или неинтерактивно. В интерактивном режиме они позволяют делать ввод с клавиатуры. В неинтерактивном шеллы выполняют команды читая их из файла.
Шелл позволяет выполнять GNU команды синхронно и асинхронно. Шелл ждет окончания выполнения синхронной команды прежде чем разрешить вводить новые команды; асинхронные команды продолжают выполнение в параллели с шеллом пока он читает и выполняет дополнительные команды. Перенаправления позволяют тонко контролировать ввод и вывод команд. Кроме того шелл позволяет контролировать окружения команд.
Шеллы также предоставляют небольшой набор встроенных команд (builtins) давая функциональность которую невозможно или неудобно получить через выделенные утилиты. Например, cd, break, continue и exec не могут быть выполнены снаружи шелла, потому что они направлены на управление самим шеллом. Встроенные history, getopts, kill или pwd могут быть имплементированы в выделенных утилитах, но их гораздо удобнее использовать как встроенные команды. Все встроенные команды будут описаны ниже.
Хоть выполнение команд это и суть оболочки, основная мощь (и сложность) связана с внутренним языком программирования. Как и любой высокоуровневый язык, шелл предоставляет переменные, конструкции для конроля над потоком выполнения, кавычки и функции.
Шеллы предлагают функции специфические для интерактивного использования, а не для расширения возможностей языка программирования. Эти интерактивные функции включают контроль над задачами, редактирование командной строки, историю команд и алиасы. Каждая из этих функций будет описана в этом мануале.
2 Определения
Эти определения используются во всей оставшейся части этого манула.
- POSIX - Семейство стандартов открытых систем основанных на Unix. Bash относится к части 'Shells and Utilities' стандарта POSIX 1003.1
- blank - Символ пробела или таба
- builtin - Команды которые имплементированы внутри самого шелла, вместо исполняемого файла где-либо в файловой системе
-
control operator - Символ который выполняет контролирующую функцию. Им может быть символ новой строки или один из следующих символов:
||
,&&
,&
,;
,;;
,;&
,;;&
,|
,|&
,(
или)
- exit status - Значение возвращенное командой тому кто ее вызвал. Это значение ограничено 8 битами, таким образом максимальное значение - 255
- field - Часть текста которая является результатом одного из расширений шелла. После расширения при исполнении команды результирующие поля используются как имя команды и ее аргументы
- filename - Строка символов используемая для идентификации файла
- job - Набор процессов составляющих пайплайн и некоторые процессы происходящие от него, которые находятся в одной группе процессов
- job control - Механизм которым пользователи могут выборочно останавливать (suspend) и перезапускать (resume) выполнение процессов
-
metacharacter - Символ который, когда раскавыченный, разделяет слова. Метасимвол это пробел, таб, новая строка или один из следующих символов:
|
,&
,;
,(
,)
,<
или>
- name - word состоящее исключительно из букв, цифр и подчеркиваний, и начинающееся с буквы или подчеркивания. Names используются как имена переменых и функций. То же что и identifier
- operator - control operator или redirection operator. Смотри '3.6 Перенаправления' чтобы получить список операторов перенаправления. Операторы содержат как минимум один раскавыченный метасимвол
- process group - Коллекция связанных процессов которые имеют один process group ID (PGID)
- process group ID - Уникальный идентификатор который отображает procces group на протяжении жизни процесса
- reserved word - word которое имеет специальное значение в шелле. Много зарезервированных слов представлено в конструкциях для контроля потоков исполнения, такие как for и while
- return status - То же что и exit status
- signal - Механизм с помощью которого процессы могут быть уведомлены ядром о событиях происходящих в системе
- special builtin - Встроенные команды которые могут быть классифицированы стандартом POSIX как специальные
- token - Последовательность символов рассматриваемая шеллом как одиночная единица. Это любое word или operator
- word - Последовательность символов рассматриваемая шеллом как единое целое. Слова могут не содержать раскавыченных metacharacters
3 Базовые Функции Оболочки
Bash это акроним для 'Bourne-Again SHell'. Шелл Борна это традиционный Unix шелл написанный Стивеном Борном. Все встроенные команды Шелла Борна доступны в Bash, Правила оценки и цитирования взяты из спецификации POSIX для 'стандартной' оболочки Unix.
Эта глава кратко резюмирует 'строительные блоки' шелла: команды, структуры управления, функции шелла, параметры шелла, расширения, перенаправления, которые являются способом прямого ввода и вывода из и в именованный файл, и то как шелл выполняет команды.
3.1 Синтакс Шелла
Когда шелл читает ввод, он делает это через последовательность операций. Если ввод показывает что начинается комментарий, то шелл игнорирует символ комментария ('#') и остальную строку.
Иначе, грубо говоря, шелл читает инпут и разделяет его на слова и операторы, применяя правила для выбора того какие значения назначать различным словам и символам.
Затем шелл парсит эти токены в команды и другие конструкции, убирает особый смысл у одних слов и символов, расширяет другие, перенаправляет ввод и вывод как надо, выполняет указанные команды, ждет код ответа этих команд и делает его доступным для последующей инспекции или обработки.
3.1.1 Работа Шелла
Далее краткое описание работы шелла когда он читает и выполняет команду. Обычно шелл делает следующее:
- Читает ввод из файла (см. '3.8 Шелл скрипты'), из строки которая передана аргументом в
-c
опцию вызова (см. '6.1 Вызов Bash') или из пользовательского терминала - Разделяет ввод на слова и операторы, используя правила кавычек описанные в '3.1.2 Кавычинг'. Эти токены выделяются с помощью metacharacters. Разворачивание алиасов выполняется на этом этапе (см. '6.6 Алиасы')
- Парсинг токенов в простые и сложные команды (см. '3.2 Команды Шелла')
- Выполнение различных расширений (см. '3.5 Шелл Расширения'), разбиение расширенных токенов в список имен файлов (см. '3.5.8 Расширение Имен Файлов'), команд и аргументов
- Выполнение необходимых перенаправлений (см. '3.6 Перенаправления') и удаление операторов перенаправления и их операндов из списка аргументов
- Выполнение команд (см. '3.7 Выполнение Команд')
- Опциональное ожидание завершения команд и сбор их статускодов (см. '3.7.5 Статускод')
3.1.2 Кавычинг
Кавычинг используется для удаления специальных значений определенных символов и слов в шелле. Кавычинг может быть использован для отключения специальной обработки для специльных символов, для предотвращения от распознавания зарезервированых слов как таковых, и для предотвращения разворачивания параметров.
Каждый из метасимволов (см. '2 Определения') имеет специальное значение и поэтому должен быть закавычен если он должен отображать себя. Когда используется символ разворачивания из истории команд, обычно это '!', он должен быть закавычен для предотвращения разворачивания.
Имеется три кавычинговых механизма: escape character, одиночные кавычки, двойные кавычки.
3.1.2.1 Эскейп Символы
Незакавыченный бэкслэш '\' это Bash escape символ. Он отображает буквальное значение следующего за ним символа, символ новой строки - исключение. Если встречается пара \newline в которой бэкслэш незакавычен, то символ новой строки рассматривается как продолжение строки (он удаляется из введенной строки и по факту игнорируется).
root@mars:~# echo niga\ #enter
>pidor #enter
nigapidor
3.1.2.2 Одиночные Кавычки
Символы заключенные в одиночные кавычки (" ' ") отоборажают буквальное значение каждого символа в кавычках. Одиночная кавычка не может быть между одиночными кавычками, даже если она заэкранирована бэкслэшем.
root@mars:~# echo 'niga'pidor'
> ^C
root@mars:~# echo 'niga\'pidor'
> ^C
3.1.2.3 Двойные Кавычки
Заключенные в двойные кавычки символы (' " ') отображаются буквально за исключением $
, ~
и \
и если разворачивание из истории включено, то еще !
. Когда шелл в режиме POSIX, то '!' не имеет специального значения в двойных кавычках, даже когда разворачивание из истории включено. '$' и '~' сохраняют свой особый смысл в двойных кавычках. Бэкслэш сохраняет специальное значение только когда за ним следует один из следующих символов: $
, ~
, "
, \
или newline
. В двойных кавычках бэкслэши, после которых идут перечисленные символы, будут удалены. Бэкслэши предшествующие символам без специального значения будут оставаться неизменными. Двойная кавычка может быть закавычена в двойные кавычки, с использованием предваряющего ее бэкслэша. Если разворачивание из истории включено, то оно будет выполняться пока '!' встречающийся в двойных кавычках не будет заэкранирован бэкслэшем. Предшествующий восклицательному знаку бэкслэш не удаляется.
Специальные параметры *
и @
имеют специальное значение в двойных кавычках.
3.1.2.4 ANSI-C Кавычинг
Слова в форме $'string'
обрабатываются по особому. Строка развернется в string, и заменит заэкранированные символы так как описано в ANSI C стандарте. Бэкслэшем заэкранированные последовательности, если они есть, будут декодированы следующим образом:
- \a - Алерт
- \b - Backspace
- \e/\E - Эскейп-символ (не ANSI C)
- \f - - form feed (типа перенос строки)
- \n - Новая строка
- \r - Возврат каретки
- \t - Горизонтальный таб
- \v - Вертикальный таб
- \ - Бэкслэш
- ' - Одиночная кавычка
- " - Двойная кавычка
- ? - Знак вопроса
- \nnn - Восьмибитный символ (ниже будет пример, можно искать их по таблице ASCI)
- \xHH - Шестнадцатиричный символ
- \uHHHH - Unicode (ISO/IEC 10646) символ в шестнадцатиричном виде
- \UHHHHHHHH - То же что и выше
- \cx - control-x символ
Результат разворачивания будет одинарно-закавыченный, как если бы знака доллара не было.
root@mars:~# echo $'aa\bb'
ab
root@mars:~# echo $'aa\fb'
aa
b
root@mars:~# echo $'aa\nb'
aa
b
root@mars:~# echo $'aa\rb'
ba
root@mars:~# echo $'aa\tb'
aa b
root@mars:~# echo $'aa\vb'
aa
b
root@mars:~# echo $'aa\044b'
aa$b
root@mars:~# echo $'aa\x24b'
aa$b
root@mars:~# echo $'aa\u0024b'
aa$b
root@mars:~# echo $'aa\U00000024b'
aa$b
3.1.2.5 Локаль-специфичные Переводы
Строка в двойных кавычках с предшествующим долларом ('$') будет переведена основываясь на текущей локали. gettext
выполнит поиск message catalog'a и перевод, используя переменные LC_MESSAGES и TEXTDOMAIN как объясняется ниже. Смотри документацию к gettext для дополнительных деталей. Если текущая локаль C или POSIX или если нет доступных переводов, то знак доллара будет проигнорирован. Если строка переведена и в ней выполнена замена, то результат будет в двойных кавычках.
Некоторые системы используют message catalog выбранный с помощью переменной LC_MESSAGES. Другие создают имя message catalog'a из значения переменной TEXTDOMAIN, возможно добавляя суффикс '.mo'. Если ты используешь переменную TEXTDOMAIN, тебе может потребоваться установить в переменную TEXTDOMAINDIR расположение файла message catalog'a. Некоторые все еще используют обе переменные таким образом: TEXTDOMAINDIR/LC_MESSAGES/LC_MESSAGES/TEXTDOMAIN.mo.
3.1.3 Комментарии
В неинтерактивном шелле или интерактивном, но с включенной shopt опцией interactive_comments, слова начинающиеся с '#' и вся дальнейшая строка за этим словом будет игнорироваться. В интерактивном шелле без опции interactive_comments комментарии не разрешены. Опция interactive_comments по умолчанию включена.
root@mars:~# shopt interactive_comments
interactive_comments off
root@mars:~# echo niga # pidor
niga # pidor
root@mars:~# shopt -s interactive_comments
root@mars:~# shopt interactive_comments
interactive_comments on
root@mars:~# echo niga # pidor
niga
3.2 Команды Шелла
Такие простые команды как echo a b c состоят из самой команды и следующих за ней аргументов разделенных пробелами.
Множество комплексных шелл команд состоят из простых команд объединенных вместе различными способами: пайплайном в котором вывод одной команды входит в ввод следующей, циклом или условной конструкцией, или каким-то другим способом.
3.2.1 Зарезервированные Слова
Зарезервированные слова это слова которые имеют специальное значение для шелла. Они используются для начала и окончания составных команд.
Следующие слова известны как зарезервированные когда они незаковычены и являются первым словом в команде:
if | then | elif | else | fi | time |
for | in | until | while | do | done |
case | esac | coproc | select | function | |
{ | } | [[ | ]] | ! |
in
распознается как зарезервированное слово если оно третье после команды case или select. in
и do
распознаются как зарезервированные слова если они третьи после команды for.
3.2.2 Простые Команды
Простые команды это вид команд который встречается чаще всего. Это просто последовательность слов разделенная с помощью blanks и заканчивающаяся одним из контрольных операторов шелла. Первое слово обычно определяет выполняемую команду, оставшиеся слова будут аргументами команды.
Статускод простой команды это exit status предоставляемый функцией waitpid стандарта POSIX 1003.1, или 128+n если команда была завершена сигналом n.
3.2.3 Пайплайны
Пайплайн это последовательность из одной или более команд разделенных операторами управления '|' или '|&'.
Формат пайплайнов
[time [-p]] [!] command1 [ | or |& command2 ] …
Вывод каждой команды в пайплайне соединяется через пайп с вводом следующей команды. То есть каждая команда читает аутпут предыдущей команды. Это соединение устанавливается до каких-либо перенаправлений определенных командой.
Если используется |&
, то stderr вместе с stdout command1, подключается к stdin command2 через пайп; это сокращение для 2>&1 |
. Это подразумевает что перенаправление stderr в stdout будет выполнено после редиректов определенных командой.
Я не понял два абзаца выше, поэтому вот оригинал:
The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command’s output. This connection is performed before any redirections specified by the command.
If ‘|&’ is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.
Зарезервированное слово time
выводит статистику времени выполнения пайплайна. Статистика содержит затраченное время и время в user и system спейсах. Опция -p
изменяет формат вывода на определенный POSIX'ом. Когда шелл в POSIX режиме ...
OpenSSL
OpenSSL
http://www.opennet.ru/base/sec/openssl.txt.html
RFC про PKI: https://tools.ietf.org/html/rfc5280
Рекомендуется использовать бинари одной версии
Иначе все может сломаться и раздебажить будет крайне сложно
Перед началом работы нужно понимать какая версия openssl у тебя установлена
root@postgres-client:~# openssl version
OpenSSL 1.1.1d 10 Sep 2019
Ключ -a
покажет много дополнительной информации
Например OPENSSLDIR в которую будет ходить openssl за конфигурацией и сертами
-d
- покажет только ssldir
root@postgres-client:~# openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
root@postgres-client:~# ls -lh /usr/lib/ssl
total 4.0K
lrwxrwxrwx 1 root root 14 Feb 17 01:08 certs -> /etc/ssl/certs
drwxr-xr-x 2 root root 4.0K Mar 4 12:48 misc
lrwxrwxrwx 1 root root 20 Feb 17 01:08 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root 16 Feb 17 01:08 private -> /etc/ssl/private
Обычно в ней каходятся ссылки на /etc/ssl/
Так как это дефолтная папка для сертов в линуксе
Папка misc содержит несколько скриптов, некоторые из них нужны для создания CA
Скачать исходники можно тут
https://www.openssl.org/source/
Простейшая сборка
./config
make
make install
config - имеет разные параметры, можно собрать под себя
После сборки и установки у меня стало доступно два openssl
root@postgres-client:~# /usr/bin/openssl version
OpenSSL 1.1.1d 10 Sep 2019
root@postgres-client:~# /usr/local/bin/openssl version
OpenSSL 1.1.1j 16 Feb 2021 (Library: OpenSSL 1.1.1d 10 Sep 2019)
Папки private/ и certs/ изначально пустые, это потому что изначально у вас еще нет приватных ключей и доверенных сертификатов
Но так как это лишь ссылки на такие же папки в /etc/, то в certs уже могут быть доверенные сертификаты которые туда положила ОС
openssl это криптографический тулкит, который состоит из множества различных утилит (ниже видно насколько их много)
root@postgres-client:~# /usr/local/bin/openssl help
Standard commands
asn1parse ca ciphers cms
crl crl2pkcs7 dgst dhparam
dsa dsaparam ec ecparam
enc engine errstr gendsa
genpkey genrsa help list
nseq ocsp passwd pkcs12
pkcs7 pkcs8 pkey pkeyparam
pkeyutl prime rand rehash
req rsa rsautl s_client
s_server s_time sess_id smime
speed spkac srp storeutl
ts verify version x509
Message Digest commands (see the `dgst' command for more details)
blake2b512 blake2s256 gost md4
md5 mdc2 rmd160 sha1
sha224 sha256 sha3-224 sha3-256
sha3-384 sha3-512 sha384 sha512
sha512-224 sha512-256 shake128 shake256
sm3
Cipher commands (see the `enc' command for more details)
aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb
aes-256-cbc aes-256-ecb aria-128-cbc aria-128-cfb
aria-128-cfb1 aria-128-cfb8 aria-128-ctr aria-128-ecb
aria-128-ofb aria-192-cbc aria-192-cfb aria-192-cfb1
aria-192-cfb8 aria-192-ctr aria-192-ecb aria-192-ofb
aria-256-cbc aria-256-cfb aria-256-cfb1 aria-256-cfb8
aria-256-ctr aria-256-ecb aria-256-ofb base64
bf bf-cbc bf-cfb bf-ecb
bf-ofb camellia-128-cbc camellia-128-ecb camellia-192-cbc
camellia-192-ecb camellia-256-cbc camellia-256-ecb cast
cast-cbc cast5-cbc cast5-cfb cast5-ecb
cast5-ofb des des-cbc des-cfb
des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb
des-ede3-ofb des-ofb des3 desx
idea idea-cbc idea-cfb idea-ecb
idea-ofb rc2 rc2-40-cbc rc2-64-cbc
rc2-cbc rc2-cfb rc2-ecb rc2-ofb
rc4 rc4-40 seed seed-cbc
seed-cfb seed-ecb seed-ofb sm4-cbc
sm4-cfb sm4-ctr sm4-ecb sm4-ofb
Вырезка выше состоит из нескольких частей:
- Commands
- Message Digest
- Ciphers
openssl не поставляет с собой каких либо корневых сертов
Но, как описано выше, можно использовать ОСные серты, это считается нормой
Но они могут быть устаревшими, например когда мы установили ультрадревний дистрибутив
Есть вот такой регулярно обновляемый сертстор от мозиллы:
https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
Но он в их личном формате, что может быть не очень удобно
Есть еще от курла:
http://curl.haxx.se/docs/caextract.html
Он в формате PEM (Privacy-Enhanced Mail)
Но если сильно хочется мозилловский, то есть масса конвертеров на разных языках
Perl: https://raw.githubusercontent.com/bagder/curl/master/lib/mk-ca-bundle.pl
root@postgres-client:~# perl mk-ca-bundle.pl
SHA256 of old file: 0
Downloading certdata.txt ...
Get certdata with curl!
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1141k 100 1141k 0 0 125k 0 0:00:09 0:00:09 --:--:-- 203k
Downloaded certdata.txt
SHA256 of new file: 3bdc63d1de27058fec943a999a2a8a01fcc6806a611b19221a7727d3d9bbbdfd
Processing 'certdata.txt' ...
Done (129 CA certs processed, 20 skipped).
Он сам скачает и создаст ca-bundle.crt в котором куча сертов
Можно в крон засунуть и он будет апдейтить
Создание сертификата состоит из нескольких этапов:
- Генерация приватного ключа
- Создание Certificate Signing Request (CSR)
- Отправка CSR в CA
- Получение сертификата от CA
Прежде чем генерировать приватный ключ нужно принять несколько решений:
- Алгоритм - openssl умеет rsa, dsa, ecdsa, каждый алгоритм имеет преимущества в разных сценариях использования
- Размер ключа - дефолтные значения величины ключа могут быть не очень безопасными, короткие ключи легче перебрать брут форсом, ну а сверхдлинные требуют больше ресурсов для работы
- Пароль ключа - использование пароля для ключа - опционально, но рекомендуемо, так как защищенные ключи могут безопасно храниться, переноситься и бэкапиться. Иногда запароленные ключи будут доставлять неудобства, например нужно будет постоянно вводить пароль при рестарте сервера. В продакшне пароли не приносят большей безопасности
Для генерации rsa ключа:
root@mars:/var/tmp/test# /usr/local/bin/openssl genrsa -aes128 -out fd.key 16384
Generating RSA private key, 16384 bit long modulus (2 primes)
........................+++
..........................................................................................................................................................................................+++
e is 65537 (0x010001)
Enter pass phrase for fd.key:
Verifying - Enter pass phrase for fd.key:
root@mars:/var/tmp/test# ls -lh
total 16K
-rw------- 1 root root 13K Mar 15 14:00 fd.key
Выше я сгенерил максимально длинный (можно и длинее, но не рекомендуется)
Может показаться что ключ это просто кусок рандомных данных, на самом деле у него есть структура которую можно посмотреть так:
(на примере более короткого ключа, у длинного который выше слишком длинный вывод)
root@mars:/var/tmp/test# openssl rsa -in small.key -noout -text
Enter pass phrase for small.key:
RSA Private-Key: (512 bit, 2 primes)
modulus:
00:92:8f:7d:3f:54:d1:ea:4a:e9:5f:25:f4:24:5e:
3d:35:60:75:63:1b:20:4c:29:9a:c5:69:a7:4d:2b:
f2:e6:8e:04:c7:74:86:d8:ec:55:5b:1a:18:fa:1d:
4d:2e:68:b0:3c:b3:e1:a3:d3:af:00:81:89:0b:3b:
40:bb:4c:0e:21
publicExponent: 65537 (0x10001)
privateExponent:
57:44:f9:df:6c:32:52:c0:a8:95:ef:93:a0:d4:3c:
be:3b:e1:aa:51:cc:b9:8d:4c:8b:a0:8d:ee:75:ec:
fd:3b:4d:0e:f7:b1:af:ba:c3:ee:67:30:b8:ea:2a:
51:04:9e:e1:e1:a8:76:19:88:44:8c:55:60:78:cd:
3c:8e:0d:c1
prime1:
00:c2:16:d7:a0:25:17:1e:a1:37:56:3c:b4:ac:53:
42:66:d8:89:b6:6e:5c:bc:4d:d5:68:f9:f9:79:b6:
59:40:4f
prime2:
00:c1:4f:7e:24:af:8d:80:59:3f:a8:2f:1d:74:7d:
37:65:5f:8a:fa:e0:39:22:fe:1b:f2:d9:a3:b8:9a:
c2:3e:8f
exponent1:
57:3d:91:3a:88:b1:75:b1:1d:80:83:d4:ea:48:9a:
66:44:1a:d2:87:94:e3:87:50:cf:d8:dc:cc:5a:ac:
8f:7d
exponent2:
2d:ee:89:76:86:10:05:33:2f:a0:f2:b0:f9:00:d7:
ac:ca:aa:e7:39:67:da:1c:ae:df:61:3f:39:99:ec:
15:99
coefficient:
48:dd:15:cd:36:d6:72:cd:a8:47:9d:36:8b:b9:b8:
9b:3f:63:ee:02:0a:22:e9:a6:95:6c:aa:ba:4c:52:
ab:62
Вытащить из него публичный можно так:
root@mars:/var/tmp/test# openssl rsa -in small.key -pubout -out small.pub
Enter pass phrase for small.key:
writing RSA key
root@mars:/var/tmp/test# ls -lh
total 24K
-rw------- 1 root root 576 Mar 15 14:09 small.key
-rw-r--r-- 1 root root 182 Mar 15 14:24 small.pub
"Вытащить" это условно, приватный ключ содержит в себе компоненты (некоторые из которых нужны для ускорения шифрования/расшифрования)
Из этих компонентов можно получить публичный ключ (в случае rsa, у dsa другой механизм, что там да как я не знаю)
openssl rsa -in private.pem -text -noout | less
modulus - n
privateExponent - d
publicExponent - e
prime1 - p
prime2 - q
exponent1 - d mod (p-1)
exponent2 - d mod (q-1)
coefficient - (q^-1) mod p
Поэтому DSA используется для электронной подписи и процесс генерации у него иной:
openssl dsaparam -genkey 2048 | openssl dsa -out dsa.key -aes128
Generating DSA parameters, 2048 bit long prime
This could take some time
[...]
read DSA key
writing DSA key
Enter PEM pass phrase: ****************
Verifying - Enter PEM pass phrase: ****************
Как видно для разных алгоритмов используются разные команды (генерация rsa не похожа на генерацию dsa, легко запутаться)
Чтобы экономить время можно использовать универсальную команду openssl genpkey
для генерации приватных ключей
Имея приватный ключ можно сгенерировать CSR
Ты формируешь что-то типо сертификата и отправляешь его на подпись в CA, чтобы он стал доверенным
root@mars:/var/tmp/test# openssl genrsa -out test.key 2048 ^C
root@mars:/var/tmp/test# openssl rsa -in test.key -pubout -out test.pub ^C
root@mars:/var/tmp/test# openssl req -new -key test.key -out test.csr ^C
root@mars:/var/tmp/test# openssl req -in test.csr -noout -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = RU, L = Saint-Petersburg, O = Vandud Ltd., CN = vandud.ru, emailAddress = test@vandud.ru
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:ae:ce:40:5c:7a:ca:47:07:e7:8d:dc:e0:1e:91:
ba:e8:f5:61:66:ac:3c:c2:91:02:e0:68:92:29:ba:
01:a7:53:a1:2c:5a:eb:42:fc:37:cb:22:5b:41:92:
4d:b4:00:40:bd:18:52:7c:30:46:f9:03:97:06:d0:
2c:72:c6:26:49:be:ac:21:a1:48:fc:0d:33:44:2f:
8f:fe:ff:86:80:7f:d4:55:3e:9f:1d:cb:98:03:df:
3e:22:d4:47:a5:cf:2f:ea:9f:01:4b:e4:ac:9c:38:
48:33:e6:8e:16:6f:63:94:7d:33:04:ce:df:55:7c:
e8:42:d8:3c:cd:54:ad:44:44:ba:46:9b:91:72:9f:
55:8e:bc:a5:17:6c:e1:fb:1e:63:db:43:fc:0f:b1:
bf:7c:30:40:6e:92:2d:e5:f7:0a:3d:fe:4d:51:d2:
a6:4c:fb:34:43:3d:b8:d0:1d:80:31:d5:82:b1:8d:
61:4e:6e:c6:ad:79:28:d4:5f:b9:c9:c1:bc:23:34:
6d:8c:31:19:d8:42:ca:21:81:ff:c4:e5:2e:9a:b0:
21:80:52:36:89:6c:17:d6:f2:b5:ec:0a:6b:1c:eb:
19:41:20:59:ce:58:45:22:0a:05:de:a6:1f:82:d5:
31:fb:3d:7e:65:d6:fb:38:9d:f8:39:da:87:7c:72:
56:01
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
98:ea:53:c2:dd:00:0a:e1:0d:10:0e:f5:85:b4:84:2b:99:ed:
69:f9:3e:af:2b:d3:22:83:84:c1:64:47:b1:8e:40:3d:78:ce:
8c:a0:3a:b1:35:1c:3c:97:a2:e7:63:cf:cd:58:1b:29:c6:97:
ca:2c:09:67:08:6d:f1:8a:a3:80:c3:de:27:0a:cf:5e:77:a0:
38:94:8f:0d:0d:32:f0:40:da:5c:c6:de:a7:a8:a8:f2:45:60:
ce:a6:be:50:29:1b:08:21:e6:06:4a:b7:84:1f:87:2b:a3:b6:
18:ca:ef:7f:a8:33:60:9a:fe:32:18:a4:87:4b:e0:31:e6:de:
87:10:33:b5:9e:f7:4e:ab:fc:a4:53:88:34:74:cd:1b:e7:71:
11:60:6b:e8:e5:66:9e:43:55:4f:e5:fa:56:35:6b:25:e0:7c:
cf:a0:94:d0:ed:66:31:29:bd:46:2b:46:8e:13:f3:d0:99:8f:
5d:e6:bf:84:84:9a:fb:89:b7:e7:be:d9:65:02:66:4c:a5:12:
f4:f8:fe:b7:ec:cc:59:2d:af:1c:0f:75:b0:57:b5:f8:66:36:
12:16:49:ab:1e:9e:c5:bd:1d:15:7c:f9:34:f0:21:fa:0f:3f:
31:2f:d8:73:33:7f:89:01:6c:af:fd:3a:b0:61:d7:7a:68:83:
27:ce:f7:34
Генерация CSR это интерактивный процесс (то есть ты отвечаешь на вопросы)
В какой-то момент предлагается ввести пароль для CSR, его рекомендуется опустить, так как безопасности это не прибавляет, а проблем может доставить
CSR с дефолтными значениями (если ничего не вписывать, а просто щелкать enter, то openssl проставит свои дефолты, если все таки хочется оставить поле пустым то нужно вписать точку):
root@mars:/var/tmp/test# openssl req -new -key test.key -out test1.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
root@mars:/var/tmp/test# openssl req -in test1.csr -noout -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c4:48:03:11:5c:96:7a:5a:76:12:d2:65:16:e9:
a9:43:46:31:fb:67:83:62:e2:6b:62:b5:a9:7e:d1:
09:de:f5:22:2b:ce:20:38:3e:b9:50:87:0d:7e:b8:
90:11:07:ed:eb:85:2a:0a:eb:15:fb:17:83:39:28:
58:a1:0e:cc:5f:70:04:dc:f4:78:f2:cb:27:88:62:
cd:67:16:ca:42:c2:a5:a0:11:8b:35:10:c8:86:80:
12:b0:72:00:bb:8d:d5:b5:47:72:50:4f:81:ca:29:
72:c3:4f:1a:22:be:86:dc:2d:b9:b7:3b:59:32:45:
66:c5:7c:a3:26:37:fc:97:c3:ea:cc:1d:e5:ca:58:
7d:fa:53:0e:53:f3:94:8c:80:b7:8d:17:0a:6f:d1:
f0:cf:e9:47:bf:7a:69:62:82:90:4d:72:93:94:1d:
00:d8:9b:a6:57:e6:a8:e1:ad:26:5b:54:49:10:f9:
05:ed:8a:cd:93:20:de:76:a1:c3:e0:79:8e:01:7a:
96:5c:bf:e7:13:1a:68:f7:b8:30:07:c6:ce:7a:28:
1e:6e:82:ab:5a:98:f4:9b:a3:17:35:56:52:49:12:
73:41:2d:a8:d7:00:b1:02:52:5d:56:eb:f2:ca:d2:
4a:44:18:ab:c9:55:b3:38:37:09:64:87:e9:7b:fb:
ca:a7
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
4f:f8:28:32:3b:e4:09:1c:58:1d:7c:00:bf:92:3d:d2:18:e9:
50:12:a4:29:83:fe:be:a4:02:79:12:d1:04:4c:7f:ae:3d:ba:
45:c7:53:14:11:d3:b5:91:5f:a5:83:fb:84:d6:2e:3b:a7:7d:
5c:e5:18:48:e0:d6:17:7a:55:f1:31:71:96:6b:51:a0:1d:a1:
99:f8:e1:94:1e:02:c0:86:56:f1:7f:1e:73:42:16:dd:55:fb:
19:af:37:81:35:27:96:97:b1:35:ef:a3:0d:94:87:ea:d8:3c:
c4:13:c0:86:38:00:94:45:99:e8:6d:be:26:47:13:ee:cc:28:
bb:b8:5b:0a:71:44:76:92:39:bd:8b:55:0e:35:c1:30:8b:5e:
7d:7b:ba:7b:57:cb:8e:1f:30:73:06:cf:d1:6d:69:9e:14:84:
b3:82:19:56:73:88:8f:24:1b:21:ff:58:b6:49:dd:cf:7c:0b:
a2:84:fb:d6:67:db:7e:5e:1a:f3:8f:00:40:04:ad:7f:2c:2f:
c8:a9:5a:b8:78:73:4e:ce:79:12:64:ae:44:cf:27:d1:54:f9:
5e:1d:d9:b9:ed:0e:44:08:e8:9b:b9:2e:cc:6a:13:1e:47:ab:
7d:11:d4:e7:8a:16:9d:14:ac:12:f3:e7:37:13:4e:8c:78:b3:
bd:9d:74:f8
Дальше этот CSR отправляем на подпись в CA и получаем в ответ сертификат
csr to crt
root@mars:/var/tmp/test# openssl x509 -req -in test.csr -signkey test.key -out test.crt
Signature ok
subject=C = RU, L = Saint-Petersburg, O = Vandud Ltd., CN = vandud.ru, emailAddress = test@vandud.ru
Getting Private key
Для перевыпуска можно не писать кучу команд, а сформировать CSR на основе старого сертификата (в котором можно заменить ключ)
openssl x509 -x509toreq -in fd.crt -out fd.csr -signkey fd.key
Можно автоматизировать генерацию CSR с помощью конфигa:
root@mars:/var/tmp/test# cat test.conf
[req]
prompt = no
distinguished_name = dn
req_extensions = ext
[dn]
CN = www.vandudwithconf.com
emailAddress = webmaster@feistyduck.com
O = Feisty Duck Ltd
L = London
C = GB
[ext]
subjectAltName = DNS:www.feistyduck.com,DNS:feistyduck.com
root@mars:/var/tmp/test# openssl req -new -config test.conf -key test.key -out test3.csr
root@mars:/var/tmp/test# openssl req -in test3.csr -noout -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN = www.vandudwithconf.com, emailAddress = webmaster@feistyduck.com, O = Feisty Duck Ltd, L = London, C = GB
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c4:48:03:11:5c:96:7a:5a:76:12:d2:65:16:e9:
a9:43:46:31:fb:67:83:62:e2:6b:62:b5:a9:7e:d1:
09:de:f5:22:2b:ce:20:38:3e:b9:50:87:0d:7e:b8:
90:11:07:ed:eb:85:2a:0a:eb:15:fb:17:83:39:28:
58:a1:0e:cc:5f:70:04:dc:f4:78:f2:cb:27:88:62:
cd:67:16:ca:42:c2:a5:a0:11:8b:35:10:c8:86:80:
12:b0:72:00:bb:8d:d5:b5:47:72:50:4f:81:ca:29:
72:c3:4f:1a:22:be:86:dc:2d:b9:b7:3b:59:32:45:
66:c5:7c:a3:26:37:fc:97:c3:ea:cc:1d:e5:ca:58:
7d:fa:53:0e:53:f3:94:8c:80:b7:8d:17:0a:6f:d1:
f0:cf:e9:47:bf:7a:69:62:82:90:4d:72:93:94:1d:
00:d8:9b:a6:57:e6:a8:e1:ad:26:5b:54:49:10:f9:
05:ed:8a:cd:93:20:de:76:a1:c3:e0:79:8e:01:7a:
96:5c:bf:e7:13:1a:68:f7:b8:30:07:c6:ce:7a:28:
1e:6e:82:ab:5a:98:f4:9b:a3:17:35:56:52:49:12:
73:41:2d:a8:d7:00:b1:02:52:5d:56:eb:f2:ca:d2:
4a:44:18:ab:c9:55:b3:38:37:09:64:87:e9:7b:fb:
ca:a7
Exponent: 65537 (0x10001)
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:www.feistyduck.com, DNS:feistyduck.com
Signature Algorithm: sha256WithRSAEncryption
b8:f9:45:9e:2c:af:80:7b:06:3a:eb:77:3b:86:b6:16:2d:bb:
71:56:c4:fd:e4:25:db:39:be:3f:3e:45:32:f9:df:61:dd:0d:
ab:51:42:f0:ad:ba:25:42:5b:49:14:e0:ad:2d:9c:14:35:93:
ea:ea:4c:96:ad:da:20:95:fd:ea:4e:4f:05:a5:64:d0:37:18:
98:60:91:3a:15:aa:15:3a:80:df:44:d6:57:6c:a8:16:6d:ba:
ff:ba:b3:42:84:5c:86:8c:75:70:08:d9:b1:88:d8:97:10:fd:
5c:d2:28:9a:64:c7:1a:6a:ee:f3:2b:4a:f7:40:74:e3:ef:7c:
f1:fc:f2:c9:97:c2:97:4b:50:7a:1a:4f:e7:a2:96:12:65:db:
75:24:0b:0c:f4:0c:a8:6f:66:9c:3f:16:27:9e:d4:20:15:ca:
6a:36:58:0a:40:82:c8:22:e5:ac:6e:08:17:83:1f:8a:2b:64:
ba:4c:c1:74:40:91:4c:00:8f:f4:1c:92:75:ba:4a:26:55:48:
3c:76:72:52:3f:33:2e:e5:22:bd:01:33:ac:78:9f:70:68:54:
24:d1:3b:d2:2e:92:a4:db:34:6f:be:ec:ff:cd:6d:08:6a:62:
88:07:81:12:b3:52:2f:33:cb:d6:71:0a:6a:b6:f5:85:7a:1c:
26:51:dd:a5
Сгенерить самосерт так:
root@mars:~/nginx# openssl genrsa -out vandud.key 4096
root@mars:~/nginx# openssl req -new -x509 -days 10 -key vandud.key -out vandud.crt
Дефолтный серт поддерживает один хостнейм
Но в наши дни такой подход не годится, требуется мультидоменность
Расширения X509 позволяет это сделать
X509 дает еще массу полезных возможностей
Например CRL и механизм проверки пути сертификации
Когда серт имеет alternative names, common names игнорятся. Поэтому нужно перечислять все домены в altnames
Можно перечислить все расширения которые тебе нужны в текстовом файле
Пример:
root@mars:/var/tmp/test# cat test.ext
subjectAltName = DNS:ext.vandud.ru, DNS:*.vandud.ru
# Подписываю CSR
root@mars:/var/tmp/test# openssl x509 -req -in test.csr -signkey ca.key -out test.crt -extfile test.ext
Signature ok
subject=C = RU, ST = SAINT-P., L = SAINT-P., O = Sub Unit, OU = au, CN = auo.aeu.au
Getting Private key
# Получили Subject Alternative Name в серте
root@mars:/var/tmp/test# openssl x509 -in test.crt -noout -text | grep X509 -A1
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:ext.vandud.ru, DNS:*.vandud.ru
У сертификатов есть basic constraints, оно указывет пренадлежит ли серт CA и годен ли он для подписи других сертов
У не CA сертов это расширение опущено или установлено в FALSE
X509v3 Basic Constraints: critical
CA:FALSE
Key Usage (KU) и Extended Key Usage (EKU) ограничивают места применения серта
Серты могут использоваться для подписи других сертов, для подписи файлов, для подписи ...
Расширение CRL Distribution Points указывет где можно найти CRL этого CA
root@mars:/var/tmp/test# wget crl.starfieldtech.com/sfs3-20.crl -q
root@mars:/var/tmp/test# openssl crl -in sfs3-20.crl -inform der -noout -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certificates.starfieldtech.com/repository, CN = Starfield Secure Certification Authority, serialNumber = 10688435
Last Update: Mar 16 12:05:46 2021 GMT
Next Update: Mar 23 12:05:46 2021 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:49:4B:52:27:D1:1B:BC:F2:A1:21:6A:62:7B:51:42:7A:8A:D7:D5:56
DirName:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority
serial:02:01
X509v3 CRL Number:
3588
X509v3 Issuing Distribution Point: critical
Full Name:
URI:http://crl.starfieldtech.com/sfs3-20.crl
No Revoked Certificates.
Signature Algorithm: sha256WithRSAEncryption
75:2f:f7:ba:da:67:88:7d:f8:a5:02:9c:9d:0d:8c:4b:e9:6c:
56:2c:b7:77
...
:78:76:9e:d1:5e:f9:6b:ab:a3:47:d0:fd:45:4a:
fe:1e:de:6c
CRL распрастраняются по незащищенному соединению неспроста
За безопасность беспокоиться не стоит, потому что файл CRL подписан CA которому пренадлежит этот CRL
А распрастранять его по https нельзя, потому что может возникнуть проблема курицы и яйца (чтобы установить https подключение для получения crl нужно иметь этот crl)
CRL обновляется регулярно, обычно еженедельно
[22:36:30] vandud@macbook: tmp [0]$ openssl crl -in gds1-31.crl -inform DER -text -noout
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
Last Update: Mar 28 15:41:03 2021 GMT
Next Update: Apr 4 15:41:03 2021 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7
DirName:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
serial:03:01
X509v3 CRL Number:
3748
X509v3 Issuing Distribution Point: critical
Full Name:
URI:http://crl.godaddy.com/gds1-31.crl
No Revoked Certificates.
Signature Algorithm: sha256WithRSAEncryption
bd:9e:86:f8:bf:5d:3a:0f:12:b2:b3:48:a1:0f:88:96:43:f4:
d7:ea:dc:73:a5:44:0b:c7:e6:d6:fc:95:52:66:bc:8b:a9:02:
d3:73:68:dc:f5:fd:e3:f1:0a:c7:c7:da:5f:7e:47:8f:8e:44:
ad:53:79:b9:75:b1:98:f6:74:b9:65:bd:40:51:fe:1f:20:b6:
50:a7:63:2f:1e:83:00:f2:94:4a:48:3c:df:4e:0b:8f:6c:75:
c2:d8:cc:2b:75:c7:61:ad:a3:2b:7d:78:d7:69:cf:8a:8b:11:
3b:57:23:2a:53:c3:f3:9e:6e:a2:53:c1:d6:2c:5d:da:e3:0c:
38:85:f7:24:16:0e:47:d9:f7:76:87:ad:ae:63:2d:46:2a:34:
0e:ba:16:4a:07:76:60:34:e4:07:d0:84:a4:0e:46:6e:95:1a:
26:0b:cf:f0:e9:d0:53:8b:4f:ce:ec:86:04:13:9d:e1:1f:58:
d3:a1:d0:6a:ad:23:a6:1a:a5:77:6e:b0:eb:a3:a8:ce:e9:c4:
a6:ca:a8:31:d6:2e:3a:46:9b:e9:1f:d7:9f:20:76:75:13:eb:
f2:fd:af:15:b4:db:a4:d0:be:a7:39:73:51:5a:82:c0:b2:2f:
e2:bc:dd:03:cc:aa:02:9e:c3:db:0a:3a:d6:27:eb:9e:1c:9d:
f4:44:a5:79
Certificate Policies и CPS (certificate policy statment)
X509v3 Certificate Policies:
Policy: 2.16.840.1.114413.1.7.23.1
CPS: https://certs.godaddy.com/repository/
Это расширение используется для указания политики под которой был выдан серт
Например это то место по которому бразуер понимер DV, OV или EV серт перед ним
Браузер понимает что перед ним EV сертификат благодаря то что в коде браузера зашиты OID'ы
https://hg.mozilla.org/mozilla-central/file/eab4a81e4457/security/certverifier/ExtendedValidation.cpp
- Список адресов OCSP респондеров центра сертификации (Online Certificate Status Protocol) которые могут быть использованы для проверки того отозван ли серт в реальном времени
- Также это расширение может содержать ссылку на сертификат эмитента (следующий в цепочке серт)
Authority Information Access:
CA Issuers - URI:http://crt.usertrust.com/GandiStandardSSLCA2.crt
OCSP - URI:http://ocsp.usertrust.com
Пользователи часто ошибаются (или забыват) и кладут невалидные серты в цепочку, браузер благодаря этому расширению может самостоятельно собрать валидную цепочку
Subject Key Identifier и Authority Key Identifier это уникальные идентификаторы которые помогают выбрать нужный серт для построения цепочки
Дело в том что ЦА часто используют один приватный ключ в множестве сертификатов
В реальном мире много цепочек поставляемых серверами - невалидные, но это не мешает браузерам строить правильные цепочки самостоятельно по альтернативным путям
root@mars:/var/tmp/a# echo | openssl s_client -connect online.sberbank.ru:443 -servername online.sberbank.ru > online.sberbank.ru.crt 2>/dev/null
root@mars:/var/tmp/a# openssl x509 -in online.sberbank.ru.crt -noout -ext authorityInfoAccess
Authority Information Access:
OCSP - URI:http://status.thawte.com
CA Issuers - URI:http://cacerts.thawte.com/ThawteEVRSACA2018.crt
root@mars:/var/tmp/a# wget http://cacerts.thawte.com/ThawteEVRSACA2018.crt -q
root@mars:/var/tmp/a# openssl x509 -in ThawteEVRSACA2018.crt -inform der -out ThawteEVRSACA2018.pem.crt -outform pem
root@mars:/var/tmp/a# openssl x509 -in online.sberbank.ru.crt -noout -ext authorityKeyIdentifier
X509v3 Authority Key Identifier:
keyid:E7:01:FC:0C:16:18:CA:7D:B2:8C:EC:87:27:A3:6F:61:81:3B:84:39
root@mars:/var/tmp/a# openssl x509 -in ThawteEVRSACA2018.pem.crt -noout -ext subjectKeyIdentifier
X509v3 Subject Key Identifier:
E7:01:FC:0C:16:18:CA:7D:B2:8C:EC:87:27:A3:6F:61:81:3B:84:39
Subject Alternative Name это расширение позволяет перечислить все имена для которых этот сертификат валиден
Если его нет то используется поле CN (Common Name) из Subject
Если расширение Subject Alt Name есть, то Common Name игнорируется и инфа берется только из расширения
root@mars:/var/tmp/a# openssl x509 -in online.sberbank.ru.crt -noout -subject
subject=businessCategory = Private Organization, jurisdictionC = RU, serialNumber = 1027700132195, C = RU, L = Moscow, O = Sberbank of Russia, CN = online.sberbank.ru
root@mars:/var/tmp/a# openssl x509 -in online.sberbank.ru.crt -noout -ext subjectAltName
X509v3 Subject Alternative Name:
DNS:online.sberbank.ru
Ключи и сертификаты могут храниться в разных форматах, поэтому часто можно иметь необходимость преобразовывать одно в другое
- Binary (DER) certificate - Содержит x.509 серт в сырой форме
- ASCII (PEM) certificate - Содержит DER закодированный в Base64 и обрамленный в '-----BEGIN CERTIFICATE-----' и '-----END CERTIFICATE-----'. Обычно используется один серт на один файл, но зависит от ПО
- Binary (DER) key - Содерджит приватный ключ в сыром виде
- ASCII (PEM) key - Ключ в Base64, иногда с дополнительной метадатой
- PKCS#7 certificate - Сложный формат для передачи подписанных или зашифрованных данных
- PKCS#12 (PFX) key and certificate - Сложный формат, позволяет хранить и защищать ключ и полную цепочку сертификатов. Обычно используется в microsoft'овских продуктах
Для конвертации из PEM в DER и наоборот есть очень простые команды
openssl x509 -inform PEM -in fd.pem -outform DER -out fd.der
openssl x509 -inform DER -in fd.der -outform PEM -out fd.pem
Для ключей то же самое
root@mars:/var/tmp/a# openssl rsa -in key.pem -inform PEM -out key.der -outform DER
writing RSA key
root@mars:/var/tmp/a# openssl rsa -in key.der -inform DER -out key.pem2 -outform PEM
writing RSA key
root@mars:/var/tmp/a# diff key.pem key.pem2
Чтобы засунуть PEM серт, ключ и промежуточные сертификаты в PFX
openssl pkcs12 -export \
-name "My Certificate" \
-out fd.p12 \
-inkey fd.key \
-in fd.crt \
-certfile fd-chain.crt
Enter Export Password: ****************
Verifying - Enter Export Password: ****************
Вернуть обратно не так просто
Нужно выполнить команду которая преобразует все в PEM но засунет это в один файл
openssl pkcs12 -in fd.p12 -out fd.pem -nodes
А потом ты вручную все разделишь на серты и ключи
Есть еще такой вариант
$ openssl pkcs12 -in fd.p12 -nocerts -out fd.key -nodes
$ openssl pkcs12 -in fd.p12 -nokeys -clcerts -out fd.crt
$ openssl pkcs12 -in fd.p12 -nokeys -cacerts -out fd-chain.crt
Посмотреть доступные комплекты алгоритмов шифрования можно командой openssl ciphers
, ключ -v
для вербозности
root@mars:/var/tmp/a# openssl ciphers -v | head -3
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
Вывод содерджит:
1. Suite name | 2. Required minimum protocol version | 3. Key exchange algorithm | 4. Authentication algorithm | 5. Cipher algorithm and strength | 6. MAC (integrity) algorithm | 7. Export suite indicator |
---|---|---|---|---|---|---|
TLS_AES_256_GCM_SHA384 | TLSv1.3 | Kx=any | Au=any | Enc=AESGCM(256) | Mac=AEAD | |
TLS_CHACHA20_POLY1305_SHA256 | TLSv1.3 | Kx=any | Au=any | Enc=CHACHA20/POLY1305(256) | Mac=AEAD | |
TLS_AES_128_GCM_SHA256 | TLSv1.3 | Kx=any | Au=any | Enc=AESGCM(128) | Mac=AEAD |
Можно передать какое-то ключевое слово для поискa:
root@mars:/var/tmp/a# openssl ciphers -v 'SSLv3'
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
...
Есть имена групп, которыми обозначены некоторые часто импользуемые наборы шифров
Например по слову HIGH будут отобраны очень сильные шифры
root@mars:/var/tmp/a# openssl ciphers 'HIGH'
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:...
Keyword | Meaning |
---|---|
DEFAULT | Список дефолтных шифров. Они определяются во время компиляции |
COMPLEMENTOFDEFAULT | То что есть в ALL но не включено в DEFAULT |
ALL | Все шифры кроме eNULL |
COMPLEMENTOFALL | То что не включено в ALL - eNULL |
HIGH | Сильнокриптильные шифры, сейчас это те у которых длина ключа больше 128 бит |
MEDIUM | Среднекриптильные шифры |
LOW | Слабокриптильные шифры, 64 или 56 битные алгоритмы |
EXP, EXPORT | |
TLSv1,SSLv3,SSLv2 | Тут понятно |
Можно делать выборку по алгоритму дайджеста
root@mars:/var/tmp/a# openssl ciphers -v 'MD5'
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
NULL-MD5 SSLv3 Kx=RSA Au=RSA Enc=None Mac=MD5
Keyword | Meaning |
---|---|
MD5 | Cipher suites using MD5. Obsolete and insecure |
SHA, SHA1 | Cipher suites using SHA1 |
SHA256 (v1.0.0+) | Cipher suites using SHA256 |
SHA384 (v1.0.0+) | Cipher suites using SHA384 |
Authentication keyword | Meaning |
---|---|
aDH | Cipher suites effectively using DH authentication, i.e., the certificates carry DH keys.(v1.0.2+) |
aDSS, DSS | Cipher suites using DSS authentication, i.e., the certificates carry DSS keys |
aECDH (v1.0.0+) | Cipher suites that use ECDH authentication |
aECDSA (v1.0.0+) | Cipher suites that use ECDSA authentication |
aNULL | Cipher suites offering no authentication. This is currently the anonymous DH algo-rithms. Insecure |
aRSA | Cipher suites using RSA authentication, i.e., the certificates carry RSA keys |
PSK | Cipher suites using PSK (Pre-Shared Key) authentication |
SRP | Cipher suites using SRP (Secure Remote Password) authentication |
Key exchange algorithms:
Keyword | Meaning |
---|---|
ADH | Anonymous DH cipher suites. Insecure |
AECDH (v1.0.0+) | UAnonymous ECDH cipher suites. Insecure |
DH | Cipher suites using DH (includes ephemeral and anonymous DH) |
ECDH (v1.0.0+) | Cipher suites using ECDH (includes ephemeral and anonymous ECDH) |
EDH (v1.0.0+) | Cipher suites using ephemeral DH key agreement |
EECDH (v1.0.0+) | Cipher suites using ephemeral ECDH |
kECDH (v1.0.0+) | Cipher suites using ECDH key agreement |
kEDH | Cipher suites using ephemeral DH key agreements (includes anonymous DH) |
kEECDH (v1.0.0+) | Cipher suites using ephemeral ECDH key agreement (includes anonymous ECDH) |
kRSA, RSA | Cipher suites using RSA key exchange |
Cipher keywords:
Keyword | Meaning |
---|---|
3DES | Cipher suites using triple DES |
AES | Cipher suites using AES |
AESGCM (v1.0.0+) | Cipher suites using AES GCM |
CAMELLIA | Cipher suites using Camellia |
DES | Cipher suites using single DES. Obsolete and insecure |
eNULL, NULL | Cipher suites that don’t use encryption. Insecure |
IDEA | Cipher suites using IDEA |
RC2 | Cipher suites using RC2. Obsolete and insecure |
RC4 | Cipher suites using RC4. Insecure |
SEED | Cipher suites using SEED |
Гостовские шифры
Keyword | Meaning |
---|---|
@STRENGTH | Sorts the current cipher suite list in order of encryption algorithm key length |
aGOST | Cipher suites using GOST R 34.10 (either 2001 or 94) for authentication. Requires aGOST-capable engine |
aGOST01 | Cipher suites using GOST R 34.10-2001 authentication |
aGOST94 | Cipher suites using GOST R 34.10-94 authentication. Obsolete. Use GOST R 34.10-2001 instead |
kGOST | Cipher suites using VKO 34.10 key exchange, specified in RFC 4357 |
GOST94 | Cipher suites using HMAC based on GOST R 34.11-94 |
GOST89MAC | Cipher suites using GOST 28147-89 MAC instead of HMAC |
Для поиска можно комбинировать кейворды через '+'
root@mars:/var/tmp/a# openssl ciphers -v 'AES+RSA'
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES256-CCM8 TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM8(256) Mac=AEAD
AES256-CCM TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM(256) Mac=AEAD
...
Через плюс выбирается "пересечение", а через двоеточие или пробел можно сложить два множества
root@mars:/var/tmp/a# openssl ciphers -v 'AES+RSA:AES+DH+SHA'
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES256-CCM8 TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM8(256) Mac=AEAD
AES256-CCM TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM(256) Mac=AEAD
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD
AES128-CCM8 TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM8(128) Mac=AEAD
AES128-CCM TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM(128) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
ADH-AES256-SHA SSLv3 Kx=DH Au=None Enc=AES(256) Mac=SHA1
DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1
DHE-DSS-AES128-SHA SSLv3 Kx=DH Au=DSS Enc=AES(128) Mac=SHA1
ADH-AES128-SHA SSLv3 Kx=DH Au=None Enc=AES(128) Mac=SHA1
Модификаторы
Есть несколько модификаторов с помощью которых можно формировать итоговый список шифров
Keyword | Meaning |
---|---|
Append | Добавит в конец списка. Если такой уже есть в списке, то изменит его положение в нем |
Delete (-) | Удалит все вхождения шифра в списке |
Permanently delete (!) | То же что выше, но в добавок еще и не даст добавить удаленный шифр в будущем |
Move to the end (+) | Переместит в конец списка. Полезно когда ты хочешь чтобы какой-то набор был включен, но использовался в последнюю очередь |
Сортировать по силе шифра можно словом @STRENGTH
Это работает плохо, поэтому вопрос приоритетности различных алгоритмов лучше контролировать вручную
Есть две типичных ошибки которые можно получить при работе с утилитой
root@mars:/var/tmp/a# openssl ciphers -v 'DES-CBC-SHA'
Error in cipher list
139928168608896:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl/ssl_lib.c:2560:
root@mars:/var/tmp/a# openssl ciphers -v '@DES-CBC-SHA'
Error in cipher list
140285746746496:error:140E6118:SSL routines:ssl_cipher_process_rulestr:invalid command:ssl/ssl_ciph.c:1193:
Если присмотреться то видно:
- no cipher match
- invalid command
openssl имеет встроенную утилиту для бенчмаркинга speed
Вызов без агрументов выдаст большой вывод в котором мало интересного
root@three:~# openssl speed rc4 aes
Doing md4 for 3s on 16 size blocks: 10747405 md4's in 2.98s
Doing md4 for 3s on 64 size blocks: 9176936 md4's in 3.00s
Doing md4 for 3s on 256 size blocks: 5508233 md4's in 2.99s
Doing md4 for 3s on 1024 size blocks: ^C
root@three:~#
В конце тестинга выдаст такой вывод
...
OpenSSL 1.1.1d 10 Sep 2019
built on: Mon Mar 22 23:08:47 2021 UTC
options:bn(64,64) rc4(16x,int) des(int) aes(partial) blowfish(ptr)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-AWQHHq/openssl-1.1.1d=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes 16384 bytes
rc4 353922.28k 541043.50k 623075.05k 643742.57k 658066.09k 672067.30k
aes-128 cbc 166991.50k 173247.44k 171517.44k 173914.79k 172188.17k 174058.15k
aes-192 cbc 145605.16k 148606.40k 148814.17k 149922.50k 147187.50k 155242.51k
aes-256 cbc 128802.94k 131946.26k 133212.90k 135339.69k 130652.81k 131705.51k
В первой части вывода содержится всякая инфа о сборке openssl
Это полезно для сравнения разных сборок и разных версий
Вторая часть содержит бенчмарк симетричной криптографии
А третья часть про ассиметричную криптографию
Не стоит полагаться только на результаты, в реальной жизни на перфоманс влияет множетсво факторов
Но можно на них полагаться для того чтобы прикинуть примерные эстимэйты
Также нужно учитывать что по умолчанию команда speed
использует один процесс, а сервера имеют много ядер, поэтому можно указать сколько экземпляров speed'a
запустить в параллель через опцию -multi
root@three:~# ps aux | grep multi
root 31984 0.0 0.2 6844 5000 pts/0 S+ 07:44 0:00 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31985 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31986 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31987 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31988 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31989 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31990 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31991 24.8 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
root 31992 24.9 0.1 6844 2940 pts/0 R+ 07:44 0:23 openssl speed -multi 8 rc4 aes rsa ecdh sha
Еще по дефолту не будет использовать самые быстрые из доступных шифров
Например если сервер поддерживает aes-ni (хардварное ускорение шифрования), то для бенчмарка нужно будет явно указать ключ -evp
чтобы использовать его
Если ты захочешь поднять свой собственный CA, то все что тебе понадобится уже есть в openssl
Самое сложное в поднятии приватного ЦА это сохранение безопасности. Например приватный ключ должен оставаться оффлайн, потому что вся безопасность зависит от него
С другой стороны CRL и OCSP должны регулярно обновляться
Создание ЦА ключает несколько шагов:
- Конфигурирование
- Создание структуры директорий
- Создание ключевых файлов
- Генерация корневого ключа и серта
Конфигурационные файлы не нужны большую часть времени, но они необходимы для некоторых операций
Рекомендуется почитать man config -> OpenSSL Config
Root CA Configuration
В первой части описывается базовая инфа об УЦ
[default]
name = root-ca
domain_suffix = example.com
aia_url = http://$name.$domain_suffix/$name.crt
crl_url = http://$name.$domain_suffix/$name.crl
ocsp_url = http://ocsp.$name.$domain_suffix:9080
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ca_dn]
countryName = "GB"
organizationName = "Example"
commonName = "Root CA"
Вторая часть контролирует работу УЦ
Большая часть параметров self-explanatory
Мы просто указываем куда мы хотим складывать наши файлы
А в полиси указываем что CN и ON для подписываемых сертов будут браться из корневого серта (это просто потому что у нас private CA)
[ca_default]
home = .
database = $home/db/index
serial = $home/db/serial
crlnumber = $home/db/crlnumber
certificate = $home/$name.crt
private_key = $home/private/$name.key
RANDFILE = $home/private/random
new_certs_dir = $home/certs
unique_subject = no
copy_extensions = none
default_days = 3650
default_crl_days = 365
default_md = sha256
policy = policy_c_o_match
[policy_c_o_match]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Третьей частью идет секция которая конфигурирует команду req
Которой мы воспользуемся лишь один раз (для создания корневого сертификата)
Наиболее важная часть это extensions'ы. В них и задается что это CA-cert (basicConstraint) и что им можно подписывать другие серты (keyUsage)
[req]
default_bits = 4096
encrypt_key = yes
default_md = sha256
utf8 = yes
string_mask = utf8only
prompt = no
distinguished_name = ca_dn
req_extensions = ca_ext
[ca_ext]
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
Четвертая часть описывает информацию которая будет использована при контруировании сертификатов выпускаемых этим корневым CA
Все выпускаемые сертификаты будут CA (basicConstraints - CA=true), и они не смогут так же как корневой выпускать CA-сертификаты, так как pathlen=0
Также, подписываемые sub-CA сертами серты, смогут использоваться для TLS клиент- и сервер-аутентификации
В теории nameConstraints ограничивает допустимые доменные имена, серты для которых смогут подписать sub-CA
Это позволяет делегировать возможность подписывать сертификаты и быть уверенным что sub-CA не сможет подписывать что-попало
Но на деле на это расширение мало кто смотрит
[sub_ca_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:true,pathlen:0
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,keyCertSign,cRLSign
nameConstraints = @name_constraints
subjectKeyIdentifier = hash
[crl_info]
URI.0 = $crl_url
[issuer_info]
caIssuers;URI.0 = $aia_url
OCSP;URI.0 = $ocsp_url
[name_constraints]
permitted;DNS.0=example.com
permitted;DNS.1=example.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
И наконец пятая часть конфига, она содержит расширения которые будут задействованы в сертификате для подписы OCSP ответов
Мы сгенерим специальный серт и делегируем ему возможность подписывать OCSP
Этот серт не будет CA как другие
[ocsp_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
Root CA Directory Structure
Следующий шаг это создание структуры директорий которую мы описали в конфиге и инициализация некоторых файлов которые будут использоваться на протяжении работы CA
root@three:~/openssl_ca# mkdir root-ca
root@three:~/openssl_ca# cd root-ca/
root@three:~/openssl_ca/root-ca# ls
root@three:~/openssl_ca/root-ca# mkdir certs db private
root@three:~/openssl_ca/root-ca# chmod 700 private/
root@three:~/openssl_ca/root-ca# touch db/index
root@three:~/openssl_ca/root-ca# openssl rand -hex 16 > db/serial # большое число из 16-ти 16-ти-битных чисел (hex 16)
# если смотреть через x509 -text то выглядит так
# Serial Number:
# 9a:9c:cd:76:9c:cb:72:ee:9d:82:80:ac:4b:e7:de:ab
root@three:~/openssl_ca/root-ca# echo 1001 > db/crlnumber
root@three:~/openssl_ca/root-ca# tree
.
├── certs
├── db
│ ├── crlnumber
│ ├── index
│ └── serial
└── private
- certs/ - новые серты будут складываться сюда
- db/
- index - базаданных сертификатов
- crlnumber - серийник для следующего CRL
- serial - серийник для следующего сертификата
- при необходимости openssl может создавать тут дополнительные файлы
- private/ - приватные ключи. Один для CA и другой для OCSP-responder'a. Никакие другие пользователи не должны иметь сюда доступ
Root CA Generation
Мы уже выполнили два шага (собрали конфиг и насоздавали папок)
Теперь генерируем ключ и CSR
root@three:~/openssl_ca/root-ca# openssl req -new -config root-ca.conf -out root-ca.csr -keyout private/root-ca.key
Generating a RSA private key
.......................................................................................................................................................++++
.....................................................++++
writing new private key to 'private/root-ca.key'
Enter PEM pass phrase: #test
Verifying - Enter PEM pass phrase: #test
-----
root@three:~/openssl_ca/root-ca# tree
.
├── certs
├── db
│ ├── crlnumber
│ ├── index
│ └── serial
├── private
│ └── root-ca.key
├── root-ca.conf
└── root-ca.csr
И выпускаем самоподписанный серт
openssl ca -selfsign -config root-ca.conf -in root-ca.csr -out root-ca.crt -extensions ca_ext
После подписи index и serial поменялись сами
root@three:~/openssl_ca/root-ca# tree
.
├── certs
│ └── 9A9CCD769CCB72EE9D8280AC4BE7DEAB.pem
├── db
│ ├── crlnumber
│ ├── index
│ ├── index.attr
│ ├── index.old
│ ├── serial
│ └── serial.old
├── private
│ └── root-ca.key
├── root-ca.conf
├── root-ca.crt
└── root-ca.csr
Как видно серт положился и в certs и в корень
Потому что в конфиге написано "класть в certs", а в опции cli указано "-out root-ca.crt"
Structure of the Database File
root@three:~/openssl_ca/root-ca# cat db/index
V 310403100538Z 9A9CCD769CCB72EE9D8280AC4BE7DEAB unknown /C=GB/O=Example/CN=Root CA
База данных это просто текстовый файл
Содержит информацию о сертах
Одна строка - один серт
Каждая строка содержит 6 полей разделенных табами:
- status: V - valid, R - revoked, E - expired
- expiration date: YYMMDDHHMMSSZ
- дата отзыва серта, пусто пока не отозван
- серийник серта
- путь до файла или unknown если не известно
- Distinguished name
Root CA Operations
Для генерации CRL для нового CA используется -gencrl
openssl ca -gencrl -config root-ca.conf -out root-ca.crl
Вот что получается
root@three:~/openssl_ca/root-ca# cat root-ca.crl
-----BEGIN X509 CRL-----
MIICijB0AgEBMA0GCSqGSIb3DQEBCwUAMDExCzAJBgNVBAYTAkdCMRAwDgYDVQQK
DAdFeGFtcGxlMRAwDgYDVQQDDAdSb290IENBFw0yMTA0MDUxMDI1NTRaFw0yMjA0
MDUxMDI1NTRaoA8wDTALBgNVHRQEBAICEAEwDQYJKoZIhvcNAQELBQADggIBAKGK
be+WkQPWgOQX9N/Yenj8WoCylFDRjIW/6lmTBZ6oO18MWRDnRZ1DAzopStILmuq4
SobGg/BggZJnPaSk7aarwPYVSHRCKoyjEeM1ib/qHjcSEHXfE77i6K9fUiQ8zeNY
Czj+/F2lYVDz+fKkHtQBdL6HErpSAyNQXH7EshWORS2uJ9Kto4YgzId0/yUZUIk8
9daHRy1uJzxzlasFoAKDSl8Ht1iEpv5zyD4KV5i+RtEzhrJiwLEd1yQ8N5FNU4X+
A95iuqRUOLugI4iLM9/l9Xbqvv9E9yyCf1JiUntbTBcHJQ7qsyo7QfJ7fFpGx9Em
YhiM1AHOYObmU9cxsoLFk3g5ZAcr2rpEzJHXoKClbVhzRVLzFL+3VkOUpOOF1pEu
23kOy8v45c/gLDQV+qC/gdmbKd+nWTcRZ+lvOyOVjNTqc8S3oyebKEY3VTJ2H8cx
LYTXFy5oSvTYFsqobRCIaF8U+wu18y6N0RsMlrbw8leU+Z9GN/zfuf/Nzsf7vVzg
Dvk0mgsFLD7+z4X8T6Fy33ZZK7qj2cxk+k2ZauEaNajQKBOsLOaddQVn2lHPzRlY
pO402E1EFYaNUhT9FCPRdXsKc8g49YpQQjzolp/flaoJNstlp3Gdy3VBzWAZII5V
+/X2TbZ6aIcSPGA3QnocJZeUP6Wa+5G9mEFjMh/R
-----END X509 CRL-----
А внутри вот так
root@three:~/openssl_ca/root-ca# openssl crl -in root-ca.crl -text -noout
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = GB, O = Example, CN = Root CA
Last Update: Apr 5 10:25:54 2021 GMT
Next Update: Apr 5 10:25:54 2022 GMT
CRL extensions:
X509v3 CRL Number:
4097
No Revoked Certificates.
Signature Algorithm: sha256WithRSAEncryption
a1:8a:6d:ef:96:91:03:d6:80:e4:17:f4:df:d8:7a:78:fc:5a:
80:b2:94:50:d1:8c:85:bf:ea:59:93:05:9e:a8:3b:5f:0c:59:
10:e7:45:9d:43:03:3a:29:4a:d2:0b:9a:ea:b8:4a:86:c6:83:
f0:60:81:92:67:3d:a4:a4:ed:a6:ab:c0:f6:15:48:74:42:2a:
8c:a3:11:e3:35:89:bf:ea:1e:37:12:10:75:df:13:be:e2:e8:
af:5f:52:24:3c:cd:e3:58:0b:38:fe:fc:5d:a5:61:50:f3:f9:
f2:a4:1e:d4:01:74:be:87:12:ba:52:03:23:50:5c:7e:c4:b2:
15:8e:45:2d:ae:27:d2:ad:a3:86:20:cc:87:74:ff:25:19:50:
89:3c:f5:d6:87:47:2d:6e:27:3c:73:95:ab:05:a0:02:83:4a:
5f:07:b7:58:84:a6:fe:73:c8:3e:0a:57:98:be:46:d1:33:86:
b2:62:c0:b1:1d:d7:24:3c:37:91:4d:53:85:fe:03:de:62:ba:
a4:54:38:bb:a0:23:88:8b:33:df:e5:f5:76:ea:be:ff:44:f7:
2c:82:7f:52:62:52:7b:5b:4c:17:07:25:0e:ea:b3:2a:3b:41:
f2:7b:7c:5a:46:c7:d1:26:62:18:8c:d4:01:ce:60:e6:e6:53:
d7:31:b2:82:c5:93:78:39:64:07:2b:da:ba:44:cc:91:d7:a0:
a0:a5:6d:58:73:45:52:f3:14:bf:b7:56:43:94:a4:e3:85:d6:
91:2e:db:79:0e:cb:cb:f8:e5:cf:e0:2c:34:15:fa:a0:bf:81:
d9:9b:29:df:a7:59:37:11:67:e9:6f:3b:23:95:8c:d4:ea:73:
c4:b7:a3:27:9b:28:46:37:55:32:76:1f:c7:31:2d:84:d7:17:
2e:68:4a:f4:d8:16:ca:a8:6d:10:88:68:5f:14:fb:0b:b5:f3:
2e:8d:d1:1b:0c:96:b6:f0:f2:57:94:f9:9f:46:37:fc:df:b9:
ff:cd:ce:c7:fb:bd:5c:e0:0e:f9:34:9a:0b:05:2c:3e:fe:cf:
85:fc:4f:a1:72:df:76:59:2b:ba:a3:d9:cc:64:fa:4d:99:6a:
e1:1a:35:a8:d0:28:13:ac:2c:e6:9d:75:05:67:da:51:cf:cd:
19:58:a4:ee:34:d8:4d:44:15:86:8d:52:14:fd:14:23:d1:75:
7b:0a:73:c8:38:f5:8a:50:42:3c:e8:96:9f:df:95:aa:09:36:
cb:65:a7:71:9d:cb:75:41:cd:60:19:20:8e:55:fb:f5:f6:4d:
b6:7a:68:87:12:3c:60:37:42:7a:1c:25:97:94:3f:a5:9a:fb:
91:bd:98:41:63:32:1f:d1
openssl req -new -config root-ca.conf -out sub-ca.csr -keyout private/sub-ca.key
openssl ca -config root-ca.conf -in sub-ca.csr -out sub-ca.crt -extensions sub_ca_ext
Отзыв делается так
root@three:~/openssl_ca/root-ca# openssl ca -config root-ca.conf -revoke certs/9A9CCD769CCB72EE9D8280AC4BE7DEAC.pem -crl_reason keyCompromise
Using configuration from root-ca.conf
Enter pass phrase for ./private/root-ca.key:
Revoking Certificate 9A9CCD769CCB72EE9D8280AC4BE7DEAC.
Data Base Updated
root@three:~/openssl_ca/root-ca# cat db/index
V 310403100538Z 9A9CCD769CCB72EE9D8280AC4BE7DEAB unknown /C=GB/O=Example/CN=Root CA
R 310403103149Z 210405103713Z,keyCompromise 9A9CCD769CCB72EE9D8280AC4BE7DEAC unknown /C=GB/O=Example/CN=Root CA
Важно указать правильный резон для ревока
Возможные варианты:
- unspecified
- keyCompromise
- CACompromise
- affiliationChanged
- superseded
- cessationOfOperation
- certificateHold
- removeFromCRL
После отзыва перегенерируем CRL
root@three:~/openssl_ca/root-ca# openssl ca -gencrl -config root-ca.conf -out root-ca.crl
Using configuration from root-ca.conf
Enter pass phrase for ./private/root-ca.key:
И видим наш отозванный серт в CRL
root@three:~/openssl_ca/root-ca# openssl crl -in root-ca.crl -text -noout
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = GB, O = Example, CN = Root CA
Last Update: Apr 5 10:40:26 2021 GMT
Next Update: Apr 5 10:40:26 2022 GMT
CRL extensions:
X509v3 CRL Number:
4098
Revoked Certificates:
Serial Number: 9A9CCD769CCB72EE9D8280AC4BE7DEAC
Revocation Date: Apr 5 10:37:13 2021 GMT
CRL entry extensions:
X509v3 CRL Reason Code:
Key Compromise
Signature Algorithm: sha256WithRSAEncryption
77:ca:42:a4:97:08:36:00:ad:ba:6b:f6:ed:a6:a4:7f:e5:2e:
b3:7f:3c:63:7b:a7:83:d0:c5:08:ca:2e:3d:1e:2d:51:f7:97:
cb:2a:30:58:3d:32:57:ab:c0:c5:6e:50:cb:00:04:df:43:73:
99:b1:61:2e:d0:ab:5e:bf:e2:a0:9c:e5:42:b1:8b:b0:ad:be:
88:0d:29:34:81:e5:2e:4e:8a:99:19:ec:89:95:b8:dc:17:46:
28:03:ad:88:15:ca:9d:c8:82:53:53:3a:08:23:ae:40:3a:09:
bb:02:cb:9d:c4:45:01:07:4a:0c:d6:58:11:82:5a:4b:13:9d:
49:53:8a:51:10:90:8f:1d:bd:da:34:b4:b2:f3:46:94:84:d0:
05:10:c9:2e:90:be:12:0a:f6:36:de:14:ec:12:d0:f3:5e:9c:
37:ec:57:21:6c:79:dc:45:7b:62:c0:85:26:19:0a:4e:dc:47:
Create a Certificate for OCSP Signing
Выпускаем CSR
openssl req -new -newkey rsa:2048 -subj "/C=GB/O=Example/CN=OCSP Root Responder" -keyout private/root-ocsp.key -out root-ocsp.csr
Подписываем его рутовым сертом
openssl ca -config root-ca.conf -in root-ocsp.csr -out root-ocsp.crt -extensions ocsp_ext -days 30
Лайфтайм уменьшен до 30 дней в отличие от дефолтных 3650 дней потому что этот серт не имеет revocation information и не может быть отозван
Поэтому чем меньше тем лучше
Вот доказательство того что он не может быть отозван
root@three:~/openssl_ca/root-ca# openssl x509 -in sub-ca.crt -noout -ext crlDistributionPoints
X509v3 CRL Distribution Points:
Full Name:
URI:http://root-ca.example.com/root-ca.crl
root@three:~/openssl_ca/root-ca# openssl x509 -in root-ocsp.crt -noout -ext crlDistributionPoints
root@three:~/openssl_ca/root-ca#
Теперь мы имеем все для старта ocsp responder'a
По-уму респондерские серты и ключи нужно уносить с CA на отдельную машину
Но в тестовых целях это не важно
Запускаем респондера
openssl ocsp -port 9080 -index db/index -rsigner root-ocsp.crt -rkey private/root-ocsp.key -CA root-ca.crt -text
Он начинает слушать порт и писать лог в stdout
Дергаем его из сосендей консоли
root@three:~/openssl_ca/root-ca# openssl ocsp -issuer root-ca.crt -CAfile root-ca.crt -cert sub-ca.crt -url http://localhost:9080
Response verify OK
sub-ca.crt: good
This Update: Apr 5 11:11:43 2021 GMT
Получаем ответ что все ок
Отзываем только что проверенный серт
root@three:~/openssl_ca/root-ca# openssl ca -config root-ca.conf -revoke certs/9A9CCD769CCB72EE9D8280AC4BE7DEAF.pem -crl_reason keyCompromise
Using configuration from root-ca.conf
Enter pass phrase for ./private/root-ca.key:
Revoking Certificate 9A9CCD769CCB72EE9D8280AC4BE7DEAF.
Data Base Updated
Перегенерируем CRL
root@three:~/openssl_ca/root-ca# openssl ca -gencrl -config root-ca.conf -out root-ca.crl
Using configuration from root-ca.conf
Enter pass phrase for ./private/root-ca.key:
Проверяем снова и видим что он отoзван
root@three:~/openssl_ca/root-ca# openssl ocsp -issuer root-ca.crt -CAfile root-ca.crt -cert sub-ca.crt -url http://localhost:9080
Response verify OK
sub-ca.crt: revoked
This Update: Apr 5 11:13:33 2021 GMT
Reason: keyCompromise
Revocation Time: Apr 5 11:12:32 2021 GMT
Creating a Subordinate CA
За основу конфига для sub-ca можно взять конфиг корневого ca и изменить некоторые поля
[default]
name = sub-ca
ocsp_url = http://ocsp.$name.$domain_suffix:9081
[ca_dn]
countryName = "GB"
organizationName = "Example"
commonName = "Sub CA"
[ca_default]
default_days = 365
default_crl_days = 30
copy_extensions = copy
В конец добавляем два новых профиля
[server_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,digitalSignature,keyEncipherment
subjectKeyIdentifier = hash
[client_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
Они отличаются только keyUsage и extendedKeyUsage
Далее можно генерить csr и подписывать его рутовым сертом
openssl req -new -config sub-ca.conf -out sub-ca.csr2 -keyout private/sub-ca.key2
openssl ca -config root-ca.conf -in sub-ca.csr2 -out sub-ca.crt2 -extensions sub_ca_ext
Subordinate CA Operations
Теперь можно подписывать клиентские серты
openssl ca \
-config sub-ca.conf \
-in server.csr \
-out server.crt \
-extensions server_ext # здесь можно указывать нужную директиву из конфига (server_ext, client_ext)
Генерация CRL и отзыв сертов делается аналогично тому что было описано выше для рутового CA
OpenSSL Config
Заметки по man config
Description
Конфигурационный файл разделен на несколько секций
Каждая секция начинается со строки [ section_name ]
и заканчивается началом новой секции или концом файла
Имя секции может содержать буквы, цифры и подчеркивание
Первая секция обычно дефолтная и начинается от начала файла до первой именованой секции
Окружение мапится на секцию ENV
Комменты пишутся через решетку
Можно делать импорты через .include filename
Дефолтный конфиг /usr/lib/ssl/openssl.cnf
В инклудах рекомендуется использовать абсолютные пути, потому что относительные пути будут меняться в зависимости от приложения и в итоге не будут работать как ожидается
Каждая секция содержит некоторое количество пар name=value
name содержит цифробуквы и может содержать знаки: .
, ,
, ;
, _
Поле value умеет раскрывать переменные если они указаны через доллар $var
и ${var}
Переменная заменится на значение ключа из текущей секции
Можно также подставлять значения из других секций, это делается так $section::name
или ${section::name}
Через $ENV::var
можно подставлять переменные окружения
Также можно использовать ENV::name
для назначения значений переменным окружения, но это будет работать только если программа использует библиотеку CONF для поиска переменных окружения вместо вызова getenv
value не должно превышать 64к в длину после раскрытия всех переменных, иначе все сломается
Есть возможность пропускать некоторые символы используя какие-то кавычки или \
Например бэкслеш в конце строки позволяет сделать value многострочным
Также можно использовать \n
, \r
, \b
, \t
Описанные выше правила экранирования и разворачивания применимы и к .include
OpenSSL Library Configuration
Разные приложения могут ориентироваться на конфиги openssl
Например cli команды OpenSSL смотрят в мастер конфиг (дефолтный) (если не указана опция смотреть в какой-то другой)
В конфиге можно задать парметры для библиотеки
В дефолтной секции должно содержаться имя openssl_conf
в значении которого указывается имя главной конф. секции
Некоторые приложения могут ориентироваться на какое-то другое имя вместо openssl_conf
Ключ отображает имя конфигурируемого модуля, а возможное значение зависит от этого модуля
ASN1 Object Configuration Module
Этот модуль имеет имя oid_section
Это имя указывает на секцию в которой содержатся пары oid'ов
Например
openssl_conf = openssl_init
[openssl_init]
oid_section = new_oids
[new_oids]
some_new_oid = 1.2.3.4
some_other_oid = 1.2.3.5
shortName = some object long name, 1.2.3.6
Engine Configuration Module
Этот модуль имеет имя engines
которое ссылается на секцию в которой содержится конфигурационная информация движков
Эта секция представляет из себя таблицу из имен движков и секций описывающих эти движки
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
# Configure ENGINE named "foo"
foo = foo_section
# Configure ENGINE named "bar"
bar = bar_section
[foo_section]
... foo ENGINE specific commands ...
[bar_section]
... "bar" ENGINE specific commands ...
ENGINE specific commands:
- engine_id - позволяет задать (переопределить) engine-name
- dynamic_path - подгружает engine из указанного пути
- init - нужно ли инициализировать этот engine
- default_algorithms - определяет дефолтные алгоритмы
[engine_section]
# Configure ENGINE named "foo"
foo = foo_section
[foo_section]
# Load engine from DSO
dynamic_path = /some/path/fooengine.so
# A foo specific ctrl.
some_ctrl = some_value
# Another ctrl that doesn't take a value.
other_ctrl = EMPTY
# Supply all default algorithms
default_algorithms = ALL
EVP Configuration Module
Этот модуль имеет имя alg_section
и указывает на секцию с командами алгоритмов
На текущий момент имеется только одна команда: fips_mode
(принимает on\off)
Если fips включен, но библиотека не поддерживает fips, то все свалится с ошибкой
SSL Configuration Module
Этот модуль имеет имя ssl_conf
и указывает на секцию с ssl конфигурацией
Каждая строка в этой секции содержит имя конфигурации и секцию содержащую ее
ssl_conf = ssl_sect
[ssl_sect]
server = server_section
[server_section]
RSA.Certificate = server-rsa.pem
ECDSA.Certificate = server-ecdsa.pem
Ciphers = ALL:!RC4
Дефолтная секция
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
Notes
Если в конфиге указано развернуть переменную окружения которой не существует, то все свалится с ошибкой
Например предыдущие версии openssl использовали в дефолтном конфиге перенную HOME, а в non-Unix системах ее нет
Это можно обойти указывая в дефолтной секции дефолтные значения
И когда поиск в окружении сфейлится, будет использовано дефолтное значение
Но нужно чтобы место определения дефолтного значения в конфиге было раньше чем место вызова переменной
Пример безопасного использования переменной окружения
TMP=/tmp
TEMP=$ENV::TMP
tmpfile=${ENV::TEMP}/tmp.filename
Если в рамках одной секции несколько раз описывается одна и та же переменная, то засчитается только последнее описание
PKI
https://pki-tutorial.readthedocs.io/en/latest/
Testing with OpenSSL
OpenSSL имеет встроенную клиентскую утилиту для подключения к защищенным серверам
openssl s_client -connect server.com:443
Она похожа на telnet или nc
Позволяет контролировать следующий за SSL/TLS уровень
На вход требует сервер и порт
Пример
Дернем страничку через TELNET
root@three:~# telnet example.com 80
Trying 93.184.216.34...
Connected to example.com.
Escape character is '^]'.
GET / HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
...
Content-Length: 1256
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...
<style type="text/css">
body {
background-color: #f0f0f2;
...
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
^CConnection closed by foreign host.
То же самое через S_CLIENT
root@three:~# openssl s_client -connect example.com:443
CONNECTED(00000003)
... # разная отладачная инфа про серты
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, CN = www.example.org
issuer=C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
---
... # еще какая-то инфа
---
SSL handshake has read 4654 bytes and written 719 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
...
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
...
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
...
---
read R BLOCK ### И наконец полезная инфа (делаем свой запрос)
GET / HTTP/1.1
Host: example.com
HTTP/1.1 200 OK # (получаем ответ)
... # headers
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta cha...
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
^C
остановился на странице 49
CA,CSR,CRT
CA
openssl req -sha256 -new -x509 -days 365 -nodes -out server-ca.crt -keyout server-ca.key
CSR
openssl req -sha256 -new -nodes -subj "/CN=two.vandud.ru" -out server.csr -keyout server.key
Sign CSR
root@two:~# openssl x509 -req -sha256 -days 365 -in server.csr -CA server-ca.crt -CAkey server-ca.key -CAcreateserial -out server.crt
Signature ok
subject=CN = two.vandud.ru
Getting CA Private Key
LVS
jq
https://stedolan.github.io/jq/manual/
Certbot
Сертбот нужно запускать от рута, потому что ему нужно запускать свои скрипты и иметь доступ к директориям с сертами
Требуется:
- python3.6+
- root доступ в
/etc/letsencrypt
,/var/log/letsencrypt
,/var/lib/letsencrypt
- возможно биндиться на 80 порт в случае использования standalone режима
- возможность чтения и редактирования конфига вебсервера в случае использования nginx/apache плагина
Если эти требования невыполнимы, то можно воспользоваться letsencrypt_nosudo или simp_le
Certbot можно установить через пакетный менеджер твоей ОС, snap или docker (крайне не рекомендуется, потому что сложно)
Обычно достаточно apt install certbot
Есть пакеты которые помогают certbot'у интегрироваться с apache/nginx и прочими сервисами
root@four:~# apt-cache search certbot | grep -v doc
certbot - automatically configure HTTPS using Let's Encrypt
python3-certbot - main library for certbot
python3-certbot-apache - Apache plugin for Certbot
python3-certbot-dns-cloudflare - Cloudflare DNS plugin for Certbot
python3-certbot-dns-digitalocean - DigitalOcean DNS plugin for Certbot
python3-certbot-dns-dnsimple - DNSimple DNS plugin for Certbot
python3-certbot-dns-gandi - Gandi LiveDNS plugin for Certbot
python3-certbot-dns-gehirn - Gehirn DNS plugin for Certbot
python3-certbot-dns-google - Google DNS plugin for Certbot
python3-certbot-dns-linode - Linode DNS plugin for Certbot
python3-certbot-dns-ovh - OVH DNS plugin for Certbot
python3-certbot-dns-rfc2136 - RFC 2136 DNS plugin for Certbot
python3-certbot-dns-route53 - Route53 DNS plugin for Certbot
python3-certbot-dns-sakuracloud - SakuraCloud DNS plugin for Certbot
python3-certbot-nginx - Nginx plugin for Certbot
Также можно установить через pip
Сертбот использует некоторое количество различных подкомманд для запроса различных действий: выпуск, перевыпуск, отзыв
Сертбот имеет два вида плагинов: аутентификаторы и инсталлеры
Аутентификаторы используются с командой certonly
для получения сертификата:
- Проверяют что ты контролируешь домен для которого запрашиваешь сертификат
- Получают сертификат
- Кладут его в
/etc/letsencrypt
Инсталлеры используются с командой install
для установки, и они уже могут модифицировать конфигурацию вебсервера
Плагины делающие и то и то вызываются через certbot run
(run
- дефолт, если не указана другая подкоманда). Так же в команде run
можно определять четкие комбинации плагинов auth&install
Plugin | Auth | Inst | Notes | Use |
---|---|---|---|---|
apache | Y | Y | Получение и установка сертификата для apache | --apache |
nginx | Y | Y | Получение и установка сертификата для nginx | certbot --nginx |
webroot | Y | N | Получение сертификата через запись в webroot запущенного вебсервера |
certonly --webroot \ --webroot-path PATH
|
standalone | Y | N | Получение сертификата. Certbot вешается на 80 порт и таким образом проводит auth | certonly --standalone |
DNS plugins | Y | N | Категория плагинов автоматизирующих получение сертификата через изменение DNS записей для подтверждения контроля над доменом. Это единственный способ получить wildcard сертификат | |
manual | Y | N | Помогает получить сертификат давая инструкции для самостоятельной валидации домена. Позволяет использовать скрипты | certonly --manual |
Под капотом плагины используют один из нескольких acme протоколов для подтверждения контроля над доменом
Некоторые плагины поддерживает больше одного и тогда можно указать предпочитаемый через --preferred-challenges
Каждый домен будет использовать последний определенный перед ним webroot
certbot certonly --webroot -w /var/www/example -d www.example.com -d example.com \
-w /var/www/other -d other.example.net -d another.other.example.net
Команда выше создаст один серт на все перечисленные домены. Если нужны раздельные серты, то команду нужно запускать несколько раз
webroot плагин создает временный файл для каждого запрошенного домена в ${webroo-path}/.well-known/acme-challenge/
А проверяющий сервер lets encrypt сделает запрос до этого временного файла
"GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1"
Важно чтобы скрытая папка .well-known
и ее содержимое было доступно через интернет для проверки (может потребоваться править конфиг вебсервера)
Плагин nginx корректно работает для большинства конфигураций, но нужно делать бэкап конфигов (несмотря на то что сертботовские изменения можно откатить через certbot --nginx rollback
)
standalone режим позволяет получить сертификат не полагаясь на существующий вебсервер
Плагин вешается на 80/443 порт и сам становится вебсервером
--<challenge-type>-address
позволяет указать интерфес и протокол на который нужно биндиться
Если нужно получить wildcard сертификат или сертбот запускается на сервере с которого нельзя провести проверку через webroot, то можно воспользоваться dns плагинами
Эти плагины устанавливаются отдельно и у них свои доки
manual плагин умеет http и dns проверку, можно указать желаемую через --preferred-challenges
Это то же самое что и автоматическая проверка, только не автоматическая
Проверка по http попросит положить временный файл в well-known сайта
А проверка по dns попросит добавить TXT запись
manual плагину можно указывать на скрипты предподготовки и очистки мусора после получения сертификата
Иногда нужно четко определить auth и install плагины, это можно делать через ключи
-
--authenticator/-a
- auth plugin -
--installer/-i
- installer plugin
Пример
certbot run -a webroot -i apache -w /var/www/html -d example.com
Или можно пройти проверку вручную, а установить через плагин nginx (но автоматически такое не продлить)
Пример полной процедуры
root@four:~# certbot run -a manual -i nginx -d four.vandud.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): s@vandud.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for four.vandud.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:
bBGyo54bGqOsHD0tj9javAZLxoh6L4_OJHqY4cDadmg._OridQhxi5LDrFVF7NMSrzUfVRDYUuSXKz7wSkmQWYg
And make it available on your web server at this URL:
http://four.vandud.ru/.well-known/acme-challenge/bBGyo54bGqOsHD0tj9javAZLxoh6L4_OJHqY4cDadmg
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/default
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/default
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://four.vandud.ru
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=four.vandud.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/four.vandud.ru/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/four.vandud.ru/privkey.pem
Your cert will expire on 2021-08-12. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
root@four:~#
Чтобы отобразить список сертификатов о которых знает сертбот нужно запустить подкоманду certificates
root@four:~# certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: four.vandud.ru
Domains: four.vandud.ru
Expiry Date: 2021-08-12 21:07:09+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/four.vandud.ru/fullchain.pem
Private Key Path: /etc/letsencrypt/live/four.vandud.ru/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Поле 'Certificate Name' содержит имя сертификата, которое можно использовать для перевыпуска (сертбот возьмет всю инфу из старого серта и перевыпустит)
--force-renewal
, --duplicate
и --expand
контролируют поведение при пересоздании с существующим именем сертификата
-
--force-renewal
- позволит перевыпустить раньше чем надо -
--duplicate
- создать новый независимый сертификат с доменами из указанного -
--expand
- перевыпустить старый серт и добавить новые домены
Рекомендуется использовать --cert-name
вместо --expand
, потому что больше контроля
Есть ограничение скорости перевыпуска сертификатов
Оно нужно для ограничения злоупотребления сервисом
Лимиты описаны здесь: https://letsencrypt.org/docs/rate-limits/
--cert-name
позволяет модифицировать домены в сертификате
Например команда:
certbot certonly --cert-name example.com -d example.com
Перевыпустит сертификат example.com в котором два домена (example.com и www.example.com) только с example.com (уберет www.)
Сертбот поддерживате два типа приватных ключей: rsa и ecdsa
Через --key-type
и --elliptic-curve
можно этим управлять
Для отзыва нужно использовать подкоманду revoke
То какой сертификат отзывать, указывается двумя способами
-
--cert-name
- имя сертификата изcertbot certificates
-
--cert-path
- путь до файла сертификата
Также при отзыве можно указать причину отзыва во флаге --reason
-
unspecified
- default keycompromise
affiliationchanged
superseded
cessationofoperation
По умолчанию сертбот для отзыва сертификата использует acme account key. Если сертификат был создан с того же аккаунта что и удаляется, то все получится
А если аккаунты разные, то для отзыва потребуется передать команде revoke
еще и приватный ключ сертификата через --key-path
certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem \
--key-path /etc/letsencrypt/live/example.com/privkey.pem
Если запустить команду certbot renew
, то она попытается обновить сертификаты которые истекают меньше чем через 30 дней
renew
в отличие от certonly
изначально дизайнилась для автоматического использования и она может взаимодействовать сразу с множеством сертификатов
У renew
есть pre и post хуки. Они позволяют выполнять команды до перевыпуска и после (например релоадить вебсервер)
--pre-hook "nginx -s stop"
--post-hook "nginx -s start"
Если хук свалится с ошибкой, то ошибка будет напечатана на экран, но обновление все равно продолжится
-
--deploy-hook
- выполнится только после успешного обновления сертификата
/etc/letsencrypt
- директория с конфигами сертбота
root@four:/etc/letsencrypt# tree -a
.
|-- accounts
| `-- acme-v02.api.letsencrypt.org
| `-- directory
| `-- 1da4ab1e38f6367e285fbd28fc2ae0ca
| |-- meta.json
| |-- private_key.json
| `-- regr.json
|-- archive
| `-- four.vandud.ru
| |-- cert1.pem
| |-- chain1.pem
| |-- fullchain1.pem
| `-- privkey1.pem
|-- cli.ini
|-- csr
| `-- 0000_csr-certbot.pem
|-- keys
| `-- 0000_key-certbot.pem
|-- live
| |-- four.vandud.ru
| | |-- cert.pem -> ../../archive/four.vandud.ru/cert1.pem
| | |-- chain.pem -> ../../archive/four.vandud.ru/chain1.pem
| | |-- fullchain.pem -> ../../archive/four.vandud.ru/fullchain1.pem
| | |-- privkey.pem -> ../../archive/four.vandud.ru/privkey1.pem
| | `-- README
| `-- README
|-- options-ssl-nginx.conf
|-- renewal
| `-- four.vandud.ru.conf
|-- renewal-hooks
| |-- deploy
| |-- post
| `-- pre
|-- ssl-dhparams.pem
|-- .updated-options-ssl-nginx-conf-digest.txt
`-- .updated-ssl-dhparams-pem-digest.txt
Некоторые выполняемые файлы могут быть найдены в renewal-hooks
Хуки из этих папок (deploy,post,pre) только для renew
и выполняются в алфавитном порядке
Это поведение выключается ключом --no-directory-hooks
Если команда certbot renew
выполняется корректно и без вмешательста человека, то ее можно засунуть в cron
Если сертификат выпускается через certbot certonly
в котором через ключ -d
перечисляется все домены, то можно использовать ключ -n/--nonenteractive
чтобы отключить запрос пользовательского ввода
--force-renewal
- позволяет обновить серт игнорируя дату истечения (раньше чем за месяц обновить нельзя)
Это сделано специально, потому что у УЦ есть лимиты, и если все будут перевыпускать серты каждый день, то у УЦ что-то закончится
ЦА отправит алерт на почту если сертификат не будет продлен
Linux hostname (как правильно изменить)
Чтобы было так
root@anxiety:~# hostname
anxiety
root@anxiety:~# hostname -f
anxiety.vandud.ru
Нужно сделать так
root@anxiety:~# cat /etc/hostname
anxiety
root@anxiety:~# cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 anxiety.vandud.ru anxiety
...
При загрузке системы из файла /etc/hostname
хостнейм положится в /proc/sys/kernel/hostname
Дальше утилиты типа hostname
используют именно имя из /proc
root@anxiety:~# hostname test
root@anxiety:~# cat /proc/sys/kernel/hostname
test
root@anxiety:~# hostname
test
А hostname -f
берет инфу из файла /etc/hosts
Он находит в файле /etc/hosts
подходящую строку и берет из нее первый хостнейм
root@anxiety:~# hostname
test
root@anxiety:~# hostname -f
testtesttest
root@anxiety:~# cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 testtesttest anxiety.vandud.ru anxiety test
...
В примере выше он нашел последнее имя test
и как полное имя взял первое testtesttest
Кстати hostnamectl
покажет какое имя статическое, а какое временное
root@anxiety:~# hostnamectl
Static hostname: anxiety
Transient hostname: test
Icon name: computer-vm
Chassis: vm
Machine ID: ec697124f3421da2bd81ecfae2cab1fc
Boot ID: f47d3ce45e3642c3a30e2ca26902264a
Virtualization: kvm
Operating System: Debian GNU/Linux 11 (bullseye)
Kernel: Linux 5.10.0-20-amd64
Architecture: x86-64
Можно сделать и так
root@anxiety:~# echo 'vandud' > /proc/sys/kernel/hostname
root@anxiety:~# hostname
vandud
Своя инфраструктура
Имеется 3 машины:
hostname | ipv4 | ipv6 | cpu | mem | disk |
---|---|---|---|---|---|
anxiety.vandud.ru | 77.91.123.180 | 2a09:7c44:0:2c::1 2a09:7c44:0:2c:: |
4 | 8 | 80 |
blame.vandud.ru | 77.91.123.182 | 2a09:7c44:0:53::1 2a09:7c44:0:53:: |
4 | 8 | 80 |
contempt.vandud.ru | 77.91.123.184 | 2a09:7c44:0:55::1 2a09:7c44:0:55:: |
4 | 8 | 80 |
one.vandud.ru | 51.178.9.167 | - | 1 | 1 | 25 |
Reproxy
Reproxy это простой edge HTTP(s) сервер / reverse proxy поддерживающий множество провайдеров (docker, static, file, consul catalog). Один или более провайдеров предоставляют информацию о запрашиваемых серверах, запрашиваемых URL, конечных URL и health check URL. Он распрастраняется в виде одиночного бинарного файла или как docker image
- Automatic SSL termination with Let’s Encrypt
- Support of user-provided SSL certificates
- Simple but flexible proxy rules
- Static, command-line proxy rules provider
- Dynamic, file-based proxy rules provider
- Docker provider with an automatic discovery
- Consul Catalog provider with discovery by service tags
- Support of multiple (virtual) hosts
- Optional traffic compression
- User-defined size limits and timeouts
- Single binary distribution
- Docker container distribution
- Built-in static assets server with optional “SPA friendly” mode
- Support for redirect rules
- Optional limiter for the overall activity as well as for user’s activity
- Live health check and fail-over/load-balancing
- Management server with routes info and prometheus metrics
- Plugins support via RPC to implement custom functionality
- Optional logging with both Apache Log Format, and simplified stdout reports.
Сервер (host) может быть указан как FQDN (s.example.com
, *
(catch all)) или как регулярное выражение. Приоритетнее будет полное совпадение, так, если у нас будет два правила с серверами example.com
и example\.(com|org)
, то запрос example.com/some/url
уйдет на первый сервер. Запрашиваемый URL тоже может быть указан как регулярное выражение, например ^api/(.*)
, а конечный URL может содержать группы из регулярного выражения запрашиваемого URL, например http://d.example.com:8080/$1
. В итоге http://s.example.com/api/something?foo=bar
будет отпроксирован в http://d.example.com:8080/something?foo=bar
Для удобства, запросы с /
на конце и без regex группы автоматически расширяются до /(.*)
, а конечные URL в таком случае расширяются до /$1
. То есть /api/
-> http://localhost/service
будет переведен в ^/api/(.*)
-> http://localhost/service/$1
Поддерживается как HTTP так и HTTPS. Для HTTPS могут быть использованы как статичные (пользовательские) сертификаты, так и автоматически выпущенные через ACME (Let's Encrypt). Опциональный сервер ассетов может быть использован для раздачи статических файлов. Чтобы запустить Reproxy нужен как минимум один провайдер. Остальные параметры опциональны и имеют разумные дефолтные значения
Примеры:
- with a static provider:
reproxy --static.enabled --static.rule="example.com/api/(.*),https://api.example.com/$1"
- with an automatic docker discovery:
reproxy --docker.enabled --docker.auto
- as a docker container:
docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto
- with automatic SSL:
docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com
Install
Reproxy распространяется как маленький сдержанный бинарный файл, а также как docker image. И бинарь и докер имадж поддерживают множество архитектур и множество ОС, также есть deb/rpm пакеты
- бинарь может быть скачан с https://github.com/umputun/reproxy/releases
- имадж доступен на https://hub.docker.com/r/umputun/reproxy и на https://github.com/users/umputun/packages/container/reproxy/versions
Providers
Правила проксирования предоставляются провайдерами. Сейчас в приложение включены - file
, docker
, static
и consul-catalog
. Каждый провайдер может предоставлять множество правил роутинга и для проксируемых запросов и для раздачи статики (assets). Пользователь может указывать множество провайдеров одновременно
Static provider
Это простейший провайдер который указывает правила прямо в командной строке (или через переменные окружения). Поддерживается возможность указания множества правил. Каждое правило это 3 или 4 разделенных запятой элемента server,sourceurl,destination[,ping-url]
. Например:
*,^/api/(.*),https://api.example.com/$1
- proxy all request to any host/server with/api
prefix tohttps://api.example.com
example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping
- proxy all requests toexample.com
and with/foo/bar
url tohttps://api.example.com/zzz
and it seeshttps://api.example.com/ping
for the health check
Последний (четвертый) элемент определяет опциональный ping url
File provider
Этот провайдер использует yaml файл с правилами роутинга
reproxy --file.enabled --file.name=config.yml
Пример конфига:
default: # the same as * (catch-all) server
- { route: "^/api/svc1/(.*)", dest: "http://127.0.0.1:8080/blah1/$1" }
- {
route: "/api/svc3/xyz",
dest: "http://127.0.0.3:8080/blah3/xyz",
ping: "http://127.0.0.3:8080/ping",
}
srv.example.com:
- { route: "^/api/svc2/(.*)", dest: "http://127.0.0.2:8080/blah2/$1/abc" }
- { route: "^/web/", dest: "/var/www", "assets": true }
Изменения в файле подтягиваются автоматически
Docker provider
https://reproxy.io/#docker-provider
Consul Catalog provider
https://reproxy.io/#consul-catalog-provider
Compose-specific details
https://reproxy.io/#compose-specific-details
SSL support
Режим работы по SSL может быть выставлен в auto
(ACME/LE сертификаты), static
(существующие сертификаты) или none
(по умолчанию none
). Если стоит auto
, то сертификаты будут выпущены автоматически для всех найденных server names. Пользователь может изменить это поведение явно указав нужные домены в --ssl.fqdn
Headers
Reproxy позволяет удалять входящие заголовки с помощью опции --drop-header
которая может быть указана множество раз. Этот параметр может быть полезен чтобы быть уверенным что некоторые заголовки установлены внутренними сервисами, а не подсунуты пользователем. Например, если какой-то из сервисов ответственный за аутентификацию подставляет заголовки X-Auth-User
и X-Auth-Token
, то может быть полезно удалять такие заголовки у входящих от пользователей запросов, это можно делать так --drop-header=X-Auth-User --drop-header=X-Auth-Token
или через переменную окружения DROP_HEADERS=X-Auth-User,X-Auth-Token
Также доступна противополжная функция подстановки заголовков в исходящие ответы. Это можно делать с помощью параметра --header
который можно указывать много раз или через переменную HEADER
Пример того как это выглядит в docker-compose:
environment:
- HEADER=
X-Frame-Options:SAMEORIGIN,
X-XSS-Protection:1; mode=block;,
Content-Security-Policy:default-src 'self'; style-src 'self' 'unsafe-inline';
Logging
По умолчанию запросы не логируются, но это поведение можно изменить с помощью опции --logger.enabled
. Лог ротируется автоматически и имеет Apache Combined Log Format
С помощью опции --logger.stdout
можно сказать Reproxy выводить краткий лог зарпосов в stdout (это не влияет на логирование в файл, а просто добавляет краткий лог в stdout)
Assets Server
Пользователь может включить сервер ассетов для обслуживания запросов к статике (по умолчанию он выключен). Пока установлен параметр --assets.location
он будет пытаться обработать запросы по пути assets.root
как запросы к статике (assets.root - часть урла, assets.location - путь до файлов). Сервер ассетов может быть использован без каких-либо провайдеров, в этом режиме Reproxy работает как простой web-server для раздачи статического контента. Также есть режим SPA который можно включить параметром --assets.spa
, в таком случае каждый запрос к ненайденному файлу будет перенаправляться на index.html
В дополнение к основному серверу статики поддерживается множество кастомных. Каждый провайдер имеет собственный вариант указания его, а некоторые провайдеры его и вовсе не имеют
- static provider - if source element prefixed by
assets:
orspa:
it will be treated as file-server. For example*,assets:/web,/var/www,
will serve all/web/*
request with a file server on top of/var/www directory
- file provider - setting optional fields
assets: true
orspa: true
- docker provider -
reproxy.assets=web-root:location
, i.e.reproxy.assets=/web:/var/www
. Switching to spa mode done by settingreproxy.spa
toyes
ortrue
Caching
Сервер ассетов имеет контроль кэширования, который задается через опцию --assets.cache=<duration>
. 0s
в этой опции отключит кэширование. <duration>
это последовательность десятичных чисел, которые могут дробными и имеют суффикс обозначающий величину, например “300ms”, “1.5h” или “2h45m”. Валидные суффиксы: “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h” и “d”
Есть два варианта указания длительности кэширования:
- A single value for all static assets. This is as simple as
--assets.cache=48h
- Custom duration for different mime types. It should include two parts - the default value and the pairs of mime:duration. In command line this looks like multiple
--assets.cache
options, i.e.--assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h
. Environment values should be comma-separated, i.e.ASSETS_CACHE=48h,text/html:24h,image/png:2h
Кастомная страница для ответа 404 может быть задана через опцию --assets.404=<path>
. Этот путь указывается относительно пути assets root
Using reproxy as a base image
https://reproxy.io/#using-reproxy-as-a-base-image
SPA-friendly mode
Некоторые SPA приложения полагаются на прокси для обработки 404 особым способом - перенаправляя на /index.html
. Это похоже на nginx'овую директиву try_files $uri $uri/ ...
и предположительно эта функция что-то важное для современных web приложений
По умолчанию в Reproxy эта функция выключена, но может быть включена с помощью --assets.spa
или ASSETS_SPA=true
Redirects
По умолчанию Reproxy пробует destination как proxy location, то есть делает внутренний http запрос и возвращает ответ клиенту
Однако это поведение можно изменить префиксируя destination url с помощью @code
. Таким образом если указать @301 https://example.com/something
, то получим редирект на Location: https://example.com/something
Поддерживаемые коды:
@301
,@perm
- permanent redirect@302
,@temp
,@tmp
- temporary redirect
More options
--gzip
enables gzip compression for responses.--max=N
allows to set the maximum size of request (default 64k). Setting it to0
disables the size check.--timeout.*
various timeouts for both server and proxy transport. Seetimeout
section in All Application Options. A zero or negative value means there will be no timeout.
Default ports
Чтобы избежать необходимости прописывать кастомные параметры/окружения, дефолтный --listen
- динамичный, он пытается быть разумным и полезным для типичных кейсов:
- If anything set by users to
--listen
all the logic below ignored and host:port passed in and used directly. - If nothing set by users to
--listen
and reproxy runs outside of the docker container, the default is127.0.0.1:80
for http mode (ssl.type=none
) and127.0.0.1:443
for ssl mode (ssl.type=auto
orssl.type=static
). - If nothing set by users to
--listen
and reproxy runs inside the docker, the default is0.0.0.0:8080
for http mode, and0.0.0.0:8443
for ssl mode.
Another default set in the similar dynamic way is --ssl.http-port
. For run inside of the docker container it set to 8080
and without to 80
.
Ping, health checks and fail-over
Reproxy предоставляет два эндпоинта для этих целей:
/ping
responds with pong and indicates what reproxy up and running/health
returns200 OK
status if all destination servers responded to their ping request with200
or417 Expectation Failed
if any of servers responded with non-200 code. It also returns json body with details about passed/failed services.
В дополнение к эндпоинтам выше, Reproxy поддерживает проверки в реальном времени. В таком случае (если они включены) каждый конечный url периодически проверяется на ping ответ и в случае ошибки исключается из роутинга. Это дает возможность возвращать множество идентичных конечных url из одного или множества провайдеров, и будут выбраны только прошедшие проверки. Если множество подходящих было обнаружено и проверки были пройдены - только один будет использоваться в соответствии со стратегией lb-type
(по умолчанию случайный выбор)
Чтобы включить проверки в реальном времени, пользователю нужно указать --health-check.enabled
(или через переменную HEALTH_CHECK_ENABLED=true
). Для кастомизации интервала - --health-check.interval=
Management API
Опционально с помощью флага --mgmt.enabled
можно включить два эндпоинта которые будут доступны на mgmt.listen
:
GET /routes
- list of all discovered routesGET /metrics
- returns prometheus metrics (http_requests_total
,response_status
andhttp_response_time_seconds
)
Errors reporting
Reproxy вернет 502 (Bad Gateway) в случае если запрос не матчится ни на один имеющийся роут или ассет. В случае неожиданных внутренних ошибок он вернет 500. По умолчанию он рендерит простейшую текстовую версию страницы ошибки - "Server error". Настройка --error.enabled
включит дефолтную html страницу, а с помощью --error.template
пользователь может установить любой кастомный html шаблон для ошибок. В таком темплейте будут доступны две переменные {{.ErrCode}}
и {{.ErrMessage}}
Например шаблон oh my! {{.ErrCode}} - {{.ErrMessage}}
будет отрендерен в oh my! 502 - Bad Gateway
Throttling
Reproxy позволяет задать ограничение в max req/sec как для всей системы, так и для пользователей. Значение 0
воспринимается как - неограничено
Ограничение на пользовательскую активность (запросы) распространяется как на сматченные, так и несматченные роуты. Все несматченные роуты рассматриваются как "single destination group" и ограничиваются в rate*3
. Это значит что если указано --throttle.user=10
то конечный пользователь сможет делать вплоть до 30 запросов в секунду на какие-то статические ассеты или несматченные роуты. Для сматченных роутов это ограничение выставляется per destination, таким образом запросы проксируемые на s1.example.com/api будут ограничены 10r/s, а запросы проксируемые на s2.example.com будут ограничены другими 10r/s
Basic auth
Reproxy поддерживает Basic Auth для всех запросов. Это полезно для защиты эндпоинтов которые находятся в разработке или тестировании до запуска их в публичный доступ. Эта функция выключена по умолчанию и не достаточно гранулярна для настройки ее на каждый роут отдельно
Таким образом включенный Basic Auth будет влиять на все запросы
Чтобы включить Basic Auth для всех запросов пользователю нужно указать типичный htpasswd файл в опции --basic-htpasswd=<file location>
или с помощью переменной BASIC_HTPASSWD=<file location>
Reproxy ожидает htpasswd файл в следующем формате:
username1:bcrypt(password2)
username2:bcrypt(password2)
...
Его можно сгенерировать с помощью htpasswd -nbB
Plugins support
https://reproxy.io/#plugins-support
Container security
https://reproxy.io/#container-security
Options
Каждая опция может быть указана двумя способами: опция командной строки и переменная окружения. Некоторые cli опции имеют короткую форму, как -l localhost:8080
и --listen localhost:8080
. Имя соответствующей переменной окружения указано в конце описания каждой опции
Все опции описывающие размеры поддерживают суффикс величины 10K (or 10k) for kilobytes, 16M (or 16m) for megabytes, 10G (or 10g) for gigabytes. Отсутствие суффикса воспринимается как байты
Некоторые опции могут быть указаны несколько раз, в таком случае пользователь может несколько раз указать cli опцию, либо через запятую перечислить значения в переменной окружения. Например опция --ssl.fqdn
одна из таких и может быть указана как --ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.com
или как переменная SSL_ACME_FQDN=a1.example.com,a2.example.com
Ниже список всех таких опций:
ssl.fqdn (SSL_ACME_FQDN)
assets.cache (ASSETS_CACHE)
docker.exclude (DOCKER_EXCLUDE)
static.rule ($STATIC_RULES)
header ($HEADER)
drop-header ($DROP_HEADERS)
All Application Options
-l, --listen= listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN]
-m, --max= max request size (default: 64K) [$MAX_SIZE]
-g, --gzip enable gz compression [$GZIP]
-x, --header= outgoing proxy headers to add [$HEADER]
--drop-header= incoming headers to drop [$DROP_HEADERS]
--basic-htpasswd= htpasswd file for basic auth [$BASIC_HTPASSWD]
--lb-type=[random|failover] load balancer type (default: random) [$LB_TYPE]
--signature enable reproxy signature headers [$SIGNATURE]
--dbg debug mode [$DEBUG]
ssl:
--ssl.type=[none|static|auto] ssl (auto) support (default: none) [$SSL_TYPE]
--ssl.cert= path to cert.pem file [$SSL_CERT]
--ssl.key= path to key.pem file [$SSL_KEY]
--ssl.acme-location= dir where certificates will be stored by autocert manager (default: ./var/acme) [$SSL_ACME_LOCATION]
--ssl.acme-email= admin email for certificate notifications [$SSL_ACME_EMAIL]
--ssl.http-port= http port for redirect to https and acme challenge test (default: 8080 under docker, 80 without) [$SSL_HTTP_PORT]
--ssl.fqdn= FQDN(s) for ACME certificates [$SSL_ACME_FQDN]
assets:
-a, --assets.location= assets location [$ASSETS_LOCATION]
--assets.root= assets web root (default: /) [$ASSETS_ROOT]
--assets.spa spa treatment for assets [$ASSETS_SPA]
--assets.cache= cache duration for assets [$ASSETS_CACHE]
--assets.not-found= path to file to serve on 404, relative to location [$ASSETS_NOT_FOUND]
logger:
--logger.stdout enable stdout logging [$LOGGER_STDOUT]
--logger.enabled enable access and error rotated logs [$LOGGER_ENABLED]
--logger.file= location of access log (default: access.log) [$LOGGER_FILE]
--logger.max-size= maximum size before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE]
--logger.max-backups= maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]
docker:
--docker.enabled enable docker provider [$DOCKER_ENABLED]
--docker.host= docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST]
--docker.network= docker network [$DOCKER_NETWORK]
--docker.exclude= excluded containers [$DOCKER_EXCLUDE]
--docker.auto enable automatic routing (without labels) [$DOCKER_AUTO]
--docker.prefix= prefix for docker source routes [$DOCKER_PREFIX]
consul-catalog:
--consul-catalog.enabled enable consul catalog provider [$CONSUL_CATALOG_ENABLED]
--consul-catalog.address= consul address (default: http://127.0.0.1:8500) [$CONSUL_CATALOG_ADDRESS]
--consul-catalog.interval= consul catalog check interval (default: 1s) [$CONSUL_CATALOG_INTERVAL]
file:
--file.enabled enable file provider [$FILE_ENABLED]
--file.name= file name (default: reproxy.yml) [$FILE_NAME]
--file.interval= file check interval (default: 3s) [$FILE_INTERVAL]
--file.delay= file event delay (default: 500ms) [$FILE_DELAY]
static:
--static.enabled enable static provider [$STATIC_ENABLED]
--static.rule= routing rules [$STATIC_RULES]
timeout:
--timeout.read-header= read header server timeout (default: 5s) [$TIMEOUT_READ_HEADER]
--timeout.write= write server timeout (default: 30s) [$TIMEOUT_WRITE]
--timeout.idle= idle server timeout (default: 30s) [$TIMEOUT_IDLE]
--timeout.dial= dial transport timeout (default: 30s) [$TIMEOUT_DIAL]
--timeout.keep-alive= keep-alive transport timeout (default: 30s) [$TIMEOUT_KEEP_ALIVE]
--timeout.resp-header= response header transport timeout (default: 5s) [$TIMEOUT_RESP_HEADER]
--timeout.idle-conn= idle connection transport timeout (default: 90s) [$TIMEOUT_IDLE_CONN]
--timeout.tls= TLS hanshake transport timeout (default: 10s) [$TIMEOUT_TLS]
--timeout.continue= expect continue transport timeout (default: 1s) [$TIMEOUT_CONTINUE]
mgmt:
--mgmt.enabled enable management API [$MGMT_ENABLED]
--mgmt.listen= listen on host:port (default: 0.0.0.0:8081) [$MGMT_LISTEN]
error:
--error.enabled enable html errors reporting [$ERROR_ENABLED]
--error.template= error message template file [$ERROR_TEMPLATE]
health-check:
--health-check.enabled enable automatic health-check [$HEALTH_CHECK_ENABLED]
--health-check.interval= automatic health-check interval (default: 300s) [$HEALTH_CHECK_INTERVAL]
throttle:
--throttle.system= throttle overall activity' (default: 0) [$THROTTLE_SYSTEM]
--throttle.user= limit req/sec per user and per proxy destination (default: 0) [$THROTTLE_USER]
plugin:
--plugin.enabled enable plugin support [$PLUGIN_ENABLED]
--plugin.listen= registration listen on host:port (default: 127.0.0.1:8081) [$PLUGIN_LISTEN]
Help Options:
-h, --help Show this help message
Status
Borg
Overview
Что такое BorgBackup
BorgBackup (коротко: Borg) это программа для дедуплицирующего резервного копирования. Опционально она поддерживает сжатие и шифрование
Главная цель Borg - предоставить эффективный и безопасный способ бэкапить данные. Дедуплицирование делает Borg пригодным для ежедневных бэкапов, так как будут сохранены только изменения. Шифрование позволяет хранить бэкапы на не полностью доверенных хранилищах
Main features
- Space efficient storage - дедупликация базируется на алгоритме content-defined chunking и используется для уменьшения кол-ва хранимых данных: каждый файл бьется на разноразмерные чанки и сохраняются только те чанки которые еще не были сохранены в репозиторий
Чанки считаются дубликатами если их id_hash совпадают. Для вычисления id_hash используется криптостойкая хэш или MAC функция
Дедуплицируются все чанки в рамках репозитория, не важно пришли эти чанки с разных машин, из предыдущих бэкапов, из одного бэкапа или даже из одного файла
По сравнению с другими подходами к дедупликации, этот метод не полагается на:- Имена файлов / каталогов остаются прежними: таким образом, вы можете перемещать свои данные, не прерывая дедупликацию, даже между машинами, совместно использующими репозиторий
- Полные файлы или временные метки остаются неизменными: если большой файл немного меняется, нужно сохранить только несколько новых фрагментов - это отлично подходит для виртуальных машин или необработанных дисков
- Абсолютное положение фрагмента данных внутри файла: материал может быть сдвинут и все равно будет найден алгоритмом дедупликации
- Speed
- performance-critical код написан на C/Cython
- локальное кэширование файлов/чанков
- быстрое обнаружение неизмененных файлов
- Data encryption - Все данные могут быть защищены с помощью 256-битного AES шифрования, целостность и подлинность данных проверяется через HMAC-SHA256. Данные шифруются на клиенте
- Obfuscation - Опционально Borg может активно обфусцировать размер файлов/чанков чтобы сделать fingerprinting атаку более сложной
- Compression - Все данные могут быть опционально сжаты:
- lz4 (super fast, low compression)
- zstd (wide range from high speed and low compression to high compression and lower speed)
- zlib (medium speed and compression)
- lzma (low speed, high compression)
- Off-site backups - Borg может хранить данные на любом удаленном хосте доступном по ssh. Если Borg установлен на удаленном хосте, может быть получен большой прирост производительности в сравнении с network filesystems (sshfs, nfs, ...)
- Backups mountable as filesystems - Бэкап архивы могут быть примонтированы как fuse для легкого интерактивного просмотра содержимого бэкапа и его восстановления
Easy to use
Инициализируй репозиторий (see borg init --help for encryption options):
root@borg-server:~# mkdir -p /var/lib/borg/my-test-backup-repo
root@borg-server:~# borg init -e none /var/lib/borg/my-test-backup-repo
root@borg-server:~# tree /var/lib/borg/my-test-backup-repo
/var/lib/borg/my-test-backup-repo
├── config
├── data
│ └── 0
│ ├── 0
│ └── 1
├── hints.1
├── index.1
├── integrity.1
└── README
2 directories, 7 files
Создай бэкап:
root@borg-server:~# borg create /var/lib/borg/my-test-backup-repo::vandud-test-backup-1 /var/log/
root@borg-server:~# borg create -v --stats /var/lib/borg/my-test-backup-repo::vandud-test-backup-2 /var/log/
Creating archive at "/var/lib/borg/my-test-backup-repo::vandud-test-backup-2"
------------------------------------------------------------------------------
Repository: /var/lib/borg/my-test-backup-repo
Archive name: vandud-test-backup-2
Archive fingerprint: 98dafada55752be228cdfc709639295b36b9161f4169152b05e707a44ecd4bb2
Time (start): Wed, 2023-12-13 16:34:54
Time (end): Wed, 2023-12-13 16:34:54
Duration: 0.70 seconds
Number of files: 24
Utilization of max. archive size: 0%
------------------------------------------------------------------------------
Original size Compressed size Deduplicated size
This archive: 53.54 MB 4.68 MB 511 B
All archives: 107.08 MB 9.35 MB 4.68 MB
Unique chunks Total chunks
Chunk index: 34 66
------------------------------------------------------------------------------
Есть еще BorgWeb
Заброшенная штука, функционал сомнительной полезности
Installation
Есть три разных пути установить Borg:
- Пакет - легко и быстро если пакет есть под твою систему
- Бинарь - легко и быстро везде (разработчики предоставляют бинарь без зависимостей)
- Исходники - можно через pip или git (значительно дольше)
Рассмотрим подробнее первые два
Distribution Package
Многие дистрибутивы уже имеют в репозиториях готовый к использованию пакет borgbackup который можно просто установить через пакетный менеджер
Может быть доступна далеко не последняя версия
Для Debian: apt install borgbackup
Standalone Binary
Есть готовый бинарь собранный через http://www.pyinstaller.org/
Доступен тут https://github.com/borgbackup/borg/releases
Работает очень даже хорошо
Надо держать в голове что эта штука распаковывает себя в
/tmp
, и если там не будет места или будет стоять опцияnoexec
то все сломается. Можно изменить директорию для распаковки задав переменнуюTEMP
перед запуском бинаря
Quick Start
Эта часть поможет начать работать с Borg и покрывает разные кейсы
A step by step example
- Перед тем как делать бэкап должен быть инициализирован репозиторий:
$ borg init --encryption=repokey /path/to/repo
- Бэкап директорий
~/src
и~/Documents
в архив с именемMonday
:$ borg create /path/to/repo::Monday ~/src ~/Documents
- На следующий день создается архив с именем
Tuesday
:
Этот бэкап будет значительно быстрее и меньше, потому что будут сохранены только новые ранее не сохраненные данные. Флаг$ borg create --stats /path/to/repo::Tuesday ~/src ~/Documents
--stats
выводит статистику по созданному архиву (например такая информация как занятое место и время выполнения) - Список всех архивов в репозитории:
$ borg list /path/to/repo
- Список файлов конкретного архива:
$ borg list /path/to/repo::Monday
- Извлечь из архива файлы относительно текущей директории:
$ borg extract /path/to/repo::Monday
- Удалить архив (это не освобождает диск):
$ borg delete /path/to/repo::Monday
- Сжатие сегментов в репозитории:
Пример:$ borg compact /path/to/repo
root@borg-server:~# du -sch /var/lib/borg/my-test-backup-repo 262M /var/lib/borg/my-test-backup-repo 262M total root@borg-server:~# borg compact /var/lib/borg/my-test-backup-repo root@borg-server:~# du -sch /var/lib/borg/my-test-backup-repo 6.0M /var/lib/borg/my-test-backup-repo 6.0M total
По умолчанию Borg все делает молча, чтобы он давал какой-то вывод нужно использовать специальные флаги:
--progress
,--list
,--verbose
и--info
Archives and repositories
Borg-архив это результат бэкапа (результат команды borg create
). Архив хранит снапшот данных файлов внутри себя. Который потом можно извлечь или примонтировать для восстановления
Репозитории это директории в файловой системе которые являются хранилищами архивов. Доступ в репозиторий может быть получен как локально так и по ссш. Под капотом репозиторий хранит блоки данных и манифест отслеживающий какой блок из какого архива. Если какие-то данные не изменялись из одного бэкапа к другому, то Borg просто ссылается на уже загруженые блоки данных (дедупликация)
Important note about free space
Нужно следить что на сервере с репозиторием всегда достаточно свободного диска (а также в ~/.cache
). Несколько гигабайтов должно быть достаточно в общем случае
Borg не использует диск зарезервированный для рута (даже когда запущен от рута). Рекомендуется зарезервировать некоторое пространство в самом Borg через опцию additional_free_space
, начать можно с 2G
borg config /path/to/repo additional_free_space 2G
Если Borg запускается без свободного диска, он попытается высвободить диск (столько сколько сможет), а пока будет безопасно отвергать текущие операции, это позволит пользователю освободить больше диска с помощью удаления архивов
Если у вас реально кончится диск, то ему будет сложно или даже невозможно освободить себе диск, потому что доп место на диске нужно для всех операций, даже для операции удаления
Ты можешь использовать мониторинг или просто включить инфу о свободном месте в логи
Important note about permissions
Чтобы избежать проблем с правами (в репозитории или в кэше) всегда работай с репозиторием из под одного и того же пользователя
Если ты хочешь бэкапить файлы других пользователей или операционных систем, скорее всего потребуется запускать Borg от рута. Если бэкапите только свои файлы то запускайте Borg как обычный пользователь
Для локального репозитория просто всегда используй одного и того же пользователя для работы с Borg
Для удаленного репозитория: всегда используй напр. borg@remote_host
. Вы можете использовать это и от разных локальных пользователей, удаленный пользователь запускающий Borg и работающий с репозиторием, всегда будет borg
Если нужно получить доступ к локальному репозиторию от другого пользователя, можно использовать этот же метод через ссш до borg@localhost
Important note about files changing during the backup process
Borg ничего не делает с консистентностью данных которые он бэкапит. Он просто читается и бэкапит каждый файл независимо от того в каком состоянии этот файл пребывает во время бэкапирования. На активных системах это может привести в двум видам неконсистентности:
- Файл может измениться во время процесса бэкапа, что может привести к несогласованности архива
- Файл может измениться во время копирования файла, что может привести к несогласованности файла
Если у вас есть набор файлов и нужно быть уверенным что они забэкапятся в конкретном или консистентном состоянии, нужно предпринять шаги для предотвращения изменения этих файлов во время бэкапа. Есть несколько общих техник для достижения этой цели
- Убедись что не запущены программы которые могут работать с этими файлами
- Снапшоты файлов, файловых систем, разделов контейнеров или логических разделов (LVM или ZFS могут быть полезными)
- Сделай дамп базы данных или останови ее
- Выключи ВМ перед тем как бэкапить ее диск
- Выключи контейнер перед тем как бэкапить его вольюм
Для некоторых систем Borg может работать хорошо и без этих предосторожностей. Если ты просто бэкапишь файлы не не очень активной системе, то Borg отработает хорошо без дополнительной заботы о консистентности. Лог файлы и кэши могут быть в не идеальном состоянии, но это и не проблема
Для баз данных, виртуальных машин и контейнеров есть специальные техники бэкапинга, которые не просто бэкапят нижележащую ФС. Для баз данных ищи в документации техники бэкапирования которые позволят сохранять состояние данных между транзакциями. Для виртуальных машин рассмотри бэкапинг машины с нее же самой или монтаж диска выключенной ВМ. Для контейнеров поможет команда docker save
Automating backups
Ниже простой скрипт который подразумевается что будет запускаться ежедневно от рута на разных локальных машинах. Он бэкапит важные файлы машины в репозиторий ~/backup/main
на удаленном сервере. Некоторые файлы исключаются из бэкапа
После бэкапирования этот скрипт также запускает borg prune
для сохранения только некоторого количества последних архивов и удаления остальных
В конце он запускает borg compact
для удаления уже удаленных объектов из сегментов файлов в репозитории для сохранения диска
Перед запуском убедись что репозиторий инициализирован и что скрипт имеет правильные права и может быть запущен рутом но не может быть запущен или прочитан кем либо еще (root:root 0700)
Можно использовать этот скрипт как стартовую точку и модифицировать его под себя
Не забудь протестировать свои бэкапы, убедись что prune удаляет то что нужно и что в архивах забэкаплено то что нужно
#!/bin/sh
# Setting this, so the repo does not need to be given on the commandline:
export BORG_REPO=ssh://username@example.com:2022/~/backup/main
# See the section "Passphrase notes" for more infos.
export BORG_PASSPHRASE='XYZl0ngandsecurepa_55_phrasea&&123'
# some helpers and error handling:
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
info "Starting backup"
# Backup the most important directories into an archive named after
# the machine this script is currently running on:
borg create \
--verbose \
--filter AME \
--list \
--stats \
--show-rc \
--compression lz4 \
--exclude-caches \
--exclude 'home/*/.cache/*' \
--exclude 'var/tmp/*' \
\
::'{hostname}-{now}' \
/etc \
/home \
/root \
/var
backup_exit=$?
info "Pruning repository"
# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-*' matching is very important to
# limit prune's operation to this machine's archives and not apply to
# other machines' archives also:
borg prune \
--list \
--glob-archives '{hostname}-*' \
--show-rc \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6
prune_exit=$?
# actually free repo disk space by compacting segments
info "Compacting repository"
borg compact
compact_exit=$?
# use highest exit code as global exit code
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit ))
if [ ${global_exit} -eq 0 ]; then
info "Backup, Prune, and Compact finished successfully"
elif [ ${global_exit} -eq 1 ]; then
info "Backup, Prune, and/or Compact finished with warnings"
else
info "Backup, Prune, and/or Compact finished with errors"
fi
exit ${global_exit}
Pitfalls with shell variables and environment variables
Это относится ко всем переменным окружения, которые вы хотите, чтобы Borg видел, а не только к BORG_PASSPHRASE
. Краткое объяснение таково: всегда экспортируйте свою переменную и используйте одинарные кавычки, если вы не уверены в деталях поведения расширения вашей оболочки. Например.:
export BORG_PASSPHRASE='complicated & long'
Это потому что экспорт дает доступ к переменным дочерним процессам одним из которых может быть Borg
Внимательнее с тем как sudo работает с экспортами
Например ты можешь удивиться что в примере ниже скрипту не будет доступна переменная и он будет запрашивать ввод пароля
export BORG_PASSPHRASE='complicated & long'
sudo ./yourborgwrapper.sh # still prompts for password
Можно обойти это так
vandud@macbook: ~ 🚀 export MYVAR=test1
vandud@macbook: ~ 🚀 sudo -E bash -c 'echo $MYVAR'
test1
vandud@macbook: ~ 🚀 sudo bash -c 'echo $MYVAR'
Passphrase notes
Если ты используешь шифрование (или аутентификацию), Borg интерактивно спросит у тебя пароль
Подробнее тут https://borgbackup.readthedocs.io/en/stable/quickstart.html#passphrase-notes
Backup compression
По умолчанию для сжатия используется lz4 (очень быстро, но слабое сжатие), но так же доступны и другие методы сжатия
Можно использовать zstd с большим диапазоном от высокой скорости (N=1) до высокой компрессии (N=22)
zstd это современный алгоритм сжатия, который предпочтительнее zlib и lzma (исключая случаи когда нужна обратная совместимость со старыми версиями Borg)
$ borg create --compression zstd,N /path/to/repo::arch ~
Можно не использовать сжатие, например когда есть быстрый сторадж и не хочется расходовать cpu
$ borg create --compression none /path/to/repo::arch ~
Если у тебя менее быстрый сторадж под репозиторием и ты хочешь чуть большую компрессию (степень компрессии можно регулировать, у zlib это диапазон от 0 до 9)
root@borg-server:~# borg create --compression zlib,9 /var/lib/borg/my-test-backup-repo/::my-test-super-backup /var/log/
Если у тебя сильно медленный сторадж и ты хочешь сильную компрессию то можно использовать lzma
Для каждого конкретного кейса нужно искать параметры опытным путем (во время опытов держи один глаз на нагрузке на ЦПУ а второй на нагрузке на сеть)
Repository encryption
Во время создания репозитория можно сделать его шифрованным
Подробности тут https://borgbackup.readthedocs.io/en/stable/quickstart.html#repository-encryption
Remote repositories
Borg может инициализировать и работать с репозиториями на удаленных хостах если хост доступен по ssh. Быстрее и проще когда Borg установлен на удаленном хосте. В таком случае используется следующий синтаксис:
root@borg-client:~# borg init -e none root@borg-server:/var/lib/borg/remotely-initialized-repository
...
root@borg-server:/var/lib/borg# ls
my-test-backup-repo remotely-initialized-repository
Удаленные операции через SSH могут быть автоматизированы с помощью ключей. Ты можешь ограничить использование пары ключей предварив описание публичного ключа командой (на удаленном сервере). Пример нижу запустит Borg в режиме сервера и ограничит его работу конкретным путем:
root@borg-server:~# cat .ssh/authorized_keys
command="borg serve --restrict-to-path /var/lib/borg/",restrict ssh-rsa AAAAB3N...yxHgs= root@borg-client
root@borg-client:~# borg init -e none root@borg-server:/var/tmp/remotely-initialized-repository
Repository path not allowed: /var/tmp/remotely-initialized-repository
root@borg-client:~# borg init -e none root@borg-server:/var/lib/borg/remotely-initialized-repository
root@borg-client:~#
Если нет возможности установить Borg на удаленный хост то можно использовать sshfs:
$ sshfs user@hostname:/path/to /path/to
$ borg init /path/to/repo
$ fusermount -u /path/to
Restoring a backup
Для восстановления обычно используется тот же самый хост и пользователь как когда бэкап был сделан. Такой расклад позволит избежать некоторых проблем:
- нет проблем с путями
- тот же маппинг user/group на userid/groupid
- нет проблем с правами
- у тебя уже есть рабочий и настроенный Borg на этом хосте (раз уж успешно был сделан бэкап)
- переменные окружения с паролями от шифрованных репозиториев
- ключи от репозиториев
- ssh ключи уже настроены
- уже прогретый кэш
Пользователь может быть:
- root - если делался полный бэкап, бэкап системных штук или бэкап файлов множества пользователей
- конкретным пользователем с правом sudo на запуск borg
- конкретным пользователем - если делался бэкап файлов этого пользователя
Borg репозиторий может быть:
- или локальной директорией (например локально примонтированный usb диск)
- или удаленным сервером бэкапов доступным по ssh
Если репозиторий шифруется тебе так же потребуется ключ и контрольная фраза (которая защищает ключ)
Ключ может быть расположен:
- в репозитории (repokey mode) - самый простой вариант
- в хомяке пользователя который делает бэкап (keyfile mode) - сложнее:
- если потеряешь хомяк то сперва надо восстановить ключ
- сперва надо найти верный хост, юзер, хомяк откуда был запущен Borg при создании бэкапа
Контрольная фраза для ключа может быть:
- введена интерактивно во время бэкапа (не удобно если бэкап автоматический)
- предоставлена через переменную окружения в бэкапирующем скрипте
Есть два путя при восстановлении файлов из бэкапа:
borg mount
- используй это если:- ты точно не знаешь какие файлы надо восстановить
- ты не знаешь какой архив содержит нужные файлы
- тебе нужно сперва взглянуть в файлы / директории для определения что нужно восстанавливать
- требуется восстановить небольшой объем данных
- тебя не беспокоит сохранность вещей которые не поддерживает FUSE (особые флаги ФС или ACL)
- клиент имеет хорошие ресурсы (ram, cpu, disk)
- предпочтительнее использовать какой-то файловый менеджер чем команды оболочки
borg extract
borg extract
- используй это если:- ты точно знаешь что тебе нужно (repo, archive, path)
- тебе нужно восстановить большой объем данных
- тебе нужно максимально точное воспроизведение метаданных файла (флаги ФС, ACL)
- на клиенте мало ресурсов
Пример borg mount
:
root@borg-client:~# mkdir /mnt/vandud-test-backup-dirs
root@borg-client:~# borg mount root@borg-server:/var/lib/borg/my-test-backup-repo::vandud-test-backup-dirs /mnt/vandud-test-backup-dirs
root@borg-client:~# ls /mnt/vandud-test-backup-dirs
bin etc sbin
root@borg-client:~# borg umount /mnt/vandud-test-backup-dirs
root@borg-client:~# borg mount root@borg-server:/var/lib/borg/my-test-backup-repo /mnt/vandud-test-backup-dirs
root@borg-client:~# ls /mnt/vandud-test-backup-dirs/
localhost-2023-12-13-16:50:28 localhost-2023-12-13-16:51:29 my-test-super-backup vandud-test-backup-2 vandud-test-backup-dirs
Пример borg extract
:
# borg extract always extracts into current directory and that directory
# should be empty (borg does not support transforming a non-empty dir to
# the state as present in your backup archive).
mkdir borg_restore
cd borg_restore
# now we find out the archive names we have in the repo:
borg list /mnt/backup/borg_repo
# we could find out the archive contents, esp. the path layout:
borg list /mnt/backup/borg_repo::myserver-system-2019-08-11
# we extract only some specific path (note: no leading / !):
borg extract /mnt/backup/borg_repo::myserver-system-2019-08-11 path/to/extract
# alternatively, we could fully extract the archive:
borg extract /mnt/backup/borg_repo::myserver-system-2019-08-11
# now move the files to the correct place...
Отличия использования удаленного сервера:
Базово все то же самое как если бы использовался локальный репозиторий, только нужно ссылаться на удаленный репозиторий по ссылке вида ssh://...
Остальные подробности начиная отсюда https://borgbackup.readthedocs.io/en/stable/usage/general.html
Borgmatic
Borgmatic это обертка вокруг Borg
В документации Borg есть такой раздел https://borgbackup.readthedocs.io/en/stable/quickstart.html#automating-backups, в нем предоставлен скрипт для автоматизации бэкапирования
По сути Borgmatic это и есть подобный скрипт - красивая запускалка для Borg
Можно установить через пакетный менеджер
Установится скорее всего старая версия в которой нет команды borgmatic config generate
Надо использовать отдельный скрипт generate-borgmatic-config
(он уже идет в пакете borgmatic)
Запускаем:
root@borg-server:~# generate-borgmatic-config
Generated a sample configuration file at /etc/borgmatic/config.yaml.
Please edit the file to suit your needs. The values are representative.
All fields are optional except where indicated.
If you ever need help: https://torsion.org/borgmatic/#issues
Получаем огромный конфиг в котором все закомментировано и прокомментировано
То есть мы получаем базу на основе которой можно собирать свой конфиг
Ansible Playbook
Предлагаю использовать следующий плейбук
---
- name: Borg
hosts: all
become: true
vars:
borg_data_dir: /opt/data/borg
borg_encryption_passphrase: CHANGEME
borg_repository: "root@{{ hostvars[groups['borg'][0]].ansible_host }}:{{ borg_data_dir }}/{{ inventory_hostname }}"
borg_ssh_key_file_path: "/root/.ssh/id_ed25519"
borg_ssh_command: "ssh -o StrictHostKeyChecking=accept-new"
borg_install_method: "pip"
# borg_source_directories: # this overrides values from inventory
# - /home
# - /etc
borg_exclude_patterns:
- "{{ borg_data_dir }}"
tasks:
- name: "Ensure {{ borg_data_dir }} exists"
ansible.builtin.file:
path: "{{ borg_data_dir }}"
state: directory
mode: "0755"
owner: root
tags:
- never
- backup_init_repo
- name: Configure Borgbackup and Borgmatic
tags:
- always
- install_backup
ansible.builtin.include_role:
name: borgbase.ansible_role_borgbackup
apply:
tags:
- always
- name: Copy SSH-Key to Target {{ borg_repository }} and Init Repo
tags:
- never
- backup_init_repo
block:
- name: Read ssh key
ansible.builtin.slurp:
src: "{{ borg_ssh_key_file_path }}.pub"
register: backup_local_ssh_key
- name: Set authorized key taken from file
ansible.posix.authorized_key:
user: "{{ borg_repository | regex_search('(.*)@', '\\1') | first }}" # part a)
state: present
key_options: "command=\"borg serve --restrict-to-path {{ borg_data_dir }}\",restrict"
key: "{{ backup_local_ssh_key['content'] | b64decode }}"
comment: "{{ inventory_hostname }}"
delegate_to: "{{ borg_repository | regex_search('@(.*):', '\\1') | first }}" # part b)
- name: Init repository
ansible.builtin.command:
cmd: "sudo -u root borgmatic init --encryption none --append-only"
Ansible Inventory
Инвентори для этого плейбука прост (в базовом случае)
Главное определить группу borg
и один хост в ней
Этот хост будет хранить бэкапы
Группа nodes
может называться как угодно, потому что плейбук катится на all
и использует хост из borg
как адрес borg_repository
в конфиге borgmatic
Ниже пример ini-inventory:
[borg] # хост из этой группы будет Borg-сервером
borg-server ansible_host=62.84.119.86
[nodes] # не важно как называется эта группа, плейбук катится на 'all'
borg-client-1 ansible_host=51.250.87.234
borg-client-2 ansible_host=51.250.66.184
borg-client-3 ansible_host=51.250.6.55
В самом низу страницы описан пример yaml-inventory который позволяет прописать кастомные параметры разным хостам (можно сделать и полноценный инвентори с host_vars
/group_vars
, тут как душе угодно)
Commands
Прикатить это все можно так
Сперва установим официальную роль конкретной версии (в моем случае были машины с ubuntu-18, актуальная версия роли не катится на такое старье):
ansible-galaxy role install borgbase.ansible_role_borgbackup,v0.9.4 --force # в моем случае были машины с ubuntu 18.04, поэтому пришлось использовать старую версию роли (новая не катится на такие старые машины)
Далее катим плейбук сперва базово, потом с тэгом который синхронизирует ssh-ключ и создаст репы на сервере из группы borg
:
ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook -i inventory.mkrf-test.yaml -kK playbook.yaml
ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook -i inventory.mkrf-prod.yaml -kK -t backup_init_repo playbook.yaml
Что бэкапить задается через переменную borg_source_directories
Проверка:
root@mon-01:~# borgmatic
Fri Dec 22 17:44:08 MSK 2023 - Starting backup.
Fri Dec 22 17:44:08 MSK 2023 - Run pg_dumpall command.
could not change directory to "/root": Permission denied
Fri Dec 22 17:44:37 MSK 2023 - Command pg_dumpall is done.
Ignoring check_last option, as "archives" is not in consistency checks.
Ignoring consistency prefix option, as "archives" is not in consistency checks.
Fri Dec 22 18:32:27 MSK 2023 - Remove pg_dumpall file.
Fri Dec 22 18:32:27 MSK 2023 - Finished backup.
root@mon-01:~# cat /etc/cron.d/borgmatic
PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
#Ansible: borgmatic
53 4 * * * root borgmatic -c /etc/borgmatic/config.yaml -C -p
#Ansible: borgmatic-check
53 22 27 * * root borgmatic -c /etc/borgmatic/config.yaml -k
root@vm-bkpp-01:~# du -sch /opt/data/borg/vm-mon-01/
18G /opt/data/borg/vm-mon-01/
18G total
root@vm-bkpp-01:~# borg list /opt/data/borg/vm-mon-01/
Warning: Attempting to access a previously unknown unencrypted repository!
Do you want to continue? [yN] y
mon-01-2023-12-22-174440 Fri, 2023-12-22 17:44:41 [dd517ed98188876bc68704f5882c1610421aa9e742584ee4acb27ff8e5ab7a89]
root@vm-bkpp-01:~# borg list /opt/data/borg/vm-mon-01/::mon-01-2023-12-22-174440 | head
drwxr-xr-x root root 0 Fri, 2023-12-22 17:39:38 etc
drwxr-xr-x root root 0 Tue, 2019-12-03 12:12:55 etc/update-manager
-rw-r--r-- root root 235 Thu, 2019-06-06 21:46:11 etc/update-manager/meta-release
-rw-r--r-- root root 807 Wed, 2019-06-19 19:49:56 etc/update-manager/release-upgrades
drwxr-xr-x root root 0 Wed, 2019-06-19 19:49:56 etc/update-manager/release-upgrades.d
drwxr-xr-x root root 0 Tue, 2019-12-03 11:54:23 etc/update-notifier
-rw-r--r-- root root 0 Tue, 2019-12-03 11:54:23 etc/update-notifier/hooks_seen
drwxr-xr-x root root 0 Tue, 2019-12-03 11:53:08 etc/gss
drwxr-xr-x root root 0 Fri, 2019-01-11 18:48:01 etc/gss/mech.d
drwxr-xr-x root root 0 Tue, 2019-12-03 11:53:22 etc/polkit-1
Ansible Inventory YAML
borg:
hosts:
vm-bkp-01:
ansible_host: 192.168.50.140
nodes:
hosts:
grun-01:
ansible_host: 192.168.50.129
vm-db-01:
ansible_host: 192.168.50.124
borgmatic_hooks:
on_error:
- echo "`date` - Error while creating a backup."
before_backup:
- echo "`date` - Starting backup."
- echo "`date` - Run pg_dumpall command."
- mkdir -p /tmp/pg_dumpall; chmod 777 /tmp/pg_dumpall; sudo -u postgres pg_dumpall -f "/tmp/pg_dumpall/`hostname`_`date +%d-%m-%Y`_dumpall.sql"
- echo "`date` - Command pg_dumpall is done."
after_backup:
- echo "`date` - Remove pg_dumpall file."
- rm /tmp/pg_dumpall/`hostname`_`date +%d-%m-%Y`_dumpall.sql
- echo "`date` - Finished backup."
borg_source_directories:
- /etc/
- /home/
- /tmp/pg_dumpall/
vm-docs-01:
ansible_host: 192.168.50.125
borg_source_directories:
- /etc/
- /home/
- /opt/
vm-glog-01:
ansible_host: 192.168.50.127
borgmatic_hooks:
on_error:
- echo "`date` - Error while creating a backup."
before_backup:
- echo "`date` - Starting backup."
- echo "`date` - Run mongodump command."
- mkdir -p /tmp/mongodump; chmod 777 /tmp/mongodump; mongodump --gzip --archive=/tmp/mongodump/`hostname`_`date +%d-%m-%Y`_mongodump.gz
- echo "`date` - Command mongodump is done."
after_backup:
- echo "`date` - Remove mongodump file."
- rm /tmp/mongodump/`hostname`_`date +%d-%m-%Y`_mongodump.gz
- echo "`date` - Finished backup."
borg_source_directories:
- /etc/
- /home/
- /tmp/mongodump/
- /usr/share/elasticsearch/
- /usr/share/graylog-server/
vm-k8sm-01:
ansible_host: 192.168.50.121
vm-k8sw-01:
ansible_host: 192.168.50.122
vm-k8sw-02:
ansible_host: 192.168.50.123
vm-mon-01:
ansible_host: 192.168.50.128
borgmatic_hooks:
on_error:
- echo "`date` - Error while creating a backup."
before_backup:
- echo "`date` - Starting backup."
- echo "`date` - Run pg_dumpall command."
- mkdir -p /tmp/pg_dumpall; chmod 777 /tmp/pg_dumpall; sudo -u postgres pg_dumpall -f "/tmp/pg_dumpall/`hostname`_`date +%d-%m-%Y`_dumpall.sql"
- echo "`date` - Command pg_dumpall is done."
after_backup:
- echo "`date` - Remove pg_dumpall file."
- rm /tmp/pg_dumpall/`hostname`_`date +%d-%m-%Y`_dumpall.sql
- echo "`date` - Finished backup."
borg_source_directories:
- /etc/
- /home/
- /var/lib/grafana/
- /tmp/pg_dumpall/
- /opt/
borg_exclude_patterns:
- /opt/data/
vm-mq-01:
ansible_host: 192.168.50.126
all:
vars:
ansible_user: user # от этого пользователя ансибл спросит пароль
borg_source_directories:
- /etc
- /home
mdadm
https://raid.wiki.kernel.org/index.php/A_guide_to_mdadm
mdadm заменил все предыдущие тулы для управления рейдами. Он менеджит почти всю юзер-спейсную часть рейдов. Есть только немного вещей которые требуют записи в /proc
, но их немного
Modes
У mdadm есть 7 режимов. Но для нормальной (обычной) работы тебе потребуется лишь несколько из них:
- Assemble - режим который используется чаще всего, но ты этого не замечаешь (потому что это происходит в фоне). При каждом старте системы запускается этот режим, он находит все диски, вычитывает с них суперблоки и собирает рейды (не забудь про initramfs, ведь mdadm это userspace программа и если наш рут на массиве, то будет курица-яйцо)
- Create - как дает понять имя - этот режим позволяет создавать новые массивы и записывает суперблоки
- Grow - этот режим отвечает за все действия по изменению размера массивов, изменению уровней итд
- Manage - режим по умолчанию и он используется в первую очередь для добавления/удаления дисков. Это может сбить с толку, так как некоторые опции (такие как
--add
) также используются в режиме--grow
, чаще всего когда добавляется девайс вместе с изменением кол-ва девайсов
- Build - это пережиток времен когда не было суперблока. Используется для пересоздания массива и не нужно использовать если не понимаешь что делаешь (опасно)
- Misc - всякое остальное
Superblocks and Raid versions
Важная глава
Объясняет многое
cloud-init
Cloud-init - это индустриальный кросс-платформенный мульти-дистрибутивный стандарт для инициализации инстансов
Он поддерживается во всех крупных cloud-провайдерах, в системах провижининга для приватных инфраструктур и на bare-metal
При загрузке инстанса cloud-init понимает в каком облаке он запущен, читает предоставленную метадату и инициализирует систему соответствующим образом
Он может сетапить сеть, девайсы, ssh-ключи и много всего другого
Getting Started
Tutorial
Для обучения и тестирования cloud-init скриптов удобно использовать lxd (там из коробки хорошая поддержка cloud-init)
Вот такой терраформ манифест создает подходящую виртуалку
terraform {
required_providers {
yandex = {
source = "yandex-cloud/yandex"
}
}
}
provider "yandex" {
token = "AQAAAAAayaoeuWVmM00"
cloud_id = "b1gaeounndt"
folder_id = "b1gaaoeuobf5v"
zone = "ru-central1-c"
}
data "yandex_compute_image" "compute_image_search" {
family = "ubuntu-2004-lts"
}
resource "yandex_compute_instance" "test" {
platform_id = "standard-v1"
zone = "ru-central1-a"
resources {
cores = 4
core_fraction = 20
memory = 4
}
boot_disk {
initialize_params {
image_id = "${data.yandex_compute_image.compute_image_search.image_id}"
size = 30
}
}
network_interface {
subnet_id = "${yandex_vpc_subnet.test_network_subnet.id}"
nat = true
}
metadata = {
ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
}
}
resource "yandex_vpc_network" "test_network" {}
resource "yandex_vpc_subnet" "test_network_subnet" {
zone = "ru-central1-a"
network_id = "${yandex_vpc_network.test_network.id}"
v4_cidr_blocks = ["10.2.0.0/16"]
}
Далее заходим на нее, и налаживаем lxd
root@fhmkp99o5k8l3iultpf3:~# apt install snapd
root@fhmkp99o5k8l3iultpf3:~# snap install lxd
root@fhmkp99o5k8l3iultpf3:~# lxd init --minimal
Далее подготавливаем cloud-init конфиг
root@fhmkp99o5k8l3iultpf3:~# cat <<EOF > /tmp/user-data
> #cloud-config
> runcmd:
> - echo 'Hello, World!' > /var/tmp/hello-world.txt
> EOF
Запускаем контейнер с этим конфигом
root@fhmkp99o5k8l3iultpf3:~# lxc launch ubuntu:focal my-test --config=user.user-data="$(cat /tmp/user-data)"
Идем внутрь и проверяем как оно там отработало
root@fhmkp99o5k8l3iultpf3:~# lxc shell my-test
root@my-test:~# cloud-init status -l
status: done
time: Wed, 10 Aug 2022 11:11:58 +0000
detail:
DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud-net][dsmode=net]
root@my-test:~# cloud-init query userdata
#cloud-config
runcmd:
- echo 'Hello, World!' > /var/tmp/hello-world.txt
root@my-test:~# cloud-init schema --system --annotate
Valid cloud-config: system userdata
root@my-test:~# cat /var/tmp/hello-world.txt
Hello, World!
Сносим этот контейнер
root@fhmkp99o5k8l3iultpf3:~# lxc stop my-test
root@fhmkp99o5k8l3iultpf3:~# lxc rm my-test
Boot Stages
При загрузке из под systemd у cloud-init есть пять стадий:
- Generator - systemd generator (так и не понял что это за зверь) включает в автозагрузку
cloud-init.target
. Cloud-init можно выключить если создать файл/etc/cloud/cloud-init.disabled
или если передать аргумент при загрузке ядраcloud-init=disabled
- Local - сервис
cloud-init-local.service
. Цель локальной стадии - найти локальные источники данных и настроить сеть - Network -
cloud-init.service
, запускается после local stage и настроенной сети, запускаетdisk_setup
иmounts
модули - Config -
cloud-config.service
, запускает конфигурационные модули - Final -
cloud-final.service
, эта стадия запускается в последнюю очередь. Занимается установкой пакетов, применением configuration management плагинов (ansible, puppet, etc), и запуском пользовательских скриптов
Cloud-init понимает запускается он впервые на новом инстансе или нет, в зависимости от этого применяется соответсвующая конфигурация
При первой загрузке применяется вся per-instance
конфигурация, а при повторной загрузке применяются per-boot
конфиги
При запуске cloud-init оставляет кэш который хранит внутреннее состояние и используется между загрузками
Соответственно если кэш присутствует, значит cloud-init уже запускался на этой системе
Это могло случится если система была перезагружена или если файловая система была приаттачена к новому инстансу и фактически это первая загрузка системы но кэш в файловой системе уже присутствует (такое бывает когда инстанс запускается из образа созданного из уже запровижененной машины)
По умолчанию cloud-init пытается понять что за кейс у него сейчас, для этого он проверяет instance id из кэша и сравнивает с id который определяется окружением, если разные то это первая загрузка. Внутри это поведение называется check
Instance ID находится в /var/lib/cloud
:
root@fhmkp99o5k8l3iultpf3:~# cat /var/lib/cloud/data/instance-id
fhmkp99o5k8l3iultpf3
Возможны ситуации когда это поведение нужно изменить, это измененное поведение называется trust
и заставляет cloud-init безусловно доверять найденной в кеше инфе
Управлять этим можно через опцию manual_cache_clean
:
- false -> check
- true -> trust
Можно вручную снести кэш через cloud-init clean
Эта команда сносит все из /var/lib/cloud
root@fhmkp99o5k8l3iultpf3:~# tree /var/lib/cloud/ | wc -l
78
root@fhmkp99o5k8l3iultpf3:~# cloud-init clean
root@fhmkp99o5k8l3iultpf3:~# tree /var/lib/cloud/ | wc -l
4
CLI Interface
Актуальный список подкомманд доступен в хелпе cloud-init --help
- analyze - анализ длительности загрузки (связано с
systemd-analyze
) - clean - чистит артифакты из
/var/lib/cloud
, так же с соответствующими ключами может почистить логи, удалить instance id файл и ребутнуть машину после удаления артифактов - collect-logs - собирает логи и всякую инфу и закладывает это в tar-архив
root@fhmkp99o5k8l3iultpf3:~# cloud-init collect-logs Wrote /root/cloud-init.tar.gz root@fhmkp99o5k8l3iultpf3:~# tar --list -f cloud-init.tar.gz cloud-init-logs-2022-08-11/ cloud-init-logs-2022-08-11/cloud-init.log cloud-init-logs-2022-08-11/dmesg.txt cloud-init-logs-2022-08-11/journal.txt cloud-init-logs-2022-08-11/dpkg-version cloud-init-logs-2022-08-11/run/ cloud-init-logs-2022-08-11/run/cloud-init/ cloud-init-logs-2022-08-11/run/cloud-init/cloud.cfg cloud-init-logs-2022-08-11/run/cloud-init/instance-data-sensitive.json cloud-init-logs-2022-08-11/run/cloud-init/instance-data.json cloud-init-logs-2022-08-11/run/cloud-init/.instance-id cloud-init-logs-2022-08-11/run/cloud-init/.ds-identify.result cloud-init-logs-2022-08-11/run/cloud-init/ds-identify.log cloud-init-logs-2022-08-11/run/cloud-init/enabled cloud-init-logs-2022-08-11/run/cloud-init/cloud-init-generator.log cloud-init-logs-2022-08-11/run/cloud-init/sem/ cloud-init-logs-2022-08-11/run/cloud-init/sem/apply_network_config.once cloud-init-logs-2022-08-11/run/cloud-init/result.json cloud-init-logs-2022-08-11/run/cloud-init/cloud-id cloud-init-logs-2022-08-11/run/cloud-init/cloud-id-ec2 cloud-init-logs-2022-08-11/run/cloud-init/status.json cloud-init-logs-2022-08-11/cloud-init-output.log cloud-init-logs-2022-08-11/version
- devel - набор подкоманд которые сейчас находятся в разбработке, они будут вынесены в top-level когда станут стабильными
- features - принтит фичи (хз что это)
- init - налаживает стадии загрузки
- modules - запускает модули, по умолчанию при запуске от ОС запускет только config и final стадии
- query - инструмент для доступа к закешированной информации собранной при загрузке системы (
/run/cloud-init/instance-data.json
) - schema - валидирует cloud-config файлы
- single - запускает один указанный модуль (а не стейдж как обычно)
- status - статус выполнения
User Data
Make
CouchDB
CouchDB схожа с MongoDB
CouchDB слушает 5984 порт
Работает по HTTP
В качестве языка запросов используется JavaScript
По такому адресу можно найти futon (панель управления)
http://servername.ru:5984/_utils/