My dotfiles use the macOS Keychain for all credentials — nothing plaintext in the repo. When you run `chezmoi apply`, secrets are pulled directly from Keychain and injected into config files.
In `chezmoi`, you can reference values through templates:
```
{{ output "security" "find-generic-password" "-s" "<service>" "-a" "<account>" "-w" | trim }}
```
This runs `security` at apply-time, fetches the password, and puts it wherever you need it.
## Adding a Secret
Let's say you need to add credentials for a new email account.
**1. Add it to Keychain:**
```bash
security add-generic-password -s "my-service" -a "
[email protected]" -w
# Type your password when prompted
```
**2. Reference it in a template:**
```bash
chezmoi edit ~/.config/mbsync/mbsyncrc # note: use the target path, not the source
```
Then add the template snippet where the password goes.
**3. Apply:**
```bash
chezmoi diff # preview changes
chezmoi apply # write files with secrets injected
```
## Examples
### Git SMTP Password
```toml
# dot_gitconfig.tmpl
[sendemail]
smtpserver = smtp.mailbox.org
smtpuser =
[email protected]
smtppass = {{ output "security" "find-generic-password" "-s" "mailbox-smtp" "-a" "
[email protected]" "-w" | trim }}
```
Add the secret:
```bash
security add-generic-password -s "mailbox-smtp" -a "
[email protected]" -w
```
### Newsboat (NewsBlur)
```
# private_dot_newsboat/config
newsblur-passwordeval "security find-generic-password -s newsblur-login -a kglitchy -w"
```
Add the secret:
```bash
security add-generic-password -s "newsblur-login" -a "kglitchy" -w
```
### Neomutt (FastMail IMAP)
```
# private_dot_config/neomutt/accounts/fastmail.muttrc
set imap_pass = "{{ output "security" "find-generic-password" "-s" "fastmail-imap" "-a" "
[email protected]" "-w" | trim }}"
```
Add the secret:
```bash
security add-generic-password -s "fastmail-imap" -a "
[email protected]" -w
```
## Naming Conventions
I try to keep service names descriptive:
| Purpose | Service (`-s`) | Account (`-a`) |
| ---------------- | ------------------- | ---------------------------- |
| Mailbox.org SMTP | `mailbox-smtp` | `
[email protected]` |
| FastMail IMAP | `fastmail-imap` | `
[email protected]`|
| NewsBlur | `newsblur-login` | `kglitchy` |
| CalDAV | `vdirsyncer-fastmail` | `
[email protected]`|
## Managing Existing Secrets
**Update a password:**
```bash
security delete-generic-password -s "service-name" -a "account-name"
security add-generic-password -s "service-name" -a "account-name" -w
```
**Check if a secret exists:**
```bash
security find-generic-password -s "service-name" -a "account-name" -w
```
Returns the password if it's there, errors if not.
**List all your service names:**
```bash
security dump-keychain 2>&1 | grep '"svce"<blob>=' | sed -E 's/.*<blob>="([^"]+)".*/\1/' | sort -u
```
## When Things Go Wrong
> [!Error] "item could not be found in the keychain"
You forgot to add the secret, or the service/account names don't match exactly. Check what you named it:
```bash
security find-generic-password -s "your-service" -a "your-account" -w
```
> [!Error] Template renders empty string
The `security` command ran but returned nothing. Double-check your names match exactly (they're case-sensitive).
> [!Error] Secret works in terminal but not chezmoi
Make sure you're using the right syntax:
```
{{ output "security" "find-generic-password" "-s" "service" "-a" "account" "-w" | trim }}
```
Note: `output` not `.chezmoi.output`, and don't forget the `| trim` at the end.
## Security Notes
- Secrets only exist in memory during `chezmoi apply` — nothing gets written to disk in plaintext
- Use the `private_` prefix on sensitive source files — chezmoi sets them to mode 0600
- Only commit the `.tmpl` templates, never the rendered files with actual secrets