VIP Authorization¶
VIP authentication and authorization go hand in hand. When an agent authenticates to a VOLTTRON platform that agent proves its identity to the platform. Once authenticated, an agent is allowed to connect to the message bus. VIP authorization is about giving a platform owner the ability to limit the capabilities of authenticated agents.
There are two parts to authorization:
- Required capabilities (specified in agent’s code)
- Authorization entries (specified via
volttron-ctl authcommands)
The following example will walk through how to specify required capabilities and grant those capabilities in authorization entries.
Single Capability¶
For this example suppose there is a temperature agent that can read and set the temperature of a particular room. The agent author anticipates that building managers will want to limit which agents can set the temperature.
In the temperature agent, a required capability is specified by
using the RPC.allow decorator:
@RPC.export
def get_temperature():
...
@RPC.allow('CAP_SET_TEMP')
@RPC.export
def set_temperature(temp):
...
In the code above, any agent can call the get_temperature method, but only
agents with the CAP_SET_TEMP capability can call set_temperature.
(Note: capabilities are arbitrary strings. This example follows the general
style used for Linux capabilities, but it is up to the agent author.)
Now that a required capability has been specified, suppose a VOLLTRON platform owner wants to allow a specific agent, say AliceAgent, to set the temperature.
The platform owner runs volttron-ctl auth add to add new authorization
entries or volttron-ctl auth update to update an existing entry.
If AliceAgent is installed on the platform, then it already has an
authorization entry. Running volttron-ctl auth list shows the existing
entries:
...
INDEX: 3
{
"domain": null,
"user_id": "AliceAgent",
"roles": [],
"enabled": true,
"mechanism": "CURVE",
"capabilities": [],
"groups": [],
"address": null,
"credentials": "JydrFRRv-kdSejL6Ldxy978pOf8HkWC9fRHUWKmJfxc",
"comments": null
}
...
Currently AliceAgent cannot set the temperature because it does
not have the CAP_SET_TEMP capability. To grant this capability
the platform owner runs volttron-ctl auth update 3:
(For any field type "clear" to clear the value.)
domain []:
address []:
user_id [AliceAgent]:
capabilities (delimit multiple entries with comma) []: CAP_SET_TEMP
roles (delimit multiple entries with comma) []:
groups (delimit multiple entries with comma) []:
mechanism [CURVE]:
credentials [JydrFRRv-kdSejL6Ldxy978pOf8HkWC9fRHUWKmJfxc]:
comments []:
enabled [True]:
updated entry at index 3
Now AliceAgent can call set_temperature via RPC.
If other agents try to call that method they will get the following
exception:
error: method "set_temperature" requires capabilities set(['CAP_SET_TEMP']),
but capability list [] was provided
Multiple Capabilities¶
Expanding on the temperature-agent example, the set_temperature method can
require agents to have multiple capabilities:
@RPC.allow(['CAP_SET_TEMP', 'CAP_FOO_BAR'])
@RPC.export
def set_temperature():
...
This requires an agent to have both the CAP_SET_TEMP and the
CAP_FOO_BAR capabilities. Multiple capabilities can also
be specified by using multiple RPC.allow decorators:
@RPC.allow('CAP_SET_TEMP')
@RPC.allow('CAN_FOO_BAR')
@RPC.export
def temperature():
...
Capability with parameter restriction¶
Capabilities can also be used to restrict access to a rpc method only with certain parameter values. For example, if AgentA exposes a method bar which accepts parameter x
AgentA’s capability enabled exported RPC method:
@RPC.export
@RPC.allow('can_call_bar')
def bar(self, x):
return 'If you can see this, then you have the required capabilities'
You can restrict access to AgentA’s bar method to AgentB with x=1. To add this auth entry use the vctl auth add command as show below
vctl auth add --capabilities '{"test1_cap2":{"x":1}}' --user_id AgentB --credential vELQORgWOUcXo69DsSmHiCCLesJPa4-CtVfvoNHwIR0
auth.json file entry for the above command would be
{
"domain": null,
"user_id": "AgentB",
"roles": [],
"enabled": true,
"mechanism": "CURVE",
"capabilities": {
"test1_cap2": {
"x": 1
}
},
"groups": [],
"address": null,
"credentials": "vELQORgWOUcXo69DsSmHiCCLesJPa4-CtVfvoNHwIR0",
"comments": null
}
Parameter values can also be regular expressions
(volttron)volttron@volttron1:~/git/myvolttron$ vctl auth add
domain []:
address []:
user_id []:
capabilities (delimit multiple entries with comma) []: {'test1_cap2':{'x':'/.*'}}
roles (delimit multiple entries with comma) []:
groups (delimit multiple entries with comma) []:
mechanism [CURVE]:
credentials []: vELQORgWOUcXo69DsSmHiCCLesJPa4-CtVfvoNHwIR0
comments []:
enabled [True]:
added entry domain=None, address=None, mechanism='CURVE', credentials=u'vELQORgWOUcXo69DsSmHiCCLesJPa4-CtVfvoNHwIR0', user_id='b22e041d-ec21-4f78-b32e-ab7138c22373'
auth.json file entry for the above command would be:
{
"domain": null,
"user_id": "90f8ef35-4407-49d8-8863-4220e95974c7",
"roles": [],
"enabled": true,
"mechanism": "CURVE",
"capabilities": {
"test1_cap2": {
"x": "/.*"
}
},
"groups": [],
"address": null,
"credentials": "vELQORgWOUcXo69DsSmHiCCLesJPa4-CtVfvoNHwIR0",
"comments": null
}