How to Authenticate with Private Container Registries Using the Apple Container CLI
The Apple Container tool authenticates to private registries through a three-step CLI workflow: login, list, and logout, with all credentials securely stored in the macOS keychain via the KeychainHelper class.
The apple/container repository provides a native macOS container runtime that integrates with private OCI registries. Understanding how to authenticate with private container registries ensures secure access to your images without exposing credentials in shell history or log files.
The Three-Step Authentication Workflow
Authentication is handled through sub-commands in Sources/ContainerCommands/Registry/. The tool never writes raw passwords to disk; instead, it leverages the system keychain using the constant Constants.keychainID ("com.apple.container.registry").
Login (container registry login)
When you execute container registry login, the implementation in RegistryLogin.swift performs the following operations:
-
Parse arguments – The command reads
--username,--password-stdin, and the target registry hostname viaFlags.Registry(defined inFlags.swiftat line 154). The--schemeflag defaults toautofor protocol detection. -
Prompt for credentials – If
usernameis omitted,KeychainHelper.userPrompt(hostname:)requests it interactively. If the password is missing,KeychainHelper.passwordPrompt()reads it from stdin (when--password-stdinis used) or interactively. -
Resolve connectivity –
Reference.resolveDomain(domain:)canonicalises the hostname, whileRequestScheme(registry.scheme)determines whether to use HTTP, HTTPS, or auto-detect based on Docker-compatible internal DNS logic. -
Validate credentials – A
RegistryClientis instantiated withBasicAuthentication(username:…, password:…)and callsclient.ping()to verify reachability and credential validity. -
Persist securely – Upon success,
KeychainHelper.save(hostname:username:password:)stores the encrypted credentials in the macOS keychain.
List (container registry list)
The list sub-command (implemented in RegistryList.swift) retrieves stored credentials without exposing passwords:
KeychainHelper.list()returns an array ofRegistryInfoobjects- Each entry is deserialized into a
RegistryResource(defined inRegistryResource.swift), containing hostname, username, and timestamps - Output renders as a table by default, or as a quiet list of hostnames with the
-qflag
Logout (container registry logout)
To remove credentials, RegistryLogout.swift handles the logout command:
- The supplied registry name is canonicalised via
Reference.resolveDomain(domain:) KeychainHelper.delete(hostname:)removes the entry from the keychain under the"com.apple.container.registry"domain
Authenticating to Non-TLS Registries
For registries without TLS certificates, force the HTTP scheme using the --scheme flag:
container registry login \
--scheme http \
--username alice \
my.private.registry:5000
As implemented in Flags.swift, the --scheme option accepts http, https, or auto (default). When set to auto, RequestScheme attempts HTTPS first, falling back to HTTP only for Docker-compatible internal DNS domains.
Security Architecture and Credential Storage
The authentication flow spans three architectural layers:
CLI Layer – RegistryLogin, RegistryLogout, and RegistryList extensions parse arguments and delegate to the service layer.
Service Layer – RegistryClient (from the Container API client) communicates with remote registries using the resolved scheme and BasicAuthentication payload. It includes retry logic for transient failures.
Persistence Layer – KeychainHelper isolates container credentials using the domain constant defined in Constants.swift. Passwords are never logged or exposed in process listings; they travel directly from stdin/interactive prompts to the encrypted keychain blob.
Practical Examples
Authenticate interactively to a standard registry:
container registry login registry.example.com
Authenticate non-interactively using stdin for the password:
container registry login \
--username alice \
--password-stdin \
registry.example.com < password.txt
List all saved credentials:
# Detailed view
container registry list
# Machine-readable hostnames only
container registry list -q
Remove stored credentials:
container registry logout registry.example.com
Summary
- Store credentials using
container registry login, which persists authentication data to the macOS keychain viaKeychainHelper. - Verify connectivity automatically through
RegistryClient.ping()before saving credentials. - Manage entries with
container registry listto view saved hosts andcontainer registry logoutto delete specific entries. - Force protocols with
--scheme httpfor registries without TLS, or rely on auto-detection for Docker-compatible domains. - Secure by default – Credentials are encrypted under
"com.apple.container.registry"and never written to logs or shell history.
Frequently Asked Questions
How does the Container tool store registry passwords?
The tool stores passwords in the macOS system keychain using the KeychainHelper class under the domain "com.apple.container.registry" (defined in Constants.swift). Passwords are read from stdin or interactive prompts and immediately encrypted, never appearing in command history or log files.
Can I use the Container CLI with HTTP-only registries?
Yes. Pass the --scheme http flag to container registry login to force HTTP instead of HTTPS. This is useful for local registries without TLS certificates. The RequestScheme logic in the API client handles the protocol selection when you use the default auto setting.
Where does the authentication logic live in the source code?
The login implementation resides in Sources/ContainerCommands/Registry/RegistryLogin.swift, logout in RegistryLogout.swift, and credential listing in RegistryList.swift. The underlying data model is defined in Sources/ContainerResource/Registry/RegistryResource.swift, while keychain constants are in Sources/Services/ContainerAPIService/Client/Constants.swift.
Why does the login command require a ping to the registry?
The client.ping() call validates that the registry is reachable and that the credentials are accepted before storing them in the keychain. This prevents saving invalid authentication data that would later cause silent failures during container run operations.
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 →