DevSecOps에 대한 인벤토리 이해하기

DevSecOps,에서 인벤토리는 소프트웨어 시스템을 구성하는 모든 빌딩 블록의 중요한 중앙 집중식 목록 역할을 합니다. 이는 IBM Cloud에서 애플리케이션을 안전하게 개발, 배치 및 유지보수하는 데 필요한 모든 것의 단일 정보 지점이 됩니다. 다음은 일반적으로 이 인벤토리에 포함되는 항목입니다.

  • IBM Cloud 리소스: 여기에는 전달 가상 서버, 서버리스 기능, Cloudant 데이터베이스 및 IBM Cloud 환경에서 프로비저닝한 기타 서비스가 포함됩니다.

  • IaC(Infrastructure as Code) 세부사항: 여기에는 Terraform 구성, IBM® Cloud Foundry Artifactory에 저장된 환경 변수 및 IBM Cloud 리소스가 구성되고 보안되는 방법을 지시하는 기타 설정이 포함됩니다.

  • 애플리케이션 종속성: 클라우드 애플리케이션이 완벽하게 작동하기 위해 의존하는 써드파티 서비스, API및 마이크로서비스입니다.

  • IBM® Key Protect for IBM Cloud® 시크릿: 비밀번호, API키 및 암호화 키와 같은 시스템 조작에 필수적인 민감한 정보를 참조합니다. 이를 위해서는 IBM Key Protect내에서 세심한 제어 및 보안 스토리지가 필요합니다.

재고의 구조 및 컨텐츠

인벤토리 모델은 아티팩트의 다음 항목을 추적합니다.

  • 아티팩트의 이름
  • 배치될 환경 또는 지역입니다.
  • 아티팩트의 빌드 위치 (파이프라인 실행, 커미트 sha)
  • 빌드된 아티팩트의 서명

아티팩트 빌드 및 배치 중에 증거를 추적합니다. 이는 변경 관리 및 준수 감사에도 도움이 됩니다.

분기

인벤토리는 Git 저장소에서 구현됩니다. Git 는 변경사항을 추적하고 감사하는 데 자체적으로 충분합니다.

분기는 환경으로 사용됩니다. 기본 분기(master)는 지속적 통합 파이프라인을 통해 작성되고 업데이트됩니다. 기타 환경은 승격을 사용하여 마스터 분기에서 업데이트됩니다. 승격에 관한 자세한 정보는 승격 절을 참조하십시오.

재고 컨텐츠

인벤토리에는 배치에 참여하는 모든 아티팩트의 인벤토리 항목이 포함되어 있습니다. 하나의 인벤토리 시작점은 단일 아티팩트를 가리킵니다. 인벤토리 항목은 폴더에 구조화할 수 있는 JSON 파일이며 항목 이름을 사용하여 이름이 지정됩니다.

인벤토리 폴더는 항목 이름의 일부입니다.

다음 항목 이름 목록에서 하나의 이름을 서비스 이름으로 선택하십시오.

  • auth/service
  • auth/db
  • ui/service
  • 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
}

코코아 재고 추가 명령을 사용하여 재고에 쓰십시오.

인벤토리 워크플로우

인벤토리에는 master 분기 외의 여러 분기가 포함되어 있습니다. 이러한 분기는 배치 스테이지, 환경이나 지역 또는 둘 다의 혼합을 나타낼 수 있습니다. 이러한 분기의 구조는 설정 및 사용법에 따라 다릅니다.

CI는 인벤토리에 기록합니다.

master 분기는 지속적 통합 빌드에서 채워집니다. 대상의 마지막 커미트(이 경우에는 staging이라고 함)에는 마지막으로 종료된 배치임을 표시하는 태그가 포함되어 있습니다.

재고의 기본 분기가 다른 분기로 전환되는 경우 이전 기본 분기의 커미트를 새 기본 분기로 리베이스하여 Git 커미트 히스토리를 선형으로 만들어야 합니다.

릴리스 스크립트를 사용자 정의하여 자원 명세에 쓰기를 건너뛸 수 있습니다. 자세한 정보는 재고로 릴리스 를 참조하십시오.

지속적 통합은 인벤토리
에 기록합니다. 지속적 통합은 인벤토리
에 기록합니다.

승격

대상 분기로 승격하면 가져오기 요청이 작성됩니다. 가져오기 요청 컨텐츠가 변경 요청 필드를 채웁니다. 가져오기 요청을 검토한 후 병합할 수 있습니다.

PR을 사용하여 대상 브랜치 승격
PR을 사용하여 대상 브랜치 승격

델타 및 배치

승격 가져오기 요청이 병합되면 배치 파이프라인이 시작될 수 있습니다. 배치 델타는 마지막으로 종료된 배치의 컨텐츠와 현재 배치의 컨텐츠 간 차이입니다. 배치 델타는 배치되는 인벤토리 항목을 나열합니다.

배치 델타 세부사항을 표시하는 배치 파이프라인 플로우
그림 3. 배치 델타 세부사항을 표시하는 배치 파이프라인 플로우

재고 결론

배치가 완료되면 latest 태그를 앞으로 이동할 수 있습니다.

개발 모드 트리거 중에는 태그가 진행되지 않습니다. 개발 모드 트리거의 목적은 CD 파이프라인만 테스트하기 위한 것입니다.

배포가 완료되었습니다.
배포가 완료되었습니다.

추가 환경으로 승격

모든 분기에서 다른 분기로 승격하고 배치할 수 있습니다.

스테이징에서 프로덕션 브랜치로의 PR을 사용한 프로모션
스테이징에서 프로덕션 브랜치로의 PR을 사용한 프로모션

인벤토리 환경

현재 배치된 상태에는 환경에 배치할 컨텐츠가 포함되어 있습니다. 대상 브랜치의 모든 승격된 커밋에는 관련 파이프라인 실행 ID와 변경 요청 ID가 태그로 포함됩니다. 예를 들어, 실패한 배치를 재시도하거나 다시 배치하는 경우 일부 커미트에는 여러 개의 태그가 있을 수 있습니다. 인벤토리는 배치를 재생할 모든 정보를 보유합니다.

태그가 있는 배포 흐름도
가 있는 배포 흐름도

태그 사용

다음 표에는 사용 가능한 인벤토리 태그가 나와 있습니다.

재고 태그
태그 설명
latest 분기에서 인벤토리의 현재 상태, 성공적으로 배치된 상태, 종료된 상태에 태그를 지정합니다.
pipeline run id 실제 배치의 빌드 번호 또는 파이프라인 실행 ID를 사용하여 분기의 현재 인벤토리 상태에 태그를 지정합니다. 병렬 배치가 트리거될 때 인벤토리 컨텐츠가 겹치지 않도록 하려면 이 태그를 사용하여 분기 히스토리에서 실제 인벤토리 지점 해시를 참조하십시오.
change request id(선택사항) 히스토리 표시에서 인벤토리의 변경 요청 ID를 추적하기 위해 변경 요청 ID의 현재 상태에 태그를 지정합니다.

여러 지역이 있는 단일 대상의 설정

단일 대상 환경에 대해 여러 개의 latest 태그가 도입되어 다양한 유형의 사용 사례에 대해 여러 개의 연속 배포 파이프라인이 동일한 대상에서 작동할 수 있습니다. 예를 들어, 프로덕션 대상 환경 및 인벤토리 분기의 여러 지역에서 동일한 대상 환경(예: us-south 또는 eu-de)을 사용할 수 있습니다.

us-south-prodeu-de-prod 와 같이 region 속성을 사용하여 각 지역마다 다른 지점을 설정하고 프로모션을 중복으로 실행할 필요가 없습니다. 대신 동일한 인벤토리 분기에 이러한 추가 대상을 지정한 후 Git 태그로 사용하십시오.

이 설정에서 prod 브랜치에는 us-south_prod_latesteu-de_prod_latest 와 같이 동일한 브랜치에 여러 개의 latest 태그가 있습니다. 각 지역을 담당하는 각 지속적 배포 파이프라인은 이러한 태그를 사용하여 배포할 수 있습니다.

지역당 여러 최신 태그가 있는 Prod 브랜치
지역당 여러 최신 태그가 있는 Prod 브랜치

예를 들어 모든 곳에 배포하려는 일련의 변경 사항을 먼저 단일 지역에 배포한 다음 해당 지역을 대상으로 연속 배포 파이프라인을 사용하여 다른 지역에 점진적으로 배포할 수 있습니다.

인벤토리 오퍼레이션

인벤토리에는 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 저장소 작업에 관한 자세한 정보는 다음 예제 시나리오를 참조하십시오.

인벤토리에서 파일 및 디렉토리를 제외하는 방법

One-파이프라인은 기본적으로 인벤토리에서 숨겨진 파일 및 .md 파일을 제외합니다. 자원 명세 저장소에 .inventoryignore 라는 파일을 작성하여 파일 또는 디렉토리를 제외하십시오. 파이프라인은 저장소의 루트에서 .inventoryignore 파일을 검색합니다.

그러나 인벤토리 제외 파일의 다른 이름을 선호하는 경우 파이프라인 내에서 inventory-ignore-file 키를 환경 속성으로 설정하여 지정할 수 있습니다. 이 파일이 자원 명세 저장소의 루트에 있는지 확인하십시오.

예를 들어, 파일 이름이 .custominventoryignore 인 경우 값이 custominventoryignore 인 환경 변수 inventory-ignore-file 를 추가하십시오.

다음은 두 가지 형식의 .custominventoryignore 파일에 대한 콘텐츠 예시입니다:

.md
sample_file
sample_directory/
# Ignore everything
**

# But keep these artifacts
!sample_directory/
!sample_file

다음은 .custominventoryignore 파일 예시에서 항목의 용도에 대해 설명합니다:

  • .md: 확장자가 .md 인 모든 파일을 제외합니다. 정규식은 지원되지 않으므로 * 과 같이 시작 부분에 *.md 를 추가하지 마세요.
  • sample_file: 전체 리포지토리에서 특정 파일을 제외합니다.
  • sample_directory/: 전체 디렉터리를 제외합니다. 정규식은 지원되지 않으므로 끝에 * 를 추가하지 말고 sample_directory/* 을 사용하세요.
  • 항목이 없거나 빈 줄이 있는 파일은 모든 파일이 제외됩니다. 인벤토리 무시 파일에 빈 항목이나 줄을 남겨두지 마세요.
  • **: 리포지토리에 있는 모든 것을 무시합니다.
  • !sample_directory/!sample_file: 무시 규칙을 무효화하여 ** 이 있더라도 이러한 특정 파일 또는 디렉토리를 유지합니다.