Trucs et astuces Kubernetes: accès aux sites de développement

Nous continuons notre série d'articles pratiques sur la façon de faciliter la vie de la maintenance et des développeurs dans leur travail quotidien avec Kubernetes. Tous sont issus de notre expérience dans la résolution des problèmes des clients et améliorés au fil du temps, mais ne prétendent toujours pas être idéaux - considérez-les davantage comme des idées et des blancs, suggérez vos solutions et améliorations dans les commentaires.


Cette fois, deux sujets seront considérés, liés conditionnellement à un sujet: l'accès des utilisateurs à l'environnement de développement.

1. Comment fermer les circuits de développement des utilisateurs inutiles?


Nous sommes souvent confrontés à la tâche de fermer l'intégralité du circuit de développement (des dizaines / centaines d'applications) derrière l'authentification de base ou la liste blanche, afin que les robots de recherche ou tout simplement des tiers ne puissent pas y arriver.

Habituellement, pour limiter l'accès, chaque entrée et chaque application doivent créer des secrets d'authentification de base distincts . Leur gestion est très problématique lors de la frappe avec une dizaine d'applications. Par conséquent, nous avons organisé un contrôle d'accès centralisé.

Pour ce faire, nginx a été créé avec une configuration de ce type:

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; } 

Plus loin dans les entrées de l'application, nous ajoutons simplement l'annotation:

ingress.kubernetes.io/auth-url: "http://dev-auth.dev-auth-infra.svc.cluster.local"

Ainsi, lors de l'accès à l'application, la demande est dev-auth , qui vérifie si l'authentification de base correcte est entrée ou si le client entre dans la liste blanche. Si l'une des conditions est remplie, la demande est confirmée et transmise à l'application.



Dans le cas de l'utilisation d'un tel service, un référentiel suffit, dans lequel une liste de tous les accès est stockée et à travers laquelle nous pouvons facilement configurer notre «centre d'autorisation unique». Sa distribution aux nouvelles applications s'effectue par l'ajout élémentaire d'annotations.

2. Comment fournissons-nous l'accès aux applications à l'intérieur de Kubernetes dans un environnement de développement?


... que ce soit Redis, RabbitMQ, PostgreSQL ou le développeur PHP préféré de Xdebug.

Très souvent, lors de la traduction d'applications vers Kubernetes, pour assurer une meilleure sécurité, nous devons bloquer l'accès de l'extérieur et complètement. Et puis les développeurs qui sont habitués à "aller leur IDE" vers la base de données ou vers Xdebug rencontrent de sérieuses difficultés.

Pour résoudre ce problème, nous utilisons un VPN directement dans le cluster Kubernetes. Le schéma général semble que lorsque vous vous connectez à un serveur VPN fonctionnant dans K8, dans le fichier de configuration OpenVPN, nous poussons l'adresse du serveur DNS, qui vit également dans K8. OpenVPN configure le VPN de telle manière que lorsqu'une ressource est demandée dans Kubernetes, elle va d'abord au serveur DNS Kubernetes - par exemple, derrière l'adresse du service redis.production.svc.cluster.local . DNS dans Kubernetes le résout en 10.244.1.15 et les demandes pour cette adresse IP passent par OpenVPN directement au cluster Kubernetes.

Pendant le fonctionnement de cette solution, nous avons réussi à l'étendre à plusieurs reprises. En particulier:

  1. Comme nous n'avons pas trouvé de panneau d'administration simple et adéquat (dans notre cas) pour rendre compte de l'accès au VPN , nous avons dû créer notre propre interface simple - le tableau officiel ne fournit que la possibilité d'exécuter des commandes de console pour émettre des certificats.

    Le panneau d'administration résultant (voir également sur le Docker Hub ) semble très ascétique:


    Vous pouvez créer de nouveaux utilisateurs ou révoquer d'anciens certificats:


    Vous pouvez également voir la configuration de ce client:

  2. Nous avons ajouté une autorisation dans VPN basée sur les utilisateurs de GitLab , où le mot de passe est vérifié et si l'utilisateur est actif dans GitLab. C'est pour les cas où le client veut gérer des utilisateurs qui peuvent se connecter à un VPN de développement uniquement basé sur GitLab, et sans l'utilisation d'administrateurs supplémentaires - dans un sens, il s'avère que "SSO pour les pauvres". Comme base, ils ont pris le tableau prêt à l'emploi déjà mentionné.

    Pour ce faire, nous avons écrit un script Python qui, lors de la connexion d'un utilisateur à OpenVPN, à l'aide du nom d'utilisateur et du mot de passe, compare le hachage dans la base de données GitLab et vérifie son état (s'il est actif).



    Voici le script lui-même:

     #!/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() 

    Et dans la configuration OpenVPN, spécifiez simplement les éléments suivants:

    auth-user-pass-verify /etc/openvpn/auth-user.py via-env
    script-security 3
    client-cert-not-required


    Ainsi, si un employé quittait le client, ils le désactivaient simplement dans GitLab, après quoi il ne pourrait pas se connecter au VPN.

Au lieu d'une conclusion


Poursuivant la série d'articles avec des recettes pratiques Flant pour le fonctionnement de Kubernetes, je couvrirai des sujets tels que la mise en évidence de nœuds individuels pour des tâches spécifiques (pourquoi et comment?) Et la configuration de services tels que php-fpm / gunicorn fonctionnant dans des conteneurs pour des charges lourdes. Abonnez-vous à notre blog pour ne pas manquer les mises à jour!

PS


Autres du cycle de trucs et astuces de K8:


Lisez aussi dans notre blog:

Source: https://habr.com/ru/post/fr427745/


All Articles