How Container Secures Registry Credentials Using macOS Keychain Services
Container stores Docker-compatible registry credentials in the macOS Keychain by wrapping Keychain Services API calls in a KeychainHelper class that isolates secrets under a dedicated security domain, prompts users via native UI, and deletes entries on logout.
The apple/container CLI tool manages OCI container images and requires authenticated access to private registries. To protect sensitive login data, the project implements a secure credential storage mechanism that leverages native macOS Keychain Services rather than plaintext configuration files.
The KeychainHelper Abstraction
At the core of this security model sits KeychainHelper, a Swift wrapper that encapsulates interaction with the macOS Keychain Services API (SecItemAdd, SecItemCopyMatching, SecItemDelete). This abstraction isolates Container's secrets from other applications by using a dedicated security domain defined in Constants.keychainID.
Storing Credentials During Login
When a user executes container registry login, the implementation in Sources/ContainerCommands/Registry/RegistryLogin.swift orchestrates a multi-step process to capture and persist credentials securely.
Prompting for Credentials
First, the command instantiates a keychain helper scoped to the container-specific domain:
let keychain = KeychainHelper(securityDomain: Constants.keychainID) // Line 63
If the username is omitted from command-line arguments, the tool invokes the native keychain UI to prompt the user:
if username == "" {
username = try keychain.userPrompt(hostname: server) // Line 65
}
Similarly, when no password is provided via stdin, the helper requests it through a secure system dialog:
if password == "" {
password = try keychain.passwordPrompt() // Line 68
print()
}
Validating and Saving
Before persistence, Container validates the credentials by attempting an authenticated ping to the target registry. Upon successful authentication, the username and password are encrypted and stored:
try keychain.save(hostname: server, username: username, password: password) // Line 96
This call maps directly to SecItemAdd, ensuring the data resides in the user's keychain rather than memory or disk files.
Removing Credentials During Logout
The container registry logout command triggers cleanup via Sources/ContainerCommands/Registry/RegistryLogout.swift. The implementation initializes the same keychain helper, resolves the registry domain, and deletes the corresponding entry:
let keychain = KeychainHelper(securityDomain: Constants.keychainID) // Line 37
let r = Reference.resolveDomain(domain: registry)
try keychain.delete(hostname: r) // Lines 39-40
This invocation translates to SecItemDelete, ensuring complete removal of the secret from secure storage.
Security Benefits
Using the macOS Keychain provides several security advantages over traditional credential storage:
- Encryption at rest: Secrets are encrypted using the user's keychain password and hardware-backed encryption when available.
- Access control: The OS mediates access to credentials, requiring user authentication for retrieval.
- Isolation: The dedicated
Constants.keychainIDsecurity domain prevents other applications from accessing Container's registry credentials. - No plaintext exposure: Credentials never appear in configuration files, environment variables, or shell history.
Practical Usage Examples
The following commands demonstrate the credential lifecycle.
Log in interactively, triggering native keychain prompts:
container registry login my.registry.example.com
Log in non-interactively using stdin for the password:
echo "s3cr3t" | container registry login --username alice --password-stdin my.registry.example.com
Remove stored credentials:
container registry logout my.registry.example.com
Summary
- Container delegates credential storage to macOS Keychain Services through the
KeychainHelperwrapper class. - Login operations in
RegistryLogin.swiftuse native UI prompts (userPrompt,passwordPrompt) and validate credentials before callingsave. - Logout operations in
RegistryLogout.swiftpermanently delete entries usingdelete. - The
Constants.keychainIDsecurity domain isolates secrets and prevents cross-application access. - Credentials remain encrypted at rest and are never written to plaintext configuration files.
Frequently Asked Questions
Where does Container store registry credentials?
Container stores credentials in the macOS system Keychain under a dedicated security domain specified by Constants.keychainID. This location is managed by the operating system's Keychain Services API, not by files in the filesystem.
How does Container protect credentials from other applications?
By initializing KeychainHelper with a unique securityDomain parameter, Container creates isolated keychain entries that other processes cannot access without explicit permission. This domain-specific scoping ensures only the Container CLI can read or modify its stored registry passwords.
Can I view my stored Container credentials in the Keychain Access app?
Yes. Because Container uses standard macOS Keychain Services, entries appear in the Keychain Access utility under the name specified by the security domain constant. You can inspect, modify, or delete these entries manually, though using container registry logout is the recommended removal method.
Does Container support credential helpers other than the macOS Keychain?
The current implementation relies exclusively on Keychain Services for macOS. There is no pluggable credential helper architecture exposed in the public source code; all credential operations route through KeychainHelper methods that wrap SecItemAdd, SecItemCopyMatching, and SecItemDelete.
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 →