{
    "componentChunkName": "component---src-pages-blog-post-tsx",
    "path": "/blog/2020-06-04/how-dynamic-credentialing-makes-apps-portable",
    "result": {"data":{"site":{"siteMetadata":{"siteUrl":"https://www.architect.io"}},"allMdx":{"edges":[{"node":{"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"How dynamic credentialing makes apps portable\",\n  \"slug\": \"how-dynamic-credentialing-makes-apps-portable\",\n  \"date\": \"2020-06-04T00:00:00.000Z\",\n  \"author\": \"David Thor\",\n  \"image\": \"./vault-dynamic-credentialing.jpeg\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"1000px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/0c676/vault-dynamic-credentialing.jpg\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"27.200000000000003%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3ZCgf//EABYQAQEBAAAAAAAAAAAAAAAAAAACEf/aAAgBAQABBQJM4x//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAEBAAMAAAAAAAAAAAAAAAABABEiMf/aAAgBAQAGPwKdly3b/8QAGhAAAgIDAAAAAAAAAAAAAAAAAAERMSFBYf/aAAgBAQABPyFytkt7Rl1wkP/aAAwDAQACAAMAAAAQcA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAgIDAAAAAAAAAAAAAAABABEhMVFh0f/aAAgBAQABPxAXN22IpgEsDw69l657n//Z')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"dynamic credentials\",\n    \"title\": \"dynamic credentials\",\n    \"src\": \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/a2510/vault-dynamic-credentialing.jpg\",\n    \"srcSet\": [\"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/0479a/vault-dynamic-credentialing.jpg 250w\", \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/41099/vault-dynamic-credentialing.jpg 500w\", \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/a2510/vault-dynamic-credentialing.jpg 1000w\", \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/c58a3/vault-dynamic-credentialing.jpg 1500w\", \"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/0c676/vault-dynamic-credentialing.jpg 1550w\"],\n    \"sizes\": \"(max-width: 1000px) 100vw, 1000px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"In my last post we talked about\\n\", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.architect.io/blog/using-hashicorp-vault-to-enable-credential-cycling\"\n  }, \"how to leverage secret managers to safely store and cycle application credentials\"), \"\\nin production. In this post we're going to take the concept of credential cycling a step further to\\nstreamline the ability for an app or service to be deployed to parallel environments through\\n\", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"dynamic credentialing\"), \".\"), mdx(\"p\", null, \"Allowing apps to be deployed without manual credential generation is critical to making it\\n\", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.architect.io/blog/the-importance-of-portability\"\n  }, \"portable\"), \" and deployable by anyone \\u2013\\nan important principal that enables peer developers to run and integrate with your application in\\ntheir own private sandboxing or integration tests. In this tutorial, we'll describe what dynamic\\ncredentialing is and apply it to a practical use-case \\u2013 integration with a hosted service,\\n\", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://auth0.com\"\n  }, \"Auth0\"), \".\"), mdx(\"h2\", {\n    \"id\": \"why-we-need-dynamic-credentialing\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, \"Why we need dynamic credentialing\", mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#why-we-need-dynamic-credentialing\",\n    \"aria-label\": \"why we need dynamic credentialing permalink\",\n    \"className\": \"anchor after\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  })))), mdx(\"p\", null, \"If you've written any backend app recently, you've likely had to connect to some hosted API service.\\nThis might be an AWS service like SNS, SQS, or S3, or it might be an independent product like Stripe\\nor Auth0. All of these services require credentials in order to access them and scope your access to\\nyour own account with the provider. As a result, it's also likely that you parameterized your app to\\nallow operators to provide these credentials at runtime.\"), mdx(\"p\", null, \"Parameterizing an application to receive credentials from an operator is an extraordinarily common\\nand useful way for a service to be deployed to multiple environments in parallel. It allows an\\noperator to run your app in dev, staging, and production environments with different parameter\\nvalues that access different accounts or scopes. This is critical to operating the service in a safe\\nway, as you wouldn't want an unstable dev environment to access production data and scopes.\"), mdx(\"p\", null, \"However, the creation of these credentials is yet another manual step an operator must perform in\\norder to stand up a new environment. While creating these credentials once or twice for static\\nproduction and staging environments isn't terribly cumbersome, the friction of credential creation\\nis an inhibitor to others who would seek to stand up their own environments. This friction prevents\\ndevelopers from standing up private sandboxes, environments to execute integration tests, and from\\ndeploying the service easily to private customer environments.\"), mdx(\"p\", null, \"Dynamic credentialing\\n\", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.hashicorp.com/blog/why-we-need-dynamic-secrets/\"\n  }, \"has many benefits\"), \", but an often\\noverlooked benefit is the ability for unlimited parallel environments to be generated without\\nendless, manual creation of credentials. By loading credentials dynamically, applications are able\\nto be freely provisioned without the manual step of credential generation for each environment. This\\ncan have enormous value for larger teams especially who benefit from the democratization of\\ndeployments to provision private sandboxes or end-to-end integration test environments without any\\nmanual steps required.\"), mdx(\"h2\", {\n    \"id\": \"implemeting-dynamic-credentialing-with-hashicorp-vault\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, \"Implemeting dynamic credentialing with Hashicorp Vault\", mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#implemeting-dynamic-credentialing-with-hashicorp-vault\",\n    \"aria-label\": \"implemeting dynamic credentialing with hashicorp vault permalink\",\n    \"className\": \"anchor after\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  })))), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.architect.io/blog/using-hashicorp-vault-to-enable-credential-cycling\"\n  }, \"In a previous post\"), \",\\nI outlined how you can setup and connect to Hashicorp Vault to store and manage application secrets.\\nWhat I didn't go into then was some of Vault's more advanced features \\u2013 namely dynamic secrets. In\\nthis tutorial, we'll walk through how to setup a postgres instance, how to use the database engine\\nto setup a dynamic secret in vault, and how applications call into vault to acquire distinct\\ncredentials for the postgres instance.\"), mdx(\"p\", null, \"Just like our last walk-through, you'll need a postgres instance to get started. Let's go ahead and\\ncreate one locally with Docker. Be sure to take note of the username and password you use when\\ncreating the instance too. Those will act as your root credentials, and Vault will need them in\\nfollow-up steps in order to request new credentials.\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-bash\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token comment\"\n  }, \"# Your postgres instance will be available on localhost:5432 once complete\"), \"\\n$ docker run -d -p \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token number\"\n  }, \"5432\"), \":5432 \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    -e \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"POSTGRES_USER\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"root \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    -e \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"POSTGRES_PASSWORD\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"password \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    -e \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"POSTGRES_DB\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"postgres \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    postgres:11\"))), mdx(\"p\", null, \"Now that you have a postgres instance running, let's go ahead and enable and configure the\\n\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"database\"), \" secrets engine in vault:\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-bash\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token comment\"\n  }, \"# Enable the secrets engine\"), \"\\n$ vault secrets \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token builtin class-name\"\n  }, \"enable\"), \" database\\n\\n\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token comment\"\n  }, \"# Create our dynamic secret\"), \"\\n$ vault \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token function\"\n  }, \"write\"), \" database/config/postgresql \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"plugin_name\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"postgresql-database-plugin \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"allowed_roles\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"readonly \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"connection_url\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"postgresql://root:password@localhost:5432/postgres?sslmode\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"disable\"))), mdx(\"p\", null, \"The steps above, you configured the secrets engine to point to your new postgres instance, and also\\ngave permission to a role, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"readonly\"), \", as an allowed member for the plugin. Now we actually need to\\ndefine that role.\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-bash\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"$ vault \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token function\"\n  }, \"write\"), \" database/roles/readonly \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"db_name\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"postgresql \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"creation_statements\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"@readonly.sql \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"\\\\\"), \"\\n    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"default_ttl\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"1h \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"max_ttl\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), \"24h\"))), mdx(\"p\", null, \"The above command will create the role, but you'll notice that in the command we refer to the\\ncontents of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"readonly.sql\"), \" as the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"creation_statements\"), \". This file contains the commands that will\\nbe used to generate postgres credentials, and looks something like the following:\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"sql\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-sql\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-sql\"\n  }, mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"CREATE\"), \" ROLE \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"{{name}}\\\"\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"WITH\"), \" LOGIN PASSWORD \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"'{{password}}'\"), \" VALID UNTIL \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"'{{expiration}}'\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \";\"), \"\\n\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"GRANT\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"SELECT\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"ON\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"ALL\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"TABLES\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"IN\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"SCHEMA\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"public\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token keyword\"\n  }, \"TO\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"{{name}}\\\"\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \";\")))), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"The handlebars parameter references like \", mdx(\"inlineCode\", {\n    parentName: \"em\"\n  }, \"{{name}}\"), \" will be populated by vault automatically.\")), mdx(\"p\", null, \"Now that we have a role capable of creating our new postgres credentials, we need to create an app\\npolicy and token that can be used to request these credentials from vault. To begin, write the\\nfollowing basic vault policy to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"policy.hcl\"), \":\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"hcl\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-hcl\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-hcl\"\n  }, \"path \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"database/creds/readonly\\\"\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"{\"), \"\\n  \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token property\"\n  }, \"capabilities\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"=\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"[\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"read\\\"\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"]\"), \"\\n\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"}\")))), mdx(\"p\", null, \"Next, we'll write that policy to vault, and generate a corresponding access token:\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-bash\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"$ vault policy \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token function\"\n  }, \"write\"), \" apps policy.hcl\\n$ vault token create -policy\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"apps\\\"\"), \"\\n\\nKey                  Value\\n---                  -----\\ntoken                \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"..\"), \".\\ntoken_accessor       \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"..\"), \".\\ntoken_duration       768h\\ntoken_renewable      \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token boolean\"\n  }, \"true\"), \"\\ntoken_policies       \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"[\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"apps\\\"\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"default\\\"\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"]\"), \"\\nidentity_policies    \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"[\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"]\"), \"\\npolicies             \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"[\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"apps\\\"\"), \" \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token string\"\n  }, \"\\\"default\\\"\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token punctuation\"\n  }, \"]\")))), mdx(\"p\", null, \"Finally, we're ready to invoke vault to request a dynamic secret! Every time you run the command\\nbelow, Vault will respond with an entirely new username/password combo:\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", {\n    parentName: \"div\",\n    \"className\": \"language-bash\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token assign-left variable\"\n  }, \"VAULT_TOKEN\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"=\"), mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \"<\"), \"token from prior command\", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token operator\"\n  }, \">\"), \" vault \", mdx(\"span\", {\n    parentName: \"code\",\n    \"className\": \"token builtin class-name\"\n  }, \"read\"), \" database/creds/readonly\"))), mdx(\"p\", null, \"Congratulations! You've successfully setup dynamic credentialing in Vault. Now, every service that\\nneeds access to your postgres DB can cite the same secret and each will be issued distinct,\\nindependent credentials. Used correctly, you'll be able to distribute service to peer teams in a\\nmore portable way so long as everyone is sharing a vault instance.\"), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, mdx(\"a\", {\n    parentName: \"em\",\n    \"href\": \"https://learn.hashicorp.com/vault/secrets-management/sm-dynamic-secrets\"\n  }, \"Special thanks to the Hashicorp team for maintaining such excellent documentation and tutorials!\"))), mdx(\"hr\", null), mdx(\"p\", null, \"Want to help inspire our own solution for dynamic credentialing that doesn't involve a broker like\\nVault? We're actively designing this feature for our microservices framework, and would love your\\ninput!\"), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/architect-team/architect-cli/issues/225\"\n  }, \"Join the conversation on Github\")));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"In my last post we talked about\n how to leverage secret managers to safely store and cycle application credentials \nin production. In this post we're going to take the concept of credential cycling a…","tableOfContents":{"items":[{"url":"#why-we-need-dynamic-credentialing","title":"Why we need dynamic credentialing"},{"url":"#implemeting-dynamic-credentialing-with-hashicorp-vault","title":"Implemeting dynamic credentialing with Hashicorp Vault"}]},"frontmatter":{"title":"How dynamic credentialing makes apps portable","description":null,"author":"David Thor","date":"2020-06-04","image":{"childImageSharp":{"gatsbyImageData":{"layout":"constrained","images":{"fallback":{"src":"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/19703/vault-dynamic-credentialing.jpg","srcSet":"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/3e58d/vault-dynamic-credentialing.jpg 250w,\n/static/f7fabfb5ee8ad2e59af0794d20f3ecec/1cb73/vault-dynamic-credentialing.jpg 500w,\n/static/f7fabfb5ee8ad2e59af0794d20f3ecec/19703/vault-dynamic-credentialing.jpg 1000w","sizes":"(min-width: 1000px) 1000px, 100vw"},"sources":[{"srcSet":"/static/f7fabfb5ee8ad2e59af0794d20f3ecec/5e279/vault-dynamic-credentialing.webp 250w,\n/static/f7fabfb5ee8ad2e59af0794d20f3ecec/46b0f/vault-dynamic-credentialing.webp 500w,\n/static/f7fabfb5ee8ad2e59af0794d20f3ecec/cccbf/vault-dynamic-credentialing.webp 1000w","type":"image/webp","sizes":"(min-width: 1000px) 1000px, 100vw"}]},"width":1000,"height":272}}}}},"next":null,"previous":null}]}},"pageContext":{"slug":"how-dynamic-credentialing-makes-apps-portable"}},
    "staticQueryHashes": ["764694655"]}