Kubernetes tips & tricks: доступ к dev-площадкам

    Мы продолжаем серию статей с практическими инструкциями о том, как облегчить жизнь эксплуатации и разработчикам в повседневной работе с 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.

    За время эксплуатации этого решения мы успели его неоднократно расширить. В частности:

    1. Так как мы не нашли простой и адекватной (для нашего случая) админки для учёта доступов к VPN, пришлось создать свой простой интерфейс — ведь официальный чарт предусматривает только вариант с запуском консольных команд для выпуска сертификатов.

      Получившаяся админка (см. также на Docker Hub) выглядит очень аскетично:


      Можно заводить новых юзеров или отзывать старые сертификаты:


      Также можно посмотреть конфиг для данного клиента:

    2. Мы добавили авторизацию в 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:


    Читайте также в нашем блоге:

    • +27
    • 4,5k
    • 8
    Флант
    500,00
    Специалисты по DevOps и высоким нагрузкам в вебе
    Поделиться публикацией

    Комментарии 8

      0
      Для этого был создан nginx с конфигурацией такого типа:
      правильно ли я понял, что этот nginx и имеет dns имя dev-auth.dev-auth-infra.svc.cluster.local и к которому идут за авторизацией?
        0
        Да.
        0
        А вы как-то даёте доступ разработчикам к выполнению exec внутри подов?
          +1
          Чаще всего хватает доступов к Kubernetes Dashboard с авторизацией в gitlab.
          Иногда даем доступ с помощью kubectl (конфиг подключения) с юзером, которому доступны только те действия, что определили с помощью RBAC.
            0
            хватает доступов к Kubernetes Dashboard с авторизацией в gitlab

            А как это реализовали, через dex?
              +1
              Нет. С помощью oauth2 proxy

              И пары аннотаций:
              ingress.kubernetes.io/auth-signin: https://$host/oauth2/sign_in
              ingress.kubernetes.io/auth-url: http://dashboard-oauth2-proxy.kube-system.svc.cluster.local:4180/oauth2/auth


              Если интересно, то можем рассказать в следующей статье более подробно о данном кейсе.
                +1
                Получается, что доступ будет во все части дашборда или есть какое-то разграничение?
                Да, было бы интересно, если расскажете. Спасибо!
                  0
                  Да, доступ есть во все части дашборды, но она запущена из под сервис аккаунта, которому разрешено только «смотреть», но не редактировать.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое