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.

For example a policy may define any of the following:

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

  • Administrators from 2 out 5 possible different organizations must sign.
  • Any member from any organization must sign.
  • Two specific certificates must both sign.

Policy Types

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

There are presently two different types of policies implemented:

Policy Types

  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: This 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”.

There are presently two different types of policies implemented:

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

  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: This 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.

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;

}

Configuration and Policies

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.

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:

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, while the last component resembling a file basename is the policy name.

Channel:
Policies:
Readers Writers Admins
Groups:
Orderer:
Policies:
Readers Writers Admins
Groups:
OrderingOrganization1:
Policies:
Readers Writers Admins
Application:
Policies:
Readers
———–> Writers
Admins
Groups:
ApplicationOrganization1:
Policies:
Readers Writers Admins
ApplicationOrganization2:
Policies:
Readers Writers Admins

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.

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, while the last component resembling a file basename is the policy name.

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

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.

Constructing a SignaturePolicy

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

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

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;
    }
}

message SignaturePolicyEnvelope {
    int32 version = 1;
    SignaturePolicy policy = 2;
    repeated MSPPrincipal identities = 3;
}

The outer SignaturePolicyEnvelope defines a version (currently only 0 is supported), a set of identities expressed as MSPPrincipals , 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.

message SignaturePolicy {
message NOutOf {
int32 N = 1; repeated SignaturePolicy policies = 2;

} oneof Type {

int32 signed_by = 1; NOutOf n_out_of = 2;

}

}

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

The outer SignaturePolicyEnvelope defines a version (currently only 0 is supported), a set of identities expressed as MSPPrincipals , 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.

For example:

The SignaturePolicy is a recursive data structure which either represents a single signature requirement from a specific MSPPrincipal, or a collection of SignaturePolicys, 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 Principals mspP1 and mspP2. It requires both that there is a signature satisfying mspP1 and a signature satisfying mspP2.

SignaturePolicyEnvelope{

version: 0, policy: SignaturePolicy{

n_out_of: NOutOf{

N: 2, policies: [

SignaturePolicy{ signed_by: 0 }, SignaturePolicy{ signed_by: 1 },

],

},

}, identities: [mspP1, mspP2],

}

As another more complex example:

This defines a signature policy over MSP Principals 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 mspP1, and another signature which either satisfies mspP2 or mspP3.

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],

}

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.

This defines a signature policy over MSP Principals mspP1, mspP2, and mspP3. It requires one signature which satisfies mspP1, 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.

Limitations: When evaluating a signature policy against a signature set, signatures are ‘consumed’, in the order in which they appear, regardless of whether they satisfy multiple policy principals.


For example. Consider a policy which requires

Limitations: When evaluating a signature policy against a signature set, signatures are ‘consumed’, in the order in which they appear, regardless of whether they satisfy multiple policy principals.

For example. Consider a policy which requires

2 of [org1.Member, org1.Admin]

The naive intent of this policy is to require that both an admin, and a member sign. For the signature set

2 of [org1.Member, org1.Admin]

The naive intent of this policy is to require that both an admin, and a member sign. For the signature set

[org1.MemberSignature, org1.AdminSignature]

the policy evaluates to true, just as expected. However, consider the signature set

[org1.MemberSignature, org1.AdminSignature]

the policy evaluates to true, just as expected. However, consider the signature set

[org1.AdminSignature, org1.MemberSignature]

This signature set does not satisfy the policy. This failure is because when org1.AdminSignature satisfies the org1.Member role it is considered ‘consumed’ by the org1.Member requirement. Because the org1.Admin principal cannot be satisfied by the org1.MemberSignature, the policy evaluates to false.

[org1.AdminSignature, org1.MemberSignature]

To avoid this pitfall, identities should be specified from most privileged to least privileged in the policy identities specification, and signatures should be ordered from least privileged to most privileged in the signature set.

This signature set does not satisfy the policy. This failure is because when org1.AdminSignature satisfies the org1.Member role it is considered ‘consumed’ by the org1.Member requirement. Because the org1.Admin principal cannot be satisfied by the org1.MemberSignature, the policy evaluates to false.

MSP Principals

To avoid this pitfall, identities should be specified from most privileged to least privileged in the policy identities specification, and signatures should be ordered from least privileged to most privileged in the signature set.

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 default MSP type, based on X.509 cryptography.

MSP Principals

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

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 default 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;
    }

message MSPPrincipal {

    Classification principal_classification = 1;

    enum Classification {
        ROLE = 0;
        ORGANIZATION_UNIT = 1;
        IDENTITY  = 2;
    }

    bytes principal = 2;
}

    Classification principal_classification = 1;

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

bytes principal = 2;

}

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

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

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 IDENTITY the principal field is set to the bytes of a certificate literal.

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

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
        CLIENT = 2; // Represents an MSP Client
        PEER = 3; // Represents an MSP Peer
    }

message MSPRole {
    string msp_identifier = 1;

    MSPRoleType role = 2;
}

    enum MSPRoleType {
        MEMBER = 0; // Represents an MSP Member
        ADMIN  = 1; // Represents an MSP Admin
        CLIENT = 2; // Represents an MSP Client
        PEER = 3; // Represents an MSP Peer
    }

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, ADMIN, CLIENT or PEER. In particular:

MSPRoleType role = 2;

}

  1. MEMBER matches any certificate issued by the MSP.
  2. ADMIN matches certificates enumerated as admin in the MSP definition.
  3. CLIENT (PEER) matches certificates that carry the client (peer) Organizational unit.

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, ADMIN, CLIENT or PEER. In particular:

(see MSP Documentation)

  1. MEMBER matches any certificate issued by the MSP.
  2. ADMIN matches certificates enumerated as admin in the MSP definition.
  3. CLIENT (PEER) matches certificates that carry the client (peer) Organizational unit.

Constructing an ImplicitMetaPolicy

(see MSP Documentation)

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:

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

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 implicitly 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.

ImplicitMetaPolicy{
rule: ANY, sub_policy: “foo”,

}

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

This policy will implicitly 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.

ImplicitMetaPolicy{
rule: MAJORITY, sub_policy: “bar”,

}

Policy Defaults

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.

The configtxgen tool uses policies which must be specified explicitly in configtx.yaml.

Policy Defaults

Note that policies higher in the hierarchy are all defined as ImplicitMetaPolicys while leaf nodes necessarily are defined as SignaturePolicys. 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 Reader, Writer, and Admin.

The configtxgen tool uses policies which must be specified explicitly in configtx.yaml.

Note that policies higher in the hierarchy are all defined as ImplicitMetaPolicys while leaf nodes necessarily are defined as SignaturePolicys. 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 Reader, Writer, and Admin.