Container Registry Authentication and Credential Storage in Apple's Container Tool
The container CLI stores registry credentials securely in the macOS Keychain under the identifier com.apple.container.registry, providing login, logout, and list commands via RegistryLogin, RegistryLogout, and RegistryList.
The apple/container project provides a Swift-based container management solution that integrates deeply with macOS security primitives. Unlike tools that cache credentials in plain-text configuration files, this implementation leverages the system Keychain for container registry authentication and credential storage, ensuring secrets remain encrypted and access-controlled by the operating system.
Keychain Integration and Security Domain
All credential operations are centralized through KeychainHelper, which abstracts macOS Keychain access using the repository-wide security domain defined in Sources/Services/ContainerAPIService/Client/Constants.swift. At line 20, the constant Constants.keychainID is set to "com.apple.container.registry", serving as the exclusive identifier for all stored entries. This design prevents credential leakage and ties authentication data to the user's system-level security policies.
The helper exposes three core methods for credential lifecycle management:
KeychainHelper.save(hostname:username:password:)– Persists credentials after validation.KeychainHelper.delete(hostname:)– Removes entries during logout.KeychainHelper.list()– Retrieves all storedRegistryInfoobjects for enumeration.
Authentication Lifecycle Commands
Logging In via RegistryLogin
The container registry login command is implemented in Sources/ContainerCommands/Registry/RegistryLogin.swift (lines 63-97). The workflow first constructs a BasicAuthentication object from the provided username and password (optionally supplied via the --password-stdin flag). It then validates connectivity by pinging the registry endpoint. Upon successful verification, the credentials are persisted using KeychainHelper.save(hostname:username:password:).
# 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
Logging Out via RegistryLogout
The container registry logout command, found in Sources/ContainerCommands/Registry/RegistryLogout.swift (lines 36-40), performs a straightforward deletion. It invokes KeychainHelper.delete(hostname:) to remove the specific entry associated with the provided registry host, ensuring no residual authentication data remains on the system.
# Log out (remove credentials)
container registry logout myregistry.example.com
Listing Stored Credentials via RegistryList
To enumerate configured registries, the registry list command uses Sources/ContainerCommands/Registry/RegistryList.swift (lines 41-50). This command calls KeychainHelper.list() to fetch all entries, then maps each RegistryInfo instance to a RegistryResource object as defined in Sources/ContainerResource/Registry/RegistryResource.swift (lines 20-52). Output is rendered as a formatted table by default, or as a simple hostname list when the -q (quiet) flag is specified.
# Show stored registry credentials
container registry list # table view
container registry list -q # quiet – only hostnames
Runtime Credential Retrieval for Image Operations
When pulling or pushing images, the system retrieves stored credentials to construct a RegistryClient. In Sources/ContainerAPIService/Client/ClientImage.swift (lines 62-71), the code resolves the connection scheme—either http or https—based on command-line flags such as --scheme and internal DNS domain checks. It then instantiates BasicAuthentication with the username and password recovered from the Keychain, passing this object to the RegistryClient initializer.
// Programmatic login handling (simplified)
let keychain = KeychainHelper(securityDomain: Constants.keychainID)
// Prompt user if needed
let username = try keychain.userPrompt(hostname: server)
let password = try keychain.passwordPrompt()
// Save credentials
try keychain.save(hostname: server, username: username, password: password)
// Later – retrieve for image pull
let stored = try keychain.list().first { $0.hostname == server }
let auth = BasicAuthentication(username: stored?.username ?? "", password: stored?.password ?? "")
let client = RegistryClient(host: server, scheme: "https", port: nil, authentication: auth)
Key Source Files
The credential management subsystem spans the following critical paths:
Sources/ContainerCommands/Registry/RegistryLogin.swift– Implements the login workflow and credential validation.Sources/ContainerCommands/Registry/RegistryLogout.swift– Handles secure credential deletion.Sources/ContainerCommands/Registry/RegistryList.swift– Provides enumeration and display logic.Sources/ContainerResource/Registry/RegistryResource.swift– Defines theRegistryResourcemodel for stored entries.Sources/Services/ContainerAPIService/Client/Constants.swift– Declares thekeychainIDconstant.Sources/ContainerAPIService/Client/ClientImage.swift– Orchestrates credential retrieval during image pull/push operations.
Summary
- Secure Storage: Credentials are stored exclusively in the macOS Keychain under the identifier
"com.apple.container.registry", never in plain-text files. - Command Interface: Users interact with credentials through
registry login,registry logout, andregistry listcommands. - Validation Flow: Login operations validate registry connectivity via ping before persisting secrets via
KeychainHelper.save(hostname:username:password:). - Runtime Usage: Image operations retrieve credentials using
KeychainHelper.list(), constructBasicAuthenticationobjects, and inject them intoRegistryClientinstances with configurable schemes (http/https).
Frequently Asked Questions
Where does the container CLI store registry credentials?
Credentials are stored in the macOS Keychain under the security domain identifier "com.apple.container.registry", defined in Sources/Services/ContainerAPIService/Client/Constants.swift. This ensures encryption at rest and aligns with system-wide access controls.
How can I log in to a registry non-interactively?
Use the --password-stdin flag with container registry login to pipe the password via standard input. This avoids exposing secrets in shell history and is handled by the RegistryLogin implementation in Sources/ContainerCommands/Registry/RegistryLogin.swift.
What authentication method is used for registry operations?
The tool utilizes BasicAuthentication objects constructed from Keychain-stored username/password pairs. These are passed to RegistryClient during instantiation, as seen in the credential retrieval flow within ClientImage.swift.
How do I configure the connection scheme for insecure registries?
Specify the --scheme flag (e.g., --scheme http) when executing commands. The ClientImage logic (lines 62-71) resolves the scheme based on this flag and internal DNS domain checks before initiating the connection.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →