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

GitLab CI/CD Pipeline ID Token ACLing: Template claim information into token_policies #318

Open
cipherboy opened this issue Oct 23, 2024 · 0 comments

Comments

@cipherboy
Copy link

GitLab supports an external secrets integration with HashiCorp Vault. GitLab generates an ID token which describes properties about the pipeline execution: the project and user that originated the request, information about environment and branch, &c. This allows for very granular permissioning of secrets, that our customers use.

For instance, one could imagine a layout of mounts like:

/project_{id}/data/<secret>

with granular ACL policies that allow certain workloads (say, only pipelines with environment=prod and branch=main) to access given secrets (which, may be shared across other workloads). Theoretically, some secrets could even be shared across different projects and they may live in some shared space.

Right now, a Vault operator(s) has to set up three things for a GitLab pipeline author:

  1. Provision the actual secret for the project.
  2. Provision the ACL policies for the project's pipelines.
  3. Provision a new JWT auth method role to associate the information in the claims to a concrete token_policy.

In particular, step 3 necessitates using per-pipeline JWT roles, which means every single pipeline needs to be unique and requires Vault operator<->pipeline author communication, despite having largely similar requirements for every pipeline if ACL policies are appropriately structured.

This is an authorization and UX problem, as having so many distinct roles which need to be kept in sync with ACL policies is complex and means that pipelines are not portable across repositories (e.g., reusable pipeline components may not be able to auth because their role information would differ and not be allowed to authenticate with the pipeline's token).

One could imagine that an ACL policy layout such as:

sys/policies/acl/project_{id}/env_{env}/branch_{branch}

in which information from the claims dictate the set of allowed policies, with no loss as to the secrets allowed within each policy.

I posit, if JWT roles supported a parameter such as token_policies_template_claims=<bool>, token_claims could take on a text/template value (perhaps using sdk/helper/template like the database plugins):

token_claims=[`project_{{.project_id}}/env_{{.environment}}/branch_{{.}}`]

This would allow all GitLab pipeline authors to use a single role globally (and even for JWT authors to set this as default) and let them only need to know the paths of the secrets they want out of Vault.

This type of hierarchy (perhaps not laid out as such) probably already exists at some organizations, but the mapping from claims->policy would have to be manually maintained by creating additional roles (which match a small subset of tokens) and manually setting the relevant policies.


In talking with some other community members, it seems like this would also benefit GitHub OIDC token validation and potentially other Kubernetes or cloud workloads where policies can be inferred from information about the workload from its corresponding ID token.

Notably, having control over token policies in the role already allowed any one to set any policy (assuming they could auth via that method). This grants a little more power to the token issuer (which, presumably is already trusted), depending on the policy, but with extensions to the SDK templating library (like glob or regex support), validation tools for role authors could be added to restrict ID token's allowed policies.

The proposed implementation in OpenBao silently ignores empty policies but enforces that there are no missing-but-referenced-during-templating claims. The latter can be worked around in the templating system if a role author wants to conditionally provision a policy based on a conditional claim (e.g., {{ if ne nil (index . "optional_claim") }}...{{ end }}).

The other restriction is that there is a 1:{0,1} correspondence between entries in the token_policies value (pre-templating) and the end set of policies. This means using range queries is a little complex (e.g., if a single claim directly encoded all policies like vault_policies=["policy-a", "policy-b"], it would be impossible to write this for arbitrarily long lists of policies... but with much repetition, could be done for bounded numbers of items via range template instructions).

Lastly, we are looking to add this for both JWT login and OIDC ID token login flows for consistency.


This was opened on OpenBao as openbao/openbao#618; I'm happy to open the JWT portions here as the JWT plugin remains under the MPL. However, I will not be able to open the changes to the SDK (to support globs and base64 decoding) as that repo contains BUSL-licensed code as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant