Files
pikasTech-unidesk/scripts/src/platform-infra-pac-consumer-rbac.ts
T

68 lines
2.9 KiB
TypeScript

import { createHash } from "node:crypto";
import { readPacAdmissionContract } from "./platform-infra-pac-provenance";
export interface PacConsumerRbacDesiredIdentity {
readonly configSha256: string;
readonly namespaces: readonly string[];
}
const pacConsumerReadOnlyRules = [
{ apiGroups: ["tekton.dev"], resources: ["pipelineruns", "taskruns"], verbs: ["get", "list", "watch"] },
{ apiGroups: [""], resources: ["pods", "pods/log"], verbs: ["get", "list", "watch"] },
] as const;
const pacConsumerDefaultRoleRef = { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: "unidesk-pac-consumer-runner" } as const;
export function renderPacConsumerRbacDesiredFragment(targetId: string): string {
const consumers = readPacAdmissionContract().consumers.filter((consumer) => consumer.node.toLowerCase() === targetId.toLowerCase());
const namespaces = [...new Set(consumers.map((consumer) => consumer.namespace))];
if (namespaces.length === 0) return "";
const configSha256 = pacConsumerRbacDesiredIdentity(targetId).configSha256;
const objects = namespaces.flatMap((namespace) => {
const labels = {
"app.kubernetes.io/managed-by": "unidesk",
"app.kubernetes.io/part-of": "platform-infra",
"unidesk.ai/pac-rbac-contract": "admission-provenance-required",
};
const annotations = {
"argocd.argoproj.io/sync-wave": "-1",
"unidesk.ai/effective-config-sha256": configSha256,
};
return [
{
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "Role",
metadata: { name: "unidesk-pac-consumer-runner", namespace, labels, annotations },
rules: pacConsumerReadOnlyRules,
},
{
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "RoleBinding",
metadata: { name: "unidesk-pac-consumer-runner-default", namespace, labels, annotations },
subjects: [{ kind: "ServiceAccount", name: "default", namespace }],
roleRef: pacConsumerDefaultRoleRef,
},
];
});
return `${objects.map((item) => Bun.YAML.stringify(item).trim()).join("\n---\n")}\n`;
}
export function pacConsumerRbacDesiredIdentity(targetId: string): PacConsumerRbacDesiredIdentity {
const consumers = readPacAdmissionContract().consumers.filter((consumer) => consumer.node.toLowerCase() === targetId.toLowerCase());
const namespaces = [...new Set(consumers.map((consumer) => consumer.namespace))].sort();
const desiredSpec = namespaces.map((namespace) => ({
namespace,
role: { name: "unidesk-pac-consumer-runner", rules: pacConsumerReadOnlyRules },
roleBinding: {
name: "unidesk-pac-consumer-runner-default",
subjects: [{ kind: "ServiceAccount", name: "default", namespace }],
roleRef: pacConsumerDefaultRoleRef,
},
}));
return {
configSha256: `sha256:${createHash("sha256").update(JSON.stringify({ targetId, desiredSpec, contract: "admission-provenance-required-v1" })).digest("hex")}`,
namespaces,
};
}