open-vault/website/content/guides/secret-mgmt/static-secrets.mdx

635 lines
18 KiB
Plaintext
Raw Normal View History

2018-01-09 23:06:00 +00:00
---
layout: guides
page_title: Static Secrets - Guides
sidebar_title: Static Secrets
2018-01-09 23:06:00 +00:00
description: |-
Vault supports generating new unseal keys as well as rotating the underlying
encryption keys. This guide covers rekeying and rotating Vault's encryption
keys.
---
# Static Secrets - Key/Value Secret Engine
2018-01-09 23:06:00 +00:00
Vault can be used to store any secret in a secure manner. The secrets may be
2018-01-09 23:06:00 +00:00
SSL certificates and keys for your organization's domain, credentials to connect
2018-02-01 17:50:59 +00:00
to a corporate database server, etc. Storing such sensitive information in
2018-01-09 23:06:00 +00:00
plaintext is not desirable. This guide demonstrates the use case of Vault as a
Secret Storage.
## Reference Material
- [Key/Value Secret Engine](/docs/secrets/kv)
- [Key/Value Secret Engine API](/api/secret/kv)
- [Client libraries](/api/libraries) for Vault API for commonly used languages
2018-01-09 23:06:00 +00:00
## Estimated Time to Complete
10 minutes
## Personas
The end-to-end scenario described in this guide involves two personas:
- **`devops`** with privileged permissions to write secrets
- **`apps`** reads the secrets from Vault
2018-01-09 23:06:00 +00:00
## Challenge
Consider the following situations:
- Developers use a single admin account to access a third-party app
(e.g. Splunk) and anyone who knows the user ID and password can log in as an
admin
- SSH keys to connect to remote machines are shared and stored as a plaintext
- API keys to invoke external system APIs are stored as a plaintext
- An app integrates with LDAP, and its configuration information is in a
plaintext
2018-02-01 17:50:59 +00:00
Organizations often seek an uniform workflow to securely store this sensitive
information.
2018-01-09 23:06:00 +00:00
## Solution
2018-02-01 17:50:59 +00:00
Vault as centralized secret storage to secure any sensitive information. Vault
encrypts these secrets using 256-bit AES in GCM mode with a randomly generated
nonce prior to writing them to its persistent storage. The storage backend never
sees the unencrypted value, so gaining access to the raw storage isn't enough to
access your secrets.
2018-01-17 01:16:20 +00:00
~> **NOTE:** This guide demonstrates secret management using [v2 of the KV
secret engine](/docs/secrets/kv/kv-v2).
2018-01-09 23:06:00 +00:00
## Prerequisites
To perform the tasks described in this guide, you need to have a Vault
environment. Refer to the [Getting
Started](/intro/getting-started/install) guide to install Vault. Make sure
2018-01-24 00:22:17 +00:00
that your Vault server has been [initialized and
unsealed](/intro/getting-started/deploy).
2018-01-09 23:06:00 +00:00
### Policy requirements
-> **NOTE:** For the purpose of this guide, you can use **`root`** token to work
with Vault. However, it is recommended that root tokens are only used for just
enough initial setup or in emergencies. As a best practice, use tokens with
appropriate set of policies based on your role in the organization.
To perform all tasks demonstrated in this guide, your policy must include the
following permissions:
```shell
# Write and manage secrets in key/value secret engine
path "secret/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Create policies to permit apps to read secrets
path "sys/policy/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Create tokens for verification & test
path "auth/token/create" {
2018-01-25 02:10:56 +00:00
capabilities = [ "create", "update", "sudo" ]
}
```
If you are not familiar with policies, complete the
[policies](/guides/identity/policies) guide.
2018-01-09 23:06:00 +00:00
## Steps
This guide demonstrates the basic steps to store secrets using Vault. The
2018-01-09 23:06:00 +00:00
scenario here is to store the following secrets:
- API key (Google API)
- Root certificate of a production database (MySQL)
To store your API key within the configured physical storage for Vault, use the
**key/value** secret engine via **`secret/`** prefixed path.
2018-01-09 23:06:00 +00:00
-> Key/Value secret engine passes through any operation back to the configured
2018-01-09 23:06:00 +00:00
storage backend for Vault. For example, if your Vault server is configured with
Consul as its storage backend, a "read" operation turns into a read from Consul
at the same path.
You will perform the following:
1. [Enable KV Secret Engine v2](#step1)
1. [Store the Google API key](#step2)
1. [Store the root certificate for MySQL](#step3)
1. [Generate a token for apps](#step4)
1. [Retrieve the secrets](#step5)
New Docs Website (#5535) * conversion stage 1 * correct image paths * add sidebar title to frontmatter * docs/concepts and docs/internals * configuration docs and multi-level nav corrections * commands docs, index file corrections, small item nav correction * secrets converted * auth * add enterprise and agent docs * add extra dividers * secret section, wip * correct sidebar nav title in front matter for apu section, start working on api items * auth and backend, a couple directory structure fixes * remove old docs * intro side nav converted * reset sidebar styles, add hashi-global-styles * basic styling for nav sidebar * folder collapse functionality * patch up border length on last list item * wip restructure for content component * taking middleman hacking to the extreme, but its working * small css fix * add new mega nav * fix a small mistake from the rebase * fix a content resolution issue with middleman * title a couple missing docs pages * update deps, remove temporary markup * community page * footer to layout, community page css adjustments * wip downloads page * deps updated, downloads page ready * fix community page * homepage progress * add components, adjust spacing * docs and api landing pages * a bunch of fixes, add docs and api landing pages * update deps, add deploy scripts * add readme note * update deploy command * overview page, index title * Update doc fields Note this still requires the link fields to be populated -- this is solely related to copy on the description fields * Update api_basic_categories.yml Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages. * Add bottom hero, adjust CSS, responsive friendly * Add mega nav title * homepage adjustments, asset boosts * small fixes * docs page styling fixes * meganav title * some category link corrections * Update API categories page updated to reflect the second level headings for api categories * Update docs_detailed_categories.yml Updated to represent the existing docs structure * Update docs_detailed_categories.yml * docs page data fix, extra operator page remove * api data fix * fix makefile * update deps, add product subnav to docs and api landing pages * Rearrange non-hands-on guides to _docs_ Since there is no place for these on learn.hashicorp, we'll put them under _docs_. * WIP Redirects for guides to docs * content and component updates * font weight hotfix, redirects * fix guides and intro sidenavs * fix some redirects * small style tweaks * Redirects to learn and internally to docs * Remove redirect to `/vault` * Remove `.html` from destination on redirects * fix incorrect index redirect * final touchups * address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Personas Introduction](/img/vault-static-secrets.png)
Step 1 through 4 are performed by `devops` persona. Step 5 describes the
commands that `apps` persona runs to read secrets from Vault.
2018-01-09 23:06:00 +00:00
### Step 1: Enable KV Secret Engine v2 ((#step1))
(**Persona:** devops)
Currently, when you start the Vault server in [**dev
mode**](/intro/getting-started/dev-server#starting-the-dev-server), it
automatically enables **v2** of the KV secret engine at **`secret/`**. If you
start the Vault server in non-dev mode, the default is v1.
If you are running the server in **dev** mode, skip to [Step 2](#step2).
Otherwise, you must perform one of the following:
- Option 1: Upgrade the v1 of KV secret engine to v2
- Option 2: Enable the KV secret engine v2 at a different path
#### CLI command
Option 1: To upgrade from **v1** to **v2**:
```shell-session
$ vault kv enable-versioning secret/
```
Option 2: To enable the KV secret engine v2 at **`secret_v2/`**:
```shell-session
$ vault secrets enable -path=secret_v2/ kv-v2
```
Or
```shell-session
$ vault secrets enable -path=secret_v2/ -version=2 kv
```
#### API call using cURL
Option 1: To upgrade from **v1** to **v2**:
```shell-session
$ curl --header "X-Vault-Token: <TOKEN>" \
--request POST \
--data @payload.json \
<VAULT_ADDRESS>/v1/sys/mounts/secret/tune
```
Where `<TOKEN>` is your valid token, and `<VAULT_ADDRESS>` is where your vault
server is running. The `payload.json` includes the version information.
**Example:**
```shell-session
$ cat payload.json
{
"options": {
"version": "2"
}
}
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/sys/mounts/secret/tune
```
Option 2: To enable the KV secret engine v2 at **`secret_v2/`**:
```shell-session
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data '{"type":"kv-v2"}' \
https://127.0.0.1:8200/v1/sys/mounts/secret_v2
```
~> **NOTE:** This guide assumes that you are working with KV secret engine
**v2** which is mounted at **`secret/`**.
### Step 2: Store the Google API key ((#step2))
(**Persona:** devops)
Everything after the **`secret/`** path is a key-value pair to write to the
secret engine. You can specify multiple values. If the value has a space, you
need to surround it with quotes. Having keys with spaces is permitted, but
strongly discouraged because it can lead to unexpected client-side behavior.
2018-01-09 23:06:00 +00:00
Let's assume that the path convention in your organization is
**`secret/<OWNER>/apikey/<APP>`** for API keys. To store the Google API key used
2018-03-20 18:54:10 +00:00
by the engineering team, the path would be `secret/eng/apikey/Google`. If you
have an API key for New Relic owned by the DevOps team, the path would look like
2018-01-24 00:22:17 +00:00
`secret/devops/apikey/New_Relic`.
2018-01-09 23:06:00 +00:00
#### CLI command
2018-01-24 00:22:17 +00:00
To create key/value secrets:
```shell-session
$ vault kv put secret/<PATH> <KEY>=VALUE>
2018-01-09 23:06:00 +00:00
```
The `<PATH>` can be anything you want it to be, and your organization should
decide on the naming convention that makes most sense.
**Example:**
```shell-session
$ vault kv put secret/eng/apikey/Google key=AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI
2018-01-09 23:06:00 +00:00
Success! Data written to: secret/eng/apikey/Google
```
2018-01-24 00:22:17 +00:00
The secret key is "key" and its value is "AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI" in
this example.
2018-01-09 23:06:00 +00:00
#### API call using cURL
Use `/secret/data/<PATH>` endpoint to create secrets:
2018-01-18 01:39:21 +00:00
```shell-session
2018-01-24 00:22:17 +00:00
$ curl --header "X-Vault-Token: <TOKEN>" \
--request POST \
--data @payload.json \
<VAULT_ADDRESS>/v1/secret/data/<PATH>
2018-01-18 01:39:21 +00:00
```
Where `<TOKEN>` is your valid token, and `secret/data/<PATH>` is the path to
your secrets. The [`payload.json`](/api/secret/kv/kv-v2#parameters-2)
contains the parameters to invoke the endpoint.
2018-01-09 23:06:00 +00:00
**Example:**
```shell-session
$ tee payload.json <<EOF
{
"data": {
"key": "AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI"
}
}
EOF
2018-01-24 00:22:17 +00:00
$ curl --header "X-Vault-Token: ..." --request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/secret/data/eng/apikey/Google
2018-01-09 23:06:00 +00:00
```
2018-01-24 00:22:17 +00:00
The secret key is "key" and its value is
"AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI" in this example.
2018-01-09 23:06:00 +00:00
### Step 3: Store the root certificate for MySQL ((#step3))
(**Persona:** devops)
2018-01-09 23:06:00 +00:00
2018-01-24 00:22:17 +00:00
For the purpose of this guide, generate a new self-sign certificate using
[OpenSSL](https://www.openssl.org/source/).
2018-01-18 01:39:21 +00:00
```shell-session
2018-01-24 00:22:17 +00:00
$ openssl req --request509 -sha256 -nodes -newkey rsa:2048 -keyout selfsigned.key -out cert.pem
2018-01-18 01:39:21 +00:00
```
Generated `cert.pem` file:
```plaintext
-----BEGIN CERTIFICATE-----
MIIDSjCCAjICCQC47CQCg4u0kDANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xFDASBgNVBAMM
C2V4YW1wbGUuY29tMR0wGwYJKoZIhvcNAQkBFg5tZUBleGFtcGxlLmNvbTAeFw0x
ODAxMTcwMTMzNThaFw0xODAyMTYwMTMzNThaMGcxCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEUMBIGA1UEAwwLZXhhbXBs
ZS5jb20xHTAbBgkqhkiG9w0BCQEWDm1lQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1cPTXpnOeUXU4tgblNLSS2rcA7eIqzc6gnMY
Sh76WxOaN8VncyJw89/28QYOSYeWRn4fYywbPhHpFmrY6+1gW/8y0+Yoj7TL2Mvs
5m1ZH9eOS6kcnnX/lr+HCfJpTHokKk/Vxr0/p6agkdZq0OYMPAmiuw1M4afd5abm
8s5R99b4DgQyNvRYJp+JMddz2cM8t2AKQH4rq2NEf/GBHqHpHKmaxTyX5Rh7zg/g
WJQ/DjxUVLpbRy+soiUJTZzamrO0iu9fcww+1Q4TZsMWizA4ChQFI7uegKkZ2Alv
SNItsv01FQH3IB7pNWuna3IXXY789R0Qp0Ha5ScryVc9syg4cQIDAQABMA0GCSqG
SIb3DQEBCwUAA4IBAQBtUcuwL0rS/uhk4v53ALF+ryRoLF93wT+O9KOvK15Pi1dX
oZ9yxu5GOGi59womsrDs1vNrBuIQNVQ69dbUYu1LkhgQGDUWQb8JpCp++WHWTIeP
YTJ5C/Q1B3rXeQrVWPvO0bMCig+/G5DGtzZmKWMQGHhfOvSwrkA58YAwjC+rqexl
skA+hQ2JiU4bzIxvlPLBOUA/p+TgUKtdzPY3lxyDO2p7+8ZD56B0PoW87zNJYRcu
VdSr7er8UkUr5nVjcw/6MJeptmx6QaiHgTUSFf2HjFfzsBa/IY1VGr/8bOII+IFN
iYQTLBNG0/q/PZGeMX/RHxmCzZz/7wE0CDPMLbyf
-----END CERTIFICATE-----
```
**NOTE:** If you don't have OpenSSL, simply copy the above certificate and
save it as `cert.pem`.
2018-01-09 23:06:00 +00:00
#### CLI command
2018-01-24 00:22:17 +00:00
The command is basically the same as the Google API key example. Now, the path
convention for certificates is **`secret/<ENVIRONMENT>/cert/<SYSTEM>`**. To
store the root certificate for production MySQL, the path becomes
`secret/prod/cert/mysql`.
2018-01-09 23:06:00 +00:00
**Example:**
```shell-session
$ vault kv put secret/prod/cert/mysql cert=@cert.pem
2018-01-09 23:06:00 +00:00
```
This example reads the root certificate from a PEM file from the disk, and store
it under `secret/prod/cert/mysql` path.
2018-01-09 23:06:00 +00:00
> **NOTE:** Any value begins with "@" is loaded from a file.
2018-01-09 23:06:00 +00:00
#### API call using cURL
To perform the same task using the Vault API, pass the token in the request header.
**Example:**
```shell-session
2018-01-24 00:22:17 +00:00
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @cert.pem \
http://127.0.0.1:8200/v1/secret/data/prod/cert/mysql
2018-01-09 23:06:00 +00:00
```
> **NOTE:** Any value begins with "@" is loaded from a file.
2018-01-09 23:06:00 +00:00
### Step 4: Generate a token for apps ((#step4))
(**Persona:** devops)
To read the secrets, `apps` persona needs "read" permit on those secret engine
paths. In this scenario, the `apps` policy must include the following:
**Example:** `apps-policy.hcl`
```shell
# Read-only permit
path "secret/data/eng/apikey/Google" {
capabilities = [ "read" ]
}
# Read-only permit
path "secret/data/prod/cert/mysql" {
capabilities = [ "read" ]
}
```
#### CLI command
First create `apps` policy, and generate a token so that you can authenticate
as an `apps` persona, and read the secrets.
```shell
# Create "apps" policy
$ vault policy write apps apps-policy.hcl
Policy 'apps' written.
# Create a new token with app policy
$ vault token create -policy="apps"
Key Value
--- -----
token e4bdf7dc-cbbf-1bb1-c06c-6a4f9a826cf2
token_accessor 54700b7e--data828-a6c4-6141-96e71e002bd7
token_duration 768h0m0s
token_renewable true
token_policies [apps default]
```
Now, `apps` can use this token to read the secrets.
#### API call using cURL
First create an `apps` policy, and generate a token so that you can authenticate
as an `app` persona.
**Example:**
```shell
# Payload to pass in the API call
$ tee payload.json <<EOF
{
"policy": "path \"secret/data/eng/apikey/Google\" { capabilities = [ \"read\" ] ...}"
}
EOF
# Create "apps" policy
$ curl --header "X-Vault-Token: ..." --request PUT \
--data @payload.json \
2018-03-23 15:41:51 +00:00
http://127.0.0.1:8200/v1/sys/policy/apps
# Generate a new token with apps policy
$ curl --header "X-Vault-Token: ..." --request POST \
--data '{"policies": ["apps"]}' \
2018-03-23 15:41:51 +00:00
http://127.0.0.1:8200/v1/auth/token/create | jq
{
"request_id": "e1737bc8-7e51-3943-42a0-2dbd6cb40e3e",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": null,
"wrap_info": null,
"warnings": null,
"auth": {
"client_token": "1c97b03a-6098-31cf-9d8b-b404e52dcb4a",
"accessor": "b10a3eb7-15fe-1924-600e-403cfda34c28",
"policies": [
"apps",
"default"
],
"metadata": null,
"lease_duration": 2764800,
"renewable": true,
"entity_id": ""
}
}
```
Now, `apps` can use this token to read the secrets.
**NOTE:** For the purpose of this guide, you created a policy for `apps`
persona, and generated a token for it. However, in a real world, you may have
a dedicated `policy author`, or `admin` to write policies. Also, the
consumer of the API key may be different from the consumer of the root
certificate. Then each persona would have a policy based on what it needs to
access.
New Docs Website (#5535) * conversion stage 1 * correct image paths * add sidebar title to frontmatter * docs/concepts and docs/internals * configuration docs and multi-level nav corrections * commands docs, index file corrections, small item nav correction * secrets converted * auth * add enterprise and agent docs * add extra dividers * secret section, wip * correct sidebar nav title in front matter for apu section, start working on api items * auth and backend, a couple directory structure fixes * remove old docs * intro side nav converted * reset sidebar styles, add hashi-global-styles * basic styling for nav sidebar * folder collapse functionality * patch up border length on last list item * wip restructure for content component * taking middleman hacking to the extreme, but its working * small css fix * add new mega nav * fix a small mistake from the rebase * fix a content resolution issue with middleman * title a couple missing docs pages * update deps, remove temporary markup * community page * footer to layout, community page css adjustments * wip downloads page * deps updated, downloads page ready * fix community page * homepage progress * add components, adjust spacing * docs and api landing pages * a bunch of fixes, add docs and api landing pages * update deps, add deploy scripts * add readme note * update deploy command * overview page, index title * Update doc fields Note this still requires the link fields to be populated -- this is solely related to copy on the description fields * Update api_basic_categories.yml Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages. * Add bottom hero, adjust CSS, responsive friendly * Add mega nav title * homepage adjustments, asset boosts * small fixes * docs page styling fixes * meganav title * some category link corrections * Update API categories page updated to reflect the second level headings for api categories * Update docs_detailed_categories.yml Updated to represent the existing docs structure * Update docs_detailed_categories.yml * docs page data fix, extra operator page remove * api data fix * fix makefile * update deps, add product subnav to docs and api landing pages * Rearrange non-hands-on guides to _docs_ Since there is no place for these on learn.hashicorp, we'll put them under _docs_. * WIP Redirects for guides to docs * content and component updates * font weight hotfix, redirects * fix guides and intro sidenavs * fix some redirects * small style tweaks * Redirects to learn and internally to docs * Remove redirect to `/vault` * Remove `.html` from destination on redirects * fix incorrect index redirect * final touchups * address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Personas Introduction](/img/vault-static-secrets2.png)
### Step 5: Retrieve the secrets ((#step5))
(**Persona:** apps)
Using the token from [Step 4](#step4), read the Google API key, and root certificate for
MySQL.
2018-01-09 23:06:00 +00:00
#### CLI command
The command to read secret is:
```shell-session
$ vault kv get secret/<PATH>
2018-01-09 23:06:00 +00:00
```
**Example:**
```shell
# Authenticate with Vault using the generated token first
2018-01-31 17:27:14 +00:00
$ vault login e4bdf7dc-cbbf-1bb1-c06c-6a4f9a826cf2
Successfully authenticated! You are now logged in.
token: e4bdf7dc-cbbf-1bb1-c06c-6a4f9a826cf2
token_duration: 2764277
token_policies: [apps default]
# Read the API key
$ vault kv get secret/eng/apikey/Google
2018-01-09 23:06:00 +00:00
Key Value
--- -----
refresh_interval 768h0m0s
key AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI
```
To return the key value alone, pass `-field=key` as an argument.
```shell-session
$ vault kv get -field=key secret/eng/apikey/Google
2018-01-09 23:06:00 +00:00
AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI
```
#### Root certificate example:
The command is basically the same:
```shell-session
$ vault kv get -field=cert secret/prod/cert/mysql
2018-01-09 23:06:00 +00:00
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA6E2Uq0XqreZISgVMUu9pnoMsq+OoK1PI54rsA9vtDE6wiRk0GWhf5vD4DGf1
...
```
#### API call using cURL
Use `secret/` endpoint to retrieve secrets from key/value secret engine:
```shell-session
$ curl --header "X-Vault-Token: <TOKEN_FROM_STEP4>" \
--request Get \
<VAULT_ADDRESS>/v1/secret/data/<PATH>
```
2018-01-09 23:06:00 +00:00
**Example:**
Read the Google API key.
```shell-session
$ curl --header "X-Vault-Token: 1c97b03a-6098-31cf-9d8b-b404e52dcb4a" \
--request GET \
http://127.0.0.1:8200/v1/secret/data/eng/apikey/Google | jq
2018-01-09 23:06:00 +00:00
{
"request_id": "5a2005ac-1149-2275-cab3-76cee71bf524",
"lease_id": "",
"renewable": false,
"lease_duration": 2764800,
"data": {
"key": "AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI"
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
**NOTE:** This example uses `jq` to parse the JSON output.
Retrieve the key value with `jq`:
```shell-session
$ curl --header "X-Vault-Token: 1c97b03a-6098-31cf-9d8b-b404e52dcb4a" \
--request GET \
http://127.0.0.1:8200/v1/secret/data/eng/apikey/Google | jq ".data.key"
2018-01-09 23:06:00 +00:00
```
#### Root certificate example:
```shell-session
$ curl --header "X-Vault-Token: 1c97b03a-6098-31cf-9d8b-b404e52dcb4a" \
--request GET \
http://127.0.0.1:8200/v1/secret/data/prod/cert/mysql | jq ".data.cert"
2018-01-09 23:06:00 +00:00
```
2018-01-18 01:39:21 +00:00
## Additional Discussion
2018-01-09 23:06:00 +00:00
### Q: How do I enter my secrets without appearing in history?
As a precaution, you may wish to avoid passing your secret as a part of the CLI
command so that the secret won't appear in the history file. Here are a few
2018-01-09 23:06:00 +00:00
techniques you can use.
#### Option 1: Use a dash "-"
An easy technique is to use a dash "-" and then press Enter. This allows you to
enter the secret in a new line. After entering the secret, press **`Ctrl+d`** to
end the pipe and write the secret to the Vault.
```shell-session
$ vault kv put secret/eng/apikey/Google key=-
2018-01-09 23:06:00 +00:00
AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI
<Ctrl+d>
```
#### Option 2: Read the secret from a file
Using the Google API key example, you can create a file containing the key (apikey.txt):
```plaintext
2018-01-09 23:06:00 +00:00
{
"key": "AAaaBBccDDeeOTXzSMT1234BB_Z8JzG7JkSVxI"
}
```
The CLI command would look like:
```shell-session
$ vault kv put secret/eng/apikey/Google @apikey.txt
2018-01-09 23:06:00 +00:00
```
#### Option 3: Disable all vault command history
Sometimes, you may not even want the vault command itself to appear in history
at all. The Option 1 and Option 2 prevents the secret to appear in the history;
however, the vault command, `vault kv put secret/eng/apikey/Google` will appear
2018-01-09 23:06:00 +00:00
in history.
In bash:
```shell-session
2018-02-06 00:17:18 +00:00
$ export HISTIGNORE="&:vault*"
2018-01-09 23:06:00 +00:00
```
**NOTE:** This prevents the use of the Up arrow key for command history as well.
### Q: How do I save multiple values?
The two examples introduced in this guide only had a single key-value pair. You
can pass multiple values in the command.
2018-01-09 23:06:00 +00:00
```shell-session
$ vault kv put secret/dev/config/mongodb url=foo.example.com:35533 db_name=users \
username=admin password=passw0rd
2018-01-09 23:06:00 +00:00
```
Or, read the secret from a file:
```shell-session
$ tee mongodb.txt <<EOF
2018-01-09 23:06:00 +00:00
{
"url": "foo.example.com:35533",
"db_name": "users",
"username": "admin",
"password": "pa$$w0rd"
2018-01-09 23:06:00 +00:00
}
EOF
$ vault kv put secret/dev/config/mongodb @mongodb.txt
2018-01-09 23:06:00 +00:00
```
## Next steps
This guide introduced the CLI commands and API endpoints to read and write
secrets in key/value secret engine. To keep it simple, the `devops` persona
generated a token for `apps`. Read [AppRole Pull
Authentication](/guides/identity/authentication) guide to learn about
programmatically generate a token for apps.