{"id":881,"date":"2025-11-11T23:17:49","date_gmt":"2025-11-11T15:17:49","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=881"},"modified":"2026-02-18T01:20:34","modified_gmt":"2026-02-17T17:20:34","slug":"1password-cli-how-not-to-store-plaintext-aws-credentials-on-localhost","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/1password-cli-how-not-to-store-plaintext-aws-credentials-on-localhost.html","title":{"rendered":"1Password CLI: How NOT to Store Plaintext AWS Credentials or .env on Localhost"},"content":{"rendered":"<h2>No More <code>~\/.aws\/credetials<\/code><\/h2>\n<p>According to AWS security best practices, human users should access AWS services using short-term credentials provided by IAM Identity Center. Long-term credentials (&quot;Access Key ID&quot; and &quot;Secret Access Key&quot;) created by IAM users should be avoided, especially since they are often stored in plaintext on disk: <code>~\/.aws\/credetials<\/code>.<\/p>\n<p>However, if you somehow have to use AWS access keys but want an extra layer of protection, 1Password CLI can help.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/best-practices.html\">https:\/\/docs.aws.amazon.com\/IAM\/latest\/UserGuide\/best-practices.html<\/a><br \/>\n<a href=\"https:\/\/developer.1password.com\/docs\/cli\/get-started\">https:\/\/developer.1password.com\/docs\/cli\/get-started<\/a><\/p>\n<p>First, delete your local plaintext AWS credentials. Don't worry, you could generate new one any time on AWS Management Console.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">rm -rf ~\/.aws\/credetials<\/code><\/pre>\n<p>Re-create aws-cli configuration file, but <strong>DO NOT<\/strong> provide any credentials.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">aws configure\n\nAWS Access Key ID [None]: JUST PRESS ENTER, DO NOT TYPE ANYTHING\nAWS Secret Access Key [None]: JUST PRESS ENTER, DO NOT TYPE ANYTHING\nDefault region name [None]: ap-northeast-1\nDefault output format [None]: json<\/code><\/pre>\n<p>Edit <code>~\/.aws\/credentials<\/code>:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-ini\">[your-profile-name]\ncredential_process = sh -c \"op item get \"AWS Access Key\" --account=my.1password.com --vault=Private --format=json --fields label=AccessKeyId,label=SecretAccessKey | jq 'map({key: .label, value: .value}) | from_entries + {Version: 1}'\"<\/code><\/pre>\n<p>The magic is <code>credential_process<\/code> which sourcing AWS credentials from an external process: 1Password CLI's <code>op item get<\/code> command.<\/p>\n<p>The one-liner script assumes you have an item named <code>AWS Access Key<\/code> in a vault named <code>Private<\/code> in 1Password, and the item has following fields:<\/p>\n<ul>\n<li><code>AccessKeyId<\/code><\/li>\n<li><code>SecretAccessKey<\/code><\/li>\n<\/ul>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/cli\/latest\/userguide\/cli-configure-sourcing-external.html\">https:\/\/docs.aws.amazon.com\/cli\/latest\/userguide\/cli-configure-sourcing-external.html<\/a><br \/>\n<a href=\"https:\/\/developer.1password.com\/docs\/cli\/reference\/management-commands\/item#item-get\">https:\/\/developer.1password.com\/docs\/cli\/reference\/management-commands\/item#item-get<\/a><\/p>\n<p>That's it.<\/p>\n<p>When you run aws-cli commands or access AWS services from your code via aws-sdk, your terminal will prompt you to unlock 1Password with biometrics to source AWS credentials (once per terminal session). No more plaintext AWS access keys on localhost!<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\"># aws-cli\naws s3 ls --profile=perp\naws logs tail --profile=perp --region=ap-northeast-1 \/aws\/containerinsights\/perp-staging\/application --follow\n\n# aws-sdk\nAWS_PROFILE=perp OTHER_ENV=123 ts-node src\/index.ts\n\n# serverless v4 supports credential_process by default\n# serverless v3 requires installing a plugin: serverless-better-credentials\n# https:\/\/github.com\/thomasmichaelwallace\/serverless-better-credentials\nsls deploy --stage=staging --aws-profile=perp\n\n# if you're using serverless-offline, you might need to add the following configs to serverless.yml\ncustom:\n  serverless-offline:\n    useInProcess: true<\/code><\/pre>\n<p>It's worth noting that if you prefer not to use 1Password, there is also a tool called <code>aws-vault<\/code> which can achieve a similar goal.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/github.com\/99designs\/aws-vault\">https:\/\/github.com\/99designs\/aws-vault<\/a><\/p>\n<h2>No More <code>.env<\/code><\/h2>\n<p>If you would like to store <code>.env<\/code> file entirely in 1Password, try 1Password Environments.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/developer.1password.com\/docs\/environments\">https:\/\/developer.1password.com\/docs\/environments<\/a><br \/>\n<a href=\"https:\/\/developer.1password.com\/docs\/environments\/local-env-file\">https:\/\/developer.1password.com\/docs\/environments\/local-env-file<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you somehow have to use AWS access keys but want an extra layer of protection, 1Password CLI can help.<\/p>\n","protected":false},"author":1,"featured_media":886,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38],"tags":[150,101,145],"class_list":["post-881","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-about-devops","tag-aws-cli","tag-cli-tool","tag-security"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/881","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=881"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/881\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/886"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=881"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=881"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=881"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}