You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Salt is a powerful configuration management tool. It allows you to control your server configurations with flat files that are easily shared with others on your team. However, it is common to need access to sensitive data like API keys and database passwords within these state files. Because this information is typically stored as plain text, this creates a serious security flaw, especially when this data could be stored in a remote repository. This guide will explore the known methods for securing your secrets within Salt.
23
+
Salt is a powerful configuration management tool which helps you manage your server deployments with configuration *state*files. These files are easily shared with others on your teamand can be checked in to version control systems like Git.
23
24
24
-
## Pillar Files
25
+
A common problem when working with Salt's state files is the need access to sensitive data, like API keys and database passwords, within those files. Directly embedding that information as plain-text inside your state files can represent a security vulnerability, especially if you were to check those files into version control. This guide will explore some common methods for securing your secrets within Salt.
25
26
26
-
The most obvious method for storing secrets in Salt is to employ a Pillar. Pillars are designed to house global values that are intended for specific minions. By putting your secrets into Pillars and not into state files you can effectively remove those secrets from version control by not committing your Pillars. This method requires some extra planning however, especially because not *all* Pillar data is sensitive, and so some Pillar files might still make it into version control. You could create a special directory at `/srv/pillar/secrets` and add that folder to your `.gitignore` file to separate your sensitive and non-sensitive data. For quick reference, it might also be necessary to create a `pillar.example` file, like those provided by Salt formulas, that lists all the known variable keys so that you can shorten the time it takes to set up a Salt system.
27
+
## Salt Pillar
27
28
28
-
You can also supply Pillar values as a dictionary through the command line, and these files will override any Pillar values set in your Pillar files.
29
+
A primary method for storing secrets in Salt is to keep them in Salt's *Pillar* feature. Salt Pillar is designed to maintain secrets and other variable information in a single location (generally, on the Salt master) and then deliver that information to specific minions. If you separate your secrets out from your states and into pillar files, you can ignore those files in your version control system.
29
30
30
-
salt '*' state.apply pillar='{"mysecret": "secret"}'
31
+
{{< note >}}
32
+
In addition to storing secrets, Salt Pillar can also maintain non-sensitive data; for example, the versions of the packages you want to install on your minions. So, you may still want to track some pillar files in version control.
33
+
34
+
To handle this distinction, you could create a special directory at `/srv/pillar/secrets` and add set your version control system to ignore that directory (when using Git, list this directory in your `.gitignore` file). Keep all sensitive data inside pillar files within this directory, and maintain non-sensitive data in pillar files in `/srv/pillar` or another subfolder.
35
+
{{< /note >}}
36
+
37
+
### Anatomy of Pillar Data Files
38
+
39
+
Pillar data is kept in `.sls` files which are written in the same YAML syntax as states. These are generally stored within `/srv/pillar` on the Salt master, but this location can be configured via the `pillar_roots` option in your master's configuration.
40
+
41
+
For example, let's say your minion runs an application which accesses the Linode API. This pillar file keeps your API token in a variable called `linode_api_token`:
42
+
43
+
{{< file "/srv/pillar/app_secrets.sls" >}}
44
+
linode_api_token: YOUR_API_TOKEN
45
+
{{< /file >}}
46
+
47
+
As with state files, a top file (separate from your states’ top file) maps pillar data to minions. This example top file maps your `app_secrets` pillar data to your app server:
48
+
49
+
{{< file "/srv/pillar/top.sls" >}}
50
+
base:
51
+
'appserver':
52
+
- app_secrets
53
+
{{< /file >}}
54
+
55
+
{{< note >}}
56
+
You may want to create a `pillar.example` file (like those provided by Salt formulas) that lists all the known variable keys for your pillar but does not contain the actual secrets. If you check this file into your version control, other users that clone your states' repository can duplicate this example pillar file and more quickly set up their own deployments.
57
+
{{< /note >}}
58
+
59
+
### Accessing Pillar Data inside Salt States
31
60
32
-
The downside of this approach is that there are times when Pillar data could show up in the output that Salt generates, like when `file.managed` displays diffs of a modified file. To avoid displaying these diffs, you can set `file.managed`'s `show_diff` flag to false.
61
+
To inject pillar data into your states, use Salt's Jinja template syntax. While Salt uses the YAML syntax for state and pillar files, the files are first interpreted as Jinja templates (by default).
62
+
63
+
This example embeds the API token from Salt Pillar in a file on your Linode (which could later be consumed by your app to access the Linode API). The data is accessed through the `pillar` dictionary:
64
+
65
+
{{< file "/srv/salt/setup_app.sls" >}}
66
+
api_token:
67
+
file.managed:
68
+
- name: /var/your_app/api_token
69
+
- contents: {{ pillar['linode_api_token'] }}
70
+
{{< /file >}}
71
+
72
+
### Passing Pillar Data at the Command Line
73
+
74
+
You can also supply pillar values as a dictionary through the command line, and values files will override any values set in your pillar files. This example command would apply the `A_DIFFERENT_API_TOKEN` value instead of the original `YOUR_API_TOKEN` from the previous example:
75
+
76
+
salt '*' state.apply pillar='{"linode_api_token": "A_DIFFERENT_API_TOKEN"}'
77
+
78
+
{{< caution >}}
79
+
There are times when pillar data could show up in the output that Salt generates, like when `file.managed` displays diffs of a modified file. To avoid displaying these diffs, you can set `file.managed`'s `show_diff` flag to false.
80
+
{{< /caution >}}
33
81
34
82
## Environment Variables
35
83
36
-
Similar to passing in Pillar data via the command line, another way to keep sensitive values out of version control is to use environment variables. For example, you might issue the following command:
84
+
Another way to keep sensitive values out of version control is to use environment variables. The method for passing environment variables to your states is similar to how pillar data can be passed via the command line. For example, you might issue the following command:
37
85
38
-
SUPERSECRET="secret" salt '*' state.apply example.sls
86
+
LINODE_API_TOKEN="YOUR_API_TOKEN" salt '*' state.apply example.sls
39
87
40
-
The environment variable is referenced by a Salt state file through `salt['environ.get']('SUPERSECRET')`.
88
+
The environment variable is referenced by a Salt state file through the `salt['environ.get']('ENVIRONMENT_VARIABLE_NAME')` syntax. The previous `setup_app` example state can be adapted to use an environment variable as follows:
As it is with the Pillar example mentioned above, you'll want to keep `file.managed`'s diffs from appearing on screen when dealing with sensitive information by setting `show_diff: false`. For more information, see [Using Environment Variables in SLS Modules](https://docs.saltstack.com/en/latest/topics/tutorials/states_pt3.html#using-environment-variables-in-sls-modules).
97
+
As with the previous pillar example, you'll want to keep `file.managed`'s diffs from appearing on screen when dealing with sensitive information by setting `show_diff: false`. For more information, see [Using Environment Variables in SLS Modules](https://docs.saltstack.com/en/latest/topics/tutorials/states_pt3.html#using-environment-variables-in-sls-modules).
50
98
51
99
## GPG Encryption
52
100
53
-
You can use the [GPG renderer](https://docs.saltstack.com/en/latest/ref/renderers/all/salt.renderers.gpg.html) to decrypt GPG ciphers that are located in your Pillar files before those values are passed to Salt minions. This means that any value in a Pillar file can be encrypted, allowing state files to be stored in version control. This approach requires that the GPG secret key is stored on your Salt master, and it makes sense to include the public key in version control so that is available to your team.
101
+
You can use Salt's [GPG renderer](https://docs.saltstack.com/en/latest/ref/renderers/all/salt.renderers.gpg.html) to decrypt GPG ciphers that are located in your pillar files. This decryption step happens before your pillar data is passed to your minions. As a result, any value in a pillar file can be encrypted. Because the values are encrypted, you can store your pillar files in version control securely.
102
+
103
+
This approach requires that the GPG secret key is stored on your Salt master. It also makes sense to include the public key in version control so that your team members can use it to encrypt new data for your pillar files.
54
104
55
105
## SDB
56
106
57
-
Salt comes with a database interface called SDB that was initially created to store non minion-specific data, such as passwords. It was designed to connect to a package like [keyring](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.keyring_db.html), but other options are available, such as [Consul](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.consul.html) and [Vault](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.vault.html#module-salt.sdb.vault). These databases are set up using a configuration profile in `/srv/salt/master.d`. To access data, you supply an `sdb://` url, such as `password: sdb://mysecrets/mypassword`. For more information on SDB, reference the [Salt SDB documentation](https://docs.saltstack.com/en/latest/topics/sdb/).
107
+
Salt comes with a database interface called *SDB* that was initially created to store non-minion-specific data, such as passwords. It was designed to connect to a package like Salt's [*keyring*](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.keyring_db.html) module, but other options are available, such as [Consul](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.consul.html) and [Vault](https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.vault.html#module-salt.sdb.vault).
108
+
109
+
These databases are set up using a configuration profile in `/srv/salt/master.d`. To access data, you supply an `sdb://` url, such as `password: sdb://mysecrets/mypassword`. For more information on SDB, reference the [Salt SDB documentation](https://docs.saltstack.com/en/latest/topics/sdb/).
58
110
59
111
{{< note >}}
60
-
Salt also provides a module that allows [pillar data to be stored in Vault](https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.vault.html) and a module that includes [functions to interact with Vault](https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.vault.html#vault-setup).
112
+
Salt also provides a module that allows [pillar data to be stored in Vault](https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.vault.html), as well as an execution module that includes [functions to interact with Vault](https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.vault.html#vault-setup).
0 commit comments