Add support for sigstoreSigned in (podman image trust set)

NOTE: This does not edit the use-sigstore-attachments value
in registries.d, similarly to how (podman image trust set) didn't
set the lookaside paths for simple signing.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač
2022-08-24 19:48:26 +02:00
parent 9828bc4453
commit ff3f574fc0
4 changed files with 38 additions and 5 deletions

View File

@ -53,7 +53,7 @@ File(s) must exist before using this command`)
} }
func setTrust(cmd *cobra.Command, args []string) error { func setTrust(cmd *cobra.Command, args []string) error {
validTrustTypes := []string{"accept", "insecureAcceptAnything", "reject", "signedBy"} validTrustTypes := []string{"accept", "insecureAcceptAnything", "reject", "signedBy", "sigstoreSigned"}
valid, err := isValidImageURI(args[0]) valid, err := isValidImageURI(args[0])
if err != nil || !valid { if err != nil || !valid {
@ -61,7 +61,7 @@ func setTrust(cmd *cobra.Command, args []string) error {
} }
if !util.StringInSlice(setOptions.Type, validTrustTypes) { if !util.StringInSlice(setOptions.Type, validTrustTypes) {
return fmt.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy')", setOptions.Type) return fmt.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy', 'sigstoreSigned')", setOptions.Type)
} }
return registry.ImageEngine().SetTrust(registry.Context(), args, setOptions) return registry.ImageEngine().SetTrust(registry.Context(), args, setOptions)
} }

View File

@ -32,7 +32,8 @@ Trust **type** provides a way to:
Allowlist ("accept") or Allowlist ("accept") or
Denylist ("reject") registries or Denylist ("reject") registries or
Require signature (“signedBy”). Require a simple signing signature (“signedBy”),
Require a sigstore signature ("sigstoreSigned").
Trust may be updated using the command **podman image trust set** for an existing trust scope. Trust may be updated using the command **podman image trust set** for an existing trust scope.
@ -45,12 +46,14 @@ Trust may be updated using the command **podman image trust set** for an existin
#### **--pubkeysfile**, **-f**=*KEY1* #### **--pubkeysfile**, **-f**=*KEY1*
A path to an exported public key on the local system. Key paths A path to an exported public key on the local system. Key paths
will be referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to will be referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to
require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** type. require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** and **sigstoreSigned** types.
#### **--type**, **-t**=*value* #### **--type**, **-t**=*value*
The trust type for this policy entry. The trust type for this policy entry.
Accepted values: Accepted values:
**signedBy** (default): Require signatures with corresponding list of **signedBy** (default): Require simple signing signatures with corresponding list of
public keys
**sigstoreSigned**: Require sigstore signatures with corresponding list of
public keys public keys
**accept**: do not require any signatures for this **accept**: do not require any signatures for this
registry scope registry scope

View File

@ -161,6 +161,14 @@ func AddPolicyEntries(policyPath string, input AddPolicyEntriesInput) error {
newReposContent = append(newReposContent, RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath}) newReposContent = append(newReposContent, RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath})
} }
case "sigstoreSigned":
if len(pubkeysfile) == 0 {
return errors.New("at least one public key must be defined for type 'sigstoreSigned'")
}
for _, filepath := range pubkeysfile {
newReposContent = append(newReposContent, RepoContent{Type: trustType, KeyPath: filepath})
}
default: default:
return fmt.Errorf("unknown trust type %q", input.Type) return fmt.Errorf("unknown trust type %q", input.Type)
} }

View File

@ -47,6 +47,11 @@ func TestAddPolicyEntries(t *testing.T) {
Type: "signedBy", Type: "signedBy",
PubKeyFiles: []string{}, // A key is missing PubKeyFiles: []string{}, // A key is missing
}, },
{
Scope: "default",
Type: "sigstoreSigned",
PubKeyFiles: []string{}, // A key is missing
},
{ {
Scope: "default", Scope: "default",
Type: "this-is-unknown", Type: "this-is-unknown",
@ -73,6 +78,12 @@ func TestAddPolicyEntries(t *testing.T) {
PubKeyFiles: []string{"/1.pub", "/2.pub"}, PubKeyFiles: []string{"/1.pub", "/2.pub"},
}) })
assert.NoError(t, err) assert.NoError(t, err)
err = AddPolicyEntries(policyPath, AddPolicyEntriesInput{
Scope: "quay.io/sigstore-signed",
Type: "sigstoreSigned",
PubKeyFiles: []string{"/1.pub", "/2.pub"},
})
assert.NoError(t, err)
// Test that the outcome is consumable, and compare it with the expected values. // Test that the outcome is consumable, and compare it with the expected values.
parsedPolicy, err := signature.NewPolicyFromFile(policyPath) parsedPolicy, err := signature.NewPolicyFromFile(policyPath)
@ -90,6 +101,10 @@ func TestAddPolicyEntries(t *testing.T) {
xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()), xNewPRSignedByKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()),
xNewPRSignedByKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()), xNewPRSignedByKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()),
}, },
"quay.io/sigstore-signed": {
xNewPRSigstoreSignedKeyPath(t, "/1.pub", signature.NewPRMMatchRepoDigestOrExact()),
xNewPRSigstoreSignedKeyPath(t, "/2.pub", signature.NewPRMMatchRepoDigestOrExact()),
},
}, },
}, },
}, parsedPolicy) }, parsedPolicy)
@ -101,3 +116,10 @@ func xNewPRSignedByKeyPath(t *testing.T, keyPath string, signedIdentity signatur
require.NoError(t, err) require.NoError(t, err)
return pr return pr
} }
// xNewPRSigstoreSignedKeyPath is a wrapper for NewPRSigstoreSignedKeyPath which must not fail.
func xNewPRSigstoreSignedKeyPath(t *testing.T, keyPath string, signedIdentity signature.PolicyReferenceMatch) signature.PolicyRequirement {
pr, err := signature.NewPRSigstoreSignedKeyPath(keyPath, signedIdentity)
require.NoError(t, err)
return pr
}