Skip to content

Commit

Permalink
[FAB-2670] Document fabric policies creation/usage
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2670

This is a small markdown document intended to be a starting point to
understanding the policy structure of the fabric.  It is targetted for
developers who would like to roll their own configuration for a channel.

Change-Id: Ic96798e51e4e1f20ddf9c5bb7da30d6630c3bc0d
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Mar 7, 2017
1 parent 9cbf5e6 commit ce52828
Showing 1 changed file with 271 additions and 0 deletions.
271 changes: 271 additions & 0 deletions docs/policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
# Policies in Hyperledger Fabric

Configuration for a Hyperledger Fabric blockchain network is managed by policies. These policies generally reside in the channel configuration. The primary purpose of this document is to explain how policies are defined in and interact with the channel configuration. However, policies may also be specified in some other places, such as chaincodes, so this information may be of interest outside the scope of channel configuration.

## What is a Policy?

At its most basic level, a policy is a function which accepts as input a set of signed data and evaluates successfully, or returns an error because some aspect of the signed data did not satisfy the policy.

More concretely, policies test whether the signer or signers of some data meet some condition required for those signatures to be considered 'valid'. This is useful for determining that the correct parties have agreed to a transaction, or change.

For example a policy may define any of the following:
* Administrators from 2 out 5 possible different organizations must sign.
* Any member from any organization must sign.
* Two specific certificates must both sign.

Of course these are only examples, and other more powerful rules can be constructed.

## Policy Types

There are presently two different types of policies implemented in the hyperledger fabric.

1. **SignaturePolicy**: This policy type is the most powerful, and specifies the policy as a combination of evaluation rules for MSP Principals. It supports arbitrary combinations of *AND*, *OR*, and *NOutOf*, allowing the construction of extremely powerful rules like: "An admin of org A and 2 other admins, or 11 of 20 org admins".
2. **ImplicitMetaPolicy**: Tihs policy type is less flexible than SignaturePolicy, and is only valid in the context of configuration. It aggregates the result of evaluating policies deeper in the configuration hierarchy, which are ultimately defined by SignaturePolicies. It supports good default rules like "A majority of the organization admin policies".

Policies are encoded in a `common.Policy` message as defined in `fabric/protos/common/policies.proto`. They are defined by the following message:

```
message Policy {
enum PolicyType {
UNKNOWN = 0; // Reserved to check for proper initialization
SIGNATURE = 1;
MSP = 2;
IMPLICIT_META = 3;
}
int32 type = 1; // For outside implementors, consider the first 1000 types reserved, otherwise one of PolicyType
bytes policy = 2;
}
```

To encode the policy, simply pick the policy type of either `SIGNATURE` or `IMPLICIT_META`, set it to the `type` field, and marshal the corresponding policy implementation proto to `policy`.

## Configuration and Policies

The channel configuration is expressed as a hierarchy of configuration groups, each of which has a set of values and policies associated with them. For a validly configured application channel with two application organizations and one ordering organization, the configuration looks minimally as follows:

```
Channel:
Policies:
Readers
Writers
Admins
Groups:
Orderer:
Policies:
Readers
Writers
Admins
Groups:
OrdereringOrganization1:
Policies:
Readers
Writers
Admins
Application:
Policies:
Readers
-----------> Writers
Admins
Groups:
ApplicationOrganization1:
Policies:
Readers
Writers
Admins
ApplicationOrganization2:
Policies:
Readers
Writers
Admins
```

Consider the Writers policy referred to with the `------->` mark in the above example. This policy may be referred to by the shorthand notation `/Channel/Application/Writers`. Note that the elements resembling directory components are group names, whlie the last component resembling a file basename is the policy name.

Different components of the system will refer to these policy names. For instance, to call `Deliver` on the orderer, the signature on the request must satisfy the `/Channel/Readers` policy. However, to gossip a block to a peer will require that the `/Channel/Application/Readers` policy be satisfied.

By setting these different policies, the system can be configured with rich access controls.

## Constructing a SignaturePolicy

As with all policies, the SignaturePolicy is expressed as protobuf.

```
message SignaturePolicyEnvelope {
int32 version = 1;
SignaturePolicy policy = 2;
repeated MSPPrincipal identities = 3;
}
message SignaturePolicy {
message NOutOf {
int32 N = 1;
repeated SignaturePolicy policies = 2;
}
oneof Type {
int32 signed_by = 1;
NOutOf n_out_of = 2;
}
}
```

The outer `SignaturePolicyEnvelope` defines a version (currently only `0` is supported), a set of identities expressed as `MSPPrincipal`s , and a `policy` which defines the policy rule, referencing the `identities` by index. For more details on how to specify MSP Principals, see the MSP Principals section.

The `SignaturePolicy` is a recursive data structure which either represents a single signature requirement from a specific `MSPPrincipal`, or a collection of `SignaturePolicy`s, requiring that `N` of them are satisfied.

For example:

```
SignaturePolicyEnvelope{
version: 0,
policy: SignaturePolicy{
n_out_of: NOutOf{
N: 2,
policies: [
SignaturePolicy{ signed_by: 0 },
SignaturePolicy{ signed_by: 1 },
],
},
},
identities: [mspP1, mspP2],
}
```

This defines a signature policy over MSP Prinicipals `mspP1` and `mspP2`. It requires both that there is a signature satisfying `mspP1` and a signature satisfying `mspP2`.

As another more complex example:

```
SignaturePolicyEnvelope{
version: 0,
policy: SignaturePolicy{
n_out_of: NOutOf{
N: 2,
policies: [
SignaturePolicy{ signed_by: 0 },
SignaturePolicy{
n_out_of: NOutOf{
N: 1,
policies: [
SignaturePolicy{ signed_by: 1 },
SignaturePolicy{ signed_by: 2 },
],
},
},
],
},
},
identities: [mspP1, mspP2, mspP3],
}
```

This defines a signature policy over MSP Principals `mspP1`, `mspP2`, and `mspP3`. It requires one signature which satisfies `mspP0`, and another signature which either satisfies `mspP2` or `mspP3`.

Hopefully it is clear that complicated and relatively arbitrary logic may be expressed using the SignaturePolicy policy type. For code which constructs signature policies, consult `fabric/common/cauthdsl/cauthdsl_builder.go`.

## MSP Principals

The MSP Principal is a generalized notion of cryptographic identity. Although the MSP framework is designed to work with types of cryptography other than X.509, for the purposes of this document, the discussion will assume that the underlying MSP implementation is the fabric MSP type, based on X.509 cryptography.

An MSP Principal is defined in `fabric/protos/msp_principal.proto` as follows:

```
message MSPPrincipal {
enum Classification {
ROLE = 0;
ORGANIZATION_UNIT = 1;
IDENTITY = 2;
}
Classification principal_classification = 1;
bytes principal = 2;
}
```

The `principal_classification` must be set to either `ROLE` or `IDENTITY`. The `ORGANIZATIONAL_UNIT` is at the time of this writing not implemented.

In the case of `IDENTITY` the `principal` field is set to the bytes of a certificate literal.

However, more commonly the `ROLE` type is used, as it allows the principal to match many different certs issued by the MSP's certificate authority.

In the case of `ROLE`, the `principal` is a marshaled `MSPRole` message defined as follows:

```
message MSPRole {
string msp_identifier = 1;
enum MSPRoleType {
MEMBER = 0; // Represents an MSP Member
ADMIN = 1; // Represents an MSP Admin
}
MSPRoleType Role = 2;
}
```

The `msp_identifier` is set to the ID of the MSP (as defined by the MSPConfig proto in the channel configuration for an org) which will evaluate the signature, and the `Role` is set to either `MEMBER` or `ADMIN`. The `MEMBER` role will match any certificate issued by the MSP, while the `ADMIN` role will match only certificates which are enumerated as admin certificates in the MSP definition.


## Constructing an ImplicitMetaPolicy

The `ImplicitMetaPolicy` is only validly defined in the context of channel configuration. It is `Implicit` because it is constructed implicitly based on the current configuration, and it is `Meta` because its evaluation is not against MSP principals, but rather against other policies. It is defined in `fabric/protos/common/policies.proto` as follows:

```
message ImplicitMetaPolicy {
enum Rule {
ANY = 0; // Requires any of the sub-policies be satisfied, if no sub-policies exist, always returns true
ALL = 1; // Requires all of the sub-policies be satisfied
MAJORITY = 2; // Requires a strict majority (greater than half) of the sub-policies be satisfied
}
string sub_policy = 1;
Rule rule = 2;
}
```

For example, consider a policy defined at `/Channel/Readers` as

```
ImplicitMetaPolicy{
rule: ANY,
sub_policy: "foo",
}
```

This policy will implicity select the sub-groups of `/Channel`, in this case, `Application` and `Orderer`, and retrieve the policy of name `foo`, to give the policies `/Channel/Application/foo` and `/Channel/Orderer/foo`. Then, when the policy is evaluated, it will check to see if `ANY` of those two policies evaluate without error. Had the rule been `ALL` it would require both.

Consider another policy defined at `/Channel/Application/Writers` where there are 3 application orgs defined, `OrgA`, `OrgB`, and `OrgC`.

```
ImplicitMetaPolicy{
rule: MAJORITY,
sub_policy: "bar",
}
```

In this case, the policies collected would be `/Channel/Application/OrgA/bar`, `/Channel/Application/OrgB/bar`, and `/Channel/Application/OrgC/bar`. Because the rule requires a `MAJORITY`, this policy will require that 2 of the three organization's `bar` policies are satisfied.

## Policy Defaults

The `configtxgen` tool creates default policies as follows:

```
/Channel/Readers : ImplicitMetaPolicy for ANY of /Channel/*/Readers
/Channel/Writers : ImplicitMetaPolicy for ANY of /Channel/*/Writers
/Channel/Admins : ImplicitMetaPolicy for MAJORITY of /Channel/*/Admins
/Channel/Application/Readers : ImplicitMetaPolicy for ANY of /Channel/Application/*/Readers
/Channel/Application/Writers : ImplicitMetaPolicy for ANY of /Channel/Application/*/Writers
/Channel/Application/Admins : ImplicitMetaPolicy for MAJORITY of /Channel/Application/*/Admins
/Channel/Orderer/Readers : ImplicitMetaPolicy for ANY of /Channel/Orderer/*/Readers
/Channel/Orderer/Writers : ImplicitMetaPolicy for ANY of /Channel/Orderer/*/Writers
/Channel/Orderer/Admins : ImplicitMetaPolicy for MAJORITY of /Channel/Orderer/*/Admins
# Here * represents either Orderer, or Application, and this is repeated for each org
/Channel/*/Org/Readers : SignaturePolicy for 1 of MSP Principal Org Member
/Channel/*/Org/Writers : SignaturePolicy for 1 of MSP Principal Org Member
/Channel/*/Org/Admins : SignaturePolicy for 1 of MSP Principal Org Admin
```

Note that policies higher in the hierarchy are all defined as `ImplicitMetaPolicy`s while leaf nodes necessarily are defined as `SignaturePolicy`s. This set of defaults works nicely because the `ImplicitMetaPolicies` do not need to be redefined as the number of organizations change, and the individual organizations may pick their own rules and thresholds for what is means to be a a Reader, Writer, and Admin.

0 comments on commit ce52828

Please sign in to comment.