Vault: By default, userpass doesn't allow users to update own passwords

Created on 16 Apr 2019  路  23Comments  路  Source: hashicorp/vault

Describe the bug
By default, using the userpass auth method, a user cannot update their own password

To Reproduce
Steps to reproduce the behavior:

  1. vault server -dev
  2. export VAULT_ADDR='http://127.0.0.1:8200'
  3. vault auth enable userpass
  4. vault write auth/userpass/users/testuser password=test
  5. vault login -method=userpass username=testuser password=test
  6. vault write auth/userpass/users/testuser password=newpass
  7. You get permission denied

Expected behavior
I would think a sane default would allow users to update their own passwords. If there is a way to do this with policies, I've been unable to determine how. I have tried using something like the following, but it allows all users to update all other users' passwords (expected, because of the wildcard). Also, seems the policy paths for userpass don't support identity.entity.{name,id}

path "auth/userpass/users/*" {
  capabilities = ["update"]
}

Environment:

  • Vault Server Version (retrieve with vault status): 1.1.0
  • Vault CLI Version (retrieve with vault version): Vault v1.1.0 ('36aa8c8dd1936e10ebd7a4c1d412ae0e6f7900bd+CHANGES')
  • Server Operating System/Architecture: Linux/AMD64

Most helpful comment

agreed but vault provides a login mechanism that does not require this workaround - i think password reset security is fundamental to a product that is about the security of secrets - just my 2 cents

All 23 comments

Hi @jrdemasi,

policies are deny by default. So in my opinion, the behavior you experienced is correct.
You can and should use ACL Templating (https://learn.hashicorp.com/vault/identity-access-management/policy-templating) to allow every user to change its own password:

path "auth/userpass/users/{{identity.entity.aliases.auth_userpass_6671d643.name}}" {
  capabilities = [ "update" ]
  allowed_parameters = {
    "password" = []
  }
}

Make sure that you change the userpass mount accessor. You can read the mount accessor via vault auth list or the sys/auth API endpoint.

I will close this issue for now since I don't think that this is a bug. Feel free to reopen the issue if you have any other questions.

Cheers,
Michel

@michelvocks Thanks for the info -- I had tried that, but apparently didn't get it quite right. Really appreciate the response!

I had similar issues and the documentation didn't hold my hand enough.

Since the accessor string is different per instance, it could be difficult to pre-write this policy. I wonder if it's possible to simply allow all userpass entities to have the access to manage their own password without knowing the specific accessor strings.

This was my workaround, mostly step 4 and getting the userpass accessor string for this instance.

  1. Start Vault: vault server -dev
  2. Use Vault: export VAULT_ADDR='http://127.0.0.1:8200'
  3. Enable userpass: vault auth enable userpass
  4. Create userpass policy: userpass.hcl
# Get this userpass instance accessor string
userpass_accessor="$(vault auth list | awk '/^userpass/ {print $3}')"

# Create the userpass policy using this instance accessor string
cat > userpass.hcl << EOF
path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}" {
  capabilities = [ "update" ]
  allowed_parameters = {
    "password" = []
  }
}
EOF
  1. Add userpass policy: vault policy write userpass userpass.hcl
  2. Create a testuser: vault write auth/userpass/users/testuser password=test policies=userpass
  3. Login as testuser: vault login -method=userpass username=testuser
  4. Change password: vault write auth/userpass/users/testuser password=newpass

Allowed parameters is fragile. You're better off using the endpoint designed for exactly this: https://www.vaultproject.io/api/auth/userpass/index.html#update-password-on-user

Thanks for the input, I was able to create the recommended policy:

# Get this userpass instance accessor string
userpass_accessor="$(vault auth list | awk '/^userpass/ {print $3}')"

# Create the userpass policy using this instance accessor string
cat > userpass.hcl << EOF
path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}/password" {
  capabilities = [ "update" ]
}
EOF

Then confirmed users could update their own password via HTTP API:

# Login and get token
token="$(vault login -token-only -method=userpass username=testuser)"

# Change password with user token / curl
curl \
  --header "X-Vault-Token: ${token}" \
  --request POST \
  --data '{"username":"testuser","password":"newpassword"}' \
  http://127.0.0.1:8200/v1/auth/userpass/users/testuser/password

This method doesn't seem possible through the vault CLI tool. I'll keep in mind that the HTTP API might have features unavailable to the CLI tool.

It's possible via vault write

Thanks, this did it:
vault write auth/userpass/users/testuser/password password=newpass

vault write auth/userpass/users/testuser/password password=newpass

This seems an insecure way of resetting password as the password is now available in command history

There are ways of ensuring a command doesn't appear in command history. For example, in bash you can set HISTCONTROL=ignoreboth and then start your command with a leading space.

agreed but vault provides a login mechanism that does not require this workaround - i think password reset security is fundamental to a product that is about the security of secrets - just my 2 cents

I had similar issues and the documentation didn't hold my hand enough.

Since the accessor string is different per instance, it could be difficult to pre-write this policy. I wonder if it's possible to simply allow all userpass entities to have the access to manage their own password without knowing the specific accessor strings.

This was my workaround, mostly step 4 and getting the userpass accessor string for this instance.

  1. Start Vault: vault server -dev
  2. Use Vault: export VAULT_ADDR='http://127.0.0.1:8200'
  3. Enable userpass: vault auth enable userpass
  4. Create userpass policy: userpass.hcl
# Get this userpass instance accessor string
userpass_accessor="$(vault auth list | awk '/^userpass/ {print $3}')"

# Create the userpass policy using this instance accessor string
cat > userpass.hcl << EOF
path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}" {
  capabilities = [ "update" ]
  allowed_parameters = {
    "password" = []
  }
}
EOF
  1. Add userpass policy: vault policy write userpass userpass.hcl
  2. Create a testuser: vault write auth/userpass/users/testuser password=test policies=userpass
  3. Login as testuser: vault login -method=userpass username=testuser
  4. Change password: vault write auth/userpass/users/testuser password=newpass

I tried in my server, the policy works when it wrote like:
path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}/password" {
capabilities = [ "update" ]
}

And it would not work if the policy like :
path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}" {
capabilities = [ "update" ]
allowed_parameters = {
"password" = []
}
}

For me, all the password updating via api is not working, only the cli command works
vault write auth/userpass/users/testuser password=newpass
After several tries, I fixed it. You must follow the steps: create entity and get entityID > create alias according to the entityID > create the user according to the alias name, then it works fine.

Doesn't this give you permissions to update any user's password? I think this would be a security risk, considering you could update an admin's password and login using their account/ permissions.

@lrbnew, allowed_parameters would work, but @jefferai mentioned it could be fragile.

@mennlo if you follow the steps I've outlined. The "testuser" will only have access to change it's own password. I've tested creating a second "testuser2" and the original "testuser" could not modify the second users password.

After the original 8 steps:

$ vault login -method=userpass username=testuser
Success! You are now authenticated....

$ vault write auth/userpass/users/testuser password=newpass
Success! Data written to: auth/userpass/users/testuser

$ vault write auth/userpass/users/testuser2 password=newpass
Error writing data to auth/userpass/users/testuser2: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/auth/userpass/users/testuser2
Code: 403. Errors:

* 1 error occurred:
    * permission denied

@cheyngoodman Thanks I realized I was getting auth/* permissions from a different policy.

I'm having an issue getting this to work, still getting permission denied.

[vault@vault-0 ~]$ userpass_accessor="$(vault auth list | awk '/^userpass/ {print $3}')"
[vault@vault-0 ~]$ cat > userpass.hcl << EOF
> path "auth/userpass/users/{{identity.entity.aliases.${userpass_accessor}.name}}/password" {
>   capabilities = [ "update" ]
> }
> EOF

[vault@vault-0 ~]$ vault policy write userpass userpass.hcl
Success! Uploaded policy: userpass
[vault@vault-0 ~]$ vault write auth/userpass/users/testuser password=test policies=userpass
Success! Data written to: auth/userpass/users/testuser
[vault@vault-0 ~]$ vault login -method=userpass username=testuser
Password (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                    Value
---                    -----
token                  s.UJ38gyvpdy3aVRxt2A5Wtem8
token_accessor         M5IPmYddzODsxQhv7UIfdRLo
token_duration         768h
token_renewable        true
token_policies         ["default" "userpass"]
identity_policies      []
policies               ["default" "userpass"]
token_meta_username    testuser
[vault@vault-0 ~]$ vault write auth/userpass/users/testuser password=newpass
Error writing data to auth/userpass/users/testuser: Error making API request.

URL: PUT https://vault-0.xyz.com:8200/v1/auth/userpass/users/testuser
Code: 403. Errors:

* 1 error occurred:
    * permission denied

Can anyone help me diagnose my issue?

have the same issue as @mennlo

@mennlo @mshivanna can you verify that the variable is getting expanded and your policy doesn't have ${userpass_accessor} in it?

Edit, here is my full working "userpass.hcl":

path "auth/userpass/users/{{identity.entity.aliases.auth_userpass_MY_ACCESSOR.name}}" {
  capabilities = [ "update" ]
  allowed_parameters = {
    "password" = []
  }
}

ah works now. thanks @jrdemasi
i had missed this userpass_accessor="$(vault auth list | awk '/^userpass/ {print $3}')"

only cli works rest api does not work.

curl --header "X-Vault-Token: ${token}" --request POST --data '{"username":"mshivanna","password":"mynewpassword"}' https://ourvaultserver.com/v1/auth/userpass/users/mshivanna/password

{"errors":["1 error occurred:\n\t* permission denied\n\n"]}

I think your endpoint is wrong - it should just be auth/userpass/users/mshivanna

https://www.vaultproject.io/api-docs/auth/userpass/

thank you it works now :)

Still having an issue with version 1.5.3. Have I applied the policy correctly?

GUI
It is a credential management solution so very frustrating this is not supported in the GUI as a standard option.

CLI
vault write auth/userpass/users/bobmarley password=jammingwithyou

Error writing data to auth/userpass/users/bobmarley: Error making API request.

URL: PUT https://vault.acme.com:8200/v1/auth/userpass/users/bobmarley
Code: 403. Errors:

* 1 error occurred:
        * permission denied

HTTPS

curl --header "X-Vault-Token: s.wH5rfaWhateverTokenfb8fa" --request POST --data '{"username":"bobmarley","password":"jammingwithyou"}' https://vault.acme.com:8200/auth/userpass/users/bobmarley
_`{"errors":[]}`_

curl -k --header "X-Vault-Token: s.wH5rfaWhateverTokenfb8fa" --request POST --data '{"username":"bobmarley","password":"jammingwithyou"}' https://vault.acme.com:8200/v1/auth/userpass/users/bobmarley/password
_{"errors":["1 error occurred:\n\t* permission denied\n\n"]}_

Then I tried to login to GUI, login failed new with password, didn't work.

Added to bottom 'Default' Policy (/ui/vault/policy/acl/default)
Everything above indicates permission error, here is the policy:

# Allow User Password Resets
path "auth/userpass/users/{{identity.entity.aliases.auth_userpass_b6245263d.name}}" {
  capabilities = [ "update" ]
  allowed_parameters = {
    "password" = []
  }
}

Notes

  • Yes users are able to login with exiting password
  • Yes I updated the 'auth_userpass_b6245263d' ID with the one in use on our environment
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mfischer-zd picture mfischer-zd  路  3Comments

dwdraju picture dwdraju  路  3Comments

weisinc picture weisinc  路  3Comments

narayan8291 picture narayan8291  路  3Comments

Wonder007 picture Wonder007  路  3Comments