93 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from mako.template import Template
 | |
| 
 | |
| template = '''
 | |
| % for segment, options in data.items():
 | |
| 
 | |
| %     if '#' in segment:
 | |
| # ${segment.split('#', 2)[1]}
 | |
| %     endif
 | |
| [${segment.split('#')[0]}]
 | |
| %     for option, value in sorted(options.items()):
 | |
| %         if isinstance(value, dict):
 | |
| %             for k, v in value.items():
 | |
| ${option}=${k}=${v}
 | |
| %             endfor
 | |
| %         elif isinstance(value, (list, set, tuple)):
 | |
| %             for item in (sorted(value) if isinstance(value, set) else value):
 | |
| ${option}=${item}
 | |
| %             endfor
 | |
| %         elif isinstance(value, type(None)):
 | |
| %         else:
 | |
| ${option}=${str(value)}
 | |
| %         endif
 | |
| %     endfor
 | |
| % endfor
 | |
| '''
 | |
| 
 | |
| order = [
 | |
|     'Unit',
 | |
|     'Timer',
 | |
|     'Service',
 | |
|     'Swap',
 | |
|     'Install',
 | |
| ]
 | |
| 
 | |
| def segment_order(segment):
 | |
|     return (
 | |
|         order.index(segment[0]) if segment[0] in order else float('inf'),
 | |
|         segment[0]
 | |
|     )
 | |
| 
 | |
| def generate_unitfile(data):
 | |
|     return Template(template).render(
 | |
|         data=dict(sorted(data.items(), key=segment_order)),
 | |
|     ).lstrip()
 | |
| 
 | |
| # wip
 | |
| def protection():
 | |
|     return {
 | |
|         # user
 | |
|         'UMask': '077',
 | |
|         'DynamicUser': 'yes',
 | |
|         'PrivateUsers': 'yes',
 | |
|         'RestrictSUIDSGID': 'yes',
 | |
|         'NoNewPrivileges': 'yes',
 | |
|         'LockPersonality': 'yes',
 | |
|         'RemoveIPC': 'yes',
 | |
| 
 | |
|         # fs
 | |
|         'ProtectSystem': 'strict',
 | |
|         'ProtectHome': 'yes',
 | |
|         'PrivateTmp': 'yes',
 | |
|         'PrivateDevices': 'yes',
 | |
|         'ProtectProc': 'invisible',
 | |
|         'ProcSubset': 'pid',
 | |
|         'PrivateMounts': 'yes',
 | |
|         'RestrictFileSystems': {'ext4', 'tmpfs', 'zfs'},
 | |
| 
 | |
|         'NoExecPaths': {'/'},
 | |
|         'ExecPaths': {'/bin', '/sbin', '/lib', '/lib64', '/usr'},
 | |
| 
 | |
|         'TemporaryFileSystem': {'/var'},
 | |
| 
 | |
|         # network
 | |
|         'IPAddressDeny': 'any',
 | |
|         'PrivateNetwork': 'yes',
 | |
|         'RestrictAddressFamilies': 'none',
 | |
| 
 | |
|         # syscall
 | |
|         'SystemCallArchitectures': 'native',
 | |
|         'SystemCallFilter': '~@swap @resources @reboot @raw-io @privileged @obsolete @mount @module @debug @cpu-emulation @clock',
 | |
| 
 | |
|         # else
 | |
|         'ProtectHostname': 'yes',
 | |
|         'ProtectClock': 'yes',
 | |
|         'ProtectKernelTunables': 'yes',
 | |
|         'ProtectKernelModules': 'yes',
 | |
|         'ProtectKernelLogs': 'yes',
 | |
|         'ProtectControlGroups': 'yes',
 | |
|         'RestrictNamespaces': 'yes',
 | |
|         'MemoryDenyWriteExecute': 'yes',
 | |
|         'RestrictRealtime': 'yes',
 | |
|         'CapabilityBoundingSet': '',
 | |
|     }
 |