sigs.k8s.io/release-sdk@v0.11.1-0.20240417074027-8061fb5e4952/sign/impl.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sign
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"os"
    24  	"sync"
    25  
    26  	"github.com/google/go-containerregistry/pkg/authn"
    27  	"github.com/google/go-containerregistry/pkg/crane"
    28  	"github.com/google/go-containerregistry/pkg/name"
    29  	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
    30  	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
    31  	"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
    32  	"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
    33  	"github.com/sigstore/cosign/v2/cmd/cosign/cli/verify"
    34  	"github.com/sigstore/cosign/v2/pkg/blob"
    35  	"github.com/sigstore/cosign/v2/pkg/cosign"
    36  	"github.com/sigstore/cosign/v2/pkg/providers"
    37  	"github.com/sigstore/rekor/pkg/generated/client"
    38  	"github.com/sigstore/rekor/pkg/generated/models"
    39  	"github.com/sirupsen/logrus"
    40  
    41  	"sigs.k8s.io/release-utils/env"
    42  	"sigs.k8s.io/release-utils/util"
    43  )
    44  
    45  type defaultImpl struct{}
    46  
    47  //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
    48  //counterfeiter:generate . impl
    49  //go:generate /usr/bin/env bash -c "cat ../scripts/boilerplate/boilerplate.generatego.txt signfakes/fake_impl.go > signfakes/_fake_impl.go && mv signfakes/_fake_impl.go signfakes/fake_impl.go"
    50  type impl interface {
    51  	VerifyFileInternal(ctx context.Context, ko options.KeyOpts, certOpts options.CertVerifyOptions, outputSignature, path string) error
    52  	VerifyImageInternal(ctx context.Context, certOpts options.CertVerifyOptions, keyPath string, images []string, ignoreTLog bool) (*SignedObject, error)
    53  	SignImageInternal(ro options.RootOptions, ko options.KeyOpts, signOpts options.SignOptions, imgs []string) error
    54  	SignFileInternal(ro options.RootOptions, ko options.KeyOpts, payloadPath string,
    55  		b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) error
    56  	Setenv(string, string) error
    57  	EnvDefault(string, string) string
    58  	TokenFromProviders(context.Context, *logrus.Logger) (string, error)
    59  	FileExists(string) bool
    60  	ParseReference(string, ...name.Option) (name.Reference, error)
    61  	FindTlogEntry(ctx context.Context, rClient *client.Rekor, b64Sig string, blobBytes []byte, pubKey []byte) ([]models.LogEntryAnon, error)
    62  	Digest(ref string, opt ...crane.Option) (string, error)
    63  	PayloadBytes(blobRef string) ([]byte, error)
    64  	NewRekorClient(string) (*client.Rekor, error)
    65  	NewWithContext(context.Context, name.Registry, authn.Authenticator, http.RoundTripper, []string) (http.RoundTripper, error)
    66  	ImagesSigned(context.Context, *Signer, ...string) (*sync.Map, error)
    67  }
    68  
    69  func (*defaultImpl) VerifyFileInternal(ctx context.Context, ko options.KeyOpts, certOpts options.CertVerifyOptions, outputSignature, //nolint: gocritic
    70  	path string,
    71  ) error {
    72  	verifyBlob := verify.VerifyBlobCmd{
    73  		KeyOpts:                      ko,
    74  		CertVerifyOptions:            certOpts,
    75  		CertRef:                      certOpts.Cert,
    76  		CertChain:                    certOpts.CertChain,
    77  		SigRef:                       outputSignature,
    78  		CertGithubWorkflowTrigger:    certOpts.CertGithubWorkflowTrigger,
    79  		CertGithubWorkflowSHA:        certOpts.CertGithubWorkflowSha,
    80  		CertGithubWorkflowName:       certOpts.CertGithubWorkflowName,
    81  		CertGithubWorkflowRepository: certOpts.CertGithubWorkflowRepository,
    82  		CertGithubWorkflowRef:        certOpts.CertGithubWorkflowRef,
    83  		IgnoreSCT:                    certOpts.IgnoreSCT,
    84  		SCTRef:                       "",
    85  		Offline:                      false,
    86  		IgnoreTlog:                   true,
    87  	}
    88  
    89  	return verifyBlob.Exec(ctx, path)
    90  }
    91  
    92  func (*defaultImpl) VerifyImageInternal(ctx context.Context, certOpts options.CertVerifyOptions, //nolint: gocritic
    93  	publickeyPath string, images []string, ignoreTLog bool,
    94  ) (*SignedObject, error) {
    95  	v := verify.VerifyCommand{
    96  		IgnoreTlog: ignoreTLog,
    97  		KeyRef:     publickeyPath,
    98  		CertVerifyOptions: options.CertVerifyOptions{
    99  			CertIdentity:         certOpts.CertIdentity,
   100  			CertIdentityRegexp:   certOpts.CertIdentityRegexp,
   101  			CertOidcIssuer:       certOpts.CertOidcIssuer,
   102  			CertOidcIssuerRegexp: certOpts.CertOidcIssuerRegexp,
   103  			IgnoreSCT:            certOpts.IgnoreSCT,
   104  		},
   105  		IgnoreSCT: certOpts.IgnoreSCT,
   106  	}
   107  	return &SignedObject{}, v.Exec(ctx, images)
   108  }
   109  
   110  func (*defaultImpl) SignImageInternal(ro options.RootOptions, ko options.KeyOpts, //nolint: gocritic
   111  	signOpts options.SignOptions, imgs []string, //nolint: gocritic
   112  ) error {
   113  	return sign.SignCmd(
   114  		&ro, ko, signOpts, imgs)
   115  }
   116  
   117  func (*defaultImpl) SignFileInternal(ro options.RootOptions, ko options.KeyOpts, //nolint: gocritic
   118  	payloadPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool,
   119  ) error {
   120  	// Ignoring the signature return value for now as we are setting the outputSignature path and to keep an consistent impl API
   121  	// Setting timeout as 0 is acceptable here because SignBlobCmd uses the passed context
   122  	_, err := sign.SignBlobCmd(&ro, ko, payloadPath, b64, outputSignature, outputCertificate, tlogUpload)
   123  	return err
   124  }
   125  
   126  func (*defaultImpl) Setenv(key, value string) error {
   127  	return os.Setenv(key, value)
   128  }
   129  
   130  func (*defaultImpl) EnvDefault(key, def string) string {
   131  	return env.Default(key, def)
   132  }
   133  
   134  // TokenFromProviders will try the cosign OIDC providers to get an
   135  // oidc token from them.
   136  func (d *defaultImpl) TokenFromProviders(ctx context.Context, logger *logrus.Logger) (string, error) {
   137  	if !d.IdentityProvidersEnabled(ctx) {
   138  		logger.Warn("No OIDC provider enabled. Token cannot be obtained automatically.")
   139  		return "", nil
   140  	}
   141  
   142  	tok, err := providers.Provide(ctx, "sigstore")
   143  	if err != nil {
   144  		return "", fmt.Errorf("fetching oidc token from environment: %w", err)
   145  	}
   146  	return tok, nil
   147  }
   148  
   149  // FileExists returns true if a file exists
   150  func (*defaultImpl) FileExists(path string) bool {
   151  	return util.Exists(path)
   152  }
   153  
   154  // IdentityProvidersEnabled returns true if any of the cosign
   155  // identity providers is able to obteain an OIDC identity token
   156  // suitable for keyless signing,
   157  func (*defaultImpl) IdentityProvidersEnabled(ctx context.Context) bool {
   158  	return providers.Enabled(ctx)
   159  }
   160  
   161  func (*defaultImpl) ParseReference(
   162  	s string, opts ...name.Option,
   163  ) (name.Reference, error) {
   164  	return name.ParseReference(s, opts...)
   165  }
   166  
   167  func (d *defaultImpl) FindTlogEntry(
   168  	ctx context.Context, rClient *client.Rekor, b64Sig string, blobBytes []byte, pubKey []byte,
   169  ) ([]models.LogEntryAnon, error) {
   170  	return cosign.FindTlogEntry(ctx, rClient, b64Sig, blobBytes, pubKey)
   171  }
   172  
   173  func (*defaultImpl) Digest(
   174  	ref string, opts ...crane.Option,
   175  ) (string, error) {
   176  	return crane.Digest(ref, opts...)
   177  }
   178  
   179  func (*defaultImpl) PayloadBytes(blobRef string) (blobBytes []byte, err error) {
   180  	blobBytes, err = blob.LoadFileOrURL(blobRef)
   181  	if err != nil {
   182  		return nil, fmt.Errorf("load file or url of sign payload: %w", err)
   183  	}
   184  	return blobBytes, nil
   185  }
   186  
   187  func (*defaultImpl) NewRekorClient(rekorURL string) (*client.Rekor, error) {
   188  	return rekor.NewClient(rekorURL)
   189  }
   190  
   191  func (*defaultImpl) NewWithContext(
   192  	ctx context.Context,
   193  	reg name.Registry,
   194  	auth authn.Authenticator,
   195  	t http.RoundTripper,
   196  	scopes []string,
   197  ) (http.RoundTripper, error) {
   198  	return transport.NewWithContext(ctx, reg, auth, t, scopes)
   199  }
   200  
   201  func (d *defaultImpl) ImagesSigned(ctx context.Context, s *Signer, refs ...string) (*sync.Map, error) {
   202  	return s.ImagesSigned(ctx, refs...)
   203  }