# How Container Secures Registry Credentials Using macOS Keychain Services

> Learn how container secures registry credentials using macOS Keychain Services. Discover its KeychainHelper class for isolated secrets, native UI prompts, and logout entry deletion.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-14

---

**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`](https://github.com/apple/container/blob/main/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:

```swift
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:

```swift
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:

```swift
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:

```swift
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`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Registry/RegistryLogout.swift). The implementation initializes the same keychain helper, resolves the registry domain, and deletes the corresponding entry:

```swift
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.keychainID` security 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:

```bash
container registry login my.registry.example.com

```

Log in non-interactively using stdin for the password:

```bash
echo "s3cr3t" | container registry login --username alice --password-stdin my.registry.example.com

```

Remove stored credentials:

```bash
container registry logout my.registry.example.com

```

## Summary

- Container delegates credential storage to macOS Keychain Services through the `KeychainHelper` wrapper class.
- Login operations in [`RegistryLogin.swift`](https://github.com/apple/container/blob/main/RegistryLogin.swift) use native UI prompts (`userPrompt`, `passwordPrompt`) and validate credentials before calling `save`.
- Logout operations in [`RegistryLogout.swift`](https://github.com/apple/container/blob/main/RegistryLogout.swift) permanently delete entries using `delete`.
- The `Constants.keychainID` security 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`.