notation
notation copied to clipboard
System vs User file/directory precedence
The directory structure spec defines system and user level directory paths. When both paths are present, it may be required to give precedence to system or user level based on specific scenarios.
- User level setting in
config.json
andsigningkeys.json
may take precedence over system level settings in development scenarios, or an environment shared by multiple users. - In deployment scenarios, it may be desirable to use system level
trustpolicy.json
and trust store, even if an user level (application or service role) trust store and policy exists, to allow administrator roles to enforce usage of trust policy and store.
We should come up with an approach that is flexible to support both scenarios.
@gokarnm thinks we can start directory spec implementation while working in parallel to close this. This is not a blocker to start.
Here is a proposal for how to address this.
- Only in the system level
config.json
we provide a new settingconfigurationBehavior
with supported valuesuser
/system
which allows a system admin role to setup preferred configuration priority, which cannot be overriden by a user role. This setting applies to all files/directories (config.json, signingkeys.json, plugin dir, trustpolicy.json, trust store dir etc.) - The default value of this setting if unspecified is
user
, so default behavior is user level files/directories take precedence over system level if both are present.
system
- only system level settings are applied, user level settings are ignored in all cases, even when a specific setting is missing at system level and present at user level.
user
- user level files/directories take precedence over system level if both are present.
Thoughts? @shizhMSFT @SteveLasker @priteshbandi @rgnote
As per @gokarnm , this is not a blocker to start implementation.
Related to #175 and #167
@junjie
I will add a comment to the related code to mention that the implementation may be changed later.
Thanks for capturing this @gokarnm Balancing usability and security, this is one of those places where I'd suggest we need to lean a bit more to the security side, with a "secure by default" posture. If we leave the default to be user overrides, then we must assume most deployments will allow users to change the behavior, including default configurations of system configurations, where we are most exposed to "hacking".
What I'd suggest is we default system
and force users to change to user
if they really need it.
Who owns the action item to update the Directory Structure Specification? Is this assigned to @shizhMSFT? Thinking @dtzar, @FeynmanZhou, @iamsamirzon might be able to clarify the security/usability a bit first?
@SteveLasker This is a discussion. We don't have a consensus yet. My opinion is that user file / directory should take over the system ones.
I'm assuming that the system-level directory is a security mechanism for certain things (like the trust store). Therefore, if the user directory overrides the system, wouldn't that be a security concern?
I can see a case for non-security implication changes it making sense to have the user directory override the system (i.e. configuration settings).
Maybe we could create a setting so someone concerned about security implications and wants to lock down to ignore user directory could do?
Thanks @shizhMSFT, @dtzar David is capturing the heart of the issue. What is the proper "secure by default", starting point? Then, what could someone with admin privileges change, to enable a user to override, but only if configured.
For non-security related preferences, user overrides makes sense.
Having different defaults for different configurations will be confusing and cumbersome for customers/users.
I think a setting like configuration-behavior
with the default of user
makes sense to avoid mis-configuration. If user creds are compromised a malicious actor can replace the notation invocation with the invocation to the dummy executable rendering our config protection useless.
Also, usually, the deployment host will be run as a user(not root) and if the user is compromised all bets are off. Is there any specific attack vector we are trying to defend?
Other option is to not allow user to have a config for at both system and user level. Basically, fail the operation(sign/verify) if user has defined config at both system and user level.
https://github.com/notaryproject/notation/blob/main/specs/directory.md
According to our meeting discussion, we can provide a system level /etc/notation/config.json file which contains an attribute EnableUserLevelDirectory
with default value true
, representing reading from user level directory firstly then reading system level directory. If it is false
, only read from system level. This design requires system level read permission.
@shizhMSFT @yizha1 @FeynmanZhou @patrickzheng200
A secure by default scenario would suggest system is the default and the user must have admin privileges to enable the less secure user config. As a security tool, seems we really need to start with a secure by default position to avoid the ease for a bad actor to make insecure changes.
Key decisions here as I see it:
- Do we even allow a configuration in two places (i.e. user and system)?
- If yes to 1 then do we allow anything in both places or just the non-security-specific configuration? What is deemed config versus security specifically?
- If yes to 1 then how do we handle which trumps the other in priority?
If no to 1, then we don't need to discuss 2 and 3.
We have identified at least three parties involved in the E2E scenarios: Signer
, Verifier
, and System Admin
.
- A
Signer
SHOULD be able to sign even if there is no system configuration. Here an example scenario:- Alice downloads the
notation
CLI binary and corresponding signing plugins, and installs them without root access. - Alice adds her signing keys using
notation key add
. - After
notation login
, Alice is able to donotation sign
to sign any artifact.
- Alice downloads the
- A
Verifier
SHOULD be able to verify artifacts securely. Since thenotation
CLI does not come with a default trust store and a default trust policy, thenotation verify
will always fail. TheVerifier
or theSystem Admin
have to configure thenotation
with proper trust stores and policies based on different scenarios.-
Scenario 1: Personal computers. Instances: Personal desktops, laptops, macs, etc.
- Bob downloads the
notation
CLI binary and installs it without root access. - Bob downloads certificates, inspects them, and trusts them accordingly by
notation cert add
. - Bob configures trust policies using
notation policy
(implemented in thedev-rc.1
branch). - Bob verifies artifacts using
notation verify
and downloads the artifacts securely.
- Bob downloads the
-
Scenario 2: Muti-tenant servers. Instances: University servers shared by students, etc.
- Bob downloads the
notation
CLI binary and installs it without root access if his university system admin has not pre-installed thenotation
CLI binary for all students yet. - Bob downloads certificates, inspects them, and trusts them accordingly by
notation cert add
. - Bob configures trust policies using
notation policy
(implemented in thedev-rc.1
branch). - Bob verifies artifacts using
notation verify
and downloads the artifacts securely. - Another student Charlie can do the steps b - d as Bob but using a different trust store / trust policy set.
- Bob downloads the
-
Scenario 3: Dedicated servers. Instances: CI/CD machines, production servers, etc.
- David, as a
System Admin
, installs thenotation
CLI binary and configures config file / trust store / trust policy at the system level. - Applications on the server verify artifacts using
notation verify
, download, and use the artifacts securely. - Applications are NOT allowed to use their own trust store and trust policy. It follows the principle of least privilege.
- David, as a
-
Scenario 1: Personal computers. Instances: Personal desktops, laptops, macs, etc.
To cover all above scenarios with maximum compatibility, one approach is to introduce a harden
field (default to false
) in the system level config file. When the notation
process starts up, it checks if system level config file exists. If exists and harden
is set to true
, all trust store / trust policy / plugins paths MUST only use system level paths.
Thanks @shizhMSFT, @dtzar The thing I’m most concerned with is a build redirecting the signing or verification to bypass the intended secure scenario. Can we say: If the notation cli is installed in the root, it must be configured with root access? This would enable the other scenarios when a needs local control
Thanks @shizhMSFT, @dtzar The thing I’m most concerned with is a build redirecting the signing or verification to bypass the intended secure scenario. Can we say: If the notation cli is installed in the root, it must be configured with root access? This would enable the other scenarios when a needs local control
It is not possible check if the notation cli is installed in the root since you can install multiple instances of notation
anywhere.
The goal is to avoid a bad actor to override a system configuration. If the admin scenario is configured, wouldn’t there be a config, or trust store/policy in an admin path? Can we check for the existence of that admin/root configuration and only allow that to be overridden if the root level config to enable user override is set?
From security perspective Scenario 1 - works with user specific policy Scenario 2: works with user specific policy Scenario 3: - Can this work with specific user policy? usually dedicated server will run as a specific user, can notation use that user's role?
From usability perspective Having an organization specific trust store that's distributed to all the hosts is one scenario where a system level trust store(TS) would be useful. Users can have both organization-specific ts and personal TS, notation will do a union of both the TS.
As per discussion in Notary v2 meeting on 10/17 for RC1 we will only support user level config and punt system level config for RC2. Reason: We don't have a usecase where customer would like to use system level config and we can always add system level support later.