Repository: qpid-dispatch Updated Branches: refs/heads/crolke-DISPATCH-188-1 5805c61f4 -> 89d769aa1
Policy model improvements Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/89d769aa Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/89d769aa Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/89d769aa Branch: refs/heads/crolke-DISPATCH-188-1 Commit: 89d769aa16068d0fc357c9cae8a4425ce16efc81 Parents: 5805c61 Author: Chuck Rolke <[email protected]> Authored: Fri Nov 20 15:25:31 2015 -0500 Committer: Chuck Rolke <[email protected]> Committed: Fri Nov 20 15:25:31 2015 -0500 ---------------------------------------------------------------------- doc/notes/policy.md | 257 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 182 insertions(+), 75 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/89d769aa/doc/notes/policy.md ---------------------------------------------------------------------- diff --git a/doc/notes/policy.md b/doc/notes/policy.md index e338493..7696b06 100644 --- a/doc/notes/policy.md +++ b/doc/notes/policy.md @@ -18,22 +18,18 @@ # Connection Policy Qpid Dispatch Router (QDR) uses connection and access policies to limit -user access to QDR resources. +user access to QDR resources. + +The system defines global settings: - Absolute TCP/IP connection count limit -- Per-listener TCP/IP connection count limit -- Per-listener TCP/IP host restrictions -- Per-listener TCP/IP user restrictions -- Per-listener AMQP user hostname access restrictions (TBD) -The Absolute TCP/IP connection count limit is built in to QDR and is always available. The remaining policy controls are managed by a pluggable Policy Authority module. The Policy Authority may be: +A pluggable Policy Authority defines per-listener, per-service settings: -- Absent. No per-listener policies are enforced. -- Local. A simple, built-in Policy Authority may be configured. -- User Defined. A user module may handle multi-router or centralized configurations. +- TCP/IP connection count limits +- TCP/IP connecting host/user restrictions +- TCP/IP user restrictions -The system interface to Local and User Defined modules is the same. - # Absolute TCP/IP Connection Limit QDR maintains a count of all TCP/IP connections from all remote clients and @@ -41,19 +37,6 @@ enforces a global limit. This limit covers connections incoming to all QDR *list This limit protects QDR from running out of resources like file descriptors due to incoming connections. -## Policy Configuration - "maximumConnections": { - "type" : "integer", - "default" : 0, - "description": "The maximum number of concurrent client - connections allowed. Zero implies no limit.", - "required" : false} - -## Policy Statistics - "connectionsProcessed": {"type": "integer", "graph": true}, - "connectionsDenied": {"type": "integer", "graph": true}, - "connectionsCurrent": {"type": "integer", "graph": true} - ## Usage Notes - If the policy configuration is absent or if the maximumConnections value specified in the policy is zero then absolute connection limits are not enforced. Note that connections are always tracked even when policy enforcement is disabled. - Statistics show how many total connections have been processed, how many connections have been denied by policy, and how many connections are currently active. @@ -65,6 +48,8 @@ The Policy Authority is consulted at different times in a connection life cycle. - A listener socket is accepted - An AMQP Open performative is received. +- An AMQP Begin performative is received. +- An AMQP Attach performative is received. ## Policy Authority Listener Accept @@ -74,23 +59,63 @@ The listener socket acceptance is performed before the AMQP handshake has starte - too many connection from one external host # + @param[in] listenername : listener receiving the connection + @param[in] originhost : host name of the client system originating the connection + + @return the accept is allow and a socket is opened + bool policy_listener_accept( const char *listenername, - const char *hostname, - void *netaddr_info) + const char *originhost) -The policy engine returns an allow/deny decision after deciding if this host is allowed to connect the the listener. netaddr_info is some binary info to help the policy engine determine if the the hostname is within configured IP address ranges. +The policy engine returns an allow/deny decision after deciding if this client host is allowed to open a new socket to the listener. ## Policy Authority AMQP Open -The AMQP Open performative received acceptance is called after the network socket is open and after the AMQP and security handshaking has completed. Now both the user identity and the target of the AMQP Open are both known. The open may be rejected and the connection is closed with an error. +The AMQP Open performative received acceptance is called after the network socket is open and after the AMQP and security handshaking has completed. Now both the user identity and the requested service name, contained in the hostname field of the AMQP Open, are known. - void * policy_listener_open( - const char *listenername, - const char *hostname, - const char *authid) +If the Open is allowed then the named policy is installed for this listener to control further operations on this service. -The policy engine returns a TBD policy allow/deny decision if user 'authid' connected through listenername is allowed to open a connection to hostname. If the connection is allowed then a policy configuration is returned. If the connection is denied then a null is returned and the connection is closed. +If the Open is denied then the error condition and description are returned to the listener. The listener is expected to close the connection. + + @param[in] listenername : listener receiving the Open + @param[in] originhost : host name of the client system originating the connection + @param[in] authid : authorized user name + @param[in] servicename : service named in the Open hostname field + + @param[in,out] policyname : policy to use if Open is allowed + @param[in] policynamesize : size of policy name buffer + + @param[in,out] condition : condition name to return if Open is denied + @param[in] conditionsize : size of condition buffer + @param[in,out] description : condition description if Open is denied + @param[in] descriptionsize : size of description buffer + + bool policy_listener_open( + const char *listenername, + const char *originhost, + const char *authid, + const char *servicename, + + char * policyname, + int policynamesize, + + char * condition, + int conditionsize, + char * description, + int descriptionsize) + +### AMQP Open - Connection processing + +Open processing is performed in two phases. + +#### Open - user connection origin + +First the user's connecting host origin address is checked. The connection may be denied if the user is not logging in from an acceptable host on the network. + +#### Open - user access policy + +Next the policy tables are consulted to see if this user has rights to the application. If the user is granted access by membership in a role then the user connection is allowed. Otherwise it is denied. # Local Policy Authority (LocalPA) @@ -102,15 +127,24 @@ Each QDR listener may be configured with some settings that: - define simple sets of users organized by user *role*. - define a simple ingress filter by matching user names against a list of external host addresses. Note that user identity is not defined by external host TCP/IP addresses. Rather, users may be restricted to connecting only from certain TCP/IP addresses. -- define AMQP Open parameters each user role may receive. (TBD) +- define AMQP Open parameters each user role may receive. +- define which AMQP Attach sources and targets may be accessed by this connection. -### User +### Aggregate Connection Limits -User identities are discovered during the TLS/SSL and SASL authentication phases of connection setup. The user name used for policy specifications is stored in connection field *connection.user*. +Each policy defines connection limits: -The following special user names are defined for use in policy definitions: +- maximumConnections +- maximumConnectionsPerUser +- maximumConnectionsPerHost -- **\*** (asterisk) wildcard matches all user names including the blank user name. +These limits are applied in addition to the system-wide absolute maximumConnections. They prevent a user from using all of a service's resources. + +### User + +Authorized user identities are discovered during the TLS/SSL and SASL authentication phases of connection setup. The authorized user name used for policy specifications is stored in connection field *connection.user*. + +The special user name **\*** (asterisk) wildcard matches all user names. User names are case sensitive. @@ -122,9 +156,9 @@ Role names and user names may be used interchangeably in policy specifications. Role names are case sensitive. -### Origin Statements +### connectionOrigin Statements -Origin statements are the list of configuration lines that specify ingress filter rules. +Origin statements specify groups of network hosts. #### Host Specification @@ -181,51 +215,124 @@ IPv4 CIDR format is not supported. Instead, use a host range. is "*". It stands for all addresses, IPv4 or IPv6. It may not be used in a host range statement. +### connectionPolicy Statements + +These rules create an ingress filter to allow a user to connect only from a defined set of IP addresses. If a user is included in one of the definitions for connectionPolicy then that user connection is allowed. Otherwise that user's access is controlled by the connectionAllowUnrestricted flag. + +#### connectionAllowUnrestricted Flag + +This flag offers a blanket allow-all or deny-all backstop to the connectionPolicy filter. A few simple filter rules illustrated in the sample configuration shown below ensure that the privileged users connect only from a few hosts and subnets. Now the question is what happens to users that were not filtered by the connectionPolicy rules? By having the flag set to true non-privileged users may connect from anywhere. + +In a different service you may know all the users and all the places from which they can connect. In that case a connectionPolicy can completely define the allowed connections. Then the connectionAllowUnrestricted flag may be set to False to deny any other connections. + +### policy Statements + +The policy statements define the permissions a user gets when he is allowed to access a service. These permissions include: + +- The **AMQP Open** performative ***channel-max*** upper limit value. This controls the number of sessions that may be created over this connection. +- The **AMQP Open** performative ***max-frame-size*** upper limit value. This controls the message buffering for this connections. +- The **AMQP Begin** performative ***handle-max*** upper limit value. This controls the number of links that each session may contain. +- The **AMQP Attach** performative ***max-messge-size*** upper limit value. This controls the message size and ultimately the memory that the connection can consume. +- The **AMQP Attach** performative ***source*** and ***target*** allowed values. This controls the read/write access to service resources. + ## Example configuration file -LocalPA is configured with a single Python ConfigParser-format file. +LocalPA is configured with a single Python ConfigParser-format file. For example: - # qpid-dispatch simple policy listener configuration + # qpid-dispatch simple policy listener configuration for photoserver service # - [listener1] - maximumConnections : 10 - maximumConnectionsPerUser: 5 - maximumConnectionsPerHost: 5 - # roles is a map. - # key : the role name - # value: list of users assigned to that role. + [photoserver] + # versionId is a text string identifier + versionId : 8 + + # Aggregate connection limits + maximumConnections : 10 + maximumConnectionsPerUser : 5 + maximumConnectionsPerHost : 5 + + # A role is an group of authid names roles: { - 'admin': ['alice', 'bob', 'charlie'], - 'users': ['u1', 'u2', 'u3', 'u4', 'u5', 'u6'], - 'test': ['zeke'] + 'anonymous' : ['anonymous'], + 'users' : ['u1', 'u2'], + 'paidsubscribers' : ['p1', 'p2'], + 'test' : ['zeke', 'ynot'], + 'admin' : ['alice', 'bob', 'ellen'], + 'superuser' : ['ellen'] } - # origins is a map. - # key : IP address or range of IP addresses - # value: list of roles/users allowed to connect from that address/range. - origins: { - '9.0.0.0,9.255.255.255': ['users', 'twatson'], - '10.18.0.0,10.18.255.255': ['*'], - '72.135.2.9': ['ellen'], - '*': ['test'] + # A connectionOrigin is list of network host addresses or host address ranges + connectionOrigins: { + 'Ten18': ['10.18.0.0,10.18.255.255'], + 'EllensWS': ['72.135.2.9'], + 'TheLabs': ['10.48.0.0,10.48.255.255','192.168.100.0,192.168.100.255'], + 'Localhost': ['127.0.0.1','::1'], } - [default] - maximumConnections : 2 - maximumConnectionsPerUser: 2 - maximumConnectionsPerHost: 3 - - # roles is a map. - # key : the role name - # value: list of users assigned to that role. - roles: { + # connectionPolicy restricts users to connecting only from defined origins + connectionPolicy: { + 'admin' : ['Ten18', 'TheLabs', 'Localhost'], + 'test' : ['TheLabs'], + 'superuser' : ['Localhost', 'EllensWS'] } - # origins is a map. - # key : IP address or range of IP addresses - # value: list of roles/users allowed to connect from that address/range. - origins: { - '127.0.0.1': ['*'], - '::1': ['*'] + # connectionAllowUnrestricted - If a user is not restricted by a connectionPolicy + # then is this user allowed to connect? + connectionAllowUnrestricted : True + + # policy - Based on the user's role what are his access rights? + # + # A policy contains: + # - values passed in AMQP Open and Attach performatives + # - allowed source and target names in AMQP Attach + # + policies: { + 'anonymous' : { + 'max_frame_size' : 111111, + 'channel_max' : 1, + 'max_links' : 11, + 'max_message_size' : 111111, + 'sources' : [public], + 'targets' : [] + }, + 'users' : { + 'max_frame_size' : 222222, + 'channel_max' : 2, + 'max_links' : 22, + 'max_message_size' : 222222, + 'sources' : [public, private], + 'targets' : [public] + }, + 'paidsubscribers' : { + 'max_frame_size' : 333333, + 'channel_max' : 3, + 'max_links' : 33, + 'max_message_size' : 333333, + 'sources' : [public, private], + 'targets' : [public, private] + }, + 'test' : { + 'max_frame_size' : 444444444, + 'channel_max' : 4, + 'max_links' : 44, + 'max_message_size' : 444444444, + 'sources' : [private], + 'targets' : [private] + }, + 'admin' : { + 'max_frame_size' : 555555555, + 'channel_max' : 55, + 'max_links' : 555, + 'max_message_size' : 555555555, + 'sources' : [public, private, management], + 'targets' : [public, private, management] + }, + 'superuser' : { + 'max_frame_size' : 666666666, + 'channel_max' : 666, + 'max_links' : 6666, + 'max_message_size' : 666666666, + 'sources' : [public, private, management, root], + 'targets' : [public, private, management, root] + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
