We want to simplify deployment of Vault on Google Cloud Platform. Part of this work is implementing an auth backend for authenticating GCP entities, in particular IAM service accounts.
I've split my proposal into two pieces of work to be done:
Feedback is definitely welcome, especially for the second part. Do these role constraints make sense? Would they be useful?
This backend will handle authentication of IAM service accounts, accounts which belong to an application or VM rather than an individual user. Clients will be able to use existing IAM service accounts and credentials to authenticate with Vault, rather than having to create new credentials per service account to use with another auth backend.
The only other type of IAM entity that can be used to establish identity are Google account users, which should probably fall under a separate auth backend using OAuth or Google Identity to authenticate individual users.
We initially will constrain roles by a list of service account emails/ids. The client will authenticate using a signed JWT, created by the client and signed using IAM API method signJwt for the authenticating service account.
The JWT body will contain information about the service account, at minimum:
{
'id': 1234567890,
'email': '[email protected]',
...
}
Google signs the JWT using one of the service account's system-owned private keys. The returned signed JWT contains the ID of the signing key as a kid field. These private keys are never exposed by Google and are rotated automatically.
On login, the client provides the signed JWT and the name of the role for Vault to verify:
kid key id and service account email/ID as input for IAM method projects.serviceAccounts.keys.get, Vault can get the appropriate Google's public keys to verify the signed JWT. projects.serviceAccounts.get to confirm existence/details of the service account. Using this workflow, the auth backend will need initial configuration of some root credentials with the following IAM permissions:
iam.serviceAccountKeys.getiam.serviceAccount.getOnce Vault has confirmed the client is the service account, Vault then simply checks the authorized group of service accounts to determine if the client account should be allowed to login under the given role.
It makes sense to provide the ability to constrain a service account to a Vault role by IAM permissions. Service accounts can be added to the authorized set of roles on the fly by adding or removing permissions, rather than updating or recreating a role to add/remove a service account.
However, querying the permissions of a service account and defining the Vault roles can get clumsy. This section discusses two types of constraints, IAM roles and IAM permissions, and their various issues. tl;dr: It's very hard to determine what service account has what role for an arbitrary resource.
As a brief review of IAM roles/policies:
These are separate from the Vault role and policies, where policies determine allowed actions in Vault and roles are defined by a set of policies.
Currently, to query the IAM policies or permissions on an account, there are two types API methods, defined per resource/service:
getIamPolicy(): Returns the policy set on a resource. This does not take into consideration inherited policies for parent resources. testIamPermissions(): Takes a set of permissions and outputs which permissions from that set the requesting service account has. Vault would need to assume the role of the service account being tested.These two methods support two different type of constraints.
We would define Vault role constraints by the following arguments:
resource: Path of resource to query policy and roles fromand one of:
role: Name of role defined explicitly on that resource's policy. Vault would call getIamPolicy() on the given resource and search the returned Policy for a given role/service account binding.permissions: Comma-seperated list of required permissions. Vault assumes the authenticating service account's role to call testIamPermissions() on the given resource, passing this set of permissions in and comparing the output set of allowed permissions for equality. There are three main issues with these constraints. We discuss each further, as well as smaller concerns for each type of constraint:
To query the IAM policy or permissions that a given service account has on a specific resource, Vault would thus need to parse from the resource which service to call (i.e. Cloud Resource Manager for a project, Compute Engine for GCE VM instances, etc) and support calling each service as necessary. The backend root credentials would also require additional permissions for each supported resource. The IAM methods on different resources/services are still being added as well, so supporting arbitrary resources would require more maintainance.
We can possible limit this to specific resources at first, depending on how people would want to use role constraints.
Each type of constraint we can support using these two IAM methods has its own issues.
For the IAM role constraint, we would use 'getIamPolicy()'. However, this requires that the role-user binding be defined explicitly on the given resource. For example, if we wanted to see if a service account has create permissions for some Compute Engine VM instance, if the service account had create access defined at the project level, this check would return false.
For the permissions constraint, testIamPermissions() tests the permissions of the authorized caller. For Vault to do this call on behalf of the service account currently requires the credentials of that service account, which some users may rightfully be uncomfortable with.
For the IAM role constraint, the IAM Policy format is awkward to query for a given role/user binding; we would search a list for a role and then search another list of users. The API methods don't provide much help in terms of filtering.
For the permissions constraint, we would essentially redefine the permissions of some IAM role as part of the Vault role. Editing becomes difficult compared to the role constraint. However, the permissions check has the benefit of automatically checking for inherited permissions and doesn't require searching a list of unrelated policy bindings.
@emilymye Any chance you can put this in a Google Doc, so that it's easier to comment? With a GitHub issue you can't pop comments inline.
Here's a link: https://docs.google.com/document/d/1UiRM2QCJscv4Drluk5bhB4cQMwQYBrebjNDXygWbuk8/edit?usp=sharing
While I have your attention, could I also get added to the slack team so I can view the contributers' channel?
Sure! Incoming.
Actually, there's another way to do it in Github: pull-request containing a markdown document. One great example of this working is the Kubernetes feature proposal process, e.g. https://github.com/kubernetes/community/pull/611
See also Rust RFC process: https://github.com/rust-lang/rfcs
Will update the issue when more things are ready, but just FYI I am still working on this with Vault team. We decided to create this as a standalone plugin.
@emilymye any chance external contributions are accepted, even if just testing/doc?
@pires It'll be normal OSS, it's just not quite ready to review yet :) Mostly I wanted to bump so people know we're actively working on it.
@emilymye let me know when you want the repo public; it's up to you/Google!
@emilymye @jefferai are there any plans for making this public in the next couple of weeks? I'm eager to try it out and contribute with some testing! 馃榾
@brunomcustodio we are still going through a review but our goal is to have this out and public by next week. Thanks for being patient!
Terrific! Thanks @emilymye
Closing this issue - the backend is now live and can be mounted using "vault auth-enable 'gcp'" from Vault v0.8.1 onward!
Repo: https://github.com/hashicorp/vault-plugin-auth-gcp
Docs: https://www.vaultproject.io/docs/auth/gcp.html
If you have questions, concerns, issues, please let us know via the vault-users group or by filing an issue on that repo. Thanks all!
Thank you @emilymye. Amazing!
Most helpful comment
Closing this issue - the backend is now live and can be mounted using "vault auth-enable 'gcp'" from Vault v0.8.1 onward!
Repo: https://github.com/hashicorp/vault-plugin-auth-gcp
Docs: https://www.vaultproject.io/docs/auth/gcp.html
If you have questions, concerns, issues, please let us know via the vault-users group or by filing an issue on that repo. Thanks all!