Skip to content

Commit 2714dd5

Browse files
authored
Add GitLab.com OIDC to Fulcio (#983)
Signed-off-by: cpanato <[email protected]>
1 parent be32ddb commit 2714dd5

File tree

12 files changed

+800
-4
lines changed

12 files changed

+800
-4
lines changed

config/fulcio-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ data:
3333
"Type": "spiffe",
3434
"SPIFFETrustDomain": "allow.pub"
3535
},
36+
"https://gitlab.com": {
37+
"IssuerURL": "https://gitlab.com",
38+
"ClientID": "sigstore",
39+
"Type": "gitlab-pipeline"
40+
},
3641
"https://oauth2.sigstore.dev/auth": {
3742
"IssuerURL": "https://oauth2.sigstore.dev/auth",
3843
"ClientID": "sigstore",

federation/gitlab.com/config.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2023 The Sigstore Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
url: https://gitlab.com
16+
17+
description: "GitLab OIDC tokens for job identity"
18+
type: "gitlab-pipeline"

pkg/challenges/challenges.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/sigstore/fulcio/pkg/identity/buildkite"
3030
"github.com/sigstore/fulcio/pkg/identity/email"
3131
"github.com/sigstore/fulcio/pkg/identity/github"
32+
"github.com/sigstore/fulcio/pkg/identity/gitlabcom"
3233
"github.com/sigstore/fulcio/pkg/identity/kubernetes"
3334
"github.com/sigstore/fulcio/pkg/identity/spiffe"
3435
"github.com/sigstore/fulcio/pkg/identity/uri"
@@ -60,6 +61,8 @@ func PrincipalFromIDToken(ctx context.Context, tok *oidc.IDToken) (identity.Prin
6061
switch iss.Type {
6162
case config.IssuerTypeBuildkiteJob:
6263
principal, err = buildkite.JobPrincipalFromIDToken(ctx, tok)
64+
case config.IssuerTypeGitLabPipeline:
65+
principal, err = gitlabcom.JobPrincipalFromIDToken(ctx, tok)
6366
case config.IssuerTypeEmail:
6467
principal, err = email.PrincipalFromIDToken(ctx, tok)
6568
case config.IssuerTypeSpiffe:

pkg/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const (
214214
IssuerTypeBuildkiteJob = "buildkite-job"
215215
IssuerTypeEmail = "email"
216216
IssuerTypeGithubWorkflow = "github-workflow"
217+
IssuerTypeGitLabPipeline = "gitlab-pipeline"
217218
IssuerTypeKubernetes = "kubernetes"
218219
IssuerTypeSpiffe = "spiffe"
219220
IssuerTypeURI = "uri"
@@ -468,6 +469,8 @@ func issuerToChallengeClaim(issType IssuerType, challengeClaim string) string {
468469
switch issType {
469470
case IssuerTypeBuildkiteJob:
470471
return "sub"
472+
case IssuerTypeGitLabPipeline:
473+
return "sub"
471474
case IssuerTypeEmail:
472475
return "email"
473476
case IssuerTypeGithubWorkflow:

pkg/config/config_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ func Test_issuerToChallengeClaim(t *testing.T) {
489489
if claim := issuerToChallengeClaim(IssuerTypeGithubWorkflow, ""); claim != "sub" {
490490
t.Fatalf("expected sub subject claim for GitHub issuer, got %s", claim)
491491
}
492+
if claim := issuerToChallengeClaim(IssuerTypeGitLabPipeline, ""); claim != "sub" {
493+
t.Fatalf("expected sub subject claim for GitLab issuer, got %s", claim)
494+
}
492495
if claim := issuerToChallengeClaim(IssuerTypeKubernetes, ""); claim != "sub" {
493496
t.Fatalf("expected sub subject claim for K8S issuer, got %s", claim)
494497
}

pkg/identity/gitlabcom/issuer.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2023 The Sigstore Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package gitlabcom
16+
17+
import (
18+
"context"
19+
20+
"github.com/sigstore/fulcio/pkg/identity"
21+
"github.com/sigstore/fulcio/pkg/identity/base"
22+
)
23+
24+
type gitlabIssuer struct {
25+
identity.Issuer
26+
}
27+
28+
func Issuer(issuerURL string) identity.Issuer {
29+
return &gitlabIssuer{base.Issuer(issuerURL)}
30+
}
31+
32+
func (e *gitlabIssuer) Authenticate(ctx context.Context, token string) (identity.Principal, error) {
33+
idtoken, err := identity.Authorize(ctx, token)
34+
if err != nil {
35+
return nil, err
36+
}
37+
return JobPrincipalFromIDToken(ctx, idtoken)
38+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2023 The Sigstore Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package gitlabcom
16+
17+
import (
18+
"context"
19+
"encoding/json"
20+
"testing"
21+
22+
"github.com/coreos/go-oidc/v3/oidc"
23+
"github.com/sigstore/fulcio/pkg/identity"
24+
)
25+
26+
func TestIssuer(t *testing.T) {
27+
ctx := context.Background()
28+
url := "test-issuer-url"
29+
issuer := Issuer(url)
30+
31+
// test the Match function
32+
t.Run("match", func(t *testing.T) {
33+
if matches := issuer.Match(ctx, url); !matches {
34+
t.Fatal("expected url to match but it doesn't")
35+
}
36+
if matches := issuer.Match(ctx, "some-other-url"); matches {
37+
t.Fatal("expected match to fail but it didn't")
38+
}
39+
})
40+
41+
t.Run("authenticate", func(t *testing.T) {
42+
token := &oidc.IDToken{
43+
Issuer: "https://iss.example.com",
44+
Subject: "repo:sigstore/fulcio:ref:refs/heads/main",
45+
}
46+
claims, err := json.Marshal(map[string]interface{}{
47+
"namespace_id": "1730270",
48+
"namespace_path": "cpanato",
49+
"project_id": "42831435",
50+
"project_path": "cpanato/testing-cosign",
51+
"user_id": "1430381",
52+
"user_login": "cpanato",
53+
"user_email": "[email protected]",
54+
"pipeline_id": "757451528",
55+
"pipeline_source": "push",
56+
"job_id": "3659681386",
57+
"sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
58+
"runner_id": 1,
59+
"runner_environment": "gitlab-hosted",
60+
"ref": "main",
61+
"ref_type": "branch",
62+
"ref_protected": "true",
63+
"jti": "914910cc-09f6-4217-8091-a1d3231a37db",
64+
"iss": "https://gitlab.com",
65+
"iat": 1674658264,
66+
"nbf": 1674658259,
67+
"exp": 1674661864,
68+
"sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main",
69+
"aud": "sigstore",
70+
})
71+
if err != nil {
72+
t.Fatal(err)
73+
}
74+
withClaims(token, claims)
75+
76+
identity.Authorize = func(_ context.Context, _ string) (*oidc.IDToken, error) {
77+
return token, nil
78+
}
79+
principal, err := issuer.Authenticate(ctx, "token")
80+
if err != nil {
81+
t.Fatal(err)
82+
}
83+
84+
if principal.Name(ctx) != "repo:sigstore/fulcio:ref:refs/heads/main" {
85+
t.Fatalf("got unexpected name %s", principal.Name(ctx))
86+
}
87+
})
88+
}

0 commit comments

Comments
 (0)