ProofedMesh/deploy/trillian/30-createtree-job.yaml

116 lines
4.4 KiB
YAML
Raw Permalink Normal View History

transparency-log: real Trillian backend wiring + agent-trust deploy (DEV-604) - services/transparency-log/pkg/backend/trillian.go: real gRPC client on github.com/google/trillian v1.6.1. Submit() does QueueLeaf with the canonical DSSE envelope as LeafValue and the raw content_hash bytes as LeafIdentityHash, then polls GetLatestSignedLogRoot + GetInclusionProofByHash until the leaf is sequenced. Idempotency uses Trillian's ALREADY_EXISTS signal on the inner QueuedLogLeaf.Status, so a repeated submit still returns 200 OK with the originally-assigned log_index + a valid proof against the current STH. - Unconfigured backend (missing endpoint or LogID) returns the historical ErrTrillianUnavailable so the httpapi layer keeps mapping it to 503 instead of silently 500. Existing stub-returns-503 test updated. - cmd/transparency-log: pointer-receiver Trillian wiring; flag docs mention the production SRV name. - services/transparency-log/Dockerfile: distroless multi-stage build used by deploy/trillian/40-transparency-log.yaml. - deploy/trillian/: full K8s stack for the agent-trust namespace — MySQL 8.4 StatefulSet (schema init ConfigMap vendored from upstream storage.sql v1.6.1), Trillian LogServer + LogSigner Deployments on gcr.io/trillian-opensource-ci:v1.6.1, createtree Job that writes the TreeID to a ConfigMap (re-apply safe), transparency-log Deployment with --backend=trillian pulling TRILLIAN_LOG_ID from the ConfigMap. - deploy/trillian/README.md: first-time apply + smoke-test + secret rotation + signer-key clarification (STH key is Trillian-internal; DSSE envelope signing stays with signing-service / OpenBao). - services/admin-api: go.mod / go.sum pick up the new transitive deps (trillian + grpc) via the local replace on transparency-log. - services/transparency-log/README.md: Backends table updated; next- steps list no longer carries Trillian-deployment as a follow-up. Deployed to the live cluster from this heartbeat: MySQL + LogServer + LogSigner running in agent-trust, tree id 8482455225499059043, service smoke-tested end-to-end (201 on first POST, 200 on idempotent repeat, 409 on content_hash mismatch, tree_size=2 with correct audit path). Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 18:39:44 +00:00
---
# ConfigMap populated by the createtree Job below. The transparency-log
# Deployment reads TRILLIAN_LOG_ID out of this ConfigMap. The Job owns
# writing the value; GitOps owns the structure of this object.
apiVersion: v1
kind: ConfigMap
metadata:
name: trillian-log-id
namespace: agent-trust
data:
TRILLIAN_LOG_ID: ""
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: trillian-createtree
namespace: agent-trust
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: trillian-createtree
namespace: agent-trust
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["trillian-log-id"]
verbs: ["get", "patch", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: trillian-createtree
namespace: agent-trust
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: trillian-createtree
subjects:
- kind: ServiceAccount
name: trillian-createtree
namespace: agent-trust
---
# One-shot Job: creates a Trillian LOG tree the first time it runs and
# writes the TreeID into the ConfigMap above. On a re-run the Job detects
# a non-empty ConfigMap value and exits early — so it is safe to re-apply.
apiVersion: batch/v1
kind: Job
metadata:
name: trillian-createtree
namespace: agent-trust
spec:
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
serviceAccountName: trillian-createtree
containers:
- name: createtree
image: golang:1.23-alpine3.21
env:
- name: TRILLIAN_ADMIN_SERVER
value: trillian-log-server.agent-trust.svc.cluster.local:8090
- name: NAMESPACE
value: agent-trust
- name: CONFIGMAP_NAME
value: trillian-log-id
command:
- /bin/sh
- -c
- |
set -eu
apk add --no-cache git curl ca-certificates jq
# Short-circuit if the ConfigMap already carries a tree id.
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
API="https://kubernetes.default.svc"
EXISTING=$(curl -sS --cacert "$CACERT" -H "Authorization: Bearer $TOKEN" \
"$API/api/v1/namespaces/$NAMESPACE/configmaps/$CONFIGMAP_NAME" \
| jq -r '.data.TRILLIAN_LOG_ID // ""')
if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ] && [ "$EXISTING" != "0" ]; then
echo "trillian-log-id ConfigMap already carries TRILLIAN_LOG_ID=$EXISTING, nothing to do."
exit 0
fi
echo "Building createtree from source (one-shot)..."
GOFLAGS=-mod=mod GOBIN=/usr/local/bin \
go install github.com/google/trillian/cmd/createtree@v1.6.1
echo "Calling admin RPC at $TRILLIAN_ADMIN_SERVER ..."
# Trillian v1.6+ removed per-flag hash/signature algorithm choices
# from createtree. The server always uses SHA256 + RFC6962_SHA256
# for LOG trees; the Trees row's PrivateKey column is unused in
# modern Trillian (STH signatures use the server's own key).
TREE_ID=$(createtree \
--admin_server="$TRILLIAN_ADMIN_SERVER" \
--tree_type=LOG \
--display_name=proofedmesh-transparency-log \
--description="ProofedMesh Transparency Log (ADR-0005)" \
--max_root_duration=0s 2>&1 | tail -n1)
# createtree writes the integer tree id to stdout as the last line.
TREE_ID=$(printf '%s' "$TREE_ID" | tr -d '[:space:]')
if [ -z "$TREE_ID" ] || [ "$TREE_ID" = "0" ] || ! printf '%s' "$TREE_ID" | grep -qE '^[0-9]+$'; then
echo "createtree returned no tree id" >&2
exit 1
fi
echo "Got tree id: $TREE_ID"
# Merge-patch the ConfigMap with the fresh tree id.
PATCH=$(printf '{"data":{"TRILLIAN_LOG_ID":"%s"}}' "$TREE_ID")
curl -sS --cacert "$CACERT" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-X PATCH \
-d "$PATCH" \
"$API/api/v1/namespaces/$NAMESPACE/configmaps/$CONFIGMAP_NAME"
echo
echo "Patched ConfigMap trillian-log-id with TRILLIAN_LOG_ID=$TREE_ID"