Role permissions and access restrictions
Every node entry (types, members, methods, instances) accepts two keys that become attributes of the node in the generated NodeSet:
rolePermissions:— which Role may do what (the RolePermissions attribute, OPC 10000-3 §5.2.9);accessRestrictions:— how the channel must be secured before the node can be reached (the AccessRestrictions attribute, OPC 10000-3 §5.2.10).
objectTypes:
- browseName: OvenType
subtypeOf: ua:BaseObjectType
methods:
- browseName: Calibrate
rolePermissions:
- role: ua:Anonymous
permissions: [Browse]
- role: MaintenanceRole # a role this model declares, below
permissions: [Browse, Call]
accessRestrictions: [SigningRequired]
properties:
- browseName: Secret
dataType: ua:String
rolePermissions:
- role: ua:SecurityAdmin
permissions: [all]
accessRestrictions: [SigningRequired, EncryptionRequired]
- browseName: Sealed
dataType: ua:String
rolePermissions: [] # grants nothing at all
roles:
- browseName: MaintenanceRole
description: Service technicians; may run calibration methods.
role:
A Role is an instance of RoleType. Name it by its BrowseName:
| You write | Meaning |
|---|---|
ua:Operator | a well-known role of OPC UA: Anonymous, AuthenticatedUser, Observer, Operator, Engineer, Supervisor, ConfigureAdmin, SecurityAdmin, TrustedApplication |
gds:DiscoveryAdmin | a role of an imported companion specification |
MaintenanceRole | a role this model declares (no prefix) |
/ua:Objects/…/MyRole | a full browse path, for the rare name two roles share |
The short form is looked up among roles only, so it never picks up another node of the
same name. Write ua:Operator, not WellKnownRole_Operator: the latter is the
SymbolicName the specification uses for code constants.
A role your model declares may be referenced from a type declared earlier in the file: permissions are applied once the whole model is built.
roles: — declaring roles
roles:
- browseName: MaintenanceRole
description: Service technicians; may run calibration methods.
- browseName: AuditReader
configurable: false # Identities only
- browseName: Tuner
optionals: [ua:CustomConfiguration] # one more RoleType member
Each entry is an instance of ua:RoleType under the server's RoleSet, built the way
the published NodeSets build theirs (GDS's five roles, the well-known roles of OPC UA):
| Default | |
|---|---|
typeDefinition | ua:RoleType (a subtype may be given) |
componentOf | /ua:Objects/ua:Server/ua:ServerCapabilities/ua:RoleSet |
| members | Identities, Applications and ApplicationsExclude, Endpoints and EndpointsExclude, and the six methods that edit them (AddIdentity … RemoveEndpoint). configurable: false keeps Identities only; CustomConfiguration is added through optionals: |
| member security | SecurityAdmin alone, [all], and [SigningRequired, EncryptionRequired]: otherwise any client could rewrite who holds the role |
| the role object itself | nothing; rolePermissions: on the entry sets them |
Identities is left without a value: which users hold a role is the deployment's
business, set at run time through AddIdentity. A role that needs another shape can
still be written as an instances: entry with typeDefinition: ua:RoleType.
permissions:
The bits of PermissionType, by name. They belong to OPC UA itself, so they take no
namespace prefix:
Browse, ReadRolePermissions, WriteAttribute, WriteRolePermissions,
WriteHistorizing, Read, Write, ReadHistory, InsertHistory, ModifyHistory,
DeleteHistory, ReceiveEvents, Call, AddReference, RemoveReference,
DeleteNode, AddNode.
[all] stands for every permission that applies to the node's NodeClass, as the
specification defines it for each bit. That is the mask the published NodeSets give
SecurityAdmin: 59391 on a Variable, 65423 on an Object, 61455 on a Method. all
cannot be combined with other names.
accessRestrictions:
SigningRequired, EncryptionRequired, SessionRequired,
ApplyRestrictionsToBrowse.
permissionSets: — naming a combination
When several nodes share the same permissions, name them once:
permissionSets:
caCall:
rolePermissions:
- role: ua:Anonymous
permissions: [Browse]
- role: CertificateAuthorityAdmin
permissions: [Browse, Call]
accessRestrictions: [SigningRequired]
instances:
- browseName: Directory
typeDefinition: CertificateDirectoryType
methods:
- browseName: StartSigningRequest
permissionSet: caCall
- browseName: FinishRequest
permissionSet: caCall
A node takes its permissions from one place: a permissionSet: and its own
rolePermissions:/accessRestrictions: on the same node is an error
(DSL-E-PERM-003), as is a set name
that is not defined. A set no node uses is a warning
(DSL-W-PERM-004). A method using a
set gives its arguments the derived default, like the same keys written inline;
argumentPermissions: still overrides it.
Absent, empty, inherited
- No
rolePermissions:key — the node inherits the namespace's default permissions. rolePermissions: []— the node grants nothing to anyone (HasNoPermissionsin the NodeSet).- Instances do not inherit the permissions of their type's members: each node carries
what its own entry says. Give an instance's method its permissions on the instance's
methods:entry.
A method's arguments
A method's InputArguments and OutputArguments properties are nodes too, with
permissions of their own, but no entry in the YAML. By default they get the method's
roles translated to a Variable: Call becomes Read (who may call a method may read
its signature), [all] becomes every Variable permission, and the method's
accessRestrictions are copied. That is what most published NodeSets do.
When they should carry something else, say so on the method:
methods:
- browseName: RegisterApplication
rolePermissions:
- role: ua:Anonymous
permissions: [Browse, Call]
argumentPermissions: # both argument properties get exactly this
rolePermissions:
- role: ua:Anonymous
permissions: [Browse]
Namespace defaults
A node without rolePermissions: inherits its namespace's default. The defaults are
properties of the namespace's NamespaceMetadataType object,
DefaultRolePermissions and DefaultAccessRestrictions, so they are written like any
other property value: no dedicated syntax.
The published specifications (GDS, DI, Robotics) declare these properties and leave them empty: which roles may do what by default is the deployment's decision. Declare them the same way:
namespaceMetadatas:
- optionals: [ua:DefaultRolePermissions, ua:DefaultAccessRestrictions]
A model that does fix a default writes the values as the structures they are, the role by its NodeId and the permissions as their mask:
namespaceMetadatas:
- optionals: [ua:DefaultRolePermissions, ua:DefaultAccessRestrictions]
initializers:
- variable: ua:DefaultRolePermissions
value:
- roleId: i=15680 # ua:Operator
permissions: 33 # Browse | Read
- variable: ua:DefaultAccessRestrictions
value: 1 # SigningRequired
The fields may also be written as the specification declares them, RoleId and
Permissions.
Reverse engineering
reverse writes both keys on every entry it produces, with all where the mask matches
exactly, and argumentPermissions: only where a method's arguments differ from the
default. A role goes to roles: when that short entry rebuilds exactly the same nodes,
otherwise to instances: with every permission written out; GDS's five roles all come
back as two-line roles: entries.
A NodeSet names no sets, so reverse makes them up: a combination several nodes share
goes to permissionSets: when that makes the YAML shorter (the set once, plus one
permissionSet: line per use, against the full combination at every use). The name is
built from the content, roles then restrictions, so the same NodeSet always gives the same
names: Anonymous_CertificateAuthorityAdmin_Signed, SecurityAdmin_SignedEncrypted; a
_2 tells apart two combinations that would share one. GDS 1.05.07 gets four sets, used
by 20 nodes, and its YAML shrinks from 1059 to 922 lines.
Reversing GDS 1.05.07 and compiling the result gives back the permissions of all 124 of
its nodes that have any. The one case it cannot write, input and output arguments that
differ from each other, is reported by the reverse-dropped-permissions warning.
Diagnostics: DSL-E-PERM-001 (role
not found), DSL-E-PERM-002 (not a
permission name).