"""Render a review-only Kubernetes candidate. Never apply or provision custody.""" import argparse import ipaddress import json from pathlib import Path import re import hashlib NAME = 'informed-decision' SHA = re.compile(r'sha256:[0-9a-f]{64}') LABEL = {'app.kubernetes.io/name': NAME} def render(inputs): if not isinstance(inputs,dict) or set(inputs)!={'image','policy','keycape_egress_ips','storage_class'}: raise ValueError('exact image, policy, KeyCape egress IPs and storage class inputs required') if not re.fullmatch(r'forgejo\.coulomb\.social/coulomb/informed-decision@sha256:[0-9a-f]{64}',inputs['image']): raise ValueError('immutable Informed Decision registry digest required') policy=inputs['policy'] if not isinstance(policy,dict) or set(policy)!={'origin','package','version','package_digest','pod_name'}: raise ValueError('exact policy endpoint, package pins and pod selector required') if not re.fullmatch(r'http://[a-z0-9-]+\.flex-auth\.svc\.cluster\.local:8080',policy['origin']): raise ValueError('exact in-cluster Flex Auth endpoint required') if not re.fullmatch(r'[a-z0-9][a-z0-9.-]{0,62}',policy['pod_name']): raise ValueError('exact Flex Auth pod label required') if not SHA.fullmatch(policy['package_digest']) or any( not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9._-]{0,127}',policy[key]) for key in ['package','version']): raise ValueError('exact policy package/version/digest required') if not re.fullmatch(r'[a-z0-9][a-z0-9.-]{0,62}',inputs['storage_class']): raise ValueError('explicit storage class required') ips=inputs['keycape_egress_ips'] if not isinstance(ips,list) or not 1<=len(ips)<=4: raise ValueError('one to four exact admitted KeyCape egress addresses required') cidrs=[] for ip in ips: address=ipaddress.ip_address(ip) if not address.is_global: raise ValueError('KeyCape public origin requires exact global addresses') cidrs.append(str(address)+'/'+str(address.max_prefixlen)) config={'schema':'informed-decision.review-runtime.v1','evidence_db':'/data/private/review.sqlite', 'approval_origin':'http://approval-engine.approval-engine.svc.cluster.local:8080', 'policy':{key:policy[key] for key in ['origin','package','version','package_digest']}, 'audit':{'origin':'http://audit-core.audit-core.svc.cluster.local:8080', 'sender_token_file':'/var/run/secrets/informed-decision/audit/token'}} config['policy']['caller_token_file']='/var/run/secrets/informed-decision/policy/token' raw=json.dumps(config,sort_keys=True,separators=(',',':')) config_name=NAME+'-runtime-'+hashlib.sha256(raw.encode()).hexdigest()[:12] def obj(api,kind,name,**values): return {'apiVersion':api,'kind':kind,'metadata':{'name':name,'namespace':NAME, 'annotations':{'informed-decision.coulomb.social/admission':'review-only; INFD-WP-0001-T08'}},**values} container_security={'allowPrivilegeEscalation':False,'readOnlyRootFilesystem':True,'capabilities':{'drop':['ALL']}} mount=lambda name,path:{'name':name,'mountPath':path} readonly=lambda name,path:{**mount(name,path),'readOnly':True} probe=lambda path:{'httpGet':{'path':path,'port':'http'},'periodSeconds':10,'timeoutSeconds':2} pod={'automountServiceAccountToken':False,'serviceAccountName':'review','terminationGracePeriodSeconds':45, 'securityContext':{'runAsNonRoot':True,'runAsUser':10001,'runAsGroup':10001,'fsGroup':10001, 'fsGroupChangePolicy':'OnRootMismatch','seccompProfile':{'type':'RuntimeDefault'}}, 'containers':[{'name':NAME,'image':inputs['image'],'securityContext':container_security, 'env':[{'name':'INFD_KEYCAPE_ISSUER','value':'https://kc.coulomb.social'}, {'name':'INFD_CONTAINER_CONFIG','value':'/configuration/runtime.json'}], 'ports':[{'name':'http','containerPort':8080}], 'startupProbe':{**probe('/healthz'),'failureThreshold':12}, # Keep read/recovery pages reachable during an audit outage. The # application gates acceptance on /readyz internally; monitoring # must scrape it separately. An outage must not restart the writer. 'readinessProbe':probe('/healthz'),'livenessProbe':probe('/healthz'), 'resources':{'requests':{'cpu':'50m','memory':'64Mi'},'limits':{'cpu':'500m','memory':'256Mi'}}, 'volumeMounts':[mount('data','/data'),mount('runtime','/run/informed-decision'),mount('tmp','/tmp'), readonly('configuration','/configuration'),readonly('caller','/var/run/secrets/informed-decision/policy'), readonly('audit','/var/run/secrets/informed-decision/audit')]}], 'volumes':[{'name':'data','persistentVolumeClaim':{'claimName':NAME+'-data'}}, {'name':'runtime','emptyDir':{'medium':'Memory','sizeLimit':'16Mi'}}, {'name':'tmp','emptyDir':{'medium':'Memory','sizeLimit':'16Mi'}}, {'name':'configuration','configMap':{'name':config_name,'defaultMode':0o444}}, {'name':'caller','projected':{'defaultMode':0o440,'sources':[{'serviceAccountToken':{ 'path':'token','audience':'flex-auth','expirationSeconds':3600}}]}}, {'name':'audit','secret':{'secretName':NAME+'-audit','defaultMode':0o440, 'items':[{'key':'token','path':'token'}]}}]} peer=lambda namespace,name:{'namespaceSelector':{'matchLabels':{'kubernetes.io/metadata.name':namespace}}, 'podSelector':{'matchLabels':{'app.kubernetes.io/name':name}}} http=[{'protocol':'TCP','port':8080}] objects=[ obj('v1','ServiceAccount','review',automountServiceAccountToken=False), obj('v1','PersistentVolumeClaim',NAME+'-data',spec={'accessModes':['ReadWriteOnce'], 'storageClassName':inputs['storage_class'],'resources':{'requests':{'storage':'1Gi'}}}), obj('v1','ConfigMap',config_name,immutable=True,data={'runtime.json':raw}), obj('apps/v1','Deployment',NAME,spec={'replicas':1,'strategy':{'type':'Recreate'},'progressDeadlineSeconds':600, 'selector':{'matchLabels':LABEL},'template':{'metadata':{'labels':{**LABEL,'app.kubernetes.io/component':'review'}},'spec':pod}}), obj('v1','Service',NAME,spec={'type':'ClusterIP','selector':{**LABEL,'app.kubernetes.io/component':'review'}, 'ports':[{'name':'http','port':80,'targetPort':'http','protocol':'TCP'}]}), obj('networking.k8s.io/v1','NetworkPolicy',NAME+'-review',spec={'podSelector':{'matchLabels':{**LABEL, 'app.kubernetes.io/component':'review'}},'policyTypes':['Ingress','Egress'], 'ingress':[{'from':[peer('kube-system','traefik')],'ports':http}], 'egress':[{'to':[{'namespaceSelector':{'matchLabels':{'kubernetes.io/metadata.name':'kube-system'}}, 'podSelector':{'matchLabels':{'k8s-app':'kube-dns'}}}], 'ports':[{'protocol':'UDP','port':53},{'protocol':'TCP','port':53}]}, {'to':[peer('approval-engine','approval-engine'),peer('audit-core','audit-core'), peer('flex-auth',policy['pod_name'])],'ports':http}, # Traefik's observed websecure target is 8443. Include # its exact peer for CNI enforcement after Service DNAT. {'to':[peer('kube-system','traefik')],'ports':[{'protocol':'TCP','port':8443}]}, {'to':[{'ipBlock':{'cidr':cidr}} for cidr in cidrs],'ports':[{'protocol':'TCP','port':443}]}]})] # Counterparty proposals travel in the review packet. Neither the existing # Approval Engine namespace gate nor other Flex callers admits this pod. # Audit Core already owns its prepared exact informed-decision ingress. for namespace,name,task in [('approval-engine','approval-engine','APPROVAL-WP-0002-T01'), ('flex-auth',policy['pod_name'],'INFD-WP-0001-T08 policy-owner return')]: item=obj('networking.k8s.io/v1','NetworkPolicy',NAME+'-review-ingress',spec={ 'podSelector':{'matchLabels':{'app.kubernetes.io/name':name}},'policyTypes':['Ingress'], 'ingress':[{'from':[{'namespaceSelector':{'matchLabels':{'kubernetes.io/metadata.name':NAME}}, 'podSelector':{'matchLabels':{**LABEL,'app.kubernetes.io/component':'review'}}}],'ports':http}]}) item['metadata']['namespace']=namespace item['metadata']['annotations']['informed-decision.coulomb.social/owner-review']=task objects.append(item) return {'apiVersion':'v1','kind':'List','items':objects} def main(): parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--input',type=Path,required=True) parser.add_argument('--output',type=Path) args=parser.parse_args() try: result=render(json.loads(args.input.read_text())) except (ValueError,TypeError,KeyError,OSError) as exc:parser.error(str(exc)) raw=json.dumps(result,indent=2)+'\n' if args.output:args.output.write_text(raw) else:print(raw,end='') if __name__=='__main__':main()