DEV Community

Cover image for Segurança em Contêineres: Como Melange e apko Ajudam a Proteger Seus Projetos e Criar Imagens Minimalistas
Hugo Lemos da Silva
Hugo Lemos da Silva

Posted on

Segurança em Contêineres: Como Melange e apko Ajudam a Proteger Seus Projetos e Criar Imagens Minimalistas

Introdução

A Chainguard é uma empresa que desenvolve ferramentas para criação de imagens de contêineres seguras e minimalistas. Entre suas principais soluções open source estão:

  • Melange: Uma ferramenta para criar pacotes de software reprodutíveis e auditáveis.
  • Apko: Um criador de imagens de contêiner baseadas em pacotes APK, com ênfase em segurança e controle.
  • Wolfi: Uma distribuição Linux mínima e não-GNU projetada especificamente para ambientes de contêiner.

Chainguard Apko

O que é?

Image description

O Apko é uma ferramenta para criar imagens de contêineres minimalistas e seguras usando pacotes APK sem camadas desnecessárias, melhorando a segurança e o desempenho. O Docker, por exemplo, combina etapas de construção como executar comandos para copiar arquivos, construir e implementar aplicativos. O Apko, por outro lado, é apenas uma ferramenta de composição que se concentra na produção de imagens base leves e "planas" que são reprodutíveis e contêm arquivos SBOM gerados automaticamente para cada construção bem-sucedida.

Principais recursos do Apko:

  • Geração de imagens OCI a partir de arquivos YAML.
  • Totalmente integrada ao ecossistema Wolfi.
  • Controle granular sobre dependências.
  • Ferramenta declarativa para construção de imagens OCI baseada no apk.
  • Parte do kit de ferramentas utilizado para criar imagens Wolfi/Chainguard.
  • As imagens são definidas em arquivos YAML.
  • Builds são totalmente reprodutíveis.
  • Gera automaticamente SBOMs (Bill of Materials) para cada imagem.
  • Suporte para builds agnósticos de plataforma via Docker + imagem apko.

Início rápido com Apko

Baixe a imagem apko

docker pull cgr.dev/chainguard/apko
Enter fullscreen mode Exit fullscreen mode

Isso fará o download da versão mais recente da imagem apko distroless, que é reconstruída todas as noites para maior atualização.

Verifique se você consegue executar o apko com:

docker run --rm cgr.dev/chainguard/apko version
Enter fullscreen mode Exit fullscreen mode

Image description

Criando uma imagem de teste

Vamos criar uma imagem de teste usando um dos exemplos fornecidos no repositório oficial do apko, usaremos o exemplo wolfi-base.yaml para demonstração.

Vamos criar uma pasta para salvar os arquivos de imagem e mover para esse diretório:

mkdir ~/apko
cd ~/apko
Enter fullscreen mode Exit fullscreen mode

Em seguida, crie um arquivo chamado wolfi-base.yaml para salvar sua definição de imagem. Você pode usar vim para isso:

vim wolfi-base.yaml
Enter fullscreen mode Exit fullscreen mode

A wolfi-base.yaml imagem de exemplo é definida da seguinte forma:

contents:
  keyring:
    - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
  repositories:
    - https://packages.wolfi.dev/os
  packages:
    - ca-certificates-bundle
    - wolfi-base

entrypoint:
  command: /bin/sh -l

archs:
  - x86_64
Enter fullscreen mode Exit fullscreen mode

O contents nó é usado para definir fontes de pacotes permitidas e quais pacotes devem ser incluídos na imagem. Aqui, usaremos apenas pacotes do repositório principal do Wolfi APK. Na seção packages, precisamos do pacote wolfi-base , que é um metapacote para configurar um sistema Wolfi mínimo.

O command campo dentro do entrypointnó define o comando image entry point /bin/sh -l, que o levará a um prompt de shell sempre que a imagem for executada. Finalmente, o archs nó especifica que essa imagem será construída para a x86-64arquitetura.

Salve e feche o arquivo depois de terminar de incluir esses conteúdos. Com o vim, você pode fazer isso use o :wq.

A única coisa que resta fazer agora é executar o apko para construir esta imagem.

docker run --rm -v ${PWD}:/work -w /work cgr.dev/chainguard/apko build wolfi-base.yaml wolfi-base:test wolfi-test.tar
Enter fullscreen mode Exit fullscreen mode

O seguinte comando de construção irá:

  • configurar um compartilhamento de volume no diretório atual, sincronizando seu conteúdo com o diretório de trabalho da imagem do apko; dessa forma, os artefatos gerados estarão disponíveis no seu sistema host.
  • executar a cgr.dev/chainguard/apko imagem com o build comando, marcando a imagem como wolfi-base:test-amd64 e salvando a compilação como wolfi-test.tar .

a sua saida pode se parecer com
Image description

Na saída, você pode notar que a imagem foi criada com sucesso wolfi-test.tar no contêiner, que é compartilhado com sua pasta local no host graças ao volume que você criou ao executar o docker runcomando.

Image description

Teste a imagem com o Docker

Para testar a imagem gerada com o Docker, você precisará usar o comando docker load e importar o arquivo .tar

docker load <  wolfi-test.tar
Enter fullscreen mode Exit fullscreen mode

Obeterá uma saída como esta:

Image description

você pode verificar se a imagem esta disponível com o comando

docker image list
Enter fullscreen mode Exit fullscreen mode

voce deve conseguir encontrar a imagem wolfi-base:test-amd64 na lista de imagens disponíveis.
Agora, você pode executar a imagem com o comando:

docker run -it wolfi-base:test-amd64
Enter fullscreen mode Exit fullscreen mode

Isso o levará a um contêiner executando a imagem apko-built wolfi-base:test-amd64.


Chainguard Melange

O que é?

O Melange é uma ferramenta que ajuda a criar pacotes reprodutíveis com foco na rastreabilidade e segurança. Ele usa arquivos de configuração YAML para definir como o software será empacotado e construído.

Principais recursos:

  • Compatível com APK (pacotes do Alpine Linux).
  • Reprodutibilidade: builds são auditáveis e podem ser recriados em qualquer ambiente.
  • Integração com Wolfi para criar um ecossistema de pacotes seguro.
  • Ferramenta declarativa para construção de pacotes apk.
  • Parte do kit de ferramentas utilizado para criar imagens Wolfi/Chainguard.
  • Pipelines de build são definidos (via QEMU).
  • Suporte para builds agnósticos de plataforma via Docker + imagem apko.

Início rápido com Apko

  1. Baixando a imagem melange:
docker pull cgr.dev/chainguard/melange:latest
Enter fullscreen mode Exit fullscreen mode

Baixando a imagem Melange

Isso fará o download da versão mais recente da imagem de mesclagem, que é reconstruída todas as noites para maior frescor.

docker pull cgr.dev/chainguard/melange:latest
Enter fullscreen mode Exit fullscreen mode

Verifique se você consegue executar o Melange com o comando:

docker run --rm cgr.dev/chainguard/melange version
Enter fullscreen mode Exit fullscreen mode

Image description

Clonando o Repositório de Demonstração

Para demonstrar os recursos do Melange com um aplicativo minimalista que tem funcionalidade do mundo real, consiste em um aplicativo de linha de comando PHP que consulta a API de conselhos do Slip e gera um conselho aleatório. O aplicativo é um script de arquivo único criado com Minicli.

Vamos clonar o repositório de demonstração e navegar até o diretório melange-php-demos/hello-minicli:

git clone git@github.com:chainguard-dev/melange-php-demos.git
cd melange-php-demos/hello-minicli
Enter fullscreen mode Exit fullscreen mode

Execute o seguinte comando, que usará a imagem oficial do Composer para gerar um arquivo composer.json e baixar minicli/minicli:

docker run --rm -it -v "${PWD}":/app composer require minicli/minicli
Enter fullscreen mode Exit fullscreen mode

Após receber a confirmação de que o download foi concluído, você precisará de uma segunda dependência para consultar a API do Advice Slip. Execute o comando a seguir para incluir minicli/curly, um curl wrapper para Minicli:

docker run --rm -it -v "${PWD}":/app composer require minicli/curly
Enter fullscreen mode Exit fullscreen mode

Agora você pode executar o aplicativo para ter certeza de que ele está funcional. Você pode fazer isso usando o Docker e a imagem PHP do Chainguard:

docker run --rm -it -v "${PWD}":/app cgr.dev/chainguard/php /app/minicli advice
Enter fullscreen mode Exit fullscreen mode

Você deve receber um conselho aleatório como:

Gratitude is said to be the secret to happiness.
Enter fullscreen mode Exit fullscreen mode

O arquivo YAML Melange

O arquivo melange.yaml é onde você declara os detalhes e especificações do seu pacote APK. Para código que gera binários autocontidos, é aqui que você normalmente construirá seus artefatos de aplicativo com ferramentas de compilador. No caso de linguagens interpretadas, você provavelmente construirá seu aplicativo baixando dependências de fornecedores, configurando caminhos relevantes e configurando o ambiente para produção.

O arquivo de especificação do Melange contém três seções principais:

  • package: define especificações do pacote, como nome, licença e dependências de tempo de execução. Dependências de tempo de execução serão trazidas para o sistema automaticamente como dependências quando o APK for instalado.
  • environment: define como o ambiente deve ser preparado para a construção, incluindo pacotes necessários e seus repositórios de origem. Qualquer coisa que seja necessária apenas no momento da construção vai aqui, e não deve fazer parte das dependências do tempo de execução.
  • pipeline: define o pipeline de construção para este pacote.

Uma das melhores vantagens de usar Melange é poder controlar todas as etapas do seu pipeline de construção e incluir apenas o que é necessário. Dessa forma, você poderá construir imagens de contêiner menores e mais seguras removendo dependências desnecessárias.

É assim que o melange.yaml incluído em nossa demonstração se parece, para sua referência:

package:
    name: hello-minicli
    version: 0.1.0
    description: "Minicli melange demo"
    target-architecture:
        - all
    copyright:
        - license: MIT
    dependencies:
        runtime:
            - php
            - php-curl

environment:
    contents:
        keyring:
            - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
            - ./melange.rsa.pub
        repositories:
            - https://packages.wolfi.dev/os
        packages:
            - ca-certificates-bundle
            - busybox
            - curl
            - git
            - php
            - php-phar
            - php-iconv
            - php-openssl
            - php-curl
            - composer

pipeline:
    - name: Build Minicli application
        runs: |
            MINICLI_HOME="${{targets.destdir}}/usr/share/minicli"
            EXEC_DIR="${{targets.destdir}}/usr/bin"
            mkdir -p "${MINICLI_HOME}" "${EXEC_DIR}"
            cp ./composer.json "${MINICLI_HOME}"
            /usr/bin/composer install -d "${MINICLI_HOME}" --no-dev
            cp ./minicli "${EXEC_DIR}"
            chmod +x "${EXEC_DIR}/minicli"
Enter fullscreen mode Exit fullscreen mode

Nosso pipeline de construção configurará dois diretórios distintos, separando as dependências do aplicativo de seu ponto de entrada executável. O script executável minicli será copiado para /usr/bin, enquanto os arquivos do fornecedor estarão localizados em /usr/share/minicli.

Construindo o Minicli APK com Melange

Antes de construir o pacote, você precisará criar um keypair temporário para assiná-lo. Você pode usar o seguinte comando para isso:

docker run --rm -v "${PWD}":/work cgr.dev/chainguard/melange keygen
Enter fullscreen mode Exit fullscreen mode

Isso gerará um arquivo melange.rsa e melange.rsa.pub no diretório atual.

Saída:

2024/08/01 16:55:31 INFO generating keypair with a 4096 bit prime, please wait...
2024/08/01 16:55:33 INFO wrote private key to melange.rsa
2024/08/01 16:55:33 INFO wrote public key to melange.rsa.pub
Enter fullscreen mode Exit fullscreen mode

Em seguida, crie o APK definido no arquivo melange.yaml com o seguinte comando:

docker run --privileged --rm -v "${PWD}":/work \
    cgr.dev/chainguard/melange build melange.yaml \
    --arch amd64,aarch64 \
    --signing-key melange.rsa
Enter fullscreen mode Exit fullscreen mode

Isso configurará um volume compartilhando sua pasta atual com o local /work dentro do contêiner. Nós construiremos pacotes para as plataformas amd64 e aarch64 e os assinaremos usando a chave melange.rsa criada no comando anterior.

Quando a compilação estiver concluída, você deverá encontrar uma pasta packages contendo os APKs gerados (e os arquivos de índice APK associados):

Saída:

packages
├── aarch64
│   ├── APKINDEX.json
│   ├── APKINDEX.tar.gz
│   └── hello-minicli-0.1.0-r0.apk
└── x86_64
        ├── APKINDEX.json
        ├── APKINDEX.tar.gz
        └── hello-minicli-0.1.0-r0.apk

3 directories, 6 files
Enter fullscreen mode Exit fullscreen mode

Você construiu com sucesso um pacote de software multiarquitetura com Melange!

Construindo uma Imagem de Contêiner com Apko

Com os pacotes APK e o índice APK em vigor, agora você pode criar uma imagem de contêiner e instalar seus APK(s) nela.

O arquivo apko.yaml a seguir criará uma imagem de contêiner adaptada ao aplicativo que construímos nas etapas anteriores. Como definimos as dependências do PHP como dependências de tempo de execução dentro do APK, você não precisa exigir esses pacotes novamente aqui. O comando container entrypoint será definido como /usr/bin/minicli, onde o executável do aplicativo está localizado.

Uma coisa importante a ser notada é como referenciamos o hello-minicli APK como um pacote local dentro da seção repositories do arquivo YAML. A notação @local diz ao Apko para procurar por APKs no diretório especificado, neste caso /work/packages.

Esta é a aparência do arquivo apko.yaml incluído em nossa demonstração, para sua referência:

contents:
    keyring:
        - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
        - ./melange.rsa.pub
    repositories:
        - https://packages.wolfi.dev/os
        - '@local /work/packages'
    packages:
        - wolfi-base
        - ca-certificates-bundle
        - hello-minicli@local
accounts:
    groups:
        - groupname: nonroot
            gid: 65532
    users:
        - username: nonroot
            uid: 65532
    run-as: 65532
entrypoint:
    command: /usr/bin/minicli advice
Enter fullscreen mode Exit fullscreen mode

O comando a seguir configurará um volume compartilhando sua pasta atual com o local /work no contêiner Apko, executando o comando apko build para gerar uma imagem com base no seu arquivo de definição apko.yaml.

docker run --rm --workdir /work -v ${PWD}:/work cgr.dev/chainguard/apko \
    build apko.yaml hello-minicli:test hello-minicli.tar --arch host
Enter fullscreen mode Exit fullscreen mode

Isso criará uma imagem OCI com base na arquitetura do seu sistema host (especificada pelo sinalizador --arch host). Se você receber avisos neste ponto, eles provavelmente estão relacionados aos tipos de SBOMs que estão sendo carregados e podem ser ignorados com segurança.

O comando irá gerar alguns novos arquivos no diretório do aplicativo:

  • hello-minicli.tar — a imagem OCI empacotada que pode ser importada com um comando docker load
  • sbom-%host-architecture%.spdx.json — um arquivo SBOM para sua arquitetura de host no formato spdx-json

Em seguida, carregue sua imagem no Docker:

docker load < hello-minicli.tar
Enter fullscreen mode Exit fullscreen mode

Saída:

7cbaefdf1c30: Loading layer   13.7MB/13.7MB
Loaded image: hello-minicli:test-%host-architecture%
Enter fullscreen mode Exit fullscreen mode

Observe que o %host-architecture% variará, e pode haver várias imagens carregadas no seu daemon Docker. Certifique-se de editar a variável no comando docker run a seguir para corresponder à sua arquitetura de destino.

Agora você pode executar seu programa Minicli com:

docker run --rm hello-minicli:test-%host-architecture%
Enter fullscreen mode Exit fullscreen mode

A demonstração deve gerar um aviso como:

Only those who attempt the impossible can achieve the absurd.
Enter fullscreen mode Exit fullscreen mode

Você construiu com sucesso uma imagem de contêiner minimalista com seu pacote APK instalado nela. Esta imagem é totalmente compatível com OCI e pode ser assinada com Cosign para atestado de procedência.

Conclusão

Neste guia, empacotamos um aplicativo de linha de comando PHP com Melange. Também criamos uma imagem de contêiner para instalar e executar nosso APK personalizado, usando a ferramenta Apko. Para mais informações sobre o Apko, confira nosso guia Getting Started with Apko.

Os arquivos de demonstração estão disponíveis no repositório melange-php-demos, na subpasta hello-minicli. Para obter informações adicionais sobre como depurar suas compilações e outros recursos, verifique os repositórios Melange e Apko no GitHub.


Chainguard Wolfi

O que é?

Wolfi é uma distribuição Linux não-GNU projetada para ambientes de contêiner, com pacotes otimizados para segurança e desenvolvimento moderno. Não possui shell ou gerenciador de pacotes.

Uma referência ao menor polvo do mundo.

Principais recursos:

  • Focado em contêineres.
  • Sem glibc, usando musl como libc.
  • Repositório de pacotes confiáveis.
  • Tiny Linux Distribution

    Uma distribuição Linux minimalista.

  • "Undistro" porque não inclui itens que normalmente fazem parte de uma distribuição Linux (como o kernel, páginas de manual e vários outros pacotes que não fazem sentido para contêineres).

  • Baseado no apk (gerenciador de pacotes do Alpine).

  • Usa principalmente glibc, mas MUSL está no roadmap.

  • Os pacotes são definidos como YAML e construídos com o melange.

Principais Características das Imagens Chainguard

As imagens Chainguard estão disponíveis principalmente no Chainguard Registry, mas uma seleção de imagens para desenvolvedores também está disponível no Docker Hub. Você pode encontrar a lista completa de imagens Chainguard disponíveis em nosso Directório de Imagens público ou no Chainguard Console.

Note que geralmente há uma variante -dev de cada imagem Chainguard disponível. Por exemplo, a variante -dev da imagem mariadb:latest é mariadb:latest-dev. Essas imagens normalmente contêm um shell e ferramentas como um gerenciador de pacotes para permitir que os usuários depurem e modifiquem a imagem mais facilmente.

Você pode analisar mais comparações de imagens do Chainguard e imagens externas verificando nosso painel de comparações de vulnerabilidades.

Por padrão, todas as imagens baseadas em Wolfi são construídas para x86_64.

Você pode confirmar a arquitetura disponível de uma determinada imagem Chainguard com Crane. Neste exemplo, usaremos a imagem mais recente do Ruby, mas você pode optar por usar uma imagem alternativa.

crane manifest cgr.dev/chainguard/ruby:latest | jq -r '.manifests[] | .platform'
Enter fullscreen mode Exit fullscreen mode
{
  "architecture": "amd64",
  "os": "linux"
}
{
  "architecture": "arm64",
  "os": "linux"
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)