Keep long-term AWS access keys out of ~/.aws/credentials (plaintext on disk) by storing them in your desktop keyring via libsecret, and letting the AWS CLI/SDKs fetch them on demand with credential_process.
Works with anything that uses the standard AWS credential chain: aws CLI, boto3, Go/JS/Rust SDKs, Terraform, Pulumi, etc.
libsecretand its CLI (secret-tool) — packagelibsecreton Arch,libsecret-toolson Debian/Ubuntu.- A running Secret Service keyring (GNOME Keyring, KWallet ≥ 5.97, or KeePassXC with Secret Service integration), unlocked with your session.
printf '%s' 'AKIAXXXXXXXXXXXXXXXX' | secret-tool store --label='AWS access key ID' service aws key access-key-id
printf '%s' 'your-secret-access-key' | secret-tool store --label='AWS secret access key' service aws key secret-access-keyThe service aws key ... pairs are arbitrary attribute/value lookup tags — pick any scheme, just be consistent. Verify:
secret-tool lookup service aws key access-key-idPrefer printf '%s' over echo so no trailing newline gets stored.
credential_process is a hook in the AWS config: instead of reading static keys, the SDK runs a program and parses JSON from its stdout.
~/.local/bin/aws-libsecret-creds:
#!/bin/sh
printf '{"Version":1,"AccessKeyId":"%s","SecretAccessKey":"%s"}' \
"$(secret-tool lookup service aws key access-key-id)" \
"$(secret-tool lookup service aws key secret-access-key)"chmod +x ~/.local/bin/aws-libsecret-creds[profile myprofile]
region = us-east-1
credential_process = /home/you/.local/bin/aws-libsecret-credsUse an absolute path — ~ is not expanded in credential_process.
Delete the profile's aws_access_key_id / aws_secret_access_key lines from ~/.aws/credentials. This matters: static keys in the credentials file take precedence over credential_process, so leftovers silently win.
aws sts get-caller-identity --profile myprofileIf you use a virtual MFA device with an auto-refresh tool (aws-mfa, aws-mfa-auto, oathtool scripts), the TOTP seed is just as sensitive as the secret key — store it the same way:
printf '%s' 'BASE32TOTPSEED...' | secret-tool store --label='AWS MFA TOTP seed' service aws key mfa-secretThen call your refresh tool with a lookup instead of a hardcoded seed, e.g. in .zshrc/.bashrc:
aws-mfa-auto --profile myprofile --secret "$(secret-tool lookup service aws key mfa-secret)"- Precedence: env vars (
AWS_ACCESS_KEY_ID) beat everything; static keys in~/.aws/credentialsbeatcredential_process. Clean both up or the keyring never gets consulted. - Headless/SSH sessions:
secret-toolneeds D-Bus and an unlocked keyring. Over plain SSH with no session keyring, lookups fail — the error surfaces as a credential_process failure. CI and servers should use roles/SSO instead anyway. - Tools that parse the credentials file directly (some MFA helpers, old scripts using configparser instead of the SDK) may require the profile section header to exist in
~/.aws/credentials. An empty[myprofile-long-term]section satisfies the check while boto3 falls through tocredential_process. - Rotation: rerun the two
secret-tool storecommands — same attributes overwrite in place, nothing else to touch.