-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
vault_token is written to /secrets world-readable #11900
Comments
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
At the moment, `/secrets/vault_token` is written using the nomad
process' umask, which - by default - is `0022`, which results in
writing the vault_token world-readable (`0644` / `rw-r--r--`).
This patch aims to address this by allowing to change the
permissions used from the default `666` (before umask).
The name `file_perms` was chosen to distinguish this from the
parameter `perms` in the `template` stanza (as templates always
operate on files, while Vault tokens are about permissions as
well, which would've been confusing otherwise).
Example of use:
vault {
policies = ["nomad-tls-policy"]
change_mode = "noop"
file_perms = "600"
}
I tried to extend unit tests to include basic checks for the
feature, not sure if this is sufficient, though.
Resolves hashicorp#11900
|
Hi @grembo and thanks for raising this along with the PR. I'll raise this internally for discussion and hope to come back with feedback on the PR in a timely manner. |
|
The implementation of #11905 looks good, but I'm not sure it adds significant protections. To be clear the Vault token is protected from arbitrary readers by two other layers:
It's not clear to me what dropping permissions on the token file improves: even if it's only user-readable that doesn't add any additional protections than 1 or 2 above. Non-root system process still cannot read it and chroots still protect it from other tasks. Even without chroots changing the user permissions alone are insufficient to protect the token file from being read by other tasks as all tasks in Nomad can run as the same user. That being said I'd love to lock down access to the vault token as much as possible, so I'd love to be convinced |
|
Hi @schmichael, Thank you for the detailed response. We have multiple applications for vault tokens in nomad:
Now, in an ideal world, we could issue two vault tokens through the job specification, so anything concerning issuing client certificates would happen outside of the chroot, while the vault token to access the vault transit engine is shared with the chroot. Basically one vault token used in the Update: I wonder if it would be possible to create a vault token that has permissions to issue other vault tokens and use that in a Beyond our specific use case, I think that having files containing secrets with world readable permissions never looks good - so simply from a "I have to explain this to somebody auditing the system" perspective it would be good to be able to simply set strict permissions to avoid having to deal with those questions/make it easier to audit a setup overall (also internally). Originally I though of using
On my nomad clients this isn't the case: As far as I can tell, nomad/client/allocdir/alloc_dir.go Line 319 in 3423118
It looks like it got intentionally changed to be that way in 8e54601. If my assertion is correct, this would be a good example of why setting strict permissions on the file containing the secret itself is more robust than relying on directory permissions further up the tree for protecting the content of the file. |
|
I altered the PR to include the suggested |
|
@schmichael Just to quickly sum up my lengthy statement from above:
|
|
@lgfa29 Is there anything else I could do at this point to aid the discussion? |
|
@lgfa29 @schmichael Would it help to split the PR? |
|
Hi @grembo, sorry for the delay here. We have this marked for review but no updates yet. We will let you know once we get to that PR. |
|
@schmichael @lgfa29 I updated the description above to clarify what the solution we use looks like/what we consider the most important part of addressing the issue. As discussed with @tgross, I would like to reduce the scope of this so it becomes actionable, focussing on solving these two core issues:
We could to reduce the patch so it only changes where the vault token is written to using a restrictive file mask (task's new private dir, which is not part of the container). This would be a fairly minimal change and reduce the size of #11905 dramatically. It's then up to you which additional functionality you would like to see there (e.g., actually having a See also: #11905 (comment) As the scope of this issue moved quite a lot, I would suggest that I open a new PR just focusing on the above. What do you think, would this be a reasonable path forward? |
|
Hi @grembo 👋 We're still discussing this internally. We had to step back for a while to get 1.3.0 out, but I've raise it again with the team. I will keep you posted of any updates. |
|
Hi @grembo, After discussing with the team we reached a few points:
I think the work you currently have in the PR already addresses most of this, but the file permission changes would have to be reverted. Another thing that would be great to have in the PR are more tests. It would be valuable to test some scenarios like making sure that the Going deeper into the token Vault file permission discussion, the current implementation doesn't leave the Vault token readable to any user in the host. The file is set with permission The reason why the Vault token file needs to be set to Allowing users to change this value has a high chance of creating a lot of confusion, as it may not be clear what the user ID and group ID their task is using from the host perspective, and as mentioned before, changing the permission would not result in any real benefit. This approach could also be used for other secrets, like Consul and Nomad tokens, so implementing it in a way that could support that as well will be great. Lastly, we're investigating more identity-aware approaches to managing secrets within Nomad that will make things a lot better in the future 🙂 |
|
Hi @lgfa29, Thank you for taking the time to discuss the issue and for writing a detailed response. I'll only address/clarify a few topics, I'll ask more detailed questions later (if needed) when I find the time to update the PR.
Makes sense. I assume I can re-use what exists on for /secrets. I might also explore using tmpfs on FreeBSD at some point (but that would be a separate PR).
Agreed.
This only applies to the file written inside the container (to /secrets) (which can be opted out with
Documentation I can tackle, I might need some help with tests (but I'll try first).
I (mis)understood a previous comment in this thread in a way that this was about the allocation directory,
I have some ideas about this, but as it stands, I'm happy if we can exclude this aspect from the PR and solely focus on Thanks [0] which made me realize that I need to open a PR for the FreeBSD port, which creates |
Yup, I think that would work 👍
I think it may be safer (as in backwards compatible safe) to keep both files with the same permissions for now, just in case somewhere in the implementation (either for this PR or some future change) they get copied from
Sure, feel free to reach out whenever you need help 👍
Good point. Would you mind opening a separate issue for this? |
I think any copy operation from within go will require specifying explicit permissions anyway, so I don’t think it has to be world readable within /private - it will be in /secrets though (which is the part where compatibility comes will be relevant). Copy operation on the OS level apply umask by default, so they’re also non critical.
Thanks!
Will do |
Cool, so we're probably OK. But definitely something to keep in mind during implementation 🙂 |
This complements the `env` parameter, so that the operator can author tasks that don't share their Vault token with the payload. As a result, more powerful tokens can be used in a job definition, allowing it to use template stanzas to issue all kinds of secrets (database secrets, Vault tokens with very specific policies, etc.), without sharing that issuing power with the task itself as long as a driver with `image` isolation is used. This is accomplished by creating a directory called `private` within the task's working directory, which shares many properties of the `secrets` directory (tmpfs where possible, not accessible by `nomad alloc fs` or Nomad's web UI), but isn't mounted into/bound to the container. If the `file` parameter is set to `true` (its default), the Vault token is also written to the NOMAD_SECRETS_DIR, so the default behavior is backwards compatible. Even if the operator never changes the default, they will still benefit from the improved behavior of Nomad never reading the token back in from that - potentially altered - location. See hashicorp#11900
This complements the `env` parameter, so that the operator can author tasks that don't share their Vault token with the payload. As a result, more powerful tokens can be used in a job definition, allowing it to use template stanzas to issue all kinds of secrets (database secrets, Vault tokens with very specific policies, etc.), without sharing that issuing power with the task itself as long as a driver with `image` isolation is used. This is accomplished by creating a directory called `private` within the task's working directory, which shares many properties of the `secrets` directory (tmpfs where possible, not accessible by `nomad alloc fs` or Nomad's web UI), but isn't mounted into/bound to the container. If the `file` parameter is set to `true` (its default), the Vault token is also written to the NOMAD_SECRETS_DIR, so the default behavior is backwards compatible. Even if the operator never changes the default, they will still benefit from the improved behavior of Nomad never reading the token back in from that - potentially altered - location. See hashicorp#11900
This complements the `env` parameter, so that the operator can author tasks that don't share their Vault token with the payload. As a result, more powerful tokens can be used in a job definition, allowing it to use template stanzas to issue all kinds of secrets (database secrets, Vault tokens with very specific policies, etc.), without sharing that issuing power with the task itself as long as a driver with `image` isolation is used. This is accomplished by creating a directory called `private` within the task's working directory, which shares many properties of the `secrets` directory (tmpfs where possible, not accessible by `nomad alloc fs` or Nomad's web UI), but isn't mounted into/bound to the container. If the `file` parameter is set to `true` (its default), the Vault token is also written to the NOMAD_SECRETS_DIR, so the default behavior is backwards compatible. Even if the operator never changes the default, they will still benefit from the improved behavior of Nomad never reading the token back in from that - potentially altered - location. See #11900
This complements the `env` parameter, so that the operator can author tasks that don't share their Vault token with the payload. As a result, more powerful tokens can be used in a job definition, allowing it to use template stanzas to issue all kinds of secrets (database secrets, Vault tokens with very specific policies, etc.), without sharing that issuing power with the task itself as long as a driver with `image` isolation is used. This is accomplished by creating a directory called `private` within the task's working directory, which shares many properties of the `secrets` directory (tmpfs where possible, not accessible by `nomad alloc fs` or Nomad's web UI), but isn't mounted into/bound to the container. If the `file` parameter is set to `true` (its default), the Vault token is also written to the NOMAD_SECRETS_DIR, so the default behavior is backwards compatible. Even if the operator never changes the default, they will still benefit from the improved behavior of Nomad never reading the token back in from that - potentially altered - location. See #11900
|
Closed by #13343 |

Update 2022-05-31: As things evolved and to clarify the mission: The best solution and my goal is to store the token in a separate directory that is not accessible from inside the container. #11905 accomplishes this by writing the vault token to a private directory with strict file permissions (also protecting the token from other unprivileged processes on the host running nomad). It then adds a parameter called
filewhich allows writing a copy of vault token tosecretslike beforeNomad writes a job's vault token to
/secrets/vault_tokenusing world-readable permissions, as default perms (0666) are used (and then umask is applied):nomad/client/allocrunner/taskrunner/vault_hook.go
Lines 344 to 351 in eee5d90
In practice (using a default umask
0022) this means /secrets/vault_token is world readable and writeable only by root (0644).As changing this might break existing setups, an alternative would be to add a
permsparameter to thevaultstanza like a job's template stanza already supports.If there's a chance for adoption, I'm happy to implement/open a pull request for the feature.
Update: Misread how perms work in writefile, so I updated the issue title accordingly. This makes writing a patch for this more complicated (I already prepared one), as - in theory - existing users could have altered umask. It also means that the issue could be worked around by altering umask for the nomad process, even though this might have unexpected side-effects.
The text was updated successfully, but these errors were encountered: