Verständnis der Bestandsaufnahme für DevSecOps

In DevSecOps, dient Ihr Inventar als kritische, zentralisierte Liste aller Bausteine, aus denen Ihr Softwaresystem besteht. Es ist der zentrale Informationspunkt für alles, was Sie für die sichere Entwicklung, Bereitstellung und Verwaltung Ihrer Anwendungen in IBM Cloudbenötigen. Im Folgenden ist aufgeführt, was normalerweise in diesem Bestand enthalten ist:

  • Ressourcen fürIBM Cloud: Hierzu gehören virtuelle Server, serverunabhängige Funktionen, Cloudant-Datenbanken und alle anderen Services, die Sie in Ihrer IBM Cloud-Umgebung bereitgestellt haben.

  • Details zu Infrastructure as Code (IaC): Dazu gehören Terraform-Konfigurationen, Umgebungsvariablen, die in IBM® Cloud Foundry Artifactorygespeichert werden, sowie weitere Einstellungen, die festlegen, wie Ihre IBM Cloud-Ressourcen konfiguriert und geschützt werden.

  • Anwendungsabhängigkeiten: Dies sind Services, APIs und Mikroservices anderer Anbieter, auf die Ihre Cloudanwendungen angewiesen sind, um fehlerfrei zu funktionieren.

  • IBM® Key Protect for IBM Cloud® Geheime Schlüssel: Diese Angabe bezieht sich auf sensible Informationen, die für den Systembetrieb wichtig sind, wie Kennwörter, API-Schlüssel und Verschlüsselungsschlüssel. Diese erfordern eine sorgfältige Kontrolle und eine sichere Speicherung in IBM Key Protect.

Struktur und Inhalt eines Bestands

Das Bestandsmodell verfolgt die folgenden Elemente des Artefakts:

  • Name des Artefakts
  • Umgebung oder Region, in der sie bereitgestellt wird.
  • Buildposition eines Artefakts (Pipelineausführung, Commit sha)
  • Signatur des erstellten Artefakts

Verfolgen Sie Angaben während Artefaktbuilds und -bereitstellungen. Dies hilft auch bei Change Management-und Compliance-Audits.

Verzweigungen

Der Bestand ist in einem Git-Repository (repo) implementiert. Git ist bei der Verfolgung und Prüfung von Änderungen autark.

Verzweigungen werden als Umgebungen verwendet. Die Hauptverzweigung (master) wird von der Continuous Integration-Pipeline geschrieben und aktualisiert. Andere Umgebungen werden mittels Hochstufungen von der Hauptverzweigung aus aktualisiert. Weitere Informationen zu Hochstufungen finden Sie im Abschnitt Hochstufung.

Bestandsinhalt

Der Bestand enthält für jedes Artefakt, das an der Bereitstellung beteiligt ist, einen Bestandseintrag. Ein Bestandseintrag verweist auf ein einziges Artefakt. Bestandseinträge sind JSON-Dateien, die in Ordnern strukturiert werden können und mit dem Eintragsnamen benannt sind.

Bestandsordner sind Teil des Eintragsnamens.

Beispiel

Wählen Sie einen Namen aus der folgenden Liste mit Eintragsnamen als Servicenamen:

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

Der Inhalt wird im Bestand mit der folgenden Struktur implementiert:

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

Bestandseintragsformat

Der Typ Entry stellt das Schema des Bestandseintrags zwar mithilfe von Typescript-Syntax dar, kann jedoch konvertiert werden, damit Sie ein JSON-Schema verwenden können.

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

Beispiel

Bestandseintrag für den Bildtyp des Assets

{
  "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
}

Bestandseintrag für den Nicht-Image-Assettyp, z. B. Bereitstellung, Helm-Diagramme

{
  "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
}

Verwenden Sie den Befehl cacao inventory add, um in den Bestand zu schreiben.

Bestandsworkflow

Der Bestand enthält neben der Verzweigung master mehrere Verzweigungen. Diese Verzweigungen können Bereitstellungsphasen, Umgebungen oder Regionen oder eine Kombination aus beidem darstellen. Die Struktur dieser Verzweigungen ist von der Konfiguration und der Verwendung abhängig.

CI-Schreibvorgänge im Bestand

Die Verzweigung master wird aus Continuous Integration-Builds gefüllt. Die letzte Festschreibung im Ziel (in diesem Fall namens staging) enthält einen Tag, der deutlich macht, dass es sich um die letzte abgeschlossene Bereitstellung handelt.

Wenn die Standardverzweigung für den Bestand auf eine andere Verzweigung umgeschaltet wird, müssen Sie die Commits aus der vorherigen Standardverzweigung in die neue Standardverzweigung umstellen, damit das Git-Commitprotokoll linear wird.

Sie können das Schreiben in den Bestand überspringen, indem Sie das Release-Script anpassen. Weitere Informationen finden Sie unter Release to inventory.

Kontinuierliche Integration schreibt ins Inventar
Kontinuierliche Integration schreibt ins Inventar

Umstufung

Eine Pull-Anforderung wird erstellt, wenn eine Hochstufung auf eine Zielverzweigung erfolgt. Der Inhalt der Pull-Anforderung füllt die Felder für Änderungsanforderungen. Nachdem die Pull-Anforderung geprüft wurde, können Sie sie zusammenführen.

Bewerben eines Zielzweigs durch Verwendung eines PR
Bewerben eines Zielzweigs durch Verwendung eines PR

Delta und Bereitstellung

Nach dem Zusammenführen der Pull-Anforderung für die Hochstufung kann die Bereitstellungsspipeline gestartet werden. Das Bereitstellungsdelta ist der Unterschied zwischen dem Inhalt der letzten abgeschlossenen Bereitstellung und der aktuellen Bereitstellung. Im Bereitstellungsdelta sind die Bestandselemente aufgelistet, die bereitgestellt werden.

Ablauf der Implementierungspipeline mit Details zum Implementierungsdelta
Abbildung 3. Ablauf der Implementierungspipeline mit Details zum Implementierungsdelta

Bestandszusammenfassung

Nachdem die Bereitstellung fertiggestellt worden ist, können Sie den Tag latest nach vorne verschieben.

Während des Auslösers im Einheitenmodus werden die Tags nicht erweitert. Der Zweck des Auslösers im Entwicklungsmodus ist nur zum Testen der CD-Pipeline.

Bereitstellung abgeschlossen
Bereitstellung abgeschlossen

Auf andere Umgebungen umstufen

Sie können Elemente von jeder Verzweigung auf eine andere hochstufen und bereitstellen.

Beförderung mithilfe eines PR vom Staging- zum Produktionszweig
Beförderung mithilfe eines PR vom Staging- zum Produktionszweig

Bestandslandschaft

Der aktuelle bereitgestellte Status enthält den Inhalt für die Bereitstellung in einer Umgebung. Jede beförderte Übergabe im Zielzweig enthält die entsprechende Pipeline-Lauf-ID und die Änderungsanforderungs-ID als Tag. Einige Festschreibungen können mehrere Tags aufweisen, wenn Sie beispielsweise eine fehlgeschlagene Bereitstellung wiederholen oder eine erneute Bereitstellung durchführen. Der Bestand enthält alle Informationen, die für die Wiederholung der Bereitstellungen erforderlich sind.

Bereitstellungsflussdiagramm mit Tags
Bereitstellungsflussdiagramm mit Tags

Verwendung von Tags

Die folgende Tabelle zeigt die verfügbaren Inventar-Tags.

Inventar-Tags
Tag Beschreibung
latest Kennzeichnet den aktuellen, erfolgreich bereitgestellten und abgeschlossenen Status des Bestands in einer Verzweigung.
pipeline run id Kennzeichnet den aktuellen Bestandsstatus in der Verzweigung mit der ID der Pipelineausführung oder der Buildnummer der tatsächlichen Bereitstellung. Damit es bei der Auslösung von parallelen Bereitstellung nicht zu Überschneidungen des Inventarinhalts kommt, referenzieren Sie mit diesem Tag den Hashwert für den tatsächlichen Bestandspunkt im Verzweigungsprotokoll.
change request id (fakultativ) Kennzeichnet den aktuellen Status einer Änderungsanforderungs-ID an, damit die Änderungsanforderungs-IDs im Bestand in einer Protokolldarstellung verfolgt werden können.

Konfiguration für ein einzelnes Ziel mit mehreren Regionen

Es werden mehrere latest Tags für eine einzige Zielumgebung eingeführt, so dass mehrere kontinuierliche Bereitstellungspipelines für unterschiedliche Anwendungsfälle auf demselben Ziel arbeiten können. Sie können beispielsweise dieselbe Zielumgebung (z. B. us-south oder eu-de) für mehrere Regionen in der Produktionszielumgebung und der Bestandsverzweigung verwenden.

Sie müssen nicht für jede Region einen anderen Zweig einrichten, indem Sie die Eigenschaft region verwenden, z. B. us-south-prod und eu-de-prod, und die Aktion redundant durchführen. Stattdessen geben Sie diese zusätzlichen Ziele für dieselbe Bestandsverzweigung an und verwenden Sie dann als Git-Tags.

In dieser Konfiguration hat der prod-Zweig mehrere latest-Tags auf demselben Zweig, wie us-south_prod_latest und eu-de_prod_latest. Jede Continuous-Deployment-Pipeline, die für die einzelnen Regionen zuständig ist, kann diese Tags für die Bereitstellung verwenden.

Produktionszweig mit mehreren aktuellen Tags pro Region
Produktionszweig mit mehreren aktuellen Tags pro Region

Eine Reihe von Änderungen, die Sie überall bereitstellen möchten, könnte beispielsweise zunächst in einer einzigen Region freigegeben werden und dann schrittweise in anderen Regionen bereitgestellt werden, indem kontinuierliche Bereitstellungspipelines für diese Regionen verwendet werden.

Operationen für Bestand

Der Bestand enthält einige Basisoperationen, die über die Befehlszeilenschnittstelle (CLI) oder rein über Git und die GitHub-Befehlszeilenschnittstelle ausgeführt werden.

Befehle der Befehlszeilenschnittstelle

  1. Erstellen Sie eine Pull-Anforderung für die Hochstufung von der Master- auf die Zielverzweigung im Staging.

    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. Schließen Sie eine Bereitstellung ab, indem Sie den Tag target_latest zu derselben Festschreibung wie den Tag pipeline-run-id verschieben.

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

Git und GitHub-CLI

  1. Erstellen Sie eine Pull-Anforderung für die Hochstufung von der Master- auf die Zielverzweigung im Staging.

    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. Schließen Sie eine Bereitstellung ab, indem Sie den Tag target-latest zu derselben Festschreibung wie den Tag pipeline-run-id verschieben.

    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. Setzen Sie das Staging mit Git und der GitHub-Befehlszeilenschnittstelle auf einen früheren Zustand zurück.

    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
    

Gängige Anwendungsfälle für die Arbeit mit Git-Repositorys

Weitere Informationen zum Arbeiten mit Git-Repositorys bieten die folgenden Beispielszenarios:

Dateien und Verzeichnisse im Inventar ausschließen

1-Pipeline schließt standardmäßig verdeckte Dateien und .md-Dateien im Bestand aus. Erstellen Sie eine Datei mit dem Namen .inventoryignore in Ihrem Bestandsrepository, um alle Dateien oder Verzeichnisse auszuschließen. Die Pipeline sucht im Stammverzeichnis des Repositorys nach der Datei .inventoryignore.

Wenn Sie jedoch einen anderen Namen für die Bestandsausschlußdatei bevorzugen, können Sie ihn angeben, indem Sie den Schlüssel inventory-ignore-file als Umgebungseigenschaft in Ihrer Pipeline festlegen. Stellen Sie sicher, dass sich diese Datei im Stammverzeichnis des Bestandsrepositorys befindet.

Wenn Ihre Datei beispielsweise den Namen .custominventoryignore hat, fügen Sie eine Umgebungsvariable inventory-ignore-file mit dem Wert custominventoryignore hinzu.

Im Folgenden finden Sie ein Beispiel für den Inhalt der Datei .custominventoryignore in zwei Formaten:

.md
sample_file
sample_directory/
# Ignore everything
**

# But keep these artifacts
!sample_directory/
!sample_file

Im Folgenden wird der Zweck der Einträge in der Beispieldatei .custominventoryignore erläutert:

  • .md: Schließt alle Dateien mit der Erweiterung .md aus. Fügen Sie nicht * am Anfang ein, wie *.md, da Regex nicht unterstützt wird.
  • sample_file: Schließt eine bestimmte Datei im gesamten Repository aus.
  • sample_directory/: Schließt das gesamte Verzeichnis aus. Vermeiden Sie das Hinzufügen von * am Ende, verwenden Sie sample_directory/*, da Regex nicht unterstützt wird.
  • Wenn eine Datei keine Einträge enthält oder eine leere Zeile, werden alle Dateien ausgeschlossen. Bitte lassen Sie keine leeren Einträge oder Zeilen in der Inventar-Ignore-Datei.
  • **: Ignoriert alles im Repository.
  • !sample_directory/ und !sample_file: Hebt die Ignorierregel auf, so dass diese spezifischen Dateien oder Verzeichnisse auch dann erhalten bleiben, wenn ** vorhanden ist.