Skip to content

Commit

Permalink
Adding support for configuration from yaml file (#1687)
Browse files Browse the repository at this point in the history
* Create support for configuration from yaml file

Signed-off-by: Javan lacerda <javanlacerda@google.com>

* conform code to lint

Signed-off-by: Javan lacerda <javanlacerda@google.com>

---------

Signed-off-by: Javan lacerda <javanlacerda@google.com>
  • Loading branch information
javanlacerda committed Jun 11, 2024
1 parent 99cb7c5 commit ec3f4e5
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 10 deletions.
23 changes: 13 additions & 10 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf"
"github.com/sigstore/fulcio/pkg/log"
"github.com/spiffe/go-spiffe/v2/spiffeid"
"gopkg.in/yaml.v3"
)

const defaultOIDCDiscoveryTimeout = 10 * time.Second
Expand All @@ -48,7 +49,7 @@ type verifierWithConfig struct {
}

type FulcioConfig struct {
OIDCIssuers map[string]OIDCIssuer `json:"OIDCIssuers,omitempty"`
OIDCIssuers map[string]OIDCIssuer `json:"OIDCIssuers,omitempty" yaml:"oidc-issuers,omitempty"`

// A meta issuer has a templated URL of the form:
// https://oidc.eks.*.amazonaws.com/id/*
Expand All @@ -57,7 +58,7 @@ type FulcioConfig struct {
// other special characters) Some examples we want to match:
// * https://oidc.eks.us-west-2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB
// * https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us-west1-b/clusters/tenant-cluster
MetaIssuers map[string]OIDCIssuer `json:"MetaIssuers,omitempty"`
MetaIssuers map[string]OIDCIssuer `json:"MetaIssuers,omitempty" yaml:"meta-issuers,omitempty"`

// verifiers is a fixed mapping from our OIDCIssuers to their OIDC verifiers.
verifiers map[string][]*verifierWithConfig
Expand All @@ -67,24 +68,24 @@ type FulcioConfig struct {

type OIDCIssuer struct {
// The expected issuer of an OIDC token
IssuerURL string `json:"IssuerURL,omitempty"`
IssuerURL string `json:"IssuerURL,omitempty" yaml:"issuer-url,omitempty"`
// The expected client ID of the OIDC token
ClientID string `json:"ClientID"`
ClientID string `json:"ClientID" yaml:"client-id,omitempty"`
// Used to determine the subject of the certificate and if additional
// certificate values are needed
Type IssuerType `json:"Type"`
Type IssuerType `json:"Type" yaml:"type,omitempty"`
// Optional, if the issuer is in a different claim in the OIDC token
IssuerClaim string `json:"IssuerClaim,omitempty"`
IssuerClaim string `json:"IssuerClaim,omitempty" yaml:"issuer-claim,omitempty"`
// The domain that must be present in the subject for 'uri' issuer types
// Also used to create an email for 'username' issuer types
SubjectDomain string `json:"SubjectDomain,omitempty"`
SubjectDomain string `json:"SubjectDomain,omitempty" yaml:"subject-domain,omitempty"`
// SPIFFETrustDomain specifies the trust domain that 'spiffe' issuer types
// issue ID tokens for. Tokens with a different trust domain will be
// rejected.
SPIFFETrustDomain string `json:"SPIFFETrustDomain,omitempty"`
SPIFFETrustDomain string `json:"SPIFFETrustDomain,omitempty" yaml:"spiffe-trust-domain,omitempty"`
// Optional, the challenge claim expected for the issuer
// Set if using a custom issuer
ChallengeClaim string `json:"ChallengeClaim,omitempty"`
ChallengeClaim string `json:"ChallengeClaim,omitempty" yaml:"challenge-claim,omitempty"`
}

func metaRegex(issuer string) (*regexp.Regexp, error) {
Expand Down Expand Up @@ -287,7 +288,9 @@ const (
func parseConfig(b []byte) (cfg *FulcioConfig, err error) {
cfg = &FulcioConfig{}
if err := json.Unmarshal(b, cfg); err != nil {
return nil, fmt.Errorf("unmarshal: %w", err)
if err = yaml.Unmarshal(b, cfg); err != nil {
return nil, fmt.Errorf("unmarshal: %w", err)
}
}

return cfg, nil
Expand Down
140 changes: 140 additions & 0 deletions pkg/server/grpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,146 @@ func TestGetConfiguration(t *testing.T) {
}
}

// Tests GetConfigurationFromYaml API
func TestGetConfigurationFromYaml(t *testing.T) {
_, emailIssuer := newOIDCIssuer(t)
_, spiffeIssuer := newOIDCIssuer(t)
_, uriIssuer := newOIDCIssuer(t)
_, usernameIssuer := newOIDCIssuer(t)
_, k8sIssuer := newOIDCIssuer(t)
_, buildkiteIssuer := newOIDCIssuer(t)
_, gitHubIssuer := newOIDCIssuer(t)
_, gitLabIssuer := newOIDCIssuer(t)
_, codefreshIssuer := newOIDCIssuer(t)

issuerDomain, err := url.Parse(usernameIssuer)
if err != nil {
t.Fatal("issuer URL could not be parsed", err)
}

yamlBytes := []byte(fmt.Sprintf(`
oidc-issuers:
%v:
issuer-url: %q
client-id: sigstore
type: spiffe
spiffe-trust-domain: example.com
%v:
issuer-url: %q
client-id: sigstore
type: uri
subject-domain: %q
%v:
issuer-url: %q
client-id: sigstore
type: email
%v:
issuer-url: %q
client-id: sigstore
type: username
subject-domain: %q
%v:
issuer-url: %q
client-id: sigstore
type: buildkite-job
%v:
issuer-url: %q
client-id: sigstore
type: github-workflow
%v:
issuer-url: %q
client-id: sigstore
type: gitlab-pipeline
%v:
issuer-url: %q
client-id: sigstore
type: codefresh-workflow
meta-issuers:
%v:
client-id: sigstore
type: kubernetes`,
spiffeIssuer, spiffeIssuer,
uriIssuer, uriIssuer, uriIssuer,
emailIssuer, emailIssuer,
usernameIssuer, usernameIssuer, issuerDomain.Hostname(),
buildkiteIssuer, buildkiteIssuer,
gitHubIssuer, gitHubIssuer,
gitLabIssuer, gitLabIssuer,
codefreshIssuer, codefreshIssuer,
k8sIssuer))

cfg, err := config.Read(yamlBytes)
if err != nil {
t.Fatalf("config.Read() = %v", err)
}

ctClient, eca := createCA(cfg, t)
ctx := context.Background()
server, conn := setupGRPCForTest(ctx, t, cfg, ctClient, eca)
defer func() {
server.Stop()
conn.Close()
}()

client := protobuf.NewCAClient(conn)

config, err := client.GetConfiguration(ctx, &protobuf.GetConfigurationRequest{})
if err != nil {
t.Fatal("GetConfiguration failed", err)
}

if len(config.Issuers) != 9 {
t.Fatalf("expected 9 issuers, got %v", len(config.Issuers))
}

expectedIssuers := map[string]bool{
emailIssuer: true, spiffeIssuer: true, uriIssuer: true,
usernameIssuer: true, k8sIssuer: true, gitHubIssuer: true,
buildkiteIssuer: true, gitLabIssuer: true, codefreshIssuer: true,
}
for _, iss := range config.Issuers {
var issURL string
switch {
case expectedIssuers[iss.GetIssuerUrl()]:
delete(expectedIssuers, iss.GetIssuerUrl())
issURL = iss.GetIssuerUrl()
case expectedIssuers[iss.GetWildcardIssuerUrl()]:
delete(expectedIssuers, iss.GetWildcardIssuerUrl())
issURL = iss.GetWildcardIssuerUrl()
default:
t.Fatal("issuer missing from expected issuers")
}

if iss.Audience != "sigstore" {
t.Fatalf("expected audience to be sigstore, got %v", iss.Audience)
}

if issURL == emailIssuer {
if iss.ChallengeClaim != "email" {
t.Fatalf("expected email claim for email PoP challenge, got %v", iss.ChallengeClaim)
}
} else {
if iss.ChallengeClaim != "sub" {
t.Fatalf("expected sub claim for non-email PoP challenge, got %v", iss.ChallengeClaim)
}
}

if issURL == spiffeIssuer {
if iss.SpiffeTrustDomain != "example.com" {
t.Fatalf("expected SPIFFE trust domain example.com, got %v", iss.SpiffeTrustDomain)
}
} else {
if iss.SpiffeTrustDomain != "" {
t.Fatalf("expected no SPIFFE trust domain, got %v", iss.SpiffeTrustDomain)
}
}
}

if len(expectedIssuers) != 0 {
t.Fatal("not all issuers were found in configuration")
}
}

// oidcTestContainer holds values needed for each API test invocation
type oidcTestContainer struct {
Signer jose.Signer
Expand Down

0 comments on commit ec3f4e5

Please sign in to comment.