Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppRole configuration example #15

Closed
rlueckl opened this issue Jul 15, 2019 · 15 comments · Fixed by #29
Closed

AppRole configuration example #15

rlueckl opened this issue Jul 15, 2019 · 15 comments · Fixed by #29
Assignees
Labels
docs enhancement New feature or request

Comments

@rlueckl
Copy link

rlueckl commented Jul 15, 2019

Hi,

I need some help configuring this plugin for authentication with AppRoles. The following config with token auth works great:

rundeck.storage.provider."1".type = "vault-storage"
rundeck.storage.provider."1".path = "keys"
rundeck.storage.provider."1".config.prefix = "all/qa/test"
rundeck.storage.provider."1".config.secretBackend = "custom/path/secrets"
rundeck.storage.provider."1".config.address = "https://******:8200"
rundeck.storage.provider."1".config.storageBehaviour = "vault"

rundeck.storage.provider."1".config.token = "******"

But no matter what I do, AppRole based auth doesn't work. As far as I understood, the config should look something like this:

rundeck.storage.provider."1".type = "vault-storage"
rundeck.storage.provider."1".path = "keys"
rundeck.storage.provider."1".config.prefix = "all/qa/test"
rundeck.storage.provider."1".config.secretBackend = "custom/path/secrets"
rundeck.storage.provider."1".config.address = "https://******:8200"
rundeck.storage.provider."1".config.storageBehaviour = "vault"

rundeck.storage.provider."1".config.authBackend = "approle"
rundeck.storage.provider."1".config.approleId = "APPROLE_ID"
rundeck.storage.provider."1".config.approleSecretId = "SECRET_ID"
rundeck.storage.provider."1".config.approleAuthMount = "???"

APPROLE_ID is from: $ vault read auth/foobar/approle/role/rundeck/role-id
SECRET_ID was generated with: $ vault write -f auth/foobar/approle/role/rundeck/secret-id

The AppRole is restricted to the IP of the Rundeck host and uses a policy which is only able to read and list all/qa/*:

$ vault read auth/foobar/approle/role/rundeck 
Key                      Value
---                      -----
bind_secret_id           true
bound_cidr_list          [10.*.*.*/32] # IP censored for safety reasons
local_secret_ids         false
period                   0s
policies                 [policy-qa-lr]
secret_id_bound_cidrs    [10.*.*.*/32] # IP censored for safety reasons
secret_id_num_uses       0
secret_id_ttl            0s
token_bound_cidrs        <nil>
token_max_ttl            30m
token_num_uses           10
token_ttl                30m
token_type               default

The policy looks like this:

path "custom/path/secrets/all/qa"   { capabilities = [ "list" ] }
path "custom/path/secrets/all/qa/*" { capabilities = [ "list", "read" ] }

As you can see we use a custom path in vault for AppRoles (auth/foobar/approle/role). I've tried putting different parts of this into approleAuthMount (auth/foobar, auth/foobar/approle), but it still doesn't work. I get the following exception every time:

2019-07-15 12:58:14.590 ERROR --- [tp1975736398-26] StackTrace                               : Full Stack Trace:

java.lang.NullPointerException: null
	at io.github.valfadeev.rundeck.plugin.vault.VaultStoragePlugin.hasDirectory(VaultStoragePlugin.java:300)
	at org.rundeck.storage.impl.DelegateTree.hasDirectory(DelegateTree.java:46)
	at org.rundeck.storage.conf.SubPathTree.getPath(SubPathTree.java:118)
	at org.rundeck.storage.conf.TreeStack.getPath(TreeStack.java:71)
	at org.rundeck.storage.impl.DelegateTree.getPath(DelegateTree.java:51)
	at org.rundeck.storage.conf.ListenerTree.getPath(ListenerTree.java:57)
	at org.rundeck.storage.impl.DelegateTree.getPath(DelegateTree.java:51)
	at org.rundeck.storage.conf.ConverterTree.getPath(ConverterTree.java:78)
	at org.rundeck.storage.impl.DelegateTree.getPath(DelegateTree.java:51)
	at org.rundeck.storage.conf.ConverterTree.getPath(ConverterTree.java:78)
	at org.rundeck.storage.impl.DelegateTree.getPath(DelegateTree.java:51)
	at com.dtolabs.rundeck.core.storage.AuthRundeckStorageTree.getPath(AuthRundeckStorageTree.java:131)
	at com.dtolabs.rundeck.core.storage.AuthRundeckStorageTree$getPath$0.call(Unknown Source)
[...snip...]

(Full trace attached -> rundeck_approle_exception.log)

@rlueckl
Copy link
Author

rlueckl commented Jul 15, 2019

Okay, after some digging around in the Vault source code I've found the answer here: https://github.com/BetterCloud/vault-java-driver/blob/master/src/main/java/com/bettercloud/vault/api/Auth.java#L411

approleAuthMount has to contain the path to the AppRoles including "approle" (in the very least), but without "/v1/auth" or anything else in front of it!

So basically if you have a custom setup (like we do) and your AppRole is auth/foobar/approle/role/rundeck (/v1/auth/foobar/approle/role/rundeck if you're using the API) then you have to set approleAuthMount to foobar/approle.

@gschueler : maybe you could add this info to the readme so the next person doesn't waste 2 hours reading Java source code while trying to configure the plugin.
Generally more extensive descriptions and more examples would be nice... For example: how secretBackend + prefix + path come together to form the final path in Vault.

@ltamaster
Copy link

Hi @rlueckl,

I have been trying to use the plugin with approle authentication and it worked for me.
But I noticed that the approle authentication generate a token that lives by token_num_uses calls.
So in my case, I just was able to check the key storage page ones, and any other call to the key storage gives me an error (permission deny). Did you get this problem?

I suppose that the parameter can be configurated (not very familiar with it).
I would like to know further about your use case, Do you normally refresh the token generated by the approle login?

Thanks
Luis

@rlueckl
Copy link
Author

rlueckl commented Jul 18, 2019

Hi @ltamaster,

you can configure the number of uses in your AppRole (see my example above: token_num_uses = 10). I don't know how often plugin refreshes the token, but it seems to work for now. After token_num_uses or token_max_ttl have been reached (whichever comes first) a new token has to be generated (by logging in again with the AppRole).

I don't know if the plugin can detect this. For example: the plugin has been using token X for some time. Then it gets a 403 from Vault, because the token expired. The plugin could retry the request, get another 403 again or it could try to get a new token by logging in with the approle again (and then retry the request).

@ltamaster ltamaster added docs enhancement New feature or request labels Jul 18, 2019
@ltamaster
Copy link

Hi @rlueckl ,

Yes, I think the plugin needs a way to refresh the token if it is expired.
I will work on that and I will add what you mentioned about the docs.

Luis

@rlueckl
Copy link
Author

rlueckl commented Jul 19, 2019

Thank you very much!

@linuxmail
Copy link

hi,

we have also a similar setup:

rundeck.storage.provider.'1'.type = 'vault-storage'
rundeck.storage.provider.'1'.path = 'keys'
rundeck.storage.provider.'1'.config.prefix = 'rundeck'
rundeck.storage.provider.'1'.config.address = 'https://fra-corp-vault.example.com'
rundeck.storage.provider.'1'.config.storageBehaviour = 'rundeck'
rundeck.storage.provider.'1'.config.secretBackend = 'kv'
rundeck.storage.provider.'1'.config.approleId = '8...'
rundeck.storage.provider.'1'.config.approleSecretId = '...df'
rundeck.storage.provider.'1'.config.approleAuthMount = 'approle'
rundeck.storage.provider.'1'.config.authBackend = 'approle'
rundeck.storage.provider.'1'.config.engineVersion = 2
rundeck.storage.provider.'1'.removePathPrefix=true

After 30 minutes, I have create a new secred_id on the vault host:

$ vault write -f auth/approle/role/rundeck/secret-id
Key                   Value
---                   -----
secret_id             7....
secret_id_accessor    6...85a

then copy the secret_id and replace the value rundeck.storage.provider.'1'.config.approleSecretId with the new one and do a service rundeck restart, so that Rundeck has access again.
So it seems, I'm doing it in the wrong way :-) because a Rundeck restart takes a bit time (there is no reload). Is there any workaround for it ?

cu denny

@rlueckl
Copy link
Author

rlueckl commented Aug 14, 2019

Hi @linuxmail,

You don't need to generate a new secret ID. Just restart Rundeck. That's enough to trigger a new login to Vault and the freshly generated token can be used again for as long as your approle TTL or num_uses are configured.

@linuxmail
Copy link

hi,

hmm, Ok, I would try it out, but then, I have to restart rundeck every hour :-) I tried a small script to solve it:

curl --output /dev/null -s --request POST --data '{"role_id":"eee-ffff-aaaa-bbbb-ccccdddeeeeffff","secret_id":"2eaaa-aaa-cccc-dddd"}' https://fra-corp-vault-01.example.com:8200/v1/auth/approle/login

For the Vault app role:

 vault read  auth/approle/role/rundeck
Key                        Value
---                        -----
bind_secret_id             true
local_secret_ids           false
policies                   [rundeck]
secret_id_bound_cidrs      [192.168.1.10/32]
secret_id_num_uses         0
secret_id_ttl              2h
token_bound_cidrs          []
token_explicit_max_ttl     0s
token_max_ttl              1h
token_no_default_policy    false
token_num_uses             0
token_period               0s
token_policies             [rundeck]
token_ttl                  1h
token_type                 default

but ... it has not the same affect ... As I understand .. role id and secret id just username and password for login into Vault and have access to the tokens. In that case, to have the new tokens in my curl doesn't help the Vaul Rundeck plugin. Is there a way, to push the new token somewhere to the plugin or inject it ?

@rlueckl
Copy link
Author

rlueckl commented Aug 16, 2019

2 things:

  • you can use role_id + secret_id (rundeck.storage.provider.[index].config.approleId=approleId, rundeck.storage.provider.[index].config.approleSecretId=approleSecretId) and the plugin gets a token for itself
  • OR: you can directly input a token in the config (rundeck.storage.provider.[index].config.token=xxxxxx). The plugin will use this token for every request.

If you use the first method you don't need a new role_id or secret_id (ever). You just need a new token every time token_max_ttl or token_num_uses have been reached.

The Rundeck Vault plugin doesn't check if the token has expired and doesn't get a new token automatically. The easiest way to get a new token is to restart Rundeck, so the plugin has to login again to Vault and get a new token. I don't know if it's possible to push/inject the token to the plugin (probably not).

If you use the second method (inputting a token directly into the config) you have to generate the token and put into the config then restart Rundeck every time the token has expired.

You could set your approle to have a longer token_max_ttl (depending on your security requirements) so you don't have to restart Rundeck that often. But a better solution would be if the plugin would check for an expired token and automatically log in again if the token is expired.

@linuxmail
Copy link

linuxmail commented Sep 4, 2019

hi @rlueckl

after a few days and trying .. no success. I let Rundeck restarting every 30min via Cron (service rundeckd restart) and if I visit the keystorage (for example) on the next day .. Rundeck has no access anymore. The only way to get it working again, is to recreate the secred_id.

I don't know, if it helps to recreate the approle for rundeck, because I think, it always has a ttl for the secred_id.

@linuxmail
Copy link

hi,
I've deleted the approle and did a recreate:

Key                        Value
---                        -----
bind_secret_id             true
local_secret_ids           false
policies                   [rundeck]
secret_id_bound_cidrs      [192.168.43.46/32]
secret_id_num_uses         0
secret_id_ttl              0s
token_bound_cidrs          []
token_explicit_max_ttl     0s
token_max_ttl              0s
token_no_default_policy    false
token_num_uses             0
token_period               0s
token_policies             [rundeck]
token_ttl                  12h
token_type                 default

Looks better now. Hopefully it works on the next day too :-)

@rlueckl
Copy link
Author

rlueckl commented Sep 18, 2019

Sorry, I didn't have time to test the plugin in the last weeks. Maybe @ltamaster can help here? (RE: token renewal)

@linuxmail
Copy link

hi,

I can tell you: it works. I created a cron Job that is restarting Rundeck after several hours and I don't have to do anything further. The only important thing you have to keep in mind: don't let Rundeck restart, while a job is running.

@rlueckl
Copy link
Author

rlueckl commented Sep 25, 2019

Hi @ltamaster,

any new about the token refresh functionality? (#15 (comment))

@PowerSchill
Copy link

I had the issue and even recreating the secret-id didn't work. I had to completely recreate the role.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs enhancement New feature or request
Projects
None yet
4 participants