Container Registry Authentication and Credential Management Methods in Apple Container

The Apple Container tool stores all registry credentials in the macOS Keychain under the security domain com.apple.container.registry, eliminating plain-text storage while enabling secure OCI registry operations.

The apple/container project implements a robust credential management system that leverages native macOS security primitives for container registry authentication. By delegating credential storage to the system Keychain rather than configuration files, the tool ensures that registry passwords remain encrypted at rest yet accessible for image pull and push workflows.

How Credential Storage Works

All credential operations in the codebase route through the KeychainHelper class, which abstracts macOS Keychain interactions. The helper initializes with a repository-wide security domain defined in Sources/Services/ContainerAPIService/Client/Constants.swift (line 20) as Constants.keychainID, set to the string "com.apple.container.registry".

This design centralizes authentication state within the operating system's protected storage, preventing credential leakage through filesystem access or version control while maintaining availability across application launches.

Authentication Commands

The tool provides three primary CLI commands for credential lifecycle management, each implemented as a separate Swift command structure.

Logging In to a Registry

The container registry login command, implemented in Sources/ContainerCommands/Registry/RegistryLogin.swift (lines 63-97), handles credential acquisition and validation.

The process follows this sequence:

  1. Input Collection – The command accepts --username and optionally --password-stdin to read sensitive values from standard input rather than command-line arguments.
  2. Validation – The tool constructs a BasicAuthentication object and performs a ping against the target registry to verify connectivity and credential validity.
  3. Persistence – Upon successful validation, the credentials are stored via KeychainHelper.save(hostname:username:password:), associating the username/password pair with the specific registry hostname.

Listing Stored Credentials

The container registry list command, found in Sources/ContainerCommands/Registry/RegistryList.swift (lines 41-50), enumerates all stored registry entries.

The command retrieves all credentials using KeychainHelper.list(), then maps each stored RegistryInfo object to a RegistryResource as defined in Sources/ContainerResource/Registry/RegistryResource.swift (lines 20-52). The output supports both table formatting and quiet mode (-q), which returns only hostnames for scripting purposes.

Removing Credentials

The container registry logout command, located in Sources/ContainerCommands/Registry/RegistryLogout.swift (lines 36-40), removes stored entries for a specific hostname.

The implementation calls KeychainHelper.delete(hostname:), which purges the credential record from the Keychain without affecting other stored registries.

Using Credentials for Image Operations

When pulling or pushing images, the system retrieves stored credentials to authenticate against OCI registries. In Sources/ContainerAPIService/Client/ClientImage.swift (lines 62-71), the code resolves the appropriate scheme (http or https) based on command-line flags and internal DNS domain configuration.

The workflow proceeds as follows:

  • Credential Retrieval – The client queries KeychainHelper.list() to find matching credentials for the target hostname.
  • Client Construction – It instantiates a RegistryClient with the retrieved BasicAuthentication object, configuring the scheme, host, and port parameters.
  • Transport Security – The scheme resolution ensures that insecure registries use HTTP while standard registries default to HTTPS, preventing man-in-the-middle attacks on credential transmission.

Code Examples

Authenticate with a registry using command-line flags or stdin:


# Log in to a registry (prompts for username/password or reads password from stdin)

container registry login myregistry.example.com \
    --username alice \
    --password-stdin < password.txt

View stored credentials in different output formats:


# Show stored registry credentials in table view

container registry list

# Show only hostnames (quiet mode)

container registry list -q

Remove credentials for a specific registry:


# Log out and remove stored credentials

container registry logout myregistry.example.com

Programmatically interact with the credential store:

import ContainerAPIService

// Initialize the keychain helper with the security domain
let keychain = KeychainHelper(securityDomain: Constants.keychainID)

// Save credentials after validation
try keychain.save(
    hostname: "myregistry.example.com",
    username: "alice",
    password: "secret-token"
)

// Retrieve credentials for image operations
let stored = try keychain.list().first { $0.hostname == "myregistry.example.com" }
let auth = BasicAuthentication(
    username: stored?.username ?? "",
    password: stored?.password ?? ""
)

// Construct the registry client
let client = RegistryClient(
    host: "myregistry.example.com",
    scheme: "https",
    port: nil,
    authentication: auth
)

Summary

  • Secure Storage – Credentials persist in the macOS Keychain under the identifier com.apple.container.registry, never touching unencrypted filesystem storage.
  • Command Interface – Three primary commands (login, list, logout) provide complete credential lifecycle management through KeychainHelper methods.
  • Validation – The registry login command validates credentials against the target registry via ping before storing them.
  • Runtime Integration – Image pull and push operations automatically retrieve credentials to construct authenticated RegistryClient instances with appropriate transport schemes.

Frequently Asked Questions

Where does apple/container store registry credentials?

The tool stores credentials exclusively in the macOS Keychain under the security domain "com.apple.container.registry", defined as Constants.keychainID in Sources/Services/ContainerAPIService/Client/Constants.swift. This ensures operating-system-level encryption and access control rather than relying on file-based storage.

How does the tool validate credentials before storing them?

During the registry login command execution, the tool creates a BasicAuthentication object and performs a ping operation against the target registry. Only after receiving a successful response does it call KeychainHelper.save() to persist the credentials, preventing invalid or mistyped credentials from entering the keychain.

Can I use credential management features programmatically?

Yes. The KeychainHelper class provides a Swift API for programmatic credential operations including save(hostname:username:password:), delete(hostname:), and list(). You can construct BasicAuthentication objects from retrieved credentials and pass them to RegistryClient for OCI operations.

How does the tool handle insecure registries?

The scheme selection logic in Sources/ContainerAPIService/Client/ClientImage.swift (lines 62-71) determines whether to use HTTP or HTTPS based on the --scheme command-line flag and internal DNS domain resolution. This allows the credential system to authenticate against insecure HTTP registries when explicitly configured, while defaulting to HTTPS for security.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →