DR-009-ACL-Concept: Common ACL format for all components#

One Format for Access Control List(s) (ACL)
status: proposed
context: Common ACL format for all components
decision: open
version: 0

Context#

Access Control is required on multiple components; i.e.:

  • IPC (LoLa) Who is allowed to publish which services (who can create/modify a file in the according directory) For Service Providers: Once the IPC Channel/SharedMemory is created, whom to grant which rights to what area (data/control) This permissions will be based on uid.

  • SOME/IP Same to IPC, except the permissions will be based on IP address / netmask. In addition: Should TLS be enforced for a service? Should IP & MACsec be active as basis for a certain service?

  • Crypto Needs to know who (which application - i.e. which uid (every application shall run as own user)) – created/owns a key – is allowed to write/change a key – is allowed to use a key for any operations (e.g. sign/verify/encrypt/decrypt/keyderive/etc.) – is allowed to read/extract a key (e.g. pub keys)

Consequences#

To prevent each component from implementing compeletley own mechanism for persmission enforcement; the decision should be an alignment on a common ACL format, so that all components can use:

  • the same parser as a baselib to read the ACL

  • (optionally) the same “ACLHandler” to update/edit and recompile the ACL One additional big advantage of a harmonized ACL is that:

  • it is easier to review (security reviews, etc.)

  • it is easier to debug

  • only one parser needs to be tested in depth

  • updates due to parser vulnerabilities can be centrallized

The base proposal is as follows:

  • a json file as configuration

  • for runtime efficiency: compilation of the json file to a flatbuffer/binary file

Proposed json format & properties (example):

{
  "policyVersion": 1,
  "policyId": "example-acl-policy-001",
  "defaultEffect": "deny",
  "generatedBy": "install-update-manager",
  "generatedAt": "2026-06-17T14:28:00Z",

  "services": 
  {
	"111":
	{
	  "serviceName": "someservice",
	  "serviceInstances": {
		"500":
		{
		  "providerName": "fancy_name",
		  "criticality": "ASIL-B",
		  "version": 5,
		  "tlsenable": 1,
		  "ipsecenable": 1,
		  "macsecenable":1,			  
		  "specifics": {},
		  "allow": 
		  {
			"uids": 
			{
			  "101":{"rights": ["write"],"name": "oem.app.1","version": [],"criticality": "ASIL-B","specifics": {}},
			  "102":{"rights": ["read"],"name": "oem.app.2","version": [],"criticality": "ASIL-B","specifics": {}},
			  "103":{"rights": ["read"],"name": "tier1.daemon.1","version": [],"criticality": "ASIL-B","specifics": {}}
			},
			"ips": 
			{ 
				"10.1.15.2":{"name": "ecu_1","rights": ["write"],"version": [],"criticality": "QM","specifics": {}},
				"10.1.15.3":{"name": "ecu_2_app3","rights": ["read"],"version": [],"criticality": "QM","specifics": {}}
			}
		  }
		}
	  }
	}
  },
  "crypto": 
  {
	"0":
	{
		"keyspaceName": "tls_auth",
		"keys": 
		{
			"1":
			{	
				"name": "tls_auth_priv",
				"read": [],
				"use": [{"uid": 1,"otherid": "special_handling_1"},{"vmid": 4,"uid": 2}],
				"write": [{"uid": 1, "policy": "someipd_t"}]
			},
			"2":
			{ 
				"name": "tls_auth_pub",
				"read": [{"uid": -1}],
				"use": [{"uid": 1, "policy": ""},{"vmid": 4,"uid": 2}],
				"write": [{"uid": 1, "policy": "someipd_t"}]
			}
		}
	}
  }
}
proposed json scheme:
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/acl-policy.schema.json",
  "title": "ACL Configuration Schema",
  "type": "object",
  "additionalProperties": false,
  "required": [
	"policyVersion",
	"policyId",
	"defaultEffect",
	"generatedBy",
	"generatedAt",
	"services"
  ],
  "properties": {
	"policyVersion": {
	  "type": "integer",
	  "minimum": 1
	},
	"policyId": {
	  "type": "string",
	  "minLength": 1,
	  "maxLength": 128
	},
	"defaultEffect": {
	  "type": "string",
	  "enum": [
		"deny",
		"allow"
	  ],
	  "maxLength": 128
	},
	"generatedBy": {
	  "type": "string",
	  "minLength": 1,
	  "maxLength": 128
	},
	"generatedAt": {
	  "type": "string",
	  "description": "ISO-8601 UTC timestamp without fractional seconds",
	  "maxLength": 20,
	  "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
	},
	"services": {
	  "type": "object",
	  "propertyNames": {
		"$ref": "#/$defs/uint16Key"
	  },
	  "additionalProperties": {
		"$ref": "#/$defs/service"
	  }
	},
	"crypto": {
	  "type": "object",
	  "propertyNames": {
		"$ref": "#/$defs/uint16Key"
	  },
	  "additionalProperties": {
		"$ref": "#/$defs/keyspace"
	  }
	}
  },
  "$defs": {
	"uint16Key": {
	  "type": "string",
	  "pattern": "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$"
	},
	"uidKey": {
	  "type": "string",
	  "pattern": "^(0|[1-9][0-9]{0,8}|1[0-9]{9}|20[0-9]{8}|21[0-3][0-9]{7}|214[0-6][0-9]{6}|2147[0-3][0-9]{5}|21474[0-7][0-9]{4}|214748[0-2][0-9]{3}|2147483[0-5][0-9]{2}|21474836[0-3][0-9]|214748364[0-7])$"
	},
	"criticality": {
	  "type": "string",
	  "enum": [
		"QM",
		"ASIL-A",
		"ASIL-B",
		"ASIL-C",
		"ASIL-D"
	  ],
	  "maxLength": 128
	},
	"binaryFlag": {
	  "type": "integer",
	  "enum": [
		0,
		1
	  ]
	},
	"rights": {
	  "type": "array",
	  "items": {
		"type": "string",
		"enum": [
		  "read",
		  "write",
		  "monitor"
		],
		"maxLength": 128
	  },
	  "uniqueItems": true
	},
	"specifics": {
	  "description": "OEM-specific or project-specific extension object. Unknown properties are allowed only here.",
	  "type": "object",
	  "additionalProperties": {
		"$ref": "#/$defs/specificValue"
	  }
	},
	"specificValue": {
	  "anyOf": [
		{
		  "type": "string",
		  "maxLength": 128
		},
		{
		  "type": "number"
		},
		{
		  "type": "integer"
		},
		{
		  "type": "boolean"
		},
		{
		  "type": "null"
		},
		{
		  "type": "array",
		  "items": {
			"$ref": "#/$defs/specificValue"
		  }
		},
		{
		  "type": "object",
		  "additionalProperties": {
			"$ref": "#/$defs/specificValue"
		  }
		}
	  ]
	},
	"service": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"serviceName",
		"serviceInstances"
	  ],
	  "properties": {
		"serviceName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"serviceInstances": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/serviceInstance"
		  }
		}
	  }
	},
	"serviceInstance": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"providerName",
		"criticality",
		"version",
		"tlsenable",
		"ipsecenable",
		"macsecenable",
		"specifics",
		"allow"
	  ],
	  "properties": {
		"providerName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"criticality": {
		  "$ref": "#/$defs/criticality"
		},
		"version": {
		  "type": "integer",
		  "minimum": 0,
		  "maximum": 65535
		},
		"tlsenable": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"ipsecenable": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"macsecenable": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		},
		"allow": {
		  "$ref": "#/$defs/allow"
		}
	  }
	},
	"allow": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"uids",
		"ips"
	  ],
	  "properties": {
		"uids": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uidKey"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/uidSubject"
		  }
		},
		"ips": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/ipOrCidrKey"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/ipSubject"
		  }
		}
	  }
	},
	"uidSubject": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"rights",
		"version",
		"criticality",
		"specifics"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"rights": {
		  "$ref": "#/$defs/rights"
		},
		"version": {
		  "type": "array",
		  "items": {
			"anyOf": [
			  {
				"type": "integer",
				"minimum": 0,
				"maximum": 65535
			  },
			  {
				"type": "string",
				"maxLength": 128
			  }
			]
		  }
		},
		"criticality": {
		  "$ref": "#/$defs/criticality"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		}
	  }
	},
	"ipSubject": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"rights",
		"criticality",
		"specifics"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"rights": {
		  "$ref": "#/$defs/rights"
		},
		"criticality": {
		  "$ref": "#/$defs/criticality"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		}
	  }
	},
	"ipOrCidrKey": {
	  "type": "string",
	  "maxLength": 128,
	  "anyOf": [
		{
		  "description": "IPv4 address",
		  "pattern": "^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}$"
		},
		{
		  "description": "IPv4 CIDR subnet",
		  "pattern": "^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\\/(3[0-2]|[1-2]?[0-9])$"
		},
		{
		  "description": "IPv6 address or IPv6 CIDR subnet, simplified validation",
		  "pattern": "^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}(\\/(12[0-8]|1[0-1][0-9]|[1-9]?[0-9]))?$"
		}
	  ]
	},
	"keyspace": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"keyspaceName",
		"keys"
	  ],
	  "properties": {
		"keyspaceName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"keys": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/key"
		  }
		}
	  }
	},
	"key": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"read",
		"use",
		"write"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"read": {
		  "$ref": "#/$defs/keyAccessList"
		},
		"use": {
		  "$ref": "#/$defs/keyAccessList"
		},
		"write": {
		  "$ref": "#/$defs/keyAccessList"
		}
	  }
	},
	"keyAccessList": {
	  "type": "array",
	  "items": {
		"$ref": "#/$defs/keyAccessEntry"
	  }
	},    
	"keyAccessEntry": {
	  "type": "object",
	  "additionalProperties": false,

	  "anyOf": [
		{
		  "required": ["uid"]
		},
		{
		  "required": ["policy"]
		},
		{
		  "required": ["vmid", "uid"]
		},
		{
		  "required": ["otherid"]
		}
	  ],

	  "dependentRequired": {
		"vmid": ["uid"]
	  },

	  "properties": {
		"vmid": {
		  "description": "Optional virtual machine ID. If present, uid is required as well.",
		  "type": "integer",
		  "minimum": 0,
		  "maximum": 2147483647
		},
		"uid": {
		  "type": "integer",
		  "minimum": -1,
		  "maximum": 2147483647
		},
		"policy": {
		  "type": "string",
		  "maxLength": 128
		},
		"otherid": {
		  "description": "Optional additional identifier for project-specific or non-UID based access control.",
		  "type": "string",
		  "maxLength": 128
		}
	  }
	}

  }
}

Justification for the Decision#

open