Pular para o conteúdo
ArquiteCloud
Voltar

AWS CodeArtifact: publicando pacotes Python com uv e GitHub Actions

O AWS CodeArtifact é o serviço gerenciado de repositório de artefatos da AWS. Com ele você hospeda pacotes Python (e de outras linguagens) de forma privada dentro da sua conta, com controle de acesso via IAM e integração nativa com o ecossistema AWS.

Este post cobre o ciclo completo: criar um domínio e um repositório no CodeArtifact, publicar um pacote Python manualmente usando o uv, e depois automatizar todo o processo com GitHub Actions via OIDC.

O post não cobre repositórios upstream (espelhar o PyPI público no CodeArtifact), políticas de aprovação de pacotes ou acesso entre contas AWS.

Quanto custa manter isso no ar

O CodeArtifact cobra por armazenamento e por requisições, sem cobrança por hora de execução:

RecursoPreço
Armazenamento$0,05 por GB/mês
Requisições$0,05 por 10.000 requisições

Para pacotes internos de times pequenos, o custo mensal costuma ficar na faixa de poucos centavos. Consulte a página de preços do CodeArtifact para os valores oficiais da AWS em setembro de 2026.

Camada gratuita

A AWS oferece 2 GB de armazenamento e 100.000 requisições por mês durante os primeiros 12 meses em novas contas.

Pré-requisitos

Região AWS

Os exemplos usam us-east-1. Substitua pela região que você usa no seu projeto.

Publicação manual

Passo 1: criar o domínio e o repositório

O CodeArtifact organiza repositórios dentro de domínios. Um domínio agrupa vários repositórios e centraliza o controle de acesso via IAM. Crie o domínio primeiro:

aws codeartifact create-domain --domain meu-dominio

Agora crie o repositório dentro do domínio. O --domain-owner é o ID numérico de 12 dígitos da sua conta AWS:

ACCOUNT_ID=$(aws sts get-caller-identity \
  --query Account --output text)

aws codeartifact create-repository \
  --domain meu-dominio \
  --domain-owner "$ACCOUNT_ID" \
  --repository meu-repositorio \
  --description "Pacotes Python privados"

Passo 2: obter o token de autenticação

O CodeArtifact não usa usuário e senha fixos. A autenticação é feita com um token temporário gerado a partir das suas credenciais AWS. Por padrão, o token é válido por 12 horas.

ACCOUNT_ID=$(aws sts get-caller-identity \
  --query Account --output text)

CODEARTIFACT_TOKEN=$(aws codeartifact get-authorization-token \
  --domain meu-dominio \
  --domain-owner "$ACCOUNT_ID" \
  --query authorizationToken \
  --output text)

Configure as variáveis de ambiente que o uv usa na publicação:

export UV_PUBLISH_URL="https://meu-dominio-${ACCOUNT_ID}.d.codeartifact\
.us-east-1.amazonaws.com/pypi/meu-repositorio/"
export UV_PUBLISH_USERNAME="aws"
export UV_PUBLISH_PASSWORD="$CODEARTIFACT_TOKEN"

O nome de usuário é sempre aws ao autenticar no CodeArtifact via protocolo PyPI.

Passo 3: empacotar o projeto

Com o pyproject.toml configurado, execute:

uv build

O uv cria a pasta dist/ com o arquivo .whl (wheel) e o .tar.gz (sdist). O wheel é o formato preferido para instalação; o sdist é exigido por alguns índices para publicação completa.

Validar antes de publicar

Execute uvx twine check dist/* para validar os metadados do pacote antes de fazer o upload.

Passo 4: publicar no repositório

Com as variáveis de ambiente definidas no passo anterior:

uv publish

O uv lê UV_PUBLISH_URL, UV_PUBLISH_USERNAME e UV_PUBLISH_PASSWORD automaticamente e faz o upload dos arquivos em dist/.

Passo 5: instalar o pacote do repositório privado

Para instalar um pacote hospedado no repositório privado, o uv precisa do token de autenticação embutido na URL do índice. A URL de instalação usa o caminho /simple/ (diferente da URL de publicação):

INDEX_URL="https://aws:${CODEARTIFACT_TOKEN}@meu-dominio-${ACCOUNT_ID}\
.d.codeartifact.us-east-1.amazonaws.com/pypi/meu-repositorio/simple/"

uv pip install meu-pacote --index-url "$INDEX_URL"

Para não precisar passar a URL manualmente em todo projeto, declare o índice no uv.toml (ou em pyproject.toml, na seção [tool.uv]):

# uv.toml
[[index]]
name = "codeartifact"
url = "https://meu-dominio-ACCOUNT_ID.d.codeartifact.us-east-1.amazonaws.com/pypi/meu-repositorio/simple/"

Substitua ACCOUNT_ID pelo valor real. O token de autenticação ainda precisa ser exportado via variável de ambiente:

export UV_INDEX_CODEARTIFACT_USERNAME="aws"
export UV_INDEX_CODEARTIFACT_PASSWORD="$CODEARTIFACT_TOKEN"

O uv mapeia as variáveis pelo nome do índice em maiúsculas (CODEARTIFACT vem de name = "codeartifact").


Automatizando com GitHub Actions

A publicação manual funciona, mas exige renovar o token a cada 12 horas, o que inviabiliza o uso em pipelines de CI/CD. A solução é usar o OpenID Connect (OIDC) para que o GitHub Actions assuma uma role IAM diretamente, sem credenciais de longa duração armazenadas como secrets.

O fluxo é: o GitHub emite um token OIDC assinado para a execução do workflow; a AWS valida esse token e concede credenciais temporárias para a role configurada. Nenhuma chave de acesso AWS (access key) é necessária.

Passo 6: registrar o provedor de identidade do GitHub

Registre o provedor OIDC do GitHub na sua conta AWS (faça isso uma vez por conta):

aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
Verificar se o provedor já existe

Acesse IAM > Identity providers no console AWS antes de criar. Se já existir, pule este passo. A AWS também aceita a criação via console com preenchimento automático do thumbprint.

Passo 7: criar a role IAM

Crie o arquivo de política de confiança. Substitua ORG pelo seu usuário ou organização do GitHub e REPO pelo nome do repositório:

# trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub":
            "repo:ORG/REPO:ref:refs/tags/*"
        }
      }
    }
  ]
}

A condição ref:refs/tags/* restringe o acesso à role a execuções disparadas por uma tag Git. Isso evita que qualquer branch possa publicar pacotes.

Crie a role:

aws iam create-role \
  --role-name GitHubActions-CodeArtifact \
  --assume-role-policy-document file://trust-policy.json

Agora crie e anexe a política de permissões:

# codeartifact-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "codeartifact:GetAuthorizationToken",
        "codeartifact:GetRepositoryEndpoint",
        "codeartifact:PublishPackageVersion",
        "codeartifact:PutPackageMetadata",
        "sts:GetServiceBearerToken"
      ],
      "Resource": "*"
    }
  ]
}
aws iam put-role-policy \
  --role-name GitHubActions-CodeArtifact \
  --policy-name CodeArtifactPublish \
  --policy-document file://codeartifact-policy.json
sts:GetServiceBearerToken é obrigatória

Sem essa permissão, o aws codeartifact get-authorization-token falha com erro de acesso negado, mesmo que todas as permissões de CodeArtifact estejam corretas. Ela não é óbvia nas mensagens de erro padrão.

Passo 8: configurar os secrets no GitHub

Acesse Settings > Secrets and variables > Actions no repositório e crie dois secrets:

SecretValor
AWS_ROLE_ARNarn:aws:iam::ACCOUNT_ID:role/GitHubActions-CodeArtifact
AWS_ACCOUNT_IDID de 12 dígitos da sua conta AWS

Passo 9: criar o workflow

Crie o arquivo .github/workflows/publish.yml no repositório:

# .github/workflows/publish.yml
name: Publish to CodeArtifact

on:
  push:
    tags:
      - "v*"

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Get CodeArtifact token
        run: |
          TOKEN=$(aws codeartifact get-authorization-token \
            --domain meu-dominio \
            --domain-owner ${{ secrets.AWS_ACCOUNT_ID }} \
            --query authorizationToken \
            --output text)
          echo "CODEARTIFACT_TOKEN=$TOKEN" >> "$GITHUB_ENV"

      - name: Build and publish
        env:
          UV_PUBLISH_URL: >-
            https://meu-dominio-${{ secrets.AWS_ACCOUNT_ID }}.d.codeartifact.us-east-1.amazonaws.com/pypi/meu-repositorio/
          UV_PUBLISH_USERNAME: aws
          UV_PUBLISH_PASSWORD: ${{ env.CODEARTIFACT_TOKEN }}
        run: |
          uv build
          uv publish

Cada parte do workflow:

Para publicar uma nova versão, crie e envie a tag:

git tag v1.0.0
git push origin v1.0.0

Observações importantes

Recapitulando

Neste post você criou um domínio e um repositório no AWS CodeArtifact, publicou um pacote Python com o uv usando autenticação via token temporário, e automatizou o ciclo completo com GitHub Actions usando OIDC para assumir uma role IAM sem credenciais de longa duração. O próximo passo natural é consumir o pacote privado em outros projetos da sua conta. Para funções serverless, veja o post sobre AWS Lambda: introdução ao serverless na prática, que cobre como estruturar e fazer deploy de uma função Lambda.


Compartilhe este post:

Post anterior
LocalStack: teste serviços AWS no seu computador sem gastar nada
Próximo post
Amazon Bedrock: introdução à IA generativa gerenciada na AWS