saltstack / saltstack/salt

[BUG] You can use pillar values sourced from vault ext_pillar in pillar-templated policies

Open
#66,189 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-triage
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.