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

Add GitLab.com OIDC to Fulcio #983

Merged
merged 1 commit into from
May 1, 2023
Merged

Conversation

cpanato
Copy link
Member

@cpanato cpanato commented Jan 27, 2023

Summary

  • Add GitLab.com OIDC to Fulcio

Initial work to support gitlab.com, for self-hosted we will need to discuss how we want to deal with it.
similar work that was done in #890

sample gitlab pipeline

docker-build:
  # Use the official docker image.
  image: docker:latest
  stage: build
  variables:
    COSIGN_EXPERIMENTAL: "true"

  id_tokens:
    SIGSTORE_JWT:
      aud: "sigstore"
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - apk add --update curl && rm -rf /var/cache/apk/*
    - curl -L https://github.com/sigstore/cosign/releases/download/v1.13.1/cosign-linux-amd64  -o cosign
    - chmod +x cosign
    - mv cosign /usr/bin
  script:
     - cosign sign --identity-token=${SIGSTORE_JWT} registry.gitlab.com/cpanato/testing-cosign:main

sample token payload

{
  "namespace_id": "1730270",
  "namespace_path": "cpanato",
  "project_id": "42831435",
  "project_path": "cpanato/testing-cosign",
  "user_id": "1430381",
  "user_login": "cpanato",
  "user_email": "[email protected]",
  "pipeline_id": "757451528",
  "pipeline_source": "push",
  "job_id": "3659681386",
  "ref": "main",
  "ref_type": "branch",
  "ref_protected": "true",
  "jti": "914910cc-09f6-4217-8091-a1d3231a37db",
  "iss": "https://gitlab.com",
  "iat": 1674658264,
  "nbf": 1674658259,
  "exp": 1674661864,
  "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main",
  "aud": "sigstore"
}

Fixes #243

@codecov-commenter
Copy link

codecov-commenter commented Jan 27, 2023

Codecov Report

Merging #983 (213c563) into main (be32ddb) will increase coverage by 0.11%.
The diff coverage is 62.80%.

@@            Coverage Diff             @@
##             main     #983      +/-   ##
==========================================
+ Coverage   55.91%   56.02%   +0.11%     
==========================================
  Files          48       50       +2     
  Lines        2783     2904     +121     
==========================================
+ Hits         1556     1627      +71     
- Misses       1097     1133      +36     
- Partials      130      144      +14     
Impacted Files Coverage Δ
pkg/challenges/challenges.go 37.50% <0.00%> (-1.64%) ⬇️
pkg/server/grpc_server.go 51.70% <ø> (ø)
pkg/identity/gitlabcom/issuer.go 62.50% <62.50%> (ø)
pkg/identity/gitlabcom/principal.go 62.61% <62.61%> (ø)
pkg/config/config.go 70.03% <100.00%> (+0.21%) ⬆️
pkg/server/issuer_pool.go 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

@cpanato
Copy link
Member Author

cpanato commented Jan 27, 2023

this is a payload from a self-hosted instance (changed the gitlab url for security) but that pointed to the base url for the self hosted instance

{
  "namespace_id": "4",
  "namespace_path": "cpanato",
  "project_id": "10",
  "project_path": "cpanato/testing-cosign",
  "user_id": "2",
  "user_login": "cpanato",
  "user_email": "[email protected]",
  "pipeline_id": "322",
  "pipeline_source": "push",
  "job_id": "1139",
  "ref": "main",
  "ref_type": "branch",
  "ref_protected": "true",
  "jti": "f94ba179-77b2-4b3f-b179-b2df0698ed70",
  "iss": "https://xxxxxxxxx",
  "iat": 1674821675,
  "nbf": 1674821670,
  "exp": 1674825275,
  "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main",
  "aud": "sigstore"
}

// See the License for the specific language governing permissions and
// limitations under the License.

package gitlabcom
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for not just having gitlab as the package name without the TLD (like github and buildkite)?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to make it clear this is scoped to gitlab.com (the hosted instance) for now and custom gitlab deployments are not supported (yet)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can rename that, did this in the beginning because i don't know how we want to deal with GitLab self-hosted instances

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the tokens should have the same shape, just like Kubernetes tokens, but the issuer will vary.

@haydentherapper
Copy link
Contributor

Will take a closer look on Monday, thanks for adding this!

@marshall007
Copy link
Contributor

@cpanato thanks for working on this! As an FYI we are likely going to stand up a separate OIDC issuer for CI job tokens. I'm hoping we can get that done very soon but we have not established a timeline just yet. Feel free to chime in on the discussion here: https://gitlab.com/groups/gitlab-org/-/epics/9212#note_1256006253

I think we can proceed with integrating our current issuer, but we should be mindful that the issuer claim embedded in the certs is subject to change.

return &jobPrincipal{
subject: token.Subject,
issuer: token.Issuer,
url: fmt.Sprintf("https://gitlab.com/%s/-/jobs/%s", claims.ProjectPath, claims.JobID),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there is a better stable identifier to represent the certificate identity. From #945, we want the SAN to be a "reference to specific build instructions that are responsible for signing". Is the job ID too granular? What are the other claims available?

cc @asraa

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve been told that jobID is likely the best option because it most closely maps to something like the job workflow ref from GH

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree Job ID is closest to job_workflow_ref, but I don't know if it fits the same intent for the SAN. Thinking about it's use in cosign verify --certificate-identity, SANs map more closely to a service account identity rather than a specific identifier of build instructions.

If we used the Job ID I suspect most users would use --certificate-identity-regexp="https://gitlab.com/my/repo/.*" and match on other values instead - it would be very rare that you would want to match on exact Job IDs because they are a unique identifier per run.

I think https://gitlab.com/org/repo@ref probably makes the most sense right now. @marshall007 mentioned that this may become more granular in the future, but for now GitLab CI pipelines only have a single config per repo.

cc @aladh @marshall007 Any opinions here?

PipelineID string `json:"pipeline_id"`
PipelineSource string `json:"pipeline_source"`
JobID string `json:"job_id"`
Ref string `json:"ref"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the claim is not going to be used, we can omit it from the struct.

@haydentherapper
Copy link
Contributor

haydentherapper commented Feb 2, 2023

@marshall007 Thanks for the information!

If it would be helpful to start testing integrations with GitLab-bound certificates, then I would be fine merging this in with a warning that the issuer will change in the near future, and we would only roll this out to staging, not production. If this is not yet doing to be used, then I'd hold off on this PR until #945 is in and the issuer has been stood up for GitLab.

@cpanato
Copy link
Member Author

cpanato commented Feb 8, 2023

@marshall007 @haydentherapper, thanks for the updates and clarification. I will keep my eye on the GitLab issue.

@haydentherapper should we pause this or should I make the changes you requested and move forward?

@mattmoor
Copy link
Member

mattmoor commented Feb 8, 2023

Once this lands, we should get ambient cred support into cosign: #890 (comment)

@haydentherapper
Copy link
Contributor

Sorry for the delay, @cpanato I think we should pause until GitLab has chosen its new issuer.

@mattmoor, yes, let's track that in Cosign.

@cpanato
Copy link
Member Author

cpanato commented Feb 24, 2023

@haydentherapper sure thing

@haydentherapper
Copy link
Contributor

Moving this to draft for now

@haydentherapper haydentherapper marked this pull request as draft February 28, 2023 21:44
@haydentherapper
Copy link
Contributor

Does anyone in this thread know if there's been any progress on standing up a separate issuer?

cc @wlynch

@aladh
Copy link
Contributor

aladh commented Mar 22, 2023

@haydentherapper Unfortunately, there doesn't seem to have been any progress on the new OIDC issuer. Here's the issue for reference: https://gitlab.com/gitlab-org/gitlab/-/issues/390711. I'll try to follow up internally and find out when it should be ready.

@Brcrwilliams
Copy link

@cpanato @haydentherapper Hey all. I'm sorry that roadblocks got thrown up here and slowed the momentum on this. After some discussion, we've decided that we won't be going through with the changes proposed in https://gitlab.com/gitlab-org/gitlab/-/issues/390711. Please let me know if there's anything GitLab can do to help get this PR finished. We're happy to lend a hand in this effort.

@haydentherapper
Copy link
Contributor

Not a blocker for us if you’d prefer to reuse the issuer!

We will want to include the newly added extensions in this PR too. I see an open PR being worked on now to update the mapping between extension and value, we would appreciate any feedback there since y’all have the most up to date view of the purpose of each identity token claim.

@cpanato cpanato force-pushed the gitlabcom branch 4 times, most recently from ca97df4 to e8eac6d Compare April 27, 2023 12:11
@cpanato cpanato marked this pull request as ready for review April 27, 2023 12:19
priyawadhwa
priyawadhwa previously approved these changes Apr 27, 2023
Copy link
Contributor

@priyawadhwa priyawadhwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@haydentherapper
Copy link
Contributor

@wlynch Can you take a pass over this and make sure this looks good? I'll take a look after!

wlynch
wlynch previously approved these changes Apr 27, 2023
Copy link
Member

@wlynch wlynch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks @cpanato! 🎉


// reflect hack because "claims" field is unexported by oidc IDToken
// https://github.com/coreos/go-oidc/pull/329
func withClaims(token *oidc.IDToken, data []byte) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this PR, but we should look into pulling this out into a library so we're not copying the same hacks for each identity provider. 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, i can work on that in a follow up

}

// Set workflow ref URL to SubjectAlternativeName on certificate
cert.URIs = []*url.URL{baseURL.JoinPath(p.repository, "/-/jobs/", p.jobID)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wlynch Is this correct for the SAN? I recall you said that job was too granular. pipeline_ref? Or something else?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - you're right. This should be

Suggested change
cert.URIs = []*url.URL{baseURL.JoinPath(p.repository, "/-/jobs/", p.jobID)}
cert.URIs = []*url.URL{baseURL.JoinPath(p.repository, "@", ref)}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is pipeline ref too granular? That represents the build configuration, but I could imagine creating policy around that.

If not, for ref, i think we’d need a different delimiter, unless @ creates a valid uri

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ can be a valid URI (i.e. ssh://user@host - we also use it in the GitHub Actions SAN)

re pipeline_ref: the pipeline_ref can be a URI to a location not even on GitLab which makes me a little doubtful of whether we want to use that as the SAN.
Most pipeline_refs will be just .gitlab-ci.yml, which means most SANs will be identical unless we transform them. If we do something like prepend the project URL then it becomes harder to distinguish whether the SAN was originally given to us as a URI.

As an example, if you had a repo using a config fetched from http://example.com, I think my preference would be to use https://gitlab.com/user/repo@refs/heads/main rather than http://example.com, since knowing it came from the repo from a trusted branch seems like a more useful base identifier. You'd still have the pipeline_ref in another claim as a way to have finer-grained policies.

That said, we could use it if we really wanted. What do you think? Happy to talk this through more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on @ in the SAN.

Hm, I definitely agree that if pipeline_ref points to a URI outside of gitlab, then we should avoid that. I'm good with this then. Thanks for the background!


var ref string
switch claims.RefType {
case "branch":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we don't want to mutate any claims, thoughts on removing this? I saw the comment from @wlynch though. If you think this would be good to standardize on, let's first open a PR to discuss requiring this prefix.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is without the prefix ref alone is ambiguous - you could have ref/tags/main or ref/heads/v1.0.0. ref_type is what informs what the full-formed ref is. Ideally it would be better if GitLab had a full_ref claim (this way they could also support non branch/tag refs as well), but for now I think this is the best we can do.

cc @marshall007 @Brcrwilliams FYI

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that ref type comes from the token, this looks alright.

Copy link

@Brcrwilliams Brcrwilliams Apr 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally it would be better if GitLab had a full_ref claim

@wlynch we can certainly do that: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119075

In the code, we currently refer to this as the ref_path. Do you think that makes sense as a user-facing name?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds fine. Thanks! 🚀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks y'all! So we'll assume that ref_path will be equivalent to what's here and will update once it's implemented.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we wait for the MR on the GitLab side to be merged or we stick with this implementation for now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to proceed. The result should be the same in the end for branches/tags.

pkg/identity/gitlabcom/principal.go Show resolved Hide resolved
Copy link
Contributor

@haydentherapper haydentherapper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @cpanato, if you can apply the suggested change, we'll be good to go!

I'll cut a new release early next week and get the change out in staging.

return &jobPrincipal{
subject: token.Subject,
issuer: token.Issuer,
url: `https://gitlab.com/`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment for this field says:

	// The URL of the pipeline, the container of many builds. This will be
	// set as a human-friendly SubjectAlternativeName URI in the certificate.
	url string

To make that comment accurate, this should be

Suggested change
url: `https://gitlab.com/`,
url: fmt.Sprintf("https://gitlab.com/%s/-/pipelines/%s", claims.ProjectPath, claims.ProjectID)

We could also add another claim for this in the JWT if need be.

Copy link
Contributor

@haydentherapper haydentherapper Apr 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL is just the base URL, Embed takes the URL and appends that.

We should update the comment to note that (a previous iteration of Fulcio had the URL as the SAN, some refactoring changed that). Thanks for noticing.

We do the same in GH - https://github.com/sigstore/fulcio/blob/main/pkg/identity/github/principal.go#L187-L188, and the URL comment https://github.com/sigstore/fulcio/blob/main/pkg/identity/github/principal.go#L37

url: `https://gitlab.com/`,
eventName: claims.PipelineSource,
pipelineID: claims.PipelineID,
repository: claims.ProjectPath,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In GitLab, we distinguish between projects and repositories. https://gitlab.com/gitlab-org/gitlab is a URL to a project, https://gitlab.com/gitlab-org/gitlab.git is a URL to a repository. A project contains a repository, along with other things like issues, merge requests, pipelines, etc.

TL;DR: project is the correct thing to call this, but repository is ok if we want to keep consistency with the other principals.

@cpanato cpanato dismissed stale reviews from wlynch and priyawadhwa via dff2b0c April 29, 2023 14:37
@cpanato cpanato force-pushed the gitlabcom branch 2 times, most recently from dff2b0c to 58353d4 Compare April 29, 2023 14:39
wlynch
wlynch previously approved these changes May 1, 2023

var ref string
switch claims.RefType {
case "branch":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to proceed. The result should be the same in the end for branches/tags.

Copy link
Contributor

@haydentherapper haydentherapper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cpanato!

@cpanato cpanato requested a review from priyawadhwa May 1, 2023 14:43
Copy link
Contributor

@priyawadhwa priyawadhwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@priyawadhwa priyawadhwa merged commit 2714dd5 into sigstore:main May 1, 2023
@cpanato cpanato deleted the gitlabcom branch May 1, 2023 18:02
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

Successfully merging this pull request may close these issues.

Add support for GitLab tokens