Entendendo o inventário para DevSecOps

Em DevSecOps, seu inventário funciona como uma lista centralizada e crítica de todos os blocos de construção que compõem seu sistema de software. Ele se torna o ponto único de informações para tudo que você precisa para desenvolver, implementar e manter seus aplicativos com segurança no IBM Cloud. Aqui está o que normalmente é incluído neste inventário:

  • IBM Cloud recursos: isso inclui servidores virtuais, funções sem servidor, bancos de dados Cloudant e quaisquer outros serviços que você provisionou em seu ambiente do IBM Cloud.

  • Detalhes da infraestrutura como código (IaC): isso inclui configurações do Terraform, variáveis de ambiente armazenadas em IBM® Cloud Foundry Artifactorye outras configurações que determinam como seus recursos do IBM Cloud são configurados e protegidos.

  • Dependências do Aplicativo: elas são serviços de terceiros, APIs e microsserviços nos quais seus aplicativos em nuvem dependem para funcionar perfeitamente

  • IBM® Key Protect for IBM Cloud® Segredos: Refere-se a informações confidenciais essenciais para a operação do sistema, como senhas, chaves API e chaves de criptografia. Eles requerem controle meticuloso e armazenamento seguro no IBM Key Protect.

Estrutura e conteúdo de um inventário

O modelo de inventário rastreia os seguintes itens do artefato:

  • Nome do artefato
  • Ambiente ou região em que ele será implementado.
  • Local de construção de um artefato (execução de pipeline, confirmação sha)
  • Assinatura do artefato construído

Controle a evidência durante construções e implementações de artefatos. Isso também ajuda com o gerenciamento de mudanças e auditorias de conformidade.

Ramificações

O inventário é implementado em um repositório Git (repo). Git é autossuficiente no rastreamento e auditoria de mudanças.

As ramificações são usadas como ambientes. A ramificação principal (master) é gravada e atualizada pelo pipeline de integração contínua. Outros ambientes são atualizados a partir da ramificação principal, por meio de promoções. Para obter mais informações sobre promoções, consulte a seção Promoção .

Conteúdo do inventário

O inventário contém uma entrada de inventário para cada artefato participante da implementação. Uma entrada de inventário aponta para um único artefato. As entradas de inventário são arquivos JSON que podem ser estruturados em pastas e são nomeados de acordo com o nome da entrada.

As pastas do inventário fazem parte do nome de entrada.

Exemplo

Escolha um nome na lista a seguir de nomes de entrada como um nome de serviço:.

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

O conteúdo é implementado no inventário utilizando a seguinte estrutura:

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

Formato de entrada de inventário

Embora o tipo Entry represente o esquema da entrada de inventário usando a sintaxe typescript, é possível fazer uma conversão para que passe a usar o esquema 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;
}

Exemplo

Entrada de inventário para o tipo de imagem de ativo..

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

Entrada de inventário para o tipo não de imagem de ativo, como implementação, gráficos do 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
}

Use o comando cocoa inventory add para gravar no inventário..

Fluxo de trabalho de inventário

O inventário contém várias ramificações, além da ramificação master. Essas ramificações podem representar estágios, ambientes ou regiões de implementação ou uma combinação desses itens. A estrutura dessas ramificações depende configuração e do uso.

Gravações de integração contínua no inventário

A ramificação master é preenchida a partir de construções de integração contínua. O último commit no destino (neste caso chamado staging) contém uma tag que mostra que esta foi a última implementação concluída.

Se a ramificação padrão para o inventário for alternada para uma ramificação diferente, será necessário rebasear as confirmações da ramificação padrão anterior na nova ramificação padrão para tornar o histórico de confirmação do Git linear

Você pode pular a escrita para o inventário customizando o script de liberação. Para obter mais informações, consulte Release para o inventário.

A integração contínua grava no inventário
A integração contínua grava no inventário

Promoção

Uma solicitação pull é criada ao fazer uma promoção para uma ramificação de destino. O conteúdo da solicitação pull preenche os campos da solicitação de mudança. Após a revisão da solicitação pull, é possível mesclá-la.

Promoção de um ramo-alvo usando um PR
Promoção de um ramo-alvo usando um PR

Delta e implementação

Após a mesclagem da solicitação pull da promoção, é possível iniciar o pipeline de implementação. O delta de implementação é a diferença entre o conteúdo da última implementação concluída e da implementação atual. O delta de implementação lista os itens de inventário que estão sendo implementados.

Fluxo de pipeline de implementação mostrando detalhes do delta de implementação
Figure3 Fluxo de pipeline de implementação mostrando detalhes do delta de implementação

Conclusão do inventário

Após a conclusão da implementação, é possível mover a tag latest para frente.

Durante o acionador do modo dev, as tags não serão avançadas. O propósito do acionador do modo dev é apenas para testar o pipeline de CD.

A implantação é concluída
A implantação é concluída

Promoção para outros ambientes

As promoções e implementações podem ser feitas entre quaisquer ramificações.

Promoção usando um PR da fase de preparação para a filial de produção
Promoção usando um PR da fase de preparação para a filial de produção

Cenário de inventário

O estado de implementação atual contém o conteúdo a ser implementado em um ambiente. Cada commit promovido na ramificação de destino contém o ID de execução do pipeline e o ID da solicitação de alteração relevantes como uma tag. Há situações em que alguns commits podem ter várias tags, por exemplo, ao fazer uma nova tentativa para executar uma implementação que falhou ou ao implementar novamente. No inventário, são mantidas todas as informações necessárias para reproduzir as implementações.

Diagrama de fluxo de implantação com as tags
Diagrama de fluxo de implantação com as tags

Uso de tags

A tabela a seguir mostra as tags de inventário disponíveis.

Etiquetas de inventário
Marcar Descrição
latest Identifica o atual estado de implementação bem-sucedida e concluída do inventário em uma ramificação.
pipeline run id Identifica o atual estado do inventário na ramificação, com o ID da execução de pipeline ou o número de construção da implementação real. Para evitar sobreposição do conteúdo do inventário, caso sejam acionadas implementações paralelas, use essa tag para fazer referência ao hash de ponto real do inventário no histórico da ramificação.
change request id (opcional) Identifica o estado atual de um ID de solicitação de mudança para rastrear os IDs de solicitações de mudança no inventário, em uma representação de histórico.

Configuração para um destino único com várias regiões

Várias tags latest são introduzidas para um único ambiente de destino, de modo que vários pipelines de implantação contínua possam funcionar no mesmo destino, para diferentes tipos de casos de uso. É possível usar, por exemplo, o mesmo ambiente de destino (como us-south ou eu-de) para várias regiões no ambiente de destino de produção e na ramificação de inventário.

Não é necessário configurar uma filial diferente para cada região usando a propriedade region, como us-south-prod e eu-de-prod, e executar a promoção de forma redundante. Em vez disso, especifique esses destinos adicionais para a mesma ramificação do inventário e, em seguida, utilize-os como tags Git.

Nessa configuração, a filial prod tem várias tags latest na mesma filial, como us-south_prod_latest e eu-de_prod_latest. Cada pipeline de implantação contínua que é responsável por cada região pode usar essas tags para implantar.

Ramo de produção com várias tags mais recentes por região
Ramo de produção com várias tags mais recentes por região

Por exemplo, um conjunto de alterações que você planeja implantar em todos os lugares pode ser lançado primeiro em uma única região e, em seguida, implantado gradualmente em outras regiões usando pipelines de implantação contínua para atingir essas regiões.

Operações do inventário

No inventário há algumas operações básicas que são executadas por meio da CLI ou simplesmente utilizando Git e a CLI do GitHub.

Comandos de CLI

  1. Criar uma solicitação pull de promoção a partir da ramificação principal para a ramificação de destino no ambiente de preparação.

    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. Para concluir uma implementação, mova a tag target_latest para o mesmo commit que a tag pipeline-run-id.

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

Git e CLI do GitHub

  1. Criar uma solicitação pull de promoção a partir da ramificação principal para a ramificação de destino no ambiente de preparação.

    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. Para concluir uma implementação, mova a tag target-latest para o mesmo commit que a tag 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. Reverter a preparação para um estado anterior, usando Git e a CLI do 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
    

Casos de uso comum para trabalhar com repositórios Git

Para obter mais informações sobre como trabalhar com repositórios Git, veja estes cenários de exemplo:

Como Excluir Arquivos e Diretórios no Inventário

Um pipeline exclui arquivos ocultos e arquivos .md no inventário por padrão. Crie um arquivo denominado .inventoryignore em seu Repositório de inventário para excluir quaisquer arquivos ou diretórios O pipeline procura o arquivo .inventoryignore na raiz do repositório..

No entanto, se você preferir um nome diferente para o arquivo de exclusão de inventário, poderá especificá-lo definindo a chave inventory-ignore-file como uma propriedade de ambiente no pipeline. Certifique-se de que esse arquivo esteja na raiz do repositório de inventário

Por exemplo, se seu arquivo for denominado .custominventoryignore, inclua uma variável de ambiente inventory-ignore-file com o valor custominventoryignore.

Veja a seguir o exemplo de conteúdo do arquivo .custominventoryignore em dois formatos:

.md
sample_file
sample_directory/
# Ignore everything
**

# But keep these artifacts
!sample_directory/
!sample_file

A seguir, explicamos a finalidade das entradas no arquivo de exemplo .custominventoryignore:

  • .md: exclui todos os arquivos com a extensão .md. Não adicione * no início, como *.md, pois não há suporte para regex.
  • sample_file: exclui o arquivo específico em todo o repositório.
  • sample_directory/: exclui o diretório inteiro. Evite adicionar * no final, use sample_directory/*, pois não há suporte para regex.
  • Um arquivo sem entradas ou com uma linha vazia fará com que todos os arquivos sejam excluídos. Não deixe entradas ou linhas vazias no arquivo de ignorar inventário.
  • **: Ignora tudo no repositório.
  • !sample_directory/ e !sample_file: Nega a regra de ignorar, mantendo esses arquivos ou diretórios específicos mesmo que ** esteja presente.