Aller au contenu principal

Modèle de sécurité

Semaphore détient les identifiants de votre infrastructure et exécute du code contre elle. Deux propriétés en découlent, et toutes deux orientent chaque autre décision de cette page : les secrets ne doivent jamais revenir vers un navigateur, et quiconque peut démarrer une tâche peut exécuter du code sur les machines que cette tâche atteint.

Cette page explique le modèle. Pour les paramètres qui le mettent en œuvre, voir Sécurité.

Frontières de confiance

FrontièreTraversée parProtégée par
Navigateur ↔ serveurSessions, jetons d'APITLS, cookies sécurisés, reverse proxy
Serveur ↔ base de donnéesTout l'état persistantRestriction réseau ; secrets chiffrés avant écriture
Serveur ↔ runnerCharges utiles des travaux, secrets comprisHTTPS et un jeton bearer propre à chaque runner
Tâche ↔ hôtes administrésVotre automatisationLes clés que vous avez confiées au modèle

Une tâche se trouve de l'autre côté de chacune de ces frontières. Elle reçoit dans son environnement les secrets dont elle a besoin, et à partir de cet instant le code de votre dépôt décide de ce qu'il en advient.

Identité

Les utilisateurs s'authentifient de trois manières, et toutes trois aboutissent à la même session :

  • Comptes locaux. Les mots de passe sont hachés avec Argon2id (bcrypt avant 2.20, mis à niveau à la première connexion). L'authentification à deux facteurs TOTP peut être exigée.
  • LDAP ou Active Directory. L'annuaire vérifie le mot de passe ; Semaphore ne conserve que le compte.
  • OpenID Connect. Le fournisseur authentifie et Semaphore fait correspondre les claims aux utilisateurs.

L'accès non interactif utilise des jetons d'API créés par un utilisateur, qui portent les permissions de cet utilisateur. Les runners n'utilisent pas du tout d'identité utilisateur : ils s'authentifient avec leur propre jeton délivré à l'enregistrement.

Les tâches peuvent elles aussi porter une identité. Avec les JWT de tâche, une exécution reçoit un jeton signé de courte durée nommant le projet, le modèle et l'utilisateur, qu'un magasin de secrets externe peut vérifier au lieu que vous stockiez un identifiant à longue durée de vie.

Autorisation

Il existe deux niveaux, et ils sont indépendants.

Niveau serveur. Un administrateur gère les utilisateurs, les runners globaux et les paramètres du serveur. Être administrateur du serveur ne confère pas en soi l'appartenance à un projet.

Niveau projet. Chaque membre détient un rôle dans chaque projet :

RôlePeut
OwnerTout faire dans le projet, y compris gérer les membres et le supprimer.
ManagerExécuter des tâches et gérer les ressources et les modèles.
Task RunnerExécuter des tâches. Rien d'autre.
GuestLire.

Enterprise ajoute des rôles personnalisés Enterprisesince 2.17 lorsque ces quatre rôles sont trop grossiers.

La ligne qui compte pour la sécurité passe entre Task Runner et Manager. Un Manager peut changer ce qu'un modèle exécute, et peut donc exécuter du code arbitraire avec les identifiants de ce projet. Un Task Runner ne peut démarrer que ce qui existe déjà — sauf si le modèle expose des invites ou des variables de questionnaire qui atteignent la ligne de commande, auquel cas l'auteur du modèle a délibérément élargi cette frontière.

Secrets

Les valeurs secrètes — clés privées SSH, mots de passe, jetons, variables secrètes — sont chiffrées avec la clé définie dans access_key_encryption avant d'être stockées : un simple dump de base de données ne les divulgue donc pas. L'API ne renvoie jamais une valeur secrète ; l'interface indique qu'un secret est défini, pas ce qu'il contient.

Les secrets parviennent à une tâche via son environnement au moment où elle démarre. C'est pourquoi la sortie des tâches mérite d'être traitée comme sensible : un playbook qui affiche une variable l'écrit dans un journal que les autres membres du projet peuvent lire.

Si vous préférez ne pas détenir les secrets du tout, les stockages de secrets externes conservent les valeurs dans HashiCorp Vault, OpenBao, AWS Secrets Manager ou Devolutions Server et les récupèrent à chaque exécution.

Exécuter du code non fiable

Avec la configuration par défaut, une tâche est un processus sur le serveur Semaphore, avec le système de fichiers et l'accès réseau du serveur. C'est acceptable lorsque toutes les personnes pouvant modifier un modèle ont déjà la confiance nécessaire sur le serveur.

Dans le cas contraire, éloignez l'exécution du serveur :

  • Un runner place les tâches sur une autre machine : compromettre une tâche ne compromet donc ni le service web ni la base de données.
  • L'exécuteur Docker ou Kubernetes donne à chaque travail un conteneur ou un Pod neuf, de sorte qu'une exécution ne peut pas lire les fichiers d'une autre exécution ni ceux de l'hôte.
  • Des projets séparés avec des clés séparées font qu'une tâche ne peut atteindre que ce que les identifiants de son propre projet autorisent.
attention

Un dépôt qu'un membre du projet peut modifier est du code qui sera exécuté avec les identifiants de ce projet. Protégez la branche depuis laquelle un modèle est construit, ou faites pointer les modèles vers une branche où seuls les relecteurs peuvent écrire.

Ce qui vous revient

Semaphore est auto-hébergé : certaines parties du modèle vous incombent donc :

  • TLS devant le service, qu'il soit intégré ou fourni par un reverse proxy.
  • La restriction réseau de la base de données et de la surface d'administration du serveur.
  • Les sauvegardes de la base de données et de access_key_encryption — la seconde est inutile sans la première, et la première est illisible sans la seconde.
  • Le maintien à jour de la version. Signalez les vulnérabilités à [email protected].

Et ensuite

  • Sécurité — les paramètres concrets, les paramètres de hachage et les étapes de durcissement.
  • Architecture — les composants que ces frontières séparent.
  • Équipes — attribuer des rôles dans un projet.