diff --git a/cmd/syft/cli/attest.go b/cmd/syft/cli/attest.go
index b1a602d1108..a826977d4b5 100644
--- a/cmd/syft/cli/attest.go
+++ b/cmd/syft/cli/attest.go
@@ -20,8 +20,7 @@ const (
 	attestHelp       = attestExample + attestSchemeHelp
 )
 
-//nolint:dupl
-func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions) *cobra.Command {
+func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions, ao *options.AttestOptions) *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "attest --output [FORMAT] <IMAGE>",
 		Short: "Generate an SBOM as an attestation for the given [SOURCE] container image",
@@ -50,11 +49,17 @@ func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po
 		},
 	}
 
-	// syft attest is an enhancment of the packages command, so it should have the same flags
+	// syft attest is an enhancement of the packages command, so it should have the same flags
 	err := po.AddFlags(cmd, v)
 	if err != nil {
 		log.Fatal(err)
 	}
 
+	// syft attest has its own options not included as part of the packages command
+	err = ao.AddFlags(cmd, v)
+	if err != nil {
+		log.Fatal(err)
+	}
+
 	return cmd
 }
diff --git a/cmd/syft/cli/attest/attest.go b/cmd/syft/cli/attest/attest.go
index b2b31db8eb0..d0a1baac099 100644
--- a/cmd/syft/cli/attest/attest.go
+++ b/cmd/syft/cli/attest/attest.go
@@ -97,6 +97,7 @@ func buildSBOM(app *config.Application, si source.Input, writer sbom.Writer, err
 	return sBytes, nil
 }
 
+//nolint:funlen
 func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-chan error {
 	errs := make(chan error)
 	go func() {
@@ -131,9 +132,18 @@ func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-
 			}
 
 			args := []string{"attest", si.UserInput, "--type", "custom", "--predicate", f.Name()}
+			if app.Attest.Key != "" {
+				args = append(args, "--key", app.Attest.Key)
+			}
+
 			execCmd := exec.Command(cmd, args...)
 			execCmd.Env = os.Environ()
-			execCmd.Env = append(execCmd.Env, "COSIGN_EXPERIMENTAL=1")
+			if app.Attest.Key != "" {
+				execCmd.Env = append(execCmd.Env, fmt.Sprintf("COSIGN_PASSWORD=%s", app.Attest.Password))
+			} else {
+				// no key provided, use cosign's keyless mode
+				execCmd.Env = append(execCmd.Env, "COSIGN_EXPERIMENTAL=1")
+			}
 
 			// bus adapter for ui to hook into stdout via an os pipe
 			r, w, err := os.Pipe()
diff --git a/cmd/syft/cli/commands.go b/cmd/syft/cli/commands.go
index acc18386c40..cc80b97aa34 100644
--- a/cmd/syft/cli/commands.go
+++ b/cmd/syft/cli/commands.go
@@ -45,12 +45,13 @@ func New() (*cobra.Command, error) {
 	// we also need the command to have information about the `root` options because of this alias
 	ro := &options.RootOptions{}
 	po := &options.PackagesOptions{}
+	ao := &options.AttestOptions{}
 	packagesCmd := Packages(v, app, ro, po)
 
 	// root options are also passed to the attestCmd so that a user provided config location can be discovered
 	poweruserCmd := PowerUser(v, app, ro)
 	convertCmd := Convert(v, app, ro, po)
-	attestCmd := Attest(v, app, ro, po)
+	attestCmd := Attest(v, app, ro, po, ao)
 
 	// rootCmd is currently an alias for the packages command
 	rootCmd := &cobra.Command{
diff --git a/cmd/syft/cli/options/attest.go b/cmd/syft/cli/options/attest.go
new file mode 100644
index 00000000000..d436bea9506
--- /dev/null
+++ b/cmd/syft/cli/options/attest.go
@@ -0,0 +1,25 @@
+package options
+
+import (
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+type AttestOptions struct {
+	Key string
+}
+
+var _ Interface = (*AttestOptions)(nil)
+
+func (o AttestOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
+	cmd.Flags().StringVarP(&o.Key, "key", "k", "", "the key to use for the attestation")
+	return bindAttestConfigOptions(cmd.Flags(), v)
+}
+
+func bindAttestConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
+	if err := v.BindPFlag("attest.key", flags.Lookup("key")); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/internal/config/application.go b/internal/config/application.go
index 3cf7254bcac..b5a74b6380f 100644
--- a/internal/config/application.go
+++ b/internal/config/application.go
@@ -47,6 +47,7 @@ type Application struct {
 	Log                logging            `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
 	Catalogers         []string           `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
 	Package            pkg                `yaml:"package" json:"package" mapstructure:"package"`
+	Attest             attest             `yaml:"attest" json:"attest" mapstructure:"attest"`
 	FileMetadata       FileMetadata       `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
 	FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
 	FileContents       fileContents       `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
diff --git a/internal/config/attest.go b/internal/config/attest.go
new file mode 100644
index 00000000000..f0493d7bfce
--- /dev/null
+++ b/internal/config/attest.go
@@ -0,0 +1,13 @@
+package config
+
+import "github.com/spf13/viper"
+
+type attest struct {
+	Key      string `yaml:"key" json:"key" mapstructure:"key"`
+	Password string `yaml:"password" json:"password" mapstructure:"password"`
+}
+
+func (cfg attest) loadDefaultValues(v *viper.Viper) {
+	v.SetDefault("attest.key", "")
+	v.SetDefault("attest.password", "")
+}
diff --git a/ui/event_handlers.go b/ui/event_handlers.go
index 49e5cccd35c..9a015c2163c 100644
--- a/ui/event_handlers.go
+++ b/ui/event_handlers.go
@@ -618,6 +618,9 @@ func AttestationStartedHandler(ctx context.Context, fr *frame.Frame, event party
 			text := s.Text()
 			if strings.Contains(text, "tlog entry created with index") {
 				tlogEntry = text
+			} else {
+				// no tlog entry create so user used personal PKI
+				tlogEntry = "signed attestation using provided key"
 			}
 			_, err = line.Write([]byte(fmt.Sprintf("     %s %s", auxInfoFormat.Sprintf("░░"), text)))
 			if err != nil {