AWS CodeArtifact Setup Guide for uv

2025-08-08 - 12 min read
Daniel Young
Daniel Young
Founder, DRYCodeWorks

Install Python packages from AWS CodeArtifact with uv: the keyrings.codeartifact plugin, keyring-provider set to subprocess, and one variable.

A key on a keyring opens a cabinet of package boxes, which travel along a dotted line to a laptop

This guide explains how to configure uv to install Python packages from AWS CodeArtifact using keyring for secure token management.

Prerequisites

  • Python 3.8+ installed
  • uv installed (installation guide)
  • AWS CLI configured with appropriate credentials
  • Access to your organization's CodeArtifact repository

Initial Setup (One-time)

1. Install Keyring with CodeArtifact Support

bash
uv tool install keyring --with keyrings.codeartifact

This installs the keyring tool globally, allowing secure storage of authentication tokens.

2. Configure Your Project

Add the following to your pyproject.toml:

pyproject.tomltoml
[tool.uv]
keyring-provider = "subprocess"

[[tool.uv.index]]
name = "your-index-name"
url = "https://your-domain-ACCOUNTID.d.codeartifact.REGION.amazonaws.com/pypi/your-repo/simple/"

Replace:

  • your-index-name: A descriptive name for your index (e.g., company-pypi)
  • your-domain: Your CodeArtifact domain name
  • ACCOUNTID: Your AWS account ID
  • REGION: Your AWS region (e.g., us-east-2)
  • your-repo: Your CodeArtifact repository name

3. Set Environment Variable

The environment variable name follows the pattern: UV_INDEX_<INDEX_NAME>_USERNAME

⚠️ Critical: Environment Variable Naming

The environment variable name must exactly match your index name from pyproject.toml:

  • Convert to uppercase
  • Replace hyphens with underscores
  • Use the exact same name you defined in [[tool.uv.index]]

This is the most common source of authentication failures!

bash
# For index named "your-index-name", use YOUR_INDEX_NAME (uppercase, hyphens become underscores)
export UV_INDEX_YOUR_INDEX_NAME_USERNAME=aws

# Add to your shell profile for persistence
echo 'export UV_INDEX_YOUR_INDEX_NAME_USERNAME=aws' >> ~/.zshrc  # or ~/.bashrc
source ~/.zshrc

Example: If your index is named company-pypi, the variable would be UV_INDEX_COMPANY_PYPI_USERNAME

4. Store Authentication Token

bash
aws codeartifact get-authorization-token \
    --domain your-domain \
    --domain-owner ACCOUNTID \
    --region REGION \
    --query authorizationToken \
    --output text | keyring set https://your-domain-ACCOUNTID.d.codeartifact.REGION.amazonaws.com/pypi/your-repo/simple/ aws

Note: The URL in the keyring command must exactly match the URL in your pyproject.toml.

5. Verify Setup

bash
# Test the connection
uv sync

Daily Usage

Refreshing Tokens

CodeArtifact tokens expire after 12 hours. Add this function to your shell profile (~/.zshrc or ~/.bashrc):

~/.zshrc or ~/.bashrcbash
refresh_codeartifact() {
    aws codeartifact get-authorization-token \
        --domain your-domain \
        --domain-owner ACCOUNTID \
        --region REGION \
        --query authorizationToken \
        --output text | keyring set https://your-domain-ACCOUNTID.d.codeartifact.REGION.amazonaws.com/pypi/your-repo/simple/ aws
    
    if [ $? -eq 0 ]; then
        echo "✓ CodeArtifact token refreshed at $(date '+%I:%M %p')"
    else
        echo "❌ Failed to refresh token"
        return 1
    fi
}

Then use:

bash
# Refresh token (needed every 12 hours)
refresh_codeartifact

# Work normally
uv sync
uv add package-name
uv remove package-name

Example Configuration

Here's a complete example for a company using CodeArtifact:

pyproject.toml:

pyproject.tomltoml
[project]
name = "my-project"
version = "0.1.0"
dependencies = [
    "requests>=2.31.0",
    "internal-package>=1.0.0",  # From CodeArtifact
]

[tool.uv]
keyring-provider = "subprocess"

[[tool.uv.index]]
name = "company"
url = "https://company-123456789012.d.codeartifact.us-east-1.amazonaws.com/pypi/internal/simple/"

Shell profile (~/.zshrc or ~/.bashrc):

~/.zshrc or ~/.bashrcbash
# CodeArtifact configuration
export UV_INDEX_COMPANY_USERNAME=aws

refresh_codeartifact() {
    aws codeartifact get-authorization-token \
        --domain company \
        --domain-owner 123456789012 \
        --region us-east-1 \
        --query authorizationToken \
        --output text | keyring set https://company-123456789012.d.codeartifact.us-east-1.amazonaws.com/pypi/internal/simple/ aws
    
    if [ $? -eq 0 ]; then
        echo "✓ Token refreshed successfully"
    else
        echo "❌ Token refresh failed"
        return 1
    fi
}

Troubleshooting

Authentication Errors

1. Verify environment variable is set

bash
echo $UV_INDEX_YOUR_INDEX_NAME_USERNAME
# Should output: aws

2. Check token is stored in keyring

bash
keyring get https://your-url/simple/ aws | head -c 20
# Should show start of token

3. Ensure AWS CLI is configured

bash
aws sts get-caller-identity
# Should show your AWS identity

4. Run with verbose output

bash
uv sync -v

Common Issues

IssueSolution
401 UnauthorizedToken expired - run refresh_codeartifact
Token not found in keyringURL in keyring command doesn't match pyproject.toml exactly
Environment variable not foundCheck spelling and uppercase conversion (hyphens → underscores)
AWS CLI errorsVerify AWS credentials and permissions
Keychain access errors (macOS)Grant Terminal/Python access in Keychain Access app

Required IAM Permissions

Ensure your AWS user/role has these permissions:

iam-policy.jsonjson
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codeartifact:GetAuthorizationToken",
                "sts:GetServiceBearerToken"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "codeartifact:ReadFromRepository",
            "Resource": "arn:aws:codeartifact:REGION:ACCOUNTID:repository/your-domain/your-repo"
        }
    ]
}

Quick Setup Script

Save this as setup_codeartifact.sh and customize for your organization:

setup_codeartifact.shbash
#!/bin/bash

# Configuration - CUSTOMIZE THESE
DOMAIN="your-domain"
ACCOUNT_ID="123456789012"
REGION="us-east-1"
REPO="your-repo"
INDEX_NAME="YOUR_INDEX_NAME"  # Uppercase, underscores instead of hyphens

# Colors for output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'

echo -e "${BLUE}Setting up CodeArtifact...${NC}"

# Install keyring
echo -e "${BLUE}Installing keyring...${NC}"
uv tool install keyring --with keyrings.codeartifact

# Set environment variable
export UV_INDEX_${INDEX_NAME}_USERNAME=aws
echo -e "${GREEN}✓ Environment variable set${NC}"

# Store token
echo -e "${BLUE}Storing authentication token...${NC}"
URL="https://${DOMAIN}-${ACCOUNT_ID}.d.codeartifact.${REGION}.amazonaws.com/pypi/${REPO}/simple/"

aws codeartifact get-authorization-token \
    --domain $DOMAIN \
    --domain-owner $ACCOUNT_ID \
    --region $REGION \
    --query authorizationToken \
    --output text | keyring set $URL aws

if [ $? -eq 0 ]; then
    echo -e "${GREEN}✓ Setup complete! You can now run: uv sync${NC}"
else
    echo -e "${RED}Setup failed. Check your AWS credentials.${NC}"
    exit 1
fi

Platform-Specific Notes

macOS

  • If you encounter keychain access errors, open Keychain Access app and grant Terminal/Python access
  • You may need to unlock your keychain: security unlock-keychain ~/Library/Keychains/login.keychain-db

Linux

  • keyring will use the Secret Service API (GNOME Keyring or KDE Wallet)
  • Ensure your desktop environment's keyring service is running

Windows

  • keyring uses Windows Credential Manager
  • Access via Control Panel → User Accounts → Credential Manager

CI/CD Environments

For automated environments, use environment variables instead of keyring:

GitHub Actions exampleyaml
env:
  UV_INDEX_COMPANY_USERNAME: aws
  UV_INDEX_COMPANY_PASSWORD: ${{ secrets.CODEARTIFACT_TOKEN }}
GitLab CI exampleyaml
variables:
  UV_INDEX_COMPANY_USERNAME: aws
  UV_INDEX_COMPANY_PASSWORD: ${CODEARTIFACT_TOKEN}

Security Best Practices

  • Never commit tokens to version control
  • Use IAM roles when possible instead of IAM users
  • Rotate tokens regularly (they expire every 12 hours by default)
  • Limit IAM permissions to only what's needed
  • Use separate repositories for different projects/teams
  • Enable CloudTrail logging for CodeArtifact API calls

Support resources. For issues specific to: