diff --git a/cmd/skopeo/copy.go b/cmd/skopeo/copy.go
index 6f1452a4..3b15fcbc 100644
--- a/cmd/skopeo/copy.go
+++ b/cmd/skopeo/copy.go
@@ -30,6 +30,7 @@ type copyOptions struct {
 	removeSignatures    bool                      // Do not copy signatures from the source image
 	signByFingerprint   string                    // Sign the image using a GPG key with the specified fingerprint
 	signPassphraseFile  string                    // Path pointing to a passphrase file when signing
+	signIdentity        string                    // Identity of the signed image, must be a fully specified docker reference
 	digestFile          string                    // Write digest to this file
 	format              commonFlag.OptionalString // Force conversion of the image to a specified format
 	quiet               bool                      // Suppress output information when copying images
@@ -81,6 +82,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
 	flags.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from SOURCE-IMAGE")
 	flags.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
 	flags.StringVar(&opts.signPassphraseFile, "sign-passphrase-file", "", "File that contains a passphrase for the --sign-by key")
+	flags.StringVar(&opts.signIdentity, "sign-identity", "", "Identity of signed image, must be a fully specified docker reference. Defaults to the target docker reference.")
 	flags.StringVar(&opts.digestFile, "digestfile", "", "Write the digest of the pushed image to the specified file")
 	flags.VarP(commonFlag.NewOptionalStringValue(&opts.format), "format", "f", `MANIFEST TYPE (oci, v2s1, or v2s2) to use in the destination (default is manifest type of source, with fallbacks)`)
 	flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", []string{}, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
@@ -231,11 +233,20 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) (retErr error) {
 		return err
 	}
 
+	var signIdentity reference.Named = nil
+	if opts.signIdentity != "" {
+		signIdentity, err = reference.ParseNamed(opts.signIdentity)
+		if err != nil {
+			return fmt.Errorf("Could not parse --sign-identity: %v", err)
+		}
+	}
+
 	return retry.RetryIfNecessary(ctx, func() error {
 		manifestBytes, err := copy.Image(ctx, policyContext, destRef, srcRef, &copy.Options{
 			RemoveSignatures:      opts.removeSignatures,
 			SignBy:                opts.signByFingerprint,
 			SignPassphrase:        passphrase,
+			SignIdentity:          signIdentity,
 			ReportWriter:          stdout,
 			SourceCtx:             sourceCtx,
 			DestinationCtx:        destinationCtx,
diff --git a/completions/bash/skopeo b/completions/bash/skopeo
index 91d2ad9e..2b0ab634 100644
--- a/completions/bash/skopeo
+++ b/completions/bash/skopeo
@@ -43,6 +43,7 @@ _skopeo_copy() {
     --multi-arch
     --sign-by
     --sign-passphrase-file
+    --sign-identity
     --src-creds --screds
     --src-cert-dir
     --src-tls-verify
diff --git a/docs/skopeo-copy.1.md b/docs/skopeo-copy.1.md
index f70273b8..97e00fc9 100644
--- a/docs/skopeo-copy.1.md
+++ b/docs/skopeo-copy.1.md
@@ -70,7 +70,7 @@ MANIFEST TYPE (oci, v2s1, or v2s2) to use in the destination (default is manifes
 
 Print usage statement
 
-**--multi-arch**
+**--multi-arch** _option_
 
 Control what is copied if _source-image_ refers to a multi-architecture image. Default is system.
 
@@ -89,14 +89,18 @@ Suppress output information when copying images.
 
 Do not copy signatures, if any, from _source-image_. Necessary when copying a signed image to a destination which does not support signatures.
 
-**--sign-by**=_key-id_
+**--sign-by** _key-id_
 
 Add a signature using that key ID for an image name corresponding to _destination-image_
 
-**--sign-passphrase-file**=_path_
+**--sign-passphrase-file** _path_
 
 The passphare to use when signing with the key ID from `--sign-by`. Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable.
 
+**--sign-identity** _reference_
+
+The identity to use when signing the image. The identity must be a fully specified docker reference. If the identity is not specified, the target docker reference will be used.
+
 **--src-shared-blob-dir** _directory_
 
 Directory to use to share blobs across OCI repositories.
diff --git a/integration/copy_test.go b/integration/copy_test.go
index cd3bda8f..c8e28c81 100644
--- a/integration/copy_test.go
+++ b/integration/copy_test.go
@@ -969,20 +969,6 @@ func (s *CopySuite) TestCopyAtomicExtension(c *check.C) {
 	assertDirImagesAreEqual(c, filepath.Join(topDir, "dirDA"), filepath.Join(topDir, "dirDD"))
 }
 
-// copyWithSignedIdentity creates a copy of an unsigned image, adding a signature for an unrelated identity
-// This should be easier than using standalone-sign.
-func copyWithSignedIdentity(c *check.C, src, dest, signedIdentity, signBy, registriesDir string) {
-	topDir := c.MkDir()
-
-	signingDir := filepath.Join(topDir, "signing-temp")
-	assertSkopeoSucceeds(c, "", "copy", "--src-tls-verify=false", src, "dir:"+signingDir)
-	c.Logf("%s", combinedOutputOfCommand(c, "ls", "-laR", signingDir))
-	assertSkopeoSucceeds(c, "^$", "standalone-sign", "-o", filepath.Join(signingDir, "signature-1"),
-		filepath.Join(signingDir, "manifest.json"), signedIdentity, signBy)
-	c.Logf("%s", combinedOutputOfCommand(c, "ls", "-laR", signingDir))
-	assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--dest-tls-verify=false", "dir:"+signingDir, dest)
-}
-
 // Both mirroring support in registries.conf, and mirrored remapIdentity support in policy.json
 func (s *CopySuite) TestCopyVerifyingMirroredSignatures(c *check.C) {
 	const regPrefix = "docker://localhost:5006/myns/mirroring-"
@@ -1026,10 +1012,12 @@ func (s *CopySuite) TestCopyVerifyingMirroredSignatures(c *check.C) {
 	assertSkopeoFails(c, ".*Source image rejected: None of the signatures were accepted, reasons: Signature for identity localhost:5006/myns/mirroring-primary:direct is not accepted; Signature for identity localhost:5006/myns/mirroring-mirror:mirror-signed is not accepted.*",
 		"--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:mirror-signed", dirDest)
 
+	// Fail if we specify an unqualified identity
+	assertSkopeoFails(c, ".*Could not parse --sign-identity: repository name must be canonical.*",
+		"--registries.d", registriesDir, "copy", "--src-tls-verify=false", "--dest-tls-verify=false", "--sign-by=personal@example.com", "--sign-identity=this-is-not-fully-specified", regPrefix+"primary:unsigned", regPrefix+"mirror:primary-signed")
+
 	// Create a signature for mirroring-primary:primary-signed without pushing there.
-	copyWithSignedIdentity(c, regPrefix+"primary:unsigned", regPrefix+"mirror:primary-signed",
-		"localhost:5006/myns/mirroring-primary:primary-signed", "personal@example.com",
-		registriesDir)
+	assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--src-tls-verify=false", "--dest-tls-verify=false", "--sign-by=personal@example.com", "--sign-identity=localhost:5006/myns/mirroring-primary:primary-signed", regPrefix+"primary:unsigned", regPrefix+"mirror:primary-signed")
 	// Verify that a correctly signed image for the primary is accessible using the primary's reference
 	assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"primary:primary-signed", dirDest)
 	// … but verify that while it is accessible using the mirror location
@@ -1044,9 +1032,7 @@ func (s *CopySuite) TestCopyVerifyingMirroredSignatures(c *check.C) {
 	// … it is NOT accessible when requiring a signature …
 	assertSkopeoFails(c, ".*Source image rejected: None of the signatures were accepted, reasons: Signature for identity localhost:5006/myns/mirroring-primary:direct is not accepted; Signature for identity localhost:5006/myns/mirroring-mirror:mirror-signed is not accepted; Signature for identity localhost:5006/myns/mirroring-primary:primary-signed is not accepted.*", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"remap:remapped", dirDest)
 	// … until signed.
-	copyWithSignedIdentity(c, regPrefix+"remap:remapped", regPrefix+"remap:remapped",
-		"localhost:5006/myns/mirroring-primary:remapped", "personal@example.com",
-		registriesDir)
+	assertSkopeoSucceeds(c, "", "--registries.d", registriesDir, "copy", "--src-tls-verify=false", "--dest-tls-verify=false", "--sign-by=personal@example.com", "--sign-identity=localhost:5006/myns/mirroring-primary:remapped", regPrefix+"remap:remapped", regPrefix+"remap:remapped")
 	assertSkopeoSucceeds(c, "", "--policy", policy, "--registries.d", registriesDir, "--registries-conf", "fixtures/registries.conf", "copy", "--src-tls-verify=false", regPrefix+"remap:remapped", dirDest)
 	// To be extra clear about the semantics, verify that the signedPrefix (primary) location never exists
 	// and only the remapped prefix (mirror) is accessed.