Comprendre l'inventaire pour DevSecOps

Dans DevSecOps, votre inventaire sert de liste centralisée critique de tous les éléments constitutifs de votre système logiciel. Il devient le point d'information unique de tout ce dont vous avez besoin pour développer, déployer et gérer vos applications en toute sécurité sur IBM Cloud. Voici ce qui est généralement inclus dans cet inventaire:

  • RessourcesIBM Cloud: inclut les serveurs virtuels, les fonctions sans serveur, les bases de données Cloudant et tous les autres services que vous avez mis à disposition dans votre environnement IBM Cloud.

  • Détails de l'infrastructure sous forme de code (IaC): cela inclut les configurations Terraform, les variables d'environnement stockées dans IBM® Cloud Foundry Artifactory, ainsi que d'autres paramètres qui déterminent la manière dont vos ressources IBM Cloud sont configurées et sécurisées.

  • Dépendances d'application: il s'agit de services, d'API et de microservices tiers sur lesquels vos applications cloud s'appuient pour fonctionner parfaitement.

  • IBM® Key Protect for IBM Cloud®: informations sensibles essentielles au fonctionnement du système, telles que les mots de passe, les clés d'API et les clés de chiffrement. Elles nécessitent un contrôle méticuleux et un stockage sécurisé dans IBM Key Protect.

Structure et contenu d'un inventaire

Le modèle d'inventaire suit les éléments suivants de l'artefact:

  • Nom de l'artefact
  • Environnement ou région dans lequel il sera déployé.
  • Emplacement de génération d'un artefact (exécution de pipeline, validation sha)
  • Signature de l'artefact généré

Suivez les informations collectées lors des générations et des déploiements d'artefact. Cela permet également d'effectuer des audits de gestion des changements et de conformité.

Branches

L'inventaire est implémenté en tant que référentiel Git. Git est auto-suffisant dans le suivi et l'audit des modifications.

Les branches sont utilisées comme environnements. La branche principale (master) est écrite et mise à jour par le pipeline d'intégration continue. Les autres environnements sont mis à jour à partir de la branche principale à l'aide de promotions. Pour plus d'informations sur les promotions, voir la section Promotion.

Contenu d'inventaire

L'inventaire contient une entrée d'inventaire pour chaque artefact qui participe au déploiement. Une entrée d'inventaire pointe vers un artefact. Les entrées d'inventaire sont des fichiers JSON qui peuvent être structurés dans des dossiers et qui sont nommés à l'aide du nom d'entrée.

Les dossiers d'inventaire font partie du nom d'entrée.

Exemple

Choisissez un nom dans la liste suivante de noms d'entrée comme nom de service:

  • auth/service
  • auth/db
  • ui/service
  • main_service
  • helm-charts/main_service

Le contenu est implémenté dans l'inventaire à l'aide de la structure suivante :

/
├── auth
│   ├── service
│   └── db
├── ui
│   └── service
├── helm-charts
│   └── main_service
└ main_service

Format d'entrée d'inventaire

Bien que le type Entry représente le schéma de l'entrée d'inventaire avec la syntaxe typescript, vous pouvez convertir le schéma pour utiliser un schéma JSON.

interface Entry {
  repository_url: string;
  artifact: string;
  build_number: number;
  commit_sha: string;
  name: string;
  pipeline_run_id: string;
  version: string;

  app_artifacts: {
    signature: string;
    provenance: string;

    [key: string]: any;
  }

  type: string;
  sha256: string;
  provenance: string;
  signature: string;
}

Exemple

Entrée de stock pour le type d'image de l'actif

{
  "repository_url": "https://github.com/test-org/compliance-app-20201211", # source code repository url of the image artifact
  "artifact": "us.icr.io/namespace/hello-compliance-app:20201217081811-master-b85e3d472e9cc35b429c39e8c3f9eb282738c20a@sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0", # image artifact name, should be in a format like <static_name>:<version>@sha256:<sha256> OR <static_name>@sha256:<sha256>
  "build_number": 21, # pipeline build number
  "commit_sha": "b85e3d472e9cc35b429c39e8c3f9eb282738c20a",  # should be a proper git commit sha
  "name": "hello-compliance-app", # name of the inventory entry file name
  "pipeline_run_id": "f21321bf-9054-4bf3-80a8-4fb34743b7d9", # pipeline run id where artifact was built
  "version": "v1",  # version of the artifact
  "app_artifacts": {}, # any additional information can be stored here
  "type": "image",
  "sha256": "sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0",
  "provenance": "us.icr.io/namespace/hello-compliance-app:20201217081811-master-b85e3d472e9cc35b429c39e8c3f9eb282738c20a@sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0", # The fully qualified URL where artifact is stored, in case of image artifact, it is same as the artifact field
  "signature": "owFNUX1IE3EY3vwAEy0VyoSJdkVWtu0+d3eTjNIIi0jETCSU3353cz+83V23myi2BlFgYiUFqSmZLciUzCJkRYJp9IEWFWXB0hAyrBQxEjIIuhFSf70vL8/7vM/zPi3JsaYEc+TnbqG8qrnTPDZ8w2WqiqwtacCghnQEgYQ5GzAkiLKO9PpoLyiwRtSsmugWNVGGIubE/D4bgpoNKXag60gCdo8oSYoVKl5VQsDAWIGqOkmcxAmSYHGO4AjC6gU+3eBxcYxICTRLijyEFOOiSR5SvMhBys2LLpIjWYqDJA6wwHYMeUG1+J8GL5CRW/TpVgFVG8VQ4vMAknE4BUA5OIoQGIKhKZwFkIeAdnECj+OCmxQADh2QoFmG5lkWUiTN8gJ0kDxPuxiWJAU8ekyvV6PegK54EcyGiqwDJItatg9Vy0D3a2IUpKg6UuS/T4KaaIC1fzuMDbfhmMGEvIY64FUxJ+Ew3PMU5SADgdNmKs5kTjBlrtsQ99iyY49nns8o6jsXWgkjPiYahClxVcrK5Flngumz2j7YdmD0ecutytsvxxNPHflKlRV2RyqD69NjC6Smji9XuukFyZ+lvM18gUr7F4NXge9YyZPik411tc1n9bKO/hDz7oGaX/ur94OnNHiwOG6n5ZsrsCsvtyvmkH4zOWlrRWuL7fzgj9zlcCTAhtu2LbeGLNfv3Ju0Jc9PZPk7Pm3Ov2CW+2xj8ReX6ooGamZ610yqRM/+8Qo2XnOeyZzbVKgs+f2+9unpJOve4Tmla+PdqftDWkHPm9Vq3nsyZ2DUkmP/nTb7qNw5l2SfWtiSemJx9nLaYOpx6amlOT18aeIwJQhHg1XOjJF9r18NXQvPuL9rH5tSQqbGhyN/AA=="  # The signature of the artifact
}

Entrée d'inventaire pour le type d'actif autre que l'image, tel que le déploiement, les chartes Helm

{
  "repository_url": "https://github.com/test-org/compliance-app-20201211",  # source code repository url of the artifact
  "artifact": "deployment.yaml", # artifact name, must be contant every build
  "build_number": 21, # pipeline build number
  "commit_sha": "b85e3d472e9cc35b429c39e8c3f9eb282738c20a", # must be a proper git commit sha
  "name": "hello-compliance-app-deployment", # name of the inventory entry file name
  "pipeline_run_id": "f21321bf-9054-4bf3-80a8-4fb34743b7d9", # pipeline run id where artifact was built
  "version": "v1", # version of the artifact
  "app_artifacts": {}, # any additional information can be stored here
  "type": "deployment", # type of the artifact
  "sha256": "sha256:da36831d5154307ac9ca4b8d900df2da0c6c14754977c32479dc62994b5722d0",  # sha256 of the artifact
  "provenance": "https://raw.github.ibm.com/org/my-app/commit-1/deployment.yaml", # The fully qualified URL where artifact is stored
  "signature": "owFNUX1IE3EY3vwAEy0VyoSJdkVWtu0+d3eTjNIIi0jETCSU3353cz+83V23myi2BlFgYiUFqSmZLciUzCJkRYJp9IEWFWXB0hAyrBQxEjIIuhFSf70vL8/7vM/zPi3JsaYEc+TnbqG8qrnTPDZ8w2WqiqwtacCghnQEgYQ5GzAkiLKO9PpoLyiwRtSsmugWNVGGIubE/D4bgpoNKXag60gCdo8oSYoVKl5VQsDAWIGqOkmcxAmSYHGO4AjC6gU+3eBxcYxICTRLijyEFOOiSR5SvMhBys2LLpIjWYqDJA6wwHYMeUG1+J8GL5CRW/TpVgFVG8VQ4vMAknE4BUA5OIoQGIKhKZwFkIeAdnECj+OCmxQADh2QoFmG5lkWUiTN8gJ0kDxPuxiWJAU8ekyvV6PegK54EcyGiqwDJItatg9Vy0D3a2IUpKg6UuS/T4KaaIC1fzuMDbfhmMGEvIY64FUxJ+Ew3PMU5SADgdNmKs5kTjBlrtsQ99iyY49nns8o6jsXWgkjPiYahClxVcrK5Flngumz2j7YdmD0ecutytsvxxNPHflKlRV2RyqD69NjC6Smji9XuukFyZ+lvM18gUr7F4NXge9YyZPik411tc1n9bKO/hDz7oGaX/ur94OnNHiwOG6n5ZsrsCsvtyvmkH4zOWlrRWuL7fzgj9zlcCTAhtu2LbeGLNfv3Ju0Jc9PZPk7Pm3Ov2CW+2xj8ReX6ooGamZ610yqRM/+8Qo2XnOeyZzbVKgs+f2+9unpJOve4Tmla+PdqftDWkHPm9Vq3nsyZ2DUkmP/nTb7qNw5l2SfWtiSemJx9nLaYOpx6amlOT18aeIwJQhHg1XOjJF9r18NXQvPuL9rH5tSQqbGhyN/AA=="  # The signature of the artifact
}

Utilisez la commande cacao inventory add pour écrire dans l'inventaire.

Flux de travaux d'inventaire

L'inventaire contient plusieurs branches en plus de la branche master. Ces branches peuvent représenter des étapes, des environnements ou des régions de déploiement ou un mélange de ces options. La structure de ces branches dépend de la configuration et de l'utilisation.

L'intégration continue écrit dans l'inventaire

La branche master est renseignée à partir des générations d'intégration continue. La dernière validation dans la cible (en l'occurrence, staging) contient une étiquette indiquant qu'il s'agit du dernier déploiement effectué.

Si la branche par défaut de l'inventaire est basculée vers une autre branche, vous devez resynchroniser les validations de la branche par défaut précédente dans la nouvelle branche par défaut pour rendre l'historique des validations Git linéaire.

Vous pouvez ignorer l'écriture dans l'inventaire en personnalisant le script d'édition. Pour plus d'informations, voir Mise en stock.

L'intégration continue écrit dans l'inventaire
L'intégration continue écrit dans l'inventaire

Promotion

Une demande d'extraction est créée lorsque vous effectuez la promotion vers une branche cible. Le contenu de la demande d'extraction remplit les zones de demande de changement. Une fois la demande d'extraction révisée, vous pouvez la fusionner.

Promotion d'une branche cible à l'aide d'un PR
Promotion d'une branche cible à l'aide d'un PR

Ecart de déploiement

Une fois la demande d'extraction de promotion fusionnée, le pipeline de déploiement peut démarrer. L'écart de déploiement est la différence entre le contenu du dernier déploiement effectué et celui du déploiement en cours. L'écart de déploiement répertorie les éléments d'inventaire en cours de déploiement.

Flux de pipeline de déploiement affichant les détails du delta de déploiement
Figure3. Flux de pipeline de déploiement affichant les détails du delta de déploiement

Conclusion de l'inventaire

Une fois le déploiement terminé, vous pouvez déplacer l'étiquette latest plus loin.

Lors du déclenchement du mode de développement, les balises ne seront pas avancées. L'objectif du déclencheur de mode de développement est uniquement de tester le pipeline CD uniquement.

Déploiement terminé
Déploiement terminé

Promotion vers d'autres environnements

Vous pouvez effectuer une promotion et un déploiement à partir de n'importe quelle branche vers une autre branche.

Promotion utilisant un PR de la branche staging à la branche prod
Promotion utilisant un PR de la branche staging à la branche prod

Paysage d'inventaire

L'état actuellement déployé contient le contenu à déployer dans un environnement. Chaque commit promu dans la branche cible contient l'ID de l'exécution du pipeline et l'ID de la demande de changement en tant qu'étiquette. Certaines validations peuvent comporter plusieurs étiquettes, par exemple, lorsque vous relancez un déploiement ayant échoué ou que vous effectuez un nouveau déploiement. L'inventaire contient tous les éléments d'information nécessaires pour réexécuter les déploiements.

Diagramme de déploiement avec tags
Diagramme de déploiement avec tags

Utilisation des étiquettes

Le tableau suivant présente les étiquettes d'inventaire disponibles.

Étiquettes d'inventaire
Balise Description
latest Etiquette l'état en cours, déployé et terminé de l'inventaire sur une branche.
pipeline run id Etiquette l'état d'inventaire en cours sur la branche, avec l'ID d'exécution de pipeline ou le numéro de version du déploiement réel. Pour éviter le chevauchement de contenu d'inventaire lorsque des déploiements parallèles sont déclenchés, utilisez cette étiquette pour faire référence au hachage du point d'inventaire réel dans l'historique de branche.
change request id (facultatif) Etiquette l'état en cours d'un ID de demande de changement pour assurer le suivi des ID de demande de changement dans l'inventaire, dans une représentation historique.

Configuration pour une cible avec plusieurs régions

Plusieurs tags latest sont introduits pour un seul environnement cible afin que plusieurs pipelines de déploiement continu puissent fonctionner sur la même cible, pour différents types de cas d'utilisation. Vous pouvez utiliser, par exemple, le même environnement cible (par exemple, us-south ou eu-de) pour plusieurs régions dans l'environnement cible de production et la branche d'inventaire.

Il n'est pas nécessaire de créer une branche différente pour chaque région en utilisant la propriété region, telle que us-south-prod et eu-de-prod, et d'exécuter la promotion de manière redondante. A la place, indiquez ces cibles supplémentaires pour la même branche d'inventaire, puis utilisez-les en tant qu'étiquettes Git.

Dans cette configuration, la branche prod possède plusieurs étiquettes latest sur la même branche, telles que us-south_prod_latest et eu-de_prod_latest. Chaque pipeline de déploiement continu responsable de chaque région peut utiliser ces balises pour le déploiement.

Branche de production avec plusieurs étiquettes récentes par région
Branche de production avec plusieurs étiquettes récentes par région

Par exemple, un ensemble de changements que vous prévoyez de déployer partout peut être publié dans une seule région d'abord, puis déployé progressivement dans d'autres régions en utilisant des pipelines de déploiement continu pour cibler ces régions.

Opérations d'inventaire

L'inventaire contient des informations de base qui s'exécutent à l'aide de l'interface de ligne de commande, de pure Git et de l'interface de ligne de commande GitHub.

Commandes de l'interface de ligne de commande

  1. Créez une demande d'extraction de promotion à partir de la branche principale vers la branche cible dans un environnement de préproduction.

    cocoa inventory promote \
      --source="master" \
      --target="staging" \
      --priority="moderate" \
      --assigned-to="assignee@ibm.com" \
      --description="Change description" \
      --purpose="Change purpose" \
      --impact="Change impact" \
      --backout-plan="Details on backout and rollback")
    
  2. Terminez un déploiement en déplaçant l'étiquette target_latest vers la même validation que l'étiquette pipeline-run-id.

    cocoa inventory label move \
      --to-label="${PIPELINE_RUN_ID}" \
      "target_latest"
    

Interface de ligne de commande Git et GitHub

  1. Créez une demande d'extraction de promotion à partir de la branche principale vers la branche cible dans un environnement de préproduction.

    promote() {
    
      if [ -z $1 ] || [ -z $2 ]; then
        echo "Missing source and target"
        exit 1
      fi
    
      local source="$1"
      local target="$2"
    
      if ! git show-ref "refs/remotes/origin/$target"; then
        # Create a new target branch, from the beginning of master
        git checkout master
        git checkout -b "$target" $(git rev-list --max-parents=0 HEAD)
        git_push
      fi
    
      git checkout "$source"
      git pull --rebase
    
      # Create a promotion branch for the PR
      # this can be discarded after the Promotion PR merge
      git checkout -b "promote-$source-to-$target"
      git push --set-upstream origin "promote-$source-to-$target"
    
      # Create PR from promotion branch to target branch
      gh pr create \
        --base "$target" \
        --head "promote-$source-to-$target" \
        --title "Promote $source to $target" \
        --body "" \
        --repo "https://github.com/org/inventory-repository"
    
      # promotion branch can be deleted once the PR was merged
    }
    
    $ promote master staging
    
  2. Terminez un déploiement en déplaçant l'étiquette target-latest vers la même validation que l'étiquette pipeline-run-id.

    conclude () {
      local target="$1"
      local tag="$2"
    
      latest="$1-latest"
    
      # remove the latest tag
      git push origin ":refs/tags/$latest"
      # find the commit hash of the target tag
      sha=$(git rev-list -n 1 $tag)
    
      # add the latest tag to the same commit of the target tag
      git tag -fa "$latest" -m "" $sha
      git push --tags --force
    }
    
    $ conclude staging pipeline-run-fe33b05c
    
  3. Rétablissez un état antérieur de l'environnement de préproduction à l'aide de Git et de l'interface de ligne de commande GitHub.

    revert () {
      local branch="$1"
      local commit="$2"
    
      # create a revert branch from the target branch
      git checkout "$branch"
      git pull --rebase
      git checkout -b "$branch-revert"
    
      # revert commits since the target commit, then commit and push
      git revert -n $(git rev-list --no-merges HEAD...$commit)
      git commit -m "revert $branch to $commit"
      git push --set-upstream origin "$branch-revert"
    
      # create PR from revert branch to the target branch
      gh pr create \
        --base "$branch" \
        --head "$branch-revert" \
        --title "Revert $branch to $commit" \
        --body "" \
        --repo "$REPO"
    
      # revert branch can be deleted once the PR was merged
    }
    
    $ revert staging ba3b8e5ed3320e6b4981077e1a1627f08de4f511
    

Cas d'utilisation courants pour utiliser des référentiels Git

Pour plus d'informations sur l'utilisation de référentiels Git, voir les exemples de scénario suivants :

Comment exclure des fichiers et des répertoires dans l'inventaire

One-Pipeline exclut par défaut les fichiers masqués et les fichiers .md de l'inventaire. Créez un fichier nommé .inventoryignore dans votre référentiel d'inventaire pour exclure tous les fichiers ou répertoires. Le pipeline recherche le fichier .inventoryignore à la racine du référentiel.

Toutefois, si vous préférez un nom différent pour le fichier d'exclusion d'inventaire, vous pouvez le spécifier en définissant la clé inventory-ignore-file comme propriété d'environnement dans votre pipeline. Assurez-vous que ce fichier se trouve à la racine du référentiel d'inventaire.

Par exemple, si votre fichier est nommé .custominventoryignore, ajoutez une variable d'environnement inventory-ignore-file avec la valeur custominventoryignore.

Voici un exemple de contenu du fichier .custominventoryignore dans deux formats :

.md
sample_file
sample_directory/
# Ignore everything
**

# But keep these artifacts
!sample_directory/
!sample_file

Les paragraphes suivants expliquent l'objectif des entrées du fichier de l'exemple .custominventoryignore:

  • .md: exclut tous les fichiers portant l'extension .md. N'ajoutez pas * au début, comme *.md, car les expressions rationnelles ne sont pas prises en charge.
  • sample_file: Exclut le fichier spécifique dans l'ensemble du référentiel.
  • sample_directory/: Exclut le répertoire entier. Évitez d'ajouter * à la fin, utilisez sample_directory/*, car les expressions rationnelles ne sont pas prises en charge.
  • Si un fichier ne contient aucune entrée ou une ligne vide, tous les fichiers seront exclus. Veuillez ne pas laisser d'entrées ou de lignes vides dans le fichier d'inventaire.
  • **: Ignore tout ce qui se trouve dans le référentiel.
  • !sample_directory/ et !sample_file: annule la règle d'ignorance, en conservant ces fichiers ou répertoires spécifiques même si ** est présent.