IBM Cloud Docs
了解 DevSecOps 的清单

了解 DevSecOps 的清单

在 DevSecOps, 清单是构成软件系统的所有构件的重要集中列表。 它成为在 IBM Cloud上安全地开发,部署和维护应用程序所需的所有信息的单一信息点。 以下是此库存中通常包含的内容:

  • IBM Cloud 资源: 这包括传递虚拟服务器,无服务器功能,Cloudant 数据库以及您在 IBM Cloud 环境中供应的任何其他服务。

  • 基础结构即代码 (IaC) 详细信息: 这包括 Terraform 配置,存储在 IBM® Cloud Foundry Artifactory中的环境变量以及指示如何配置和保护 IBM Cloud 资源的其他设置。

  • 应用程序依赖关系: 这些是第三方服务,API 和微服务,您的云应用程序依赖这些服务来正常运行。

  • IBM® Key Protect for IBM Cloud® 密钥: 这是指系统操作必需的敏感信息,例如密码,API 密钥和加密密钥。 这些需要在 IBM Key Protect中进行细致控制和安全存储。

清单的结构和内容

库存模型将跟踪工件的以下项:

  • 工件的名称
  • 它将部署到的环境或区域。
  • 工件的构建位置 (管道运行,落实沙)
  • 已构建工件的签名

在工件构建和部署期间跟踪证据。 这也有助于变更管理和合规性审计。

分支

库存在 Git 存储库 (存储库) 中实现。 Git 在跟踪和审计更改方面自给自足。

分支用作环境。 主分支 (master) 由持续集成管道编写和更新。 其他环境通过使用促销从主分支进行更新。 有关促销的更多信息,请参阅 促销 部分。

库存内容

库存包含参与部署的每个工件的库存条目。 一个库存条目指向单个工件。 库存条目是可以在文件夹中构造并使用条目名称进行命名的 JSON 文件。

库存文件夹是条目名称的一部分。

示例

从以下条目名称列表中选择一个名称作为服务名称:

  • 授权/服务
  • auth/db
  • 用户/服务
  • main_service
  • helm-charts/main_service

使用以下结构在清单中实现内容:

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

库存条目格式

虽然 Entry 类型使用 typescript 语法表示库存条目的模式,但您可以将其转换为使用 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;
}

示例

资产的图像类型的库存条目

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

非映像类型资产的库存条目,例如部署和 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
}

使用 cocoa inventory add 命令可写入库存。

库存工作流程

库存包含除 master 分支以外的多个分支。 这些分支可以表示部署阶段,环境或区域,或两者的混合。 这些分支的结构取决于设置和使用情况。

CI 写入库存

master 分支通过连续集成构建进行填充。 目标中的最后一个落实 (在本例中名为 staging) 包含一个标记,该标记显示它是最后完成的部署。

如果将库存的缺省分支切换到其他分支,那么必须将先前缺省分支中的落实重定基底到新的缺省分支,以使 Git 落实历史记录具有线性关系。

您可以通过定制发布脚本来跳过写入库存。 有关更多信息,请参阅 发布到库存

持续集成写入库存
持续集成写入库存

促销

当您提升到目标分支时,将创建拉取请求。 拉取请求内容将填充“变更请求”字段。 复审拉取请求后,可以将其合并。

通过使用 PR 推动目标分支
通过使用 PR 推动目标分支 "

增量和部署

合并提升拉取请求后,可以启动部署管道。 部署增量是上次完成的部署的内容与当前部署的内容之间的差异。 部署增量列出了正在部署的库存项。

显示部署增量详细信息的部署管道流
图 3. 显示部署增量详细信息的部署管道流

库存结论

部署完成后,可以提前移动 latest 标记。

在 dev 方式触发器期间,将不会对标记进行高级操作。 开发方式触发器仅用于测试 CD 管道。

部署完成
部署完成

升级到更多环境

您可以从任何分支升级并部署到另一个分支。

使用 PR 从暂存分支推广到 prod 分支
使用 PR 从暂存分支推广到 prod 分支

库存情况

当前已部署状态包含要部署到环境的内容。 目标分支中的每个提升的落实都包含相关管道运行标识和变更请求标识作为标记。 某些落实可以具有多个标记,例如,当您重试失败的部署或再次部署时。 “库存”保存用于重放部署的每一条信息。

部署流程图标签
部署流程图标签 "

使用标记

下表显示了可用的库存标签。

库存标签
标记 描述
latest 标记分支上库存的当前状态,已成功部署状态和已结束状态。
pipeline run id 使用实际部署的管道运行标识或构建号标记分支中的当前库存状态。 为了避免在触发并行部署时库存内容重叠,请使用此标记来引用分支历史记录中的实际库存点散列。
change request id(可选) 标记变更请求标识的当前状态,以在历史记录中跟踪库存中的变更请求标识。

设置具有多个区域的单个目标

针对单个目标环境引入了多个 latest 标记,以便针对不同类型的用例,多个连续部署管道可以在同一目标上工作。 例如,可以将同一目标环境 (例如 us-southeu-de) 用于生产目标环境和库存分支中的多个区域。

您不需要使用 region 属性 (例如 us-south-prodeu-de-prod) 为每个区域设置不同的分支,并以冗余方式运行提升。 请改为为同一库存分支指定这些附加目标,然后将其用作 Git 标记。

在此设置中,生产分支在同一分支上具有多个 latest 标记,例如 us-south_prod_latesteu-de_prod_latest。 负责每个区域的每个持续部署管道都可以使用这些标记进行部署。

每个区域有多个最新标签的生产分支
每个区域有多个最新标签的生产分支

例如,您计划在任何地方部署的一组更改可能会首先发布到单个区域,然后通过使用连续部署管道将这些区域作为目标逐步部署到其他区域。

库存操作

清单包含一些使用 CLI 或使用纯 Git 和 GitHub CLI 运行的基本操作。

CLI 命令

  1. 在登台中创建从主分支到目标分支的提升拉取请求。

    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. 通过将 target_latest 标记移动到与 pipeline-run-id 标记相同的落实来完成部署。

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

Git 和 GitHub CLI

  1. 在登台中创建从主分支到目标分支的提升拉取请求。

    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. 通过将 target-latest 标记移动到与 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. 使用 Git 和 GitHub CLI 将登台还原为较早状态。

    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
    

使用 Git 存储库的常见用例

有关使用 Git 存储库的更多信息,请参阅以下示例场景:

如何排除库存中的文件和目录

一-缺省情况下,管道会排除库存中的隐藏文件和 .md 文件。 在库存存储库中创建名为 .inventoryignore 的文件以排除任何文件或目录。 管道将在存储库的根目录中搜索 .inventoryignore 文件。

不过,如果你希望清单排除文件有一个不同的名称,可以通过在管道中设置 inventory-ignore-file 键作为环境属性来指定。 请确保此文件位于库存存储库的根目录中。

例如,如果您的文件名为 .custominventoryignore,请添加值为 custominventoryignore 的环境变量 inventory-ignore-file

以下是 .custominventoryignore 文件的示例内容:

.md
sample_file
sample_directory/

在此之前的文件中:

  • .md: 排除扩展名为 .md 的所有文件。 请勿在开头添加 *,如 *.md,因为不支持 regex。
  • sample_file:在整个版本库中排除特定文件。
  • sample_directory/: 排除整个目录。 避免在末尾添加 *,使用 sample_directory/*,因为不支持 regex。
  • 如果文件中没有条目或空行,所有文件都将被排除在外。 请不要在清单忽略文件中留下空条目或空行。