Skip to content

Commit

Permalink
add cosign functions for signature checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel-GrunbergerCA authored and matthyx committed Jan 19, 2023
1 parent 2ce37bd commit c357f12
Show file tree
Hide file tree
Showing 10 changed files with 2,726 additions and 278 deletions.
27 changes: 27 additions & 0 deletions core/pkg/opaprocessor/cosign_has_signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package opaprocessor

import (
"context"
"github.com/google/go-containerregistry/pkg/name"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/sigstore/cosign/pkg/cosign"
)


func has_signature(img string) bool {

This comment has been minimized.

Copy link
@matthyx

matthyx Jan 21, 2023

Contributor

Hi @spacecodedream can you be more specific with your question? What do you want to achieve?

This comment has been minimized.

Copy link
@spacecodedream

spacecodedream Jan 23, 2023

I figured it out thank you though. The world needs more people like you

ref, err := name.ParseReference(img)
if err != nil {
logger.L().Error("parsing reference", helpers.Error(err))
return false
}
sins, err := cosign.FetchSignaturesForReference(context.Background(), ref)

if err != nil {
logger.L().Error("verifying signature", helpers.Error(err))
return false

}

return len(sins) > 0
}
27 changes: 27 additions & 0 deletions core/pkg/opaprocessor/cosign_has_signature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package opaprocessor

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_has_signature(t *testing.T) {

tests := []struct {
name string
img string
want bool
}{
{
name: "valid signature",
img: "quay.io/kubescape/gateway",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, has_signature(tt.img), tt.name)
})
}
}
77 changes: 77 additions & 0 deletions core/pkg/opaprocessor/cosign_verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package opaprocessor

import (
"context"
"crypto"
"fmt"

"github.com/google/go-containerregistry/pkg/name"
"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/pkcs11key"
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
sigs "github.com/sigstore/cosign/pkg/signature"
)

// VerifyCommand verifies a signature on a supplied container image
// nolint
type VerifyCommand struct {
options.RegistryOptions
CheckClaims bool
KeyRef string
CertRef string
CertEmail string
CertIdentity string
CertOidcIssuer string
CertGithubWorkflowTrigger string
CertGithubWorkflowSha string
CertGithubWorkflowName string
CertGithubWorkflowRepository string
CertGithubWorkflowRef string
CertChain string
CertOidcProvider string
EnforceSCT bool
Sk bool
Slot string
Output string
RekorURL string
Attachment string
Annotations sigs.AnnotationsMap
SignatureRef string
HashAlgorithm crypto.Hash
LocalImage bool
}

// Exec runs the verification command
func verify(img string, key string) (bool, error) {

co := &cosign.CheckOpts{}
var ociremoteOpts []ociremote.Option
attachment := ""

pubKey, err := sigs.LoadPublicKeyRaw([]byte(key), crypto.SHA256)
if err != nil {
return false, fmt.Errorf("loading public key: %w", err)
}
pkcs11Key, ok := pubKey.(*pkcs11key.Key)
if ok {
defer pkcs11Key.Close()
}
co.SigVerifier = pubKey
ref, err := name.ParseReference(img)
if err != nil {
return false, fmt.Errorf("parsing reference: %w", err)
}
ref, err = sign.GetAttachedImageRef(ref, attachment, ociremoteOpts...)
if err != nil {
return false, fmt.Errorf("resolving attachment type %s for image %s: %w", attachment, img, err)
}

_, _, err = cosign.VerifyImageSignatures(context.TODO(), ref, co)
if err != nil {
return false, fmt.Errorf("verifying signature: %w", err)
}

return true, nil
}
49 changes: 49 additions & 0 deletions core/pkg/opaprocessor/cosign_verify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package opaprocessor

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_verify(t *testing.T) {
type args struct {
img string
key string
}
tests := []struct {
name string
args args
want bool
wantErr assert.ErrorAssertionFunc
}{
{
"valid signature",
args{
img: "hisu/cosign-tests:signed",
key: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGnMCUU0jGe6r4mPsPuyTXf61PE4e\nNwB/31SvUMmnoyd/1UxSqd+MRPXPU6pcub4k6E9G9SprVCuf6Sydcbyiqw==\n-----END PUBLIC KEY-----",
},
true,
assert.NoError,
},
{
"no signature",
args{
img: "hisu/cosign-tests:unsigned",
key: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGnMCUU0jGe6r4mPsPuyTXf61PE4e\nNwB/31SvUMmnoyd/1UxSqd+MRPXPU6pcub4k6E9G9SprVCuf6Sydcbyiqw==\n-----END PUBLIC KEY-----",
},
false,
assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := verify(tt.args.img, tt.args.key)
if !tt.wantErr(t, err, fmt.Sprintf("verify(%v, %v)", tt.args.img, tt.args.key)) {
return
}
assert.Equalf(t, tt.want, got, "verify(%v, %v)", tt.args.img, tt.args.key)
})
}
}
3 changes: 3 additions & 0 deletions core/pkg/opaprocessor/processorhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,11 @@ func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjec
if err != nil {
return nil, fmt.Errorf("rule: '%s', %s", rule.Name, err.Error())
}
rego.RegisterBuiltin2(cosignVerifySignatureDeclaration, cosignVerifySignatureDefinition)
rego.RegisterBuiltin1(cosignHasSignatureDeclaration, cosignHasSignatureDefinition)
modules[rule.Name] = getRuleData(rule)
compiled, err := ast.CompileModules(modules)

if err != nil {
return nil, fmt.Errorf("in 'runRegoOnSingleRule', failed to compile rule, name: %s, reason: %s", rule.Name, err.Error())
}
Expand Down
37 changes: 37 additions & 0 deletions core/pkg/opaprocessor/utils.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package opaprocessor

import (
"fmt"

"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/topdown/builtins"
"github.com/open-policy-agent/opa/types"
)

// ConvertFrameworksToPolicies convert list of frameworks to list of policies
Expand Down Expand Up @@ -43,3 +49,34 @@ func ConvertFrameworksToSummaryDetails(summaryDetails *reportsummary.SummaryDeta
}

}

var cosignVerifySignatureDeclaration = &rego.Function{
Name: "cosign.verify",
Decl: types.NewFunction(types.Args(types.S, types.A), types.B),
Memoize: true,
}
var cosignVerifySignatureDefinition = func(bctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error) {
aStr, err := builtins.StringOperand(a.Value, 1)
if err != nil {
return nil, fmt.Errorf("invalid parameter type: %v", err)
}
bStr, err := builtins.StringOperand(b.Value, 1)
if err != nil {
return nil, fmt.Errorf("invalid parameter type: %v", err)
}
result, _ := verify(string(aStr), string(bStr))
return ast.BooleanTerm(result), nil
}

var cosignHasSignatureDeclaration = &rego.Function{
Name: "cosign.has_signature",
Decl: types.NewFunction(types.Args(types.S), types.B),
Memoize: true,
}
var cosignHasSignatureDefinition = func(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
aStr, err := builtins.StringOperand(a.Value, 1)
if err != nil {
return nil, fmt.Errorf("invalid parameter type: %v", err)
}
return ast.BooleanTerm(has_signature(string(aStr))), nil
}

0 comments on commit c357f12

Please sign in to comment.