Intégration native de Jira : Aperçu technique

Sécurité d'accès au service d'intégration

Nous utilisons OAuth2 pour sécuriser nos API internes, chaque appel de service doit contenir un jeton OAuth avec un ensemble spécial de champs d'application demandés par le service.

Isolation des données

L'intégration native utilise Postgres comme stockage sous-jacent. Chaque tableau Postgres comporte une colonne "compte". Cette colonne de compte est utilisée pour séparer les données d'un compte de celles d'un autre au cours de l'opération. Une série de tests d'intégration permet de vérifier que les données sont régulièrement isolées.

Liste des API Jira utilisées par l'intégration

Jira Cloud et Jira Server API :

GET rest/agile/1.0/board
GET rest/agile/1.0/board/{boardId}/project
GET rest/agile/1.0/board/{boardId}/sprint
POST rest/agile/1.0/sprint
GET/DELETE rest/agile/1.0/sprint/{sprintId}
GET/POST rest/agile/1.0/sprint/{sprintId}/issue
POST rest/agile/1.0/backlog/issue
POST rest/agile/1.0/epic/none/issue
GET rest/agile/1.0/epic/{epicKey}
POST rest/agile/1.0/epic/{epicKey}/issue
POST rest/api/2/issue
POST rest/api/2/issue/bulk
GET/PUT/DELETE rest/api/2/issue/{issueKey}
GET/POST rest/api/2/issue/{issueKey}/comment
GET/PUT/DELETE rest/api/2/issue/{issueKey}/comment/{commentId}
POST rest/api/2/issue/{issueKey}/attachments
GET/POST rest/api/2/issue/{issueKey}/transitions
GET rest/api/2/issue/createmeta
GET rest/api/2/serverInfo
GET rest/api/2/attachment/{attachmentId}
GET secure/attachment/{attachmentId}/{fileName}
GET rest/api/2/issuetype
GET rest/api/2/issuetype/{issueTypeId}
POST /api/2/issueLink
DELETE /api/2/issueLink/{issueLinkId}
GET rest/api/2/issueLinkType
GET rest/api/2/project
GET rest/api/2/project/{projectKey}/statuses
GET rest/api/2/project/{projectKey}
POST rest/api/2/search
GET rest/api/2/field
GET rest/auth/latest/session
GET rest/api/2/user
GET rest/api/2/user/search
GET rest/api/2/project/{projectId}/versions
GET rest/api/2/project/{projectId}/components
GET rest/api/2/priority
GET rest/api/2/resolution
GET rest/api/2/mypermissions
GET rest/api/2/issuetypescheme/mapping
API Jira Cloud supplémentaire uniquement :
GET rest/api/2/project/{projectId}/hierarchy
GET rest/api/2/workflowscheme/project
GET rest/api/2/workflows/search
API supplémentaire du serveur Jira uniquement :
GET rest/api/2/issue/createmeta/{projectId}/issuetypes (>= 8.4.0)
GET rest/api/2/issue/createmeta/{projectId}/issuetypes/{issuetypeId} (>= 8.4.0)
GET rest/projectconfig/1/workflowscheme/{projectKey}
GET rest/projectconfig/1/workflow
En-têtes envoyés par Apptio Targetprocess :
"host",
"connection",
"content-length",
"client-ip",
"content-type",
"accept",
"authorization",
"user-agent",
"accept-encoding",
"traceparent",
"tracestate",
"elastic-apm-traceparent"

Authentification

Centre de données Jira et serveur Jira
  1. Authentification de base : Nom d'utilisateur / Mot de passe

    1.a Basique (Login/mot de passe) + Certificat**

  2. OAuth 1.0
  3. Certificat (authentification basée. Authentification du client TLS)**
  4. Clé API de la passerelle

    4.a Clé API de la passerelle + certificat**

  5. OAuth 2.0 Informations d'identification du client

    //Ceci couvre le cas d'utilisation de l'authentification au niveau de la passerelle avec OAuth2.0 et ensuite la passerelle autorise la connexion directe à Jira via Basic, OAuth 1.0 ou un certificat. Ce n'est pas pour la connexion directe de l'intégration ATP à Jira via OAuth 2.0. Certaines API Jira, comme l'API REST pour la synchronisation des sprints et la demande de tableaux Jira, ne supportent pas OAuth 2.0 (Jira ticket : https://ecosystem.atlassian.net/browse/ACJIRA-1815; https://developer.atlassian.com/server/jira/platform/rest-apis/#authentication-and-authorization )

  6. Jeton d'accès personnel

    6.a Jeton d'accès personnel + certificat**

    **Notez que les comptes hébergés sur des clusters publics ne peuvent pas utiliser de certificats auto-signés, seul un certificat SSL valide signé par une autorité de certification de confiance fonctionnera. L'autorisation à l'aide de certificats auto-signés ne peut être mise en œuvre que pour les clients de l'informatique en nuage privée.

Processus d'authentification par certificat (simplifié) :

Jira Cloud
  1. Jeton API Email/Utilisateur
  2. OAuth 2.0 Code d'autorisation

Format de stockage des données

Base de données

Nous utilisons Postgres DB comme stockage principal pour l'intégration.

Ce qui est stocké dans Postgres :

  • Profil d'intégration
  • Informations d'identification : Les données d'identification sont cryptées à l'aide de l'algorithme AES-256 (voir détails ci-dessous au paragraphe 5)
  • Routages : Targetprocess et projets Jira (leurs ID et noms)
  • Mappages de types, identifiants et noms de types, champs de types et noms de champs
  • Partages d'entités : Paire d'entités Targetprocess et de problèmes liés dans Jira. Pour les entités, nous ne stockons aucune donnée, à l'exception de leur clé d'émission/identifiant d'entité et de leur type d'entité.

Hôte de la base de données sur le même nœud à l'intérieur du cluster Kubernetes.

Mise en cache

Nous utilisons le cache en mémoire pour certaines informations presque statiques (jusqu'à 30min ) :

  • Types d'instances Jira
  • Champs de l'instance Jira
  • Réponse API de création d'instance Jira
  • Informations sur les profils configurés
Journaux

Nous utilisons Elastic Cloud pour l'enregistrement, aucune donnée sensible n'est stockée dans les journaux. Elastic Cloud en Irlande est utilisé et la journalisation peut être désactivée à la demande.

RabbitMQ

Nous utilisons rabbit MQ pour la communication des services sous-jacents. Les messages en lapin contiennent des modifications effectuées dans un outil et des modifications qui doivent être appliquées à l'outil cible.

Rabbit est situé sur les mêmes nœuds Kubernetes que le service d'intégration Jira.

Cryptage des données d'identification

Toutes les informations d'identification sont stockées dans la base de données PostgreSQL avec d'autres données d'intégration sous une forme cryptée à l'aide de l'algorithme AES-256. Schéma d'ensemble et flux détaillé ci-dessous :

  • Paire de clés publique/privée générée lors de la création du cluster, clé privée stockée localement. ( en utilisant PKCS#7 avec RSA 2048 bit)
  • Il y a un dépôt git "secrets" créé par cluster qui contient des secrets cryptés ou non cryptés en fonction de la sensibilité des données.
  • La clé de cryptage des jetons d'intégration Jira (à utiliser par l'algorithme AES256 ) est générée automatiquement (service de cryptage) ou manuellement (équipe DevOps, c'est notre cas) et cryptée avec la partie publique de la clé du cluster.
  • Le service d'intégration Jira invoque les services Secrets / Encryptor et envoie la "clé de cryptage des données"
  • La clé de chiffrement des données est déchiffrée à l'aide de la partie privée de la clé de cluster, renvoyée et utilisée pour chiffrer le jeton d'intégration Jira.
  • Même processus pour la récupération des clés - les services d'intégration Jira invoquent les services Secrets / Encryptor pour récupérer la clé de décryptage du jeton d'intégration Jira et la mettre en cache pour la durée du cycle de vie du conteneur.

Flux de traitement

Générique pour toutes les intégrations natives, chaque intégration d'outil utilise son propre adaptateur.

De Jira à Apptio Targetprocess

Le service adaptateur Jira est à l'écoute des webhooks du compte Jira. Lorsqu'une mise à jour se produit dans Jira, l'adaptateur Jira la convertit au format générique. Il peut mettre en file d'attente des données supplémentaires via l'API si elles sont nécessaires à la conversion. Lorsqu'un événement est converti, il est envoyé dans la file d'attente des événements génériques.

Le service de synchronisation des entités est à l'écoute des événements génériques. Lorsqu'un événement générique est reçu, s'il y a des règles configurées qui correspondent à cet événement (par exemple une question mise à jour dans Jira, et cette question est déjà partagée avec une question Targetprocess), la synchronisation d'entité applique les règles configurées et génère 1 ou plusieurs commandes qui doivent être appliquées à l'entité cible. L'entité sync publie ces commandes dans la file d'attente des commandes d'adaptateurs spécifiques RabbitMQ. Lors des mappages, l'application de la synchronisation des entités pourrait passer par des outils spécifiques via l'api des adaptateurs pour effectuer certaines conversions comme (pièce jointe, commentaire, utilisateur, état, etc.)

Adaptateur Targetprocess - reçoit les commandes qui doivent être appliquées à l'entité cible et applique les changements via l'API de l'outil. Si une commande contient plusieurs mises à jour de champs mais que toutes ne sont pas valides, l'adaptateur divise la mise à jour initiale en quelques petites mises à jour et applique toutes les mises à jour valides en ignorant celles qui ne le sont pas.

De Targetproces à Jira

Le flux de Targetprocess vers Jira reflète le flux de Jira vers Targetprocess décrit dans le paragraphe précédent. Les mises à jour sont générées du côté de Targetprocess et appliquées à Jira selon les mêmes règles.

Flux d'actions de l'entité

Les flux sont également similaires et ne dépendent pas de l'outil. Examinons le flux de partage de Targetprocess vers Jira.

Lorsque vous essayez de partager une entité avec Jira :

  • La synchronisation des entités vérifie via l'API de l'adaptateur Targetprocess si l'entité correspond à l'itinéraire configuré. Il est dans le bon projet, assigné à la bonne équipe, correspond à dsl, etc. Si c'est le cas, l'entité est résolue en partageant la destination cible (projet cible)
  • La synchronisation des entités vérifie si le profil a une correspondance de type pour l'entité source et résout le type d'entité cible.
  • Si le périmètre cible (projet) et le type sont résolus, l'adaptateur crée un stub d'entité cible dans Jiral. Il tente de remplir tous les champs obligatoires avec quelques erreurs.
  • Si l'entité cible est créée, la synchronisation des entités établit des règles de synchronisation entre l'entité source et l'entité cible.
  • La synchronisation des entités transfère l'état des entités du processus cible. (Valeurs de tous les champs configurés dans le profil)
  • La synchronisation des entités applique les correspondances configurées pour calculer l'état de l'entité cible et l'envoyer sous la forme d'une ou plusieurs commandes de mise à jour à l'adaptateur Jira.
  • L'adaptateur Jira applique des commandes à l'entité Jira pour qu'elle soit conforme aux mappings configurés.

Aperçu de la connectivité réseau

Il existe deux ensembles d'ACL et de groupes de sécurité utilisés pour limiter l'accès aux instances de Targetprocess depuis l'Internet :

  • Pour l'application - en entrée pour autoriser uniquement l'accès HTTPS au proxy qui achemine ensuite les données vers le serveur ou le service correspondant, tel que l'intégration Jira
  • Pour la gestion - l'accès à l'hôte Bastion pour la gestion n'est autorisé qu'à partir du bureau de Targetprocess ou seulement s'il est connecté au bureau par VPN.

Limitation du débit, politique de relance et utilisateurs / points d'extrémité dédiés

Pour les instances Jira très chargées avec un grand nombre d'intégrations, une limitation de taux sera mise en place. L'intégration native ne limite pas la fréquence de ses demandes, mais répète les demandes qui ont échoué si Jira commence à limiter le taux de demandes.

La stratégie de relance par défaut de l'intégration Targetprocess fonctionne pour les demandes à deux niveaux : les demandes des clients http et les messages d'intégration. Les demandes échouées seront réessayées 3 fois, 2, 4 et 8 secondes après le rejet, +/- 10 demandes simultanées.

Dans ce cas, nous recommandons au client de fournir un point de terminaison dédié pour accéder à l'API Jira. Sinon, si plusieurs intégrations distinctes utilisent le même point de terminaison, elles partagent la limite de débit et peuvent se bloquer mutuellement.