Мы продолжаем серию статей с практическими инструкциями о том, как облегчить жизнь эксплуатации и разработчикам в повседневной работе с Kubernetes. Все они собраны из нашего опыта решения задач от клиентов и со временем улучшались, но по-прежнему не претендуют на идеал — рассматривайте их скорее как идеи и заготовки, предлагайте свои решения и улучшения в комментариях.
На этот раз будут рассмотрены две темы, условно связанные одной темой: доступом пользователей к dev-окружению.
1. Как мы закрываем dev-контуры от лишних пользователей?
Перед нами часто стоит задача закрыть за basic auth или за белым списком весь dev-контур (десятки/сотни приложений), дабы туда не могли попасть поисковые боты или просто очень сторонние люди.
Обычно для ограничения доступов каждому Ingress и приложению надо создавать отдельные секреты basic auth. Управлять ими очень проблематично, когда набирается с десяток приложений. Поэтому мы организовали централизованное управление доступами.
Для этого был создан nginx с конфигурацией такого типа:
location / {
satisfy any;
auth_basic "Authentication or whitelist!";
auth_basic_user_file /etc/nginx/htpasswd/htpasswd;
allow 10.0.0.0/8;
allow 175.28.12.2/32;
deny all;
try_files FAKE_NON_EXISTENT @return200;
}
location @return200 {
return 200 Ok;
}
Далее в Ingress'ах приложений мы просто добавляем аннотацию:
ingress.kubernetes.io/auth-url: "http://dev-auth.dev-auth-infra.svc.cluster.local"
Таким образом, при обращении к приложению запрос уходит в сервис dev-auth
, который проверяет, введен ли корректный basic auth или же клиент входит в whitelist. Если одно из условий выполнено, запрос подтверждается и проходит в приложение.
В случае использования такого сервиса достаточно одного репозитория, в котором хранится список всех доступов и через который мы можем удобно конфигурировать свой «единый центр авторизации». Его распространение на новые приложения производится элементарным добавлением аннотации.
2. Как мы предоставляем доступ к приложениям внутри Kubernetes в dev-окружении?
… будь то Redis, RabbitMQ, PostgreSQL или любимый PHP-разработчиками Xdebug.
Очень часто, переводя приложения в Kubernetes, для обеспечения лучшей безопасности нам приходится закрывать доступ снаружи и вовсе. И тогда разработчики, которые привыкли «ходить своей IDE» в базу или в Xdebug, испытывают серьёзные трудности.
Для решения этой проблемы мы используем VPN прямо в кластере Kubernetes. Общая схема выглядит таким образом, что при подключении к VPN-серверу, запущенному в K8s, в конфигурационном файле OpenVPN мы push'им адрес DNS-сервера, который тоже живёт в K8s. OpenVPN конфигурирует VPN таким образом, что при запросе ресурса внутри Kubernetes он сначала попадает в DNS-сервер Kubernetes — например, за адресом сервиса redis.production.svc.cluster.local
. DNS в Kubernetes резолвит его в адрес 10.244.1.15 и запросы на этот IP-адрес идут через OpenVPN прямо в кластер Kubernetes.
За время эксплуатации этого решения мы успели его неоднократно расширить. В частности:
- Так как мы не нашли простой и адекватной (для нашего случая) админки для учёта доступов к VPN, пришлось создать свой простой интерфейс — ведь официальный чарт предусматривает только вариант с запуском консольных команд для выпуска сертификатов.
Получившаяся админка (см. также на Docker Hub) выглядит очень аскетично:
Можно заводить новых юзеров или отзывать старые сертификаты:
Также можно посмотреть конфиг для данного клиента:
- Мы добавили авторизацию в VPN'е на основе юзеров в GitLab, где проверяется пароль и активен ли юзер в GitLab. Это для случаев, когда клиенту хочется управлять юзерами, которые могут подключиться к dev VPN только на основе GitLab'а, и без использования дополнительных админок — в некотором смысле получается «SSO для бедных». За основу брали уже упомянутый готовый чарт.
Для этого мы написали Python-скрипт, который при подключении юзера к OpenVPN, используя логин и пароль, сравнивает хэш в базе GitLab и проверяет его статус (активен ли он).
Вот сам скрипт:
#!/usr/bin/env python3 # pip3 install psycopg2-binary bcrypt import bcrypt import sys import os import psycopg2 import yaml with open("/etc/openvpn/setup/config.yaml", 'r') as ymlfile: cfg = yaml.load(ymlfile) def get_user_info(username=''): try: connect_str = "dbname=%s user=%s host=%s password=%s" % (cfg['db'], cfg['user'], cfg['host'], cfg['pass']) # use our connection values to establish a connection conn = psycopg2.connect(connect_str) # create a psycopg2 cursor that can execute queries cursor = conn.cursor() # create a new table with a single column called "name" cursor.execute("""SELECT encrypted_password,state FROM users WHERE username='%s';""" % username) # run a SELECT statement - no data in there, but we can try it rows = cursor.fetchall() print(rows) return(rows[0]) except Exception as e: print("Uh oh, can't connect. Invalid dbname, user or password?") print(e) def check_user_auth(): username = os.environ['username'] password = bytes(os.environ['password'], 'utf-8') # hashed = bcrypt.hashpw(password, bcrypt.gensalt()) user_info = get_user_info(username=username) user_encrypted_password = bytes(user_info[0], 'utf-8') user_state = True if user_info[1] == 'active' else False if bcrypt.checkpw(password, user_encrypted_password) and user_state: print("It matches!") sys.exit(0) else: print("It does not match :(") sys.exit(1) def main(): check_user_auth() if __name__ == '__main__': main()
А в конфиге OpenVPN просто указываем следующее:
auth-user-pass-verify /etc/openvpn/auth-user.py via-env
script-security 3
client-cert-not-requiredТаким образом, если у клиента увольнялся сотрудник, его просто деактивировали в GitLab, после чего он не сможет подключиться и к VPN'у.
Вместо заключения
В продолжении цикла статей с практическими рецептами компании «Флант» по эксплуатации Kubernetes я раскрою такие темы, как выделение отдельных узлов под конкретные задачи (зачем и как?) и настройка под большие нагрузки служб вроде php-fpm/gunicorn, запущенных в контейнерах. Подписывайтесь на наш блог, чтобы не пропускать обновления!
P.S.
Другое из цикла K8s tips & tricks:
Читайте также в нашем блоге:
- «11 способов (не) стать жертвой взлома в Kubernetes»;
- «Сборка и дeплой приложений в Kubernetes с помощью dapp и GitLab CI»;
- «Мониторинг и Kubernetes» (обзор и видео доклада);
- «Наш опыт с Kubernetes в небольших проектах» (видео доклада, включающего в себя знакомство с техническим устройством Kubernetes).
Автор: Андрей Сидоров