[BUG] You can use pillar values sourced from vault ext_pillar in pillar-templated policies
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 15.7k
- Forks
- 5.6k
- Avg merge
- 2d 44m
- Merged PRs (30d)
- 80
Description
Description
This is not something I think you ought to do, but the documentation says "You cannot use pillar values sourced from Vault in pillar-templated policies" but you actually can, albeit with inconsistent behavior. Please advise whether this is just poor documentation wording or a bug.
Setup
Install vault and set up a few secrets. For purposes of this demo, the following secrets were created
@ secret/data/db
db_user: joeschmoe
@ secret/data/web
db_token: jfajsdkjkfajasdjks
git_token: jfndkjfksjfkjdfk
The following policies were also created.
db-policy
path "secret/data/db" {
capabilities = ["create", "read", "update", "patch", "delete", "list"]
}
path "secret/data/db" {
capabilities = ["create", "read", "update", "patch", "delete", "list"]
}
web-policy
path "secret/data/web" {
capabilities = ["create", "read", "update", "patch", "delete", "list"]
}
path "secret/data/web" {
capabilities = ["create", "read", "update", "patch", "delete", "list"]
}
Then install salt-master / salt-minion and configure salt-master to use vault ext_pillar and assign policies templated by the role pillar.
/etc/salt/master.d/vault.conf
peer_run:
.*:
- vault.get_config
- vault.generate_new_token
ext_pillar:
- vault: path=secret/data/{pillar[role]}
vault:
url: "http://localhost:8200"
verify: False
auth:
token: xxx-REDACTED-xxx
server:
url: "http://127.0.0.1:8200"
policies:
assign:
- "{pillar[role]}-policy"
Then use a local pillar to assign the salt-minion with a role value. E.g.
/srv/pillar/top.sls
base:
'test-minion':
- test-minion
/srv/pillar/test-minion.sls
role: db
And refresh the pillar
salt \* saltutil.refresh_pillar
Steps to Reproduce the behavior
All is well and good so far. The above configuration will allow the test-minion to read/write secrets from secret/data/db but not secret/data/web and will integrate the values as pillar.
# salt \* vault.read_secret secret/data/db
test-minion:
----------
db_user:
joeschmoe
# salt \* vault.read_secret secret/data/web
test-minion:
ERROR: Failed to read secret! VaultPermissionDeniedError: 1 error occurred:
* permission denied
ERROR: Minions returned with non-zero exit code
# salt \* pillar.items
test-minion:
----------
db_user:
joeschmoe
role:
db
However, with write access to the secret/data/db path, one could overwrite the role pillar and grant access to the secret/data/web path (albeit with highly inconsistent results). Observe the following sequence of commands / returns.
# salt \* vault.write_secret secret/data/db db_user=joeschmoe role=web
test-minion:
----------
created_time:
2024-03-08T21:52:53.330213515Z
custom_metadata:
None
deletion_time:
destroyed:
False
version:
2
# salt \* vault.read_secret secret/data/db
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* vault.read_secret secret/data/web
test-minion:
ERROR: Failed to read secret! VaultPermissionDeniedError: 1 error occurred:
* permission denied
ERROR: Minions returned with non-zero exit code
# salt \* vault.read_secret secret/data/db
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* pillar.items
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* vault.read_secret secret/data/db
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* vault.read_secret secret/data/web
test-minion:
ERROR: Failed to read secret! VaultPermissionDeniedError: 1 error occurred:
* permission denied
ERROR: Minions returned with non-zero exit code
# salt \* vault.read_secret secret/data/db
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* pillar.items
test-minion:
----------
db_user:
joeschmoe
role:
web
# salt \* vault.read_secret secret/data/web
test-minion:
----------
db_token:
jfajsdkjkfajasdjks
git_token:
jfndkjfksjfkjdfk
# salt \* vault.read_secret secret/data/db
test-minion:
ERROR: Failed to read secret! VaultPermissionDeniedError: 1 error occurred:
* permission denied
ERROR: Minions returned with non-zero exit code
# salt \* pillar.items
test-minion:
----------
role:
db
# salt \* vault.read_secret secret/data/db
test-minion:
ERROR: Failed to read secret! VaultPermissionDeniedError: 1 error occurred:
* permission denied
ERROR: Minions returned with non-zero exit code
# salt \* vault.read_secret secret/data/web
test-minion:
----------
db_token:
jfajsdkjkfajasdjks
git_token:
jfndkjfksjfkjdfk
# salt \* pillar.items
test-minion:
----------
role:
db
As you can see above, not until a couple of calls to pillar.items did the access to the secrets paths change, doing so in a highly inconsistent and unreliable manner.
Expected behavior
This situation can and ought to be avoided (i.e. don't allow write access to secrets that are integrated as pillar and used in pillar-templated policy assignments), but given the wording in the documentation (noted above) it seems like it shouldn't be possible at all. It seems to me that either the doc should be altered slightly or this is an unforeseen bug. Please advise accordingly.
Versions Report
Salt Version:
Salt: 3007.0
Python Version:
Python: 3.10.13 (main, Feb 19 2024, 03:31:20) [GCC 11.2.0]
Dependency Versions:
cffi: 1.16.0
cherrypy: unknown
dateutil: 2.8.2
docker-py: Not Installed
gitdb: Not Installed
gitpython: Not Installed
Jinja2: 3.1.3
libgit2: Not Installed
looseversion: 1.3.0
M2Crypto: Not Installed
Mako: Not Installed
msgpack: 1.0.7
msgpack-pure: Not Installed
mysql-python: Not Installed
packaging: 23.1
pycparser: 2.21
pycrypto: Not Installed
pycryptodome: 3.19.1
pygit2: Not Installed
python-gnupg: 0.5.2
PyYAML: 6.0.1
PyZMQ: 25.1.2
relenv: 0.15.1
smmap: Not Installed
timelib: 0.3.0
Tornado: 6.3.3
ZMQ: 4.3.4
Salt Package Information:
Package Type: onedir
System Versions:
dist: debian 12.5 bookworm
locale: utf-8
machine: x86_64
release: 6.1.0-18-amd64
system: Linux
version: Debian GNU/Linux 12.5 bookworm
Additional Context
In addition to the setup above, the following config file was used. Everything else was left at the defaults.
/etc/salt/master.d/master.conf
user: root
log_level: info
/etc/salt/minion.d/minion.conf
master: localhost
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the vault ext_pillar configuration in /etc/salt/master.d/vault.conf and reproduce the sequence using saltutil.refresh_pillar, vault.read_secret, and pillar.items. Compare the documented restriction with the observed policy changes and determine whether the intended outcome is a documentation correction or a fix for inconsistent access behavior. Done means the expected behavior is decided and verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- infrastructure, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100