feat(recovery): verify scoped delivery and create first full offsite bundle
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
This commit is contained in:
parent
8857d9ff6f
commit
17a8fa1495
15 changed files with 435 additions and 12 deletions
|
|
@ -40,8 +40,15 @@ def write(path,value):
|
|||
def token(action):
|
||||
name='net-kingdom-backup-'+action
|
||||
es=capture.get('sso','externalsecret',name)
|
||||
if (es['spec']['target']['name']!=name or es['spec']['data']!=[{'secretKey':'token','remoteRef':{
|
||||
entries=[]
|
||||
for entry in es['spec'].get('data',[]):
|
||||
item=dict(entry);ref=dict(item.get('remoteRef',{}))
|
||||
for key,default in [('conversionStrategy','Default'),('decodingStrategy','None'),('metadataPolicy','None')]:
|
||||
if ref.pop(key,default)!=default:raise offsite.Refused()
|
||||
item['remoteRef']=ref;entries.append(item)
|
||||
if (es['spec']['target']['name']!=name or entries!=[{'secretKey':'token','remoteRef':{
|
||||
'key':'workloads/net-kingdom/identity-backup/'+action,'property':'NC_WEBDAV_TOKEN'}}]
|
||||
or es['spec'].get('dataFrom') or es['spec'].get('secretStoreRef')!={'kind':'SecretStore','name':name}
|
||||
or not any(c['type']=='Ready' and c['status']=='True' for c in es['status'].get('conditions',[]))):raise offsite.Refused()
|
||||
secret=capture.get('sso','secret',name)
|
||||
if (set(secret['data'])!={'token'} or not any(o['uid']==es['metadata']['uid'] for o in secret['metadata'].get('ownerReferences',[]))):raise offsite.Refused()
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@ from state_hub_preflight_lane import bao,data,capabilities,revoke
|
|||
|
||||
|
||||
def verify(action,expected,receipt,kubeconfig):
|
||||
receipt['phase']='validate_approved_contract'
|
||||
ccr,lane=setup.contract(action,expected)
|
||||
receipt['phase']='verify_attended_identity'
|
||||
ident=data(bao(['token','lookup','-format=json']))['data']
|
||||
if 'platform-admin' not in ident.get('policies',[]) or 'root' in ident.get('policies',[]) or not ident.get('path','').startswith('auth/netkingdom/'):raise setup.Refused()
|
||||
capture=runtime.capture;capture.KUBE=['kubectl','--kubeconfig',kubeconfig]
|
||||
receipt['phase']='verify_cluster_identity'
|
||||
if capture.get(None,'namespace','kube-system')['metadata']['uid']!=capture.prepare.CLUSTER_UID:raise setup.Refused()
|
||||
def login(sa,audience,negative=False,namespace='sso'):
|
||||
jwt=capture.command(['-n',namespace,'create','token',sa,'--audience='+audience,'--duration=10m']).decode().strip()
|
||||
|
|
@ -35,18 +38,25 @@ def verify(action,expected,receipt,kubeconfig):
|
|||
if b'403' not in result.stderr and b'400' not in result.stderr:raise setup.Refused()
|
||||
return None
|
||||
return data(result)['auth']
|
||||
receipt['phase']='native_reader_login'
|
||||
auth=login(lane['service_account'],'openbao');token=auth['client_token']
|
||||
receipt['native_reader_metadata']={k:auth.get(k) for k in ['token_policies','identity_policies','policies','lease_duration']}
|
||||
try:
|
||||
receipt['phase']='effective_reader_policy_ttl'
|
||||
if (auth['token_policies']!=[lane['policy']] or auth.get('identity_policies')
|
||||
or auth.get('policies',auth['token_policies'])!=[lane['policy']] or not 0<auth['lease_duration']<=900):raise setup.Refused()
|
||||
paths=[lane['kv_path'],lane['kv_path'].replace('/data/','/metadata/',1),lane['kv_path']+'-sibling',
|
||||
'platform/data/workloads/railiance/backup/offsite-lane','auth/token/create']
|
||||
receipt['phase']='reader_capabilities'
|
||||
cap=capabilities(token,paths)
|
||||
receipt['capabilities_checked']=cap
|
||||
if cap[paths[0]]!=['read'] or any(cap[p]!=['deny'] for p in paths[1:]):raise setup.Refused()
|
||||
receipt['phase']='native_kv_eso_equality'
|
||||
native=data(bao(['read','-format=json',lane['kv_path']],token=token))['data']
|
||||
if set(native['data'])!={'NC_WEBDAV_TOKEN'} or native['data']['NC_WEBDAV_TOKEN']!=runtime.token(action):raise setup.Refused()
|
||||
receipt['kv_version']=native['metadata']['version']
|
||||
finally:revoke(token)
|
||||
receipt['phase']='negative_reader_logins'
|
||||
login('default','openbao',True);login(lane['service_account'],'wrong-audience',True)
|
||||
proposed={'apiVersion':'v1','kind':'ServiceAccount','metadata':{'name':lane['service_account'],'namespace':'default'},'automountServiceAccountToken':False}
|
||||
receipt['wrong_namespace_probe_attempted']=proposed['metadata']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue