notaryproject / notation

A CLI tool to sign and verify artifacts
https://notaryproject.dev/
Apache License 2.0
355 stars 84 forks source link

Trust policy UX #398

Open yizha1 opened 2 years ago

yizha1 commented 2 years ago

This is going to vary based on the user's operating system. IMO we should consider if we can get a "bare bones" cli implementation which simply writes a template similar to what's there to the user's proper directory (i.e. notation policy create -n default) and possibly opens it up or lists where it is at. (i.e. notation policy list or notation policy open (optional --name default)

_Originally posted by @dtzar in https://github.com/notaryproject/notation/pull/371#discussion_r995097376_

priteshbandi commented 2 years ago

Should this be in RC2 ? We can provide commands to open trust policy in documentation and help.

yizha1 commented 2 years ago

Should this be in RC2 ? We can provide commands to open trust policy in documentation and help.

The purpose of this issue is to agree on what we will do in RC-1. If nothing needs to be done, then we can close it. If not, we can assign people to work on it. IMO, at least documentation work needs to be done, but it's better to figure out what kind of document and where it should be put.

priteshbandi commented 2 years ago

For RC1: yes, we can add documentation on editing the trust policy document. But anything beyond documentation should come after RC1.

We could add documentation in getting started guide.

yizha1 commented 2 years ago

@priteshbandi Besides documentation, we need to think about some built-in policies for users who are not admins or security experts. Some examples here just for inspiring.

We could develop default policies for normal users, and even for a system already loaded with public certificates, users even don't need to add certificates to a trust store again (For trust store, this is not the priority right now, just for inspiring purpose).

cc: @dtzar @toddysm @shizhMSFT @vaninrao10 @iamsamirzon @gokarnm

yizha1 commented 2 years ago

Add one idea from @FeynmanZhou

https://github.com/notaryproject/notation/issues/430#issuecomment-1303124675

SteveLasker commented 2 years ago

Just a thought: The complexity of getting the trust policy file created, with some default options feels like a great first step. If we consider a secure by default, without TOFU, I struggle with what default roots we’d want to trust from a notation installation default. And, even if we did, or a particular company wanted to seed their environments with a default, we likely want to make it “easy” but secure to add more trust roots and policy configurations. Meaning, you need privileges to modify the store and policy file, but the commands should be easy to edit the files for the user. notation policy add … Asking the user to hand edit files is likely more dangerous as it’s easy to malform the file with unexpected results.

yizha1 commented 2 years ago

Proposal of UX improvement for a beginner:

Currently, notation cert generate-test wabbit-network does the following

Proposal: add a new step for notation cert generate-test wabbit-network to create a default trust policy file for the quick starter. The policy is quite simple and looks like the following:

{
    "version": "1.0",
    "trustPolicies": [
        {
            "name": "wabbit-networks",
            "registryScopes": [ "*" ],
            "signatureVerification": {
                "level" : "strict"
            },
            "trustStores": [ "ca:wabbit-networks" ],
            "trustedIdentities": [
                "*"
            ]
        }
    ]
}

With this proposal, as a beginner, the notation signing and verify experience are simplified. No need to consider how to create a trustpolicy.json file and where to store it under different OS. It's easy to do an update of trustpolicy.json for advanced users as well other than creating a new file.

The whole workflow, just four steps

$ docker push localhost:5000/net-monitor:v1
$ notation cert generate-test wabbit-networks
> output message example:
> generate a local key and add as signing key with name "wabbit-networks"
> generate X.509 self-signed certificate, and add it to trust store named "wabbit-networks" of type "ca"
> generate trust policy $HOME/.config/notation/trustpolicy.json, edit this policy file for advanced usage
$ notation sign --key "wabbit-networks" localhost:5000/net-monitor:v1
$ notation verify localhost:5000/net-monitor:v1

@priteshbandi @SteveLasker @dtzar @shizhMSFT @gokarnm @toddysm @jeremyrickard @FeynmanZhou any comments?

dtzar commented 2 years ago

We need to have a default template option separate from the cert generate-test command, but I agree this would be good also for the cert generate-test command.

dtzar commented 2 years ago

The other aspect of this is making it easier for users trust certificates they have downloaded. For instance, it could be something like:

notation cert download someregistry.io  # Adds public certificate to trust store, but doesn't add it to the trust policy
notation cert inspect someregistry.io # Displays information about the certificate itself and relevant identity information.
notation cert trust someregistry.io # Adds this certificate to the trust policy

If someone wants to "live on the wild side" and just trust whatever is there:

$notation verify someregistry.io/image:tag
Do you want to download and trust the public certificate from someregistry.io to verify? (Y/N)
$Y # Downloads public certificate to trust store, adds to trust policy file, creates trust policy file if it doesn't exist
someregistry.io certificate was downloaded, added to trust store, and trust policy
sha256:########, verification successful
iamsamirzon commented 2 years ago
omeregistry.io  # Adds public certificate to trust store, but doesn't add it to the trust policy
notation cert inspect someregi

@dtzar - Do registries have a standard way/APIs to store a cert ? Will that cert apply to all the images stored in that registry? Are you suggesting new commands for RC-1?

toddysm commented 2 years ago

@iamsamirzon I don't think the expectation is to store the certs in the registry (unless I am mistaken here @dtzar). It is an open question how the cert will be obtained. I see the scenarios of adding a cert to the cert store as follows:

The question that remains if what the default trust policy will be for the cert that is added. Would make sense to use the someregistry.io/* if the cert is issued for that SN.

SteveLasker commented 2 years ago

For cert discovery, there’s work in the DID web group for discovering X.509 certs. Microsoft will be publishing our public keys. Ian can likely add some details

FeynmanZhou commented 2 years ago

Considering the one-step command, notation cert generate-test is a good option but it might mix the usage of creating the key/cert only and creating the key/cert, trust store, and trust policy.

Per today's community call, notation init looks more appropriate and straightforward to simplify the starter experience.

sajayantony commented 2 years ago

Post call @toddysm and I discussed the issue of cert add without a scope. Basically what is the use of having a certificate without a scope.

For example notation cert add adds it to a trust store but has no policy defined which makes useless until the configuration is complete.

$XDG_CONFIG_HOME/notation/trust-store
    /x509
        /ca
            /acme-rockets
                cert1.pem

The user then has to define a policy with a scope or multiple scopes that uses the cert and hence adding a cert in itself is not useful.

{
    "version": "1.0",
    "trustPolicies": [
        {
            // Policy for all artifacts, from any registry location.
            "name": "wabbit-networks-images",   // Name of the policy.
            "registryScopes": [ "*" ],          // The registry artifacts to which the policy applies.
            "signatureVerification": {          // The level of verification - strict, permissive, audit, skip.
              "level" : "audit" 
            },
            "trustStores": ["ca:acme-rockets"], // The trust stores that contains the X.509 trusted roots.
            "trustedIdentities": [              // Identities that are trusted to sign the artifact.
              "x509.subject: C=US, ST=WA, L=Seattle, O=acme-rockets.io, OU=Finance, CN=SecureBuilder"
            ]
        }
    ]
}

Options for discussion

  1. Option one would be to support an optional registry-scope parameter when adding a cert

    • this has some challenges since there might already be a matching scope existing that is using a trust store and hence will have issues like updating/collisions. If the registry-scopes are wildcards this makes it harder. I think updating the policy object through the cert commands will turn out to much more challenging.
  2. Another option is to make the command output what the user has to do - this results in copy pasting and is as good as docs but docs in tooling.

    $ notation cert add 
    Adding .... 
    To add this to a new policy run ... 
  3. Make notation cert add more interactive. I understand that this is an RC and we want to keep backward compat as much as possible but given that users will have to explicitly upgrade to RC2 introducing this capability to make this command interactive as a breaking change seems fair since asking them to copy paste a bunch of commands is quite cumbersome and makes the usability hard.

yizha1 commented 2 years ago

Post call @toddysm and I discussed the issue of cert add without a scope. Basically what is the use of having a certificate without a scope.

@toddysm @sajayantony

The difficult parts of configuring a trust policy:

One idea: Maybe we could at least introduce "something" to initialize a trust policy file, for example notation cert add --init-policy [repo...]. Is there any problem with the following workflow?

Another idea:

After notation cert add, simliar to option-2, but print out an example of trust policy content with trustStores and trustedIdentities configured according to this specific store and certificate. Then user can just copy it to create a new file, or copy the policy part to add to an existing file.

An example,

$ notation cert add --type ca --store wabbit-networks.io wabbit-networks.pem
...
An example policy for this certificate.
{
    "version": "1.0",
    "trustPolicies": [
        {
            // Policy for all artifacts, from any registry location.
            "name": "wabbit-networks-images",   // Name of the policy.
            "registryScopes": [ "*" ],          // The registry artifacts to which the policy applies.
            "signatureVerification": {          // The level of verification - strict, permissive, audit, skip.
              "level" : "audit" 
            },
            "trustStores": ["ca:wabbit-networks.io"], // The trust stores that contains the X.509 trusted roots.
            "trustedIdentities": [              // Identities that are trusted to sign the artifact.
              "x509.subject: C=US, ST=WA, L=Seattle, O=wabbit-networks.io, OU=Finance, CN=SecureBuilder"
            ]
        }
    ]
}
dtzar commented 2 years ago

I believe we need some option which creates the actual policy file on the disk in the proper location when one doesn't exist.

yizha1 commented 2 years ago

As discussed during community meeting, only documentation will be part of RC-1, tracked by https://github.com/notaryproject/notation/issues/438, thus move this issue our of rc.1 scope.

toddysm commented 2 years ago

Just a note, #438 is not for rc.1 either. #438 is for discussion of further implementation in trust store and trust policy. The issue we need to track for rc.1 is in the docs project https://github.com/notaryproject/notaryproject.dev/issues/84