35 lines
2.2 KiB
Python
35 lines
2.2 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Exact reviewed renewal metadata; owner-admin operation, not generic KV-read delegation."""
|
||
|
|
import argparse,json,os
|
||
|
|
from pathlib import Path
|
||
|
|
from keycape_factor_metadata import call,normalized,policy_text
|
||
|
|
ROOT=Path(__file__).resolve().parents[1]
|
||
|
|
NAME="keycape-factor-renewer"
|
||
|
|
ROLE={"bound_service_account_names":[NAME],"bound_service_account_namespaces":["sso"],"audience":"openbao","token_policies":[NAME],"token_ttl":300,"token_max_ttl":300,"token_no_default_policy":True}
|
||
|
|
def execute():
|
||
|
|
policy=(ROOT/"openbao/policies"/(NAME+".hcl")).read_text()
|
||
|
|
existing=call("policy","list","-format=json")
|
||
|
|
if NAME in existing:
|
||
|
|
if normalized(policy_text(call("policy","read","-format=json",NAME)))!=normalized(policy):raise RuntimeError("existing renewal policy differs")
|
||
|
|
else:call("write","-format=json","sys/policies/acl/"+NAME,"-",payload={"policy":policy})
|
||
|
|
roles=call("list","-format=json","auth/kubernetes/role")
|
||
|
|
names=roles if isinstance(roles,list) else roles.get("data",{}).get("keys",[])
|
||
|
|
path="auth/kubernetes/role/"+NAME
|
||
|
|
if NAME in names:
|
||
|
|
data=call("read","-format=json",path)["data"]
|
||
|
|
if any(data.get(k)!=v for k,v in ROLE.items()):raise RuntimeError("existing renewal role differs")
|
||
|
|
else:call("write","-format=json",path,"-",payload=ROLE)
|
||
|
|
data=call("read","-format=json",path)["data"]
|
||
|
|
if any(data.get(k)!=v for k,v in ROLE.items()):raise RuntimeError("renewal role readback failed")
|
||
|
|
if normalized(policy_text(call("policy","read","-format=json",NAME)))!=normalized(policy):raise RuntimeError("renewal policy readback failed")
|
||
|
|
return {"success":True,"policy":NAME,"role":path,"token_max_ttl":300,"secret_values_read":False,"secret_values_written":False}
|
||
|
|
def main():
|
||
|
|
p=argparse.ArgumentParser();p.add_argument("--receipt",type=Path,required=True);a=p.parse_args()
|
||
|
|
if any(os.environ.get(k) for k in ["VAULT_TOKEN","BAO_TOKEN","OPENBAO_TOKEN"]):return 2
|
||
|
|
fd=os.open(a.receipt,os.O_WRONLY|os.O_CREAT|os.O_EXCL,0o600);result={"success":False}
|
||
|
|
try:result=execute();return 0
|
||
|
|
except RuntimeError as e:result["failure"]=str(e);return 1
|
||
|
|
except Exception as e:result["failure_type"]=type(e).__name__;return 1
|
||
|
|
finally:os.write(fd,json.dumps(result,indent=2).encode());os.close(fd)
|
||
|
|
if __name__=="__main__":raise SystemExit(main())
|