Skip to content

Commit

Permalink
add commit sha and trigger to github workflow
Browse files Browse the repository at this point in the history
Signed-off-by: Asra Ali <asraa@google.com>
  • Loading branch information
asraa committed Nov 1, 2021
1 parent 58ec2fa commit 8fde10d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 6 deletions.
2 changes: 1 addition & 1 deletion pkg/api/googleca_signing_cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func GoogleCASigningCertHandler(ctx context.Context, subj *challenges.ChallengeR
privca = googleca.KubernetesSubject(subj.Value)
}

extensions := googleca.IssuerExtension(subj.Issuer)
extensions := append(googleca.IssuerExtension(subj.Issuer), googleca.GithubWorkflowExtension(subj.WorkflowInfo)...)
req := googleca.Req(parent, privca, publicKey, extensions)
logger.Infof("requesting cert from %s for %v", parent, Subject)

Expand Down
23 changes: 23 additions & 0 deletions pkg/ca/googleca/googleca.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"sync"

privateca "cloud.google.com/go/security/privateca/apiv1beta1"
"github.com/sigstore/fulcio/pkg/challenges"
privatecapb "google.golang.org/genproto/googleapis/cloud/security/privateca/v1beta1"
"google.golang.org/protobuf/types/known/durationpb"
)
Expand Down Expand Up @@ -124,6 +125,28 @@ func GithubWorkflowSubject(id string) *privatecapb.CertificateConfig_SubjectConf
}
}

func GithubWorkflowExtension(info challenges.WorkflowResult) []*privatecapb.X509Extension {
res := []*privatecapb.X509Extension{}
if info.Sha != "" {
res = append(res, &privatecapb.X509Extension{
ObjectId: &privatecapb.ObjectId{
ObjectIdPath: []int32{1, 3, 6, 1, 4, 1, 57264, 1, 2},
},
Value: []byte(info.Sha),
})
}

if info.Trigger != "" {
res = append(res, &privatecapb.X509Extension{
ObjectId: &privatecapb.ObjectId{
ObjectIdPath: []int32{1, 3, 6, 1, 4, 1, 57264, 1, 3},
},
Value: []byte(info.Trigger),
})
}
return res
}

func KubernetesSubject(id string) *privatecapb.CertificateConfig_SubjectConfig {
return &privatecapb.CertificateConfig_SubjectConfig{
SubjectAltName: &privatecapb.SubjectAltNames{
Expand Down
20 changes: 19 additions & 1 deletion pkg/ca/x509ca/x509ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func CreateClientCertificate(rootCA *x509.Certificate, subject *challenges.Chall
}
cert.URIs = []*url.URL{k8sURI}
}
cert.ExtraExtensions = IssuerExtension(subject.Issuer)
cert.ExtraExtensions = append(IssuerExtension(subject.Issuer), GithubWorkflowExtension(subject.WorkflowInfo)...)

certBytes, err := x509.CreateCertificate(rand.Reader, cert, rootCA, publicKeyPEM, privKey)
if err != nil {
Expand All @@ -79,6 +79,24 @@ func CreateClientCertificate(rootCA *x509.Certificate, subject *challenges.Chall
return string(certPEM), nil, nil
}

func GithubWorkflowExtension(info challenges.WorkflowResult) []pkix.Extension {
res := []pkix.Extension{}
if info.Sha != "" {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2},
Value: []byte(info.Sha),
})
}

if info.Trigger != "" {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3},
Value: []byte(info.Trigger),
})
}
return res
}

func IssuerExtension(issuer string) []pkix.Extension {
if issuer == "" {
return nil
Expand Down
40 changes: 36 additions & 4 deletions pkg/challenges/challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,18 @@ const (
KubernetesValue
)

type WorkflowResult struct {
// Additional information associated with a Github Workflow
Trigger string
Sha string
}

type ChallengeResult struct {
Issuer string
TypeVal ChallengeType
Value string
// Extra information, non-empty for a Github workflow
WorkflowInfo WorkflowResult
}

func CheckSignature(pub crypto.PublicKey, proof []byte, email string) error {
Expand Down Expand Up @@ -176,6 +184,11 @@ func GithubWorkflow(ctx context.Context, principal *oidc.IDToken, pubKey, challe
if err != nil {
return nil, err
}
// Additional info
workflowInfo, err := workflowInfoFromIDToken(principal)
if err != nil {
return nil, err
}

pkixPubKey, err := x509.ParsePKIXPublicKey(pubKey)
if err != nil {
Expand All @@ -200,9 +213,10 @@ func GithubWorkflow(ctx context.Context, principal *oidc.IDToken, pubKey, challe

// Now issue cert!
return &ChallengeResult{
Issuer: issuer,
TypeVal: GithubWorkflowValue,
Value: workflowRef,
Issuer: issuer,
TypeVal: GithubWorkflowValue,
Value: workflowRef,
WorkflowInfo: workflowInfo,
}, nil
}

Expand Down Expand Up @@ -255,6 +269,25 @@ func workflowFromIDToken(token *oidc.IDToken) (string, error) {
return "https://github.com/" + claims.JobWorkflowRef, nil
}

func workflowInfoFromIDToken(token *oidc.IDToken) (WorkflowResult, error) {
// Extract custom claims
var claims struct {
Sha string `json:"sha"`
Trigger string `json:"event_name"`
// The other fields that are present here seem to depend on the type
// of workflow trigger that initiated the action.
}
if err := token.Claims(&claims); err != nil {
return WorkflowResult{}, err
}

// We use this in URIs, so it has to be a URI.
return WorkflowResult{
Trigger: claims.Trigger,
Sha: claims.Sha,
}, nil
}

func isSpiffeIDAllowed(host, spiffeID string) bool {
// Strip spiffe://
name := strings.TrimPrefix(spiffeID, "spiffe://")
Expand All @@ -266,5 +299,4 @@ func isSpiffeIDAllowed(host, spiffeID string) bool {
return true
}
return strings.Contains(spiffeDomain, "."+host)

}

0 comments on commit 8fde10d

Please sign in to comment.