Objectives & prerequisites
Learning objectives
- Declare a provider-neutral Hands contract for one Pico: identity, one named capability (
pico.state.set), and one allow rule with narrow constraints — all as ordinary data, no provider SDKs. - Bind that contract to the
KubernetesHandsadapter and observe that the adapter is not what enforces the boundary — the namespacedRolewithresourceNamesis. - Watch the Pico engine invoke exactly one reversible action — a
kubectl patchconfined to a Pico-ownedConfigMapin thehandsnamespace — under the Pico’s ownServiceAccount. - Read back the normalized
pico.hand.*lifecycle (requested→authorized→succeeded) from a Pico-owned eventsConfigMap, and the evidence JSON the Pico engine writes to its own logs, as the lab’s runtime evidence. - Explain why a valid
ServiceAccounttoken does not imply authorization — theRole’sresourceNamesdecides which resources the Hand may touch, not the token.
Prerequisites
- Completion of the Hello Pico on Manifold lab — the single-Pico runtime story this lab equips with Hands.
- Familiarity with the Part 3 · Hands lesson vocabulary (Hands, Capability, HandsProvider, ActionRequest, Policy, Evidence, Action Event).
- A local Kubernetes cluster; see the Kubernetes setup foundation for the canonical minikube install, PATH checks, and first cluster bring-up.
helmis not required for this lab.
Environment
The canonical local Kubernetes setup — supported OS, install commands for docker, minikube, and kubectl, PATH checks, and a first cluster bring-up — lives in the Kubernetes course setup foundation. Complete that page first so docker, minikube, and kubectl resolve on your PATH.
Lab-specific additions on top of that canonical setup:
Reference minikube pin:
v1.38.1was used to author this lab (anyv1.34+should work).Bash + Python 3 utilities:
grep,cat,mkdir,cp,python3, and thePyYAMLpackage (pip install pyyaml) — the static checks inverify.shuse PyYAML to validate the Hands contract and RBAC boundary.Estimated time: 30–45 minutes (of which the cluster start accounts for roughly 2–5 minutes and the
bitnami/kubectlimage pull for another 1–2 minutes on a cold cache).Cleanup step (also repeated at the end of the walkthrough):
kubectl delete namespace hands --ignore-not-found minikube delete --profile hands-lab rm -rf build/hello-pico-hands-kubernetes work/hello-pico-hands-kubernetes
Pinned versions (reference)
The walkthrough was authored and verified against these versions. Newer versions are expected to work; older Kubernetes versions may lack API resources used by the shipped manifests.
- Kubernetes API version in minikube: v1.31.0.
- Container image used as the Pico engine (carries
kubectlso theKubernetesHandsadapter can shell out under its ownServiceAccount):bitnami/kubectl:1.31.0. The Pod runsrunAsNonRoot: true,readOnlyRootFilesystem: true,allowPrivilegeEscalation: false, drops all capabilities, and mounts nohostPathvolumes.
The Pico engine is the on-cluster host that carries the Pico Element hello-hands-pico and invokes its declared Hands. bitnami/kubectl ships with bash and the kubectl binary, so a small shell script can play the role of the KubernetesHands adapter: it reads the mounted Hands contract, evaluates the Pico’s rules, and — when authorized — performs one narrow kubectl patch call against a Pico-owned ConfigMap. The authorization boundary is enforced by the API server through the Role in 03-rbac.yaml, not by the script.