Skip to content
42 changes: 32 additions & 10 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/fulcio"
legacyFulcio "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/legacy/fulcio"
rclient "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/rekor/client"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/v1/google"
Expand Down Expand Up @@ -47,7 +48,8 @@ type ProviderOpts struct {
sync.Mutex

// Keyed off fulcio URL.
signers map[string]*fulcio.SignerVerifier
signers map[string]*fulcio.SignerVerifier
legacySigners map[string]*legacyFulcio.SignerVerifier

// Keyed off rekor URL.
rekorClients map[string]*client.Rekor
Expand All @@ -70,26 +72,45 @@ func (p *ProviderOpts) rekorClient(rekorUrl string) (*client.Rekor, error) {
return rekorClient, nil
}

func (p *ProviderOpts) signerVerifier(fulcioUrl string) (*fulcio.SignerVerifier, error) {
func (p *ProviderOpts) signerVerifier(fulcioUrl string) (*fulcio.SignerVerifier, *legacyFulcio.SignerVerifier, error) {
p.Lock()
defer p.Unlock()

if sv, ok := p.signers[fulcioUrl]; ok {
return sv, nil
var sv *fulcio.SignerVerifier
var legacySv *legacyFulcio.SignerVerifier
var foundSv, foundLegacySv bool

sv, foundSv = p.signers[fulcioUrl]
legacySv, foundLegacySv = p.legacySigners[fulcioUrl]
if foundSv && foundLegacySv {
return sv, legacySv, nil
}

furl, err := url.Parse(fulcioUrl)
if err != nil {
return nil, err
return nil, nil, err
}
fulcioClient := api.NewClient(furl, api.WithUserAgent("terraform-provider-cosign"))
sv, err := fulcio.NewSigner(p.oidc, fulcioClient)
if err != nil {
return nil, err

if !foundSv {
var err error
sv, err = fulcio.NewSigner(p.oidc, fulcioClient)
if err != nil {
return nil, nil, err
}
p.signers[fulcioUrl] = sv
}

if !foundLegacySv {
var err error
legacySv, err = legacyFulcio.NewSigner(p.oidc, fulcioClient)
if err != nil {
return nil, nil, err
}
p.legacySigners[fulcioUrl] = legacySv
}

p.signers[fulcioUrl] = sv
return sv, nil
return sv, legacySv, nil
}

func (p *ProviderOpts) withContext(ctx context.Context) []remote.Option {
Expand Down Expand Up @@ -149,6 +170,7 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
oidc: &oidcProvider{},
defaultAttestationEntryType: attestationEntryType,
signers: map[string]*fulcio.SignerVerifier{},
legacySigners: map[string]*legacyFulcio.SignerVerifier{},
rekorClients: map[string]*client.Rekor{},
}

Expand Down
38 changes: 28 additions & 10 deletions internal/provider/resource_attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"os"

"github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant"
legacySecant "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/legacy"
legacyStypes "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/legacy/types"
stypes "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/types"
"github.com/chainguard-dev/terraform-provider-oci/pkg/validators"
"github.com/google/go-containerregistry/pkg/name"
Expand Down Expand Up @@ -280,7 +282,7 @@ func toPredObject(data *AttestResourceModel) *PredicateObject {
return nil
}

func (r *AttestResource) doAttest(ctx context.Context, arm *AttestResourceModel, preds []PredicateObject) (string, error, error) {
func (r *AttestResource) doAttest(ctx context.Context, arm *AttestResourceModel, preds []PredicateObject, legacy bool) (string, error, error) {
digest, err := name.NewDigest(arm.Image.ValueString())
if err != nil {
return "", nil, errors.New("unable to parse image digest")
Expand All @@ -294,6 +296,7 @@ func (r *AttestResource) doAttest(ctx context.Context, arm *AttestResourceModel,
}

statements := []*stypes.Statement{}
legacyStatements := []*legacyStypes.Statement{}

for _, data := range preds {
// Write the attestation to a temporary file.
Expand Down Expand Up @@ -341,15 +344,22 @@ func (r *AttestResource) doAttest(ctx context.Context, arm *AttestResourceModel,
return "", nil, errors.New("one of predicate or predicate_file must be specified")
}

stmt, err := secant.NewStatement(digest, reader, data.PredicateType.ValueString())
if err != nil {
return "", nil, fmt.Errorf("creating attestation statement: %w", err)
if legacy {
stmt, err := legacySecant.NewStatement(digest, reader, data.PredicateType.ValueString())
if err != nil {
return "", nil, fmt.Errorf("creating attestation statement: %w", err)
}
legacyStatements = append(legacyStatements, stmt)
} else {
stmt, err := secant.NewStatement(digest, reader, data.PredicateType.ValueString())
if err != nil {
return "", nil, fmt.Errorf("creating attestation statement: %w", err)
}
statements = append(statements, stmt)
}

statements = append(statements, stmt)
}

sv, err := r.popts.signerVerifier(arm.FulcioURL.ValueString())
sv, legacySv, err := r.popts.signerVerifier(arm.FulcioURL.ValueString())
if err != nil {
return "", nil, fmt.Errorf("creating signer: %w", err)
}
Expand All @@ -362,7 +372,13 @@ func (r *AttestResource) doAttest(ctx context.Context, arm *AttestResourceModel,
ctx, cancel := context.WithTimeout(ctx, options.DefaultTimeout)
defer cancel()

if err := secant.Attest(ctx, arm.Conflict.ValueString(), statements, sv, rekorClient, r.popts.withContext(ctx), secant.WithRekorEntryType(r.popts.defaultAttestationEntryType)); err != nil {
var attestErr error
if legacy {
attestErr = legacySecant.Attest(ctx, arm.Conflict.ValueString(), legacyStatements, legacySv, rekorClient, r.popts.withContext(ctx), legacySecant.WithRekorEntryType(r.popts.defaultAttestationEntryType))
} else {
attestErr = secant.Attest(ctx, arm.Conflict.ValueString(), statements, sv, rekorClient, r.popts.withContext(ctx), secant.WithRekorEntryType(r.popts.defaultAttestationEntryType))
}
if attestErr != nil {
return "", nil, fmt.Errorf("unable to attest image %q: %w", digest.String(), err)
}

Expand All @@ -382,7 +398,8 @@ func (r *AttestResource) Create(ctx context.Context, req resource.CreateRequest,
return
}

digest, warning, err := r.doAttest(ctx, data, preds)
// TODO: add configurable options for legacy/latest/both
digest, warning, err := r.doAttest(ctx, data, preds, false)
if err != nil {
resp.Diagnostics.AddError("error while attesting", err.Error())
return
Expand Down Expand Up @@ -430,7 +447,8 @@ func (r *AttestResource) Update(ctx context.Context, req resource.UpdateRequest,
return
}

digest, warning, err := r.doAttest(ctx, data, preds)
// TODO: add configurable options for legacy/latest/both
digest, warning, err := r.doAttest(ctx, data, preds, false)
if err != nil {
resp.Diagnostics.AddError("error while attesting", err.Error())
return
Expand Down
21 changes: 15 additions & 6 deletions internal/provider/resource_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"

"github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant"
legacySecant "github.com/chainguard-dev/terraform-provider-cosign/pkg/private/secant/legacy"
"github.com/chainguard-dev/terraform-provider-oci/pkg/validators"
"github.com/google/go-containerregistry/pkg/name"
"github.com/hashicorp/terraform-plugin-framework/path"
Expand Down Expand Up @@ -114,7 +115,7 @@ func (r *SignResource) Configure(ctx context.Context, req resource.ConfigureRequ
r.popts = popts
}

func (r *SignResource) doSign(ctx context.Context, data *SignResourceModel) (string, error, error) {
func (r *SignResource) doSign(ctx context.Context, data *SignResourceModel, legacy bool) (string, error, error) {
digest, err := name.NewDigest(data.Image.ValueString())
if err != nil {
return "", nil, errors.New("unable to parse image digest")
Expand All @@ -127,7 +128,7 @@ func (r *SignResource) doSign(ctx context.Context, data *SignResourceModel) (str
return digest.String(), errors.New("no ambient credentials are available to sign with, skipping signing"), nil
}

sv, err := r.popts.signerVerifier(data.FulcioURL.ValueString())
sv, legacySv, err := r.popts.signerVerifier(data.FulcioURL.ValueString())
if err != nil {
return "", nil, fmt.Errorf("creating signer: %w", err)
}
Expand All @@ -143,8 +144,14 @@ func (r *SignResource) doSign(ctx context.Context, data *SignResourceModel) (str
// TODO: This should probably be configurable?
var annotations map[string]any = nil

if err := secant.Sign(ctx, data.Conflict.ValueString(), annotations, sv, rekorClient, []name.Digest{digest}, r.popts.withContext(ctx)); err != nil {
return "", nil, fmt.Errorf("unable to sign image %q: %w", digest.String(), err)
var signErr error
if legacy {
signErr = legacySecant.Sign(ctx, data.Conflict.ValueString(), annotations, legacySv, rekorClient, []name.Digest{digest}, r.popts.withContext(ctx))
} else {
signErr = secant.Sign(ctx, data.Conflict.ValueString(), annotations, sv, rekorClient, []name.Digest{digest}, r.popts.withContext(ctx))
}
if signErr != nil {
return "", nil, fmt.Errorf("unable to sign image %q: %w", digest.String(), signErr)
}
return digest.String(), nil, nil
}
Expand All @@ -156,7 +163,8 @@ func (r *SignResource) Create(ctx context.Context, req resource.CreateRequest, r
return
}

digest, warning, err := r.doSign(ctx, data)
// TODO: add configurable options for legacy/latest/both
digest, warning, err := r.doSign(ctx, data, false)
if err != nil {
resp.Diagnostics.AddError("error while signing", err.Error())
return
Expand Down Expand Up @@ -198,7 +206,8 @@ func (r *SignResource) Update(ctx context.Context, req resource.UpdateRequest, r
return
}

digest, warning, err := r.doSign(ctx, data)
// TODO: add configurable options for legacy/latest/both
digest, warning, err := r.doSign(ctx, data, false)
if err != nil {
resp.Diagnostics.AddError("error while signing", err.Error())
return
Expand Down
Loading
Loading