{"id":37113426,"url":"https://github.com/nikogura/keymaster","last_synced_at":"2026-01-14T13:22:59.129Z","repository":{"id":43832614,"uuid":"220102624","full_name":"nikogura/keymaster","owner":"nikogura","description":"A tool for configuring Hashicorp Vault for Managed Secrets","archived":false,"fork":false,"pushed_at":"2024-03-30T20:27:43.000Z","size":315,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-06-21T14:37:40.924Z","etag":null,"topics":["security"],"latest_commit_sha":null,"homepage":"https://github.com/nikogura/keymaster","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikogura.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-06T22:30:42.000Z","updated_at":"2024-06-21T14:37:40.925Z","dependencies_parsed_at":"2024-03-30T19:44:29.136Z","dependency_job_id":"abf42faa-8adf-4967-82dc-15a6738628bd","html_url":"https://github.com/nikogura/keymaster","commit_stats":null,"previous_names":["nikogura/keymaster","scribd/keymaster"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nikogura/keymaster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fkeymaster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fkeymaster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fkeymaster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fkeymaster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikogura","download_url":"https://codeload.github.com/nikogura/keymaster/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fkeymaster/sbom","scorecard":{"id":687535,"data":{"date":"2025-08-11","repo":{"name":"github.com/nikogura/keymaster","commit":"dd50932597a3511802bf9dd732aca8e912b90265"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Code-Review","score":2,"reason":"Found 5/20 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T01:20:02.019Z","repository_id":43832614,"created_at":"2025-08-22T01:20:02.020Z","updated_at":"2025-08-22T01:20:02.020Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28421144,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:47:48.104Z","status":"ssl_error","status_checked_at":"2026-01-14T10:46:19.031Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["security"],"created_at":"2026-01-14T13:22:58.395Z","updated_at":"2026-01-14T13:22:59.104Z","avatar_url":"https://github.com/nikogura.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Keymaster\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/nikogura/keymaster)](https://goreportcard.com/report/github.com/nikogura/keymaster)\n\n[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/nikogura/secrets/pkg/keymaster)\n\n## Overview\nThis repo contains a library that configures your secrets provider for something called \"Managed Secrets\".\n\nManaged Secrets are an _interface_ on your secrets provider. HashiCorp Vault is the reference implementation, but there's nothing stopping us from adding modules for AWS's Secrets Manager, SSM Parameter Store, or any other storage backend. \n\nThe idea behind Managed Secrets is that your secrets are `managed`.  Users do not need to know where the secrets are stored within the backend, how it's configured, or even what it is. They don't need to know anything about the backend at all. What's more, the backend could be swapped out at any time and nobody should notice or care.\n\n## Why Manage Secrets?\n\nSecrets management is an important job, but it sucks.  Why does it suck?\n\nFirst off, anyone who's actually run/managed a secrets system knows that making sure your app has the secrets it needs is just the tip of the iceberg.  Yeah, that's all the developers care about, and that's all most people think of.  Just about any solution can provide for that use case.\n\nFor the unsung heroes who maintain the system however, there's more.  What?  Here's a short list:\n\n* Audit (who has access to what?)\n\n* Logging (Who accessed what when?)\n\n* 'Rotation' (i.e. changing secrets)\n\n* Granting of access\n\n* Revocation of access\n\n* Generating hard to guess secrets\n\nThe problem with the above tasks is, they're necessary, but they're time consuming and inglorious, so most of the time, they _don't get done_.\n\nThis is the point of Managed Secrets.  Make the necessary painless, so you have a chance at actually doing it.\n\n## What are Secrets?\n\nSecrets are defined as string values that must be kept from disclosure to unauthorized entities.\n\nSecrets are key-value pairs that are owned by a Team. One secret 'key' has multiple values, one for each Environment (e.g., development, staging, or production, though there is no limit on the names or numbers of environments). The `secrets` client can be configured to be environmentally aware based on CIDRs of client machines, and can automatically return the appropriate value for an Environment. You can specify different secrets for different environments, or just use the same secret name for all environments.\n\nYou gain access to Secrets via Roles. The Roles define which Principal can access which Secret in a given Environment. While Roles have no functional significance in terms of which Principals have access to which Secrets, and it is possible to put all such combinations inside a single Role, Roles function as an administrative aid to keep specified combinations of Principals, Secrets, and Environments logically grouped together for human interpretation.\n\nThe details of your client application will determine how you attach a Principal identity to that client. If using an IAM role as a Principal in the 'iam realm' (see below), for example, you could attach the IAM role to an EC2 instance to allow all applications on the instance to access your Secrets.\n\nEach Secret has a 'generator' which can create and recreate the value of the Secret in each Environment (with the exception of static secret values, which are manually entered by an admin; see below). This is used to initially provision a Secret, and to rotate it as needed.\n\nUltimately, access to Secrets is controlled entirely by human code review for changes to this repo. As an example, developers on Team A can request access to Secrets owned by Team B simply by creating a Role in Team B's yaml file which provides access to that Secret to a principal controlled by Team A, such as an IAM role. There are no additional automated controls that prevent access from being granted. The only control is a human one: an admin will confirm with Team B that they intend to grant access to one of their secrets. This is a deliberate design feature. It is also something that could absolutely be used by evil conspirators on different teams. However well/poorly code review is handled will determine how 'safe' secrets access really is. Can everyone get together and agree that everyone gets access to everything? They sure can. Is that a good idea? In a production environment, probably not.\n\n## Capabilities\n\nBased on the contents of a config file, these libs do the following:\n\n* Defines Secrets and their Generators for a Team.\n\n* Generate Secrets for a Team in each Environment, storing the Secrets in Vault. \n\n* Creates Vault Policies allowing Principals to access the above Secrets in each Environment.\n\n* Creates Roles per Team, generating Vault Auth endpoints allowing the `secrets` client or any other Vault savvy user to authenticate to Vault and get a token.\n\n* Roles have 'Realms' which are computing environments.  Each Realm configures a different flavor of Authentication backend.  Choices are 'k8s', 'iam', and 'tls'.\n\n* Does *not* create the per team secrets engines in Vault.  That has to be done manually by a Vault Admin.  This is deliberate, and allows `keymaster` to run with limited permissions (creating new secrets engines would require `keymaster` to run with root permissions).\n\n* At present, CA engines are general purpose - not per Team.\n\n## Other Components\n\nThis repo contains the libraries behind https://github.com/scribd/keymaster-cli.  `keymaster-cli` would be run against a set of config files as described above to configure Vault for Managed Secrets.\n\nAn example client for Managed Secrets is https://github.com/scribd/secrets.  It leverages libraries in https://github.com/scribd/vault-authenticator to attempt parallel login methods to Vault, and then grab secrets from your Role.\n\nUnder Managed Secrets, your users take your version of `secrets`, and either bake it into your containers, or use a dynamic binary system such as [dbt](https://github.com/nikogura/dbt) to inject `secrets` into containers at runtime.\n\nWith `secrets` providing your access, and `keymaster-cli` configuring Vault for you, you can make Secrets for your organization a self-service proposition while you do more interesting things.\n\n## Static Secrets\n\nSome Secrets cannot be generated, and must be manually placed into the storage backend. Third party API credentials are a good example of such 'static' secrets.\n\nIn the case of static secrets, the appropriate 'bucket' will be created in Vault when a configuration is merged, but any values will be an empty string. Note, however, that the Generator that creates values for other types of Secrets still operates on the storage bucket, and also creates a 'generator' value string for use in comparing buckets created at different times.\n\nAlthough not strictly necessary, it is probably easier to use LDAP authentication for human users for entering static secrets manually. If you have another form of human user authentication configured for Vault, that works, too. The policy authorizations to secret paths for any authentication methods aside from IAM, Kubernetes, or TLS certificate are NOT configured by Managed Secrets. Thus, while you are able to _create_ an (empty) static secret accessible by your applications via your yaml file, you will not be able to _set_ the value of the secret unless your personal username is manually given write permissions to the specific Vault path. (This is the only scenario in which some knowledge of the Vault backend, namely, the exact path at which secrets provisioned by `keymaster` are stored, is required, although all secrets belonging to a given theam are stored at the team_name/ path, making them easy to find.)\n\n## TLS Secrets\n\nTLS certificates are handled much in the same way as any other secret, but they are multi-valued.  \n\nFor a TLS Secret named 'foo.scribd.com', you should expect to find a 'foo.scribd.com.key', 'foo.scribd.com.crt', 'foo.scribd.com.serial', etc.  \n\nTLS certificate secrets are automatically renewed when they are near expiration. *N.B.: At the time of this writing, this has not been implemented. The code to regenerate exists, but it's not wired up to anything.*\n\nThe Roles defined in this repo have the power to _consume_ TLS Secrets, but they cannot _generate_ them. This is an important point. By separating generation from consumption, it severely limits the blast radius of a compromised application. The attacker can steal the credentials, but they cannot create new ones.\n\n\n# Sample Management Workflow\n\n## 1. Create Directory\n\nCreate a directory for your Team.  Put it under the path in this repo `secrets`.  \n\nName it whatever you like.  Only yaml files in the directory `secrets` in this repo are parsed and synced to Vault.  \n  \nIt's probably best to name the directory after your Team, but hey, you're the one that needs to keep track of it and communicate it to others.  Knock yourself out.\n\n## 2. Create Yaml File and Define Team Name\n\nUnder that directory, create a yaml file (example below). The file name doesn't matter here, either. Again, the author recommends you name the file after your Team, but it's only a suggestion.  \n\nEach file defines a Team. The `name` value at the top of this file will be the name of the Team's secret container. Even _this_ name doesn't matter. Only one Team is allowed per file, but each directory can have multiple files. Note, however, that spreading a single Team's info across multiple files is not currently supported; each file in a directory must contain a different Team name at the top.\n\n## 3. Define Secrets, Roles, and Environments\n\nIn your yaml file, define your Secrets, Roles, and Environments.  \n\nThe Roles allow specified Principals to read specified Secrets. As noted above, Roles are merely an administrative aid to keep specified combinations of Principals and Secrets logically grouped together. To associate a single Role with different Principals and/or grant access to different secret values in different Environments, make multiple Realm blocks (specifying 'realms', 'principals', and 'secrets') for the same Role name (the 'name' of the Role can optionally be restated for readability). See the example below for the 'app1' Role.\n\nEnvironments are merely the \"buckets\" that each secret is split into. If three different Environments are defined for a team, each secret will have three different buckets in which to place unique values for all the Secrets defined in the yaml, though they don't all need to be used. The names of the Environments can be anything, but the `secrets` binary can be customized to treat recognize certain environments by CIDR. When a client has a source IP in a CIDR that corresponds to one of these environments, `secrets` automatically recognizes the environment, and saves the calling process from needing to specify the `-e` flag with `secrets`.\n\n## 4. Add Realms to Roles\n\nRealms have 'types' ('k8s', 'iam', 'tls'), as well as 'principals'.  The 'identifiers' list is only used by the 'k8s' type and is the name of the Kubernetes Cluster.\n  \nThe possible 'principals' are:\n  * the ARNs of the IAM role (or IAM user) for the 'iam' type\n  * the FQDN of the host for the 'tls' type\n  * the namespace for the 'k8s' type (the `secrets` tool uses the `default` service account in the specified namespace to authenticate)\n\nNote: a Managed Secrets Role (defined by this README) is _unrelated_ to an AWS IAM role (a technical AWS term). A single IAM role could be specified as a Principal in multiple Managed Secrets Roles. However, keeping the scope of both types of roles the same (i.e., logically mapping one Managed Secrets Role to one AWS IAM role) makes it easier to keep track of which IAM roles have access to which Secrets. Giving them each the same name helps, too.\n\nNote: although LDAP authentication to Vault is possible, it isn't one of the authentication methods that is configured by Managed Secrets automation. A Vault admin must manually configure a specific Vault policy to allow LDAP authentication. How you set this up is dependent on how you assign users to LDAP groups.\n\n## 5. Create a Pull Request\n\nOnce you have your secrets defined, open a PR to master. Scribd configures its CI to check yaml files for syntax when a PR is opened.\n\n## 6. Get it Reviewed.\n\nGet someone to review your PR.\n\nKeeping it all secure and sane is _everyone's_ responsibility.\n\n## 7. Onboard with a Vault admin  \n\nMake a Jira task, send a Slack message, etc.\n\n**_Some manual setup must be completed by a Vault admin before a new Managed Secrets configuration can be provisioned_**. This was a deliberate choice (see \"Capabilities\" section, above).\n\n## 8. Merge your PR to Master\n\nA Vault admin must configure the storage for your secrets _before_ you merge to master or CD will fail. See Step 7.\n\n\n## Config Example\n\nThis example defines a Team\n\n    ---\n    name: test-team1                        # The name of the Team\n    secrets:                                # Definitions of the Secrets in the Team\n      - name: foo\n        generator:\n          type: alpha                       # A 10 digit alphanumeric secert\n          length: 10\n\n      - name: bar\n        generator:\n          type: hex                         # A 12 digit hexadecimal secret\n          length: 12\n\n      - name: baz\n        generator:\n          type: uuid                        # A UUID secret\n\n      - name: wip\n        generator:\n          type: chbs\n          words: 6                          # A 6 word 'correct-horse-battery-staple' secret.  6 random commonly used words joined by hyphens.\n\n      - name: zoz\n        generator:\n          type: rsa\n          blocksize: 2048                   # A RSA keypair expressed as a secret (Not currently supported)\n\n      - name: blort                         # I've clearly run out of standard throwaway names here.\n        generator:\n          type: static                      # Static secrets have to be placed manually.  API keys are a good use case for Static Secrets.\n\n      - name: foo.scribd.com\n        generator:\n          type: tls                         # A TLS Certificate/ Private Key expressed as a secret.\n          cn: foo.scribd.com\n          ca: service                       # This cert is created off of the 'service' CA\n          sans:\n            - bar.scribd.com                # Allowed alternate names for this cert\n            - baz.scribd.com\n          ip_sans:                          # IP SANS allow you to use TLS and target an IP directly\n            - 1.2.3.4\n\n    roles:                                  # Your Secret Roles  This is what you authenticate to in order to access the Secrets above.\n      - name: app1                          # A role unimaginatively named 'app1'; NOT case sensitive\n        realms:\n          - type: k8s                       # legal types are 'k8s', 'tls', and 'iam'\n            identifiers:\n              - bravo                       # for k8s, this is the name of the cluster.  Has no meaning for other realms.\n            principals:\n              - app1                        # for k8s, this is the namespace that's allowed to access the secret\n            environment: production         # each role maps to a single environment.  Which one is this?\n\n          - type: tls                       # 'tls' specifies authentication by client certs (generally only applies to SL hosts)\n            principals:\n              - foo.scribd.com              # for tls, this is the FQDN of a host that possesses a root CA-signed certificate\n            environment: development        # when this host connects, it gets development secrets\n\n          - type: iam                       # only works if the client has an IAM identity, which usually means the client\n            principals:                     # is running inside AWS\n              - \"arn:aws:iam::\u003cteam-stage-account\u003e:role/foo\"\n              - \"arn:aws:iam::\u003cteam-stage-account\u003e:user/foo\"\n              - \"arn:aws:iam::\u003cteam-stage-account\u003e:role/foo-*\" # wildcards allowed!\n              - \"arn:aws:sts::\u003cteam-stage-account\u003e:assumed-role/foo/*\" # allows entities that can assume the role to authenticate\n            environment: staging            # each principal auths to a role in a single environment.\n\n        secrets:\n          - name: foo                       # These Secrets are defined above. No 'team' in the config means 'team from this file'\n          - name: wip\n          - name: baz\n            team: test-team2                # This secret is owned by another Team.\n\n      - name: app1                          # The \"realms:\" type and/or the principals can be modified in repeated blocks beneath role names\n        realms:                             # to give the same (or different) principals access to different versions of the same (or different)\n          - type: iam                       # secrets in different environments. This example is a \"maximum\" differential of\n            principals:                     # principal, environment, and secret names, but it is also possible to change just\n              - \"arn:aws:iam::\u003cteam-prod-account\u003e:role/foo\" # one or two of these parameters\n            environment: production         # Restating the \"name\" and \"realms:\" lines is not necessary, but increases readability\n\n        secrets:\n          - name: blah                      # The top two secrets are completely different than \"foo\" and \"wip\", above\n          - name: bloo\n          - name: wip                       # This is the same secret as above, but refers to the \"production\" version\n                                            #  instead of the \"staging\" version\n\n\n    environments:\n      - production\n      - staging\n      - development      \n\n## Admin Notes\n\nThe machine running `keymaster` requires broad Vault permissions to configure secrets. We don't list them here, but the Vault API operations conducted by `keymaster` are readily apparent in the code. Additionally, `keymaster` requires create and update access to each new secrets engine enabled (and all subpaths), the AWS authentication method path, and each new Kubernetes authentication method path created.\n\nThe libraries cannot enable Vault secrets engines. The root token is required for this operation. Relying on a human user to enable a secrets engine both removes the requirement for the libraries to be run as root, and forces a human to take an affirmative action to approve an onboarding of a new team.\n\nEvery time a new team is onboarded to Managed Secrets, an admin will need to manually run:\n\n    vault secrets enable -version=2 -path=\u003cteam name\u003e -description=\"\u003cteam name\u003e Managed Secrets\" kv\n    \nKeymaster does not _remove_ deprecated secrets or Managed Secrets roles. Although it would likely be trivial to fork `keymaster` and add functionality to automatically delete secrets and roles based solely on their removal from a yaml file, we do not recommend doing this. Secret values and secret access authorization configurations are some of the most sensitive data in any environment. Retaining deletion authorization for a human user reduces the risk of loss of potentially irreplaceable information due to compromise of a CD system.\n\nThis isn’t necessary for the new or renamed role or secret to work, but over time, it will lead to a proliferation of unused roles and secret paths inside the storage backend, which will make auditing (and troubleshooting!) more difficult.\n\nIf a Managed Secrets role or secret name has changed or removed, you should manually remove the access authorization and secret. Using the reference Vault backend, this requires deleting the Vault policy corresponding to the deprecated role and the environment(s) for which it authorized secret access, and/or the old secret paths: \n\n    $ vault policy delete \u003cteam-name\u003e-\u003cold-role-name\u003e-\u003cenvironment\u003e\n\n    $ vault kv destroy \u003cteam-name\u003e/\u003csecret-name\u003e\n\nBefore removing a secret path with `kv destroy`, ensure you have moved the secret values to the new secret path. If the secret value will no longer be used, but you wish to retain the value and version history, use `vault kv delete \u003cteam-name\u003e/\u003csecret-name\u003e`\n\n\nUsing the IAM and Kubernetes authentication methods requires some understanding of these systems that is beyond the scope of Managed Secrets. HashiCorp has voluminous documentation on reference architectures for these authentication methods. Some necessary, but possibly not sufficient, key points for you to implement Managed Secrets using Vault as a storage backend:\n\n### IAM Authentication\n\nInitial points to avoid confusion:\n- \"Vault permissions\" and \"IAM permissions\" are two different things, and we've tried to make clear which one we're talking about below\n- Some necessary Vault permissions and _all_ necessary IAM permissions are _manually configured_, i.e., **_`keymaster` does not configure IAM permissions or any other AWS infrastructure_**\n\nMorever, although it would likely be trivial to fork `keymaster` and add functionality to automatically configure AWS as well as Vault based solely on the yaml file, we do not recommend doing this. As with secret and role deletion, above, separating the Vault configuration from the AWS configuration creates a barrier between catastrophic compromise of your secrets. It also lends itself to having a human admin in the loop reviewing secret setups of various developer teams.\n\nThe machine that runs Vault (and therefore Vault itself) must be able to call `sts:GetCallerIdentity` in the AWS account in which it exists (this is configured by the current [HashiCorp reference Terraform](https://github.com/scribd/terraform-vault)). Vault must also be able to assume an IAM role in the account that contains the IAM principal specified in the Managed Secrets yaml. This assumed role must be granted the `ec2:DescribeInstances`,`iam:GetInstanceProfile`,`iam:GetUser`, and `iam:GetRole` permissions. This assumed role, its permissions, _and_ the permission for Vault to assume it must be configured in AWS, independently of Managed Secrets. Additionally, this role must be [manually specified in Vault](https://www.vaultproject.io/api-docs/auth/aws#create-sts-role) as an \"STS role\".\n\nA reference architecture and workflow is: \n\n1) an EC2 machine running `keymaster` in the same (ideally, dedicated) AWS account in which Vault runs, which \n2) authenticates to Vault using IAM authentication (manually configured outside of Managed Secrets) and \n3) grants `keymaster` the Vault permission to make the appropriate API call to Vault to configure the specified IAM principal to retrieve secrets from Vault\n4) Vault uses its default IAM role (from reference Terraform) with an IAM permission policy (manually configured) to assume an IAM role (manually configured, we'll call it the `VaultLookup` IAM role) in the AWS account that contains the specified IAM principal; this `VaultLookup` IAM role must be manually specified in Vault as an \"STS role\" (see above)\n5) Vault makes various AWS API calls (using the `VaultLookup` role it has assumed) to validate that the specified IAM principal exists\n\nIf you fail to specify the `VaultLookup` role as an \"STS role\" in Vault, you'll receive the following error, which is unhelpful unless you are very familiar with AWS IAM terminology (\"internal ID\") and also understand the mechanics of how Vault integrates with IAM (using a \"client\"):\n\n    URL: PUT https://vault.foo.com/v1/auth/aws/role/specified-IAM-principal\n    Code: 400. Errors:\n\n    unable to resolve ARN \"arn:aws:iam::\u003cid of account containing IAM principal\u003e:role/specified-IAM-principal\" to internal ID: unable to fetch client for account ID \"\u003cid of account containing IAM principal\u003e\" -- default client is for account \"\u003cVault account id\u003e\"\n\n### Kubernetes Authentication\n\nEach K8s authentication method is [manually enabled in Vault](https://www.vaultproject.io/docs/auth/kubernetes#configuration) at a unique path. This path must be added to the Vault permissions granted to `keymaster`.\n\n### TLS Authentication\n\nA CA-signed certificate must be hardcoded into your private fork of [`keymaster-cli`]() in order for TLS authentication methods to be configured.\n\nManaged Secrets currently only configures the `allowed_common_names` parameter in Vault based on the principals specified in a team’s yaml. It does not configure other restrictions, such as `token_bound_cidrs`. Additional restrictions have to be manually configured after Managed Secrets has already configured the TLS role. For example, using the example yaml configuration above:\n\n    $ curl -XPOST -d @payload.json --header \"X-Vault-Token: $(\u003c .vault-token)\" https://vault.foo.com/v1/auth/cert/certs/test-team1-app1\n\nwith `payload.json` as:\n\n    {\n      \"token_bound_cidrs\": [\n        \"10.1.2.3\",\n        \"10.2.3.4\",\n        \u003cadditional IP addresses\u003e\n        ]\n    }\n\nThere are several other restrictions that can be configured manually. See Vault documentation. We'd like to extend `keymaster`'s ability to automatically configure these additional parameters. Make a PR!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikogura%2Fkeymaster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikogura%2Fkeymaster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikogura%2Fkeymaster/lists"}