Skip to content

Hide built-in k8s principals in SMT output - #15

Merged
ajwdev merged 1 commit into
mainfrom
ajw-hide-builtin-principals
Oct 2, 2026
Merged

ajwdev merged 1 commit into
mainfrom
ajw-hide-builtin-principals

Conversation

@ajwdev

@ajwdev ajwdev commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Summary

Hide built-in Kubernetes/EKS platform principals from SMT output by default.

  • src/builtins.txt: list of built-in principals (exact names and prefix* patterns): eks:*, system:kube-* users, system:nodes and friends, and the kube-system controller service accounts from upstream controller_policy.go. Only upstream Kubernetes/EKS names; nothing environment specific.
  • src/builtins.rs: is_builtin(principal).
  • SmtEncoder.include_builtins (default false), consulted when collecting candidate principals in check_access_invariant, check_namespace_isolation, check_reaches and direct_violations.
  • ::smt reaches and ::smt cluster-admin accept --all to include built-ins; help and usage text updated.
  • flake.nix adds jq and ast-grep, which the header of builtins.txt uses to regenerate the controller list.

Behavior change

Built-in principals are now hidden by default from ::smt check_access, reaches, cluster-admin and check_isolation. --all shows them for reaches and cluster-admin. check_access and check_isolation have no flag and always hide them. Escalation paths are still computed through built-in intermediaries (a via system:kube-controller-manager line can still appear); only the listed principals are filtered.

Testing

$ cargo test 2>&1 | grep -E '^test result|FAILED|^error'
test result: ok. 59 passed; 0 failed; ...
test result: ok. 22 passed; 0 failed; ...

New tests: builtins::tests::* (exact, prefix, non-matches) and smt::access::tests::builtin_principals_hidden_by_default_and_shown_with_include_builtins (testdata plus a CRB granting cluster-admin to system:kube-controller-manager). The access test helper's temp dir is now unique per call so parallel tests do not race.

Before / after

Fixture is testdata/ plus one extra ClusterRoleBinding giving system:kube-controller-manager cluster-admin. Before this change the output matches the --all run.

::smt cluster-admin (new default): 6 principals, controller-manager hidden.

FAIL  6 principal(s) can reach ("", "*", "*", "*"):
  direct (3):
          ClusterRoleBinding cluster-admin → ClusterRole cluster-admin
          2 principal(s):
            admin@example.com
            system:serviceaccount:kube-system:default
          ClusterRoleBinding pallograph-test-admin-sa → ClusterRole cluster-admin
          1 principal(s):
            system:serviceaccount:pallograph-test:admin-sa

::smt cluster-admin --all: 7 principals, adds

          ClusterRoleBinding builtin-admin → ClusterRole cluster-admin
          1 principal(s):
            system:kube-controller-manager

🤖 Generated with Claude Code

@ajwdev
ajwdev added this pull request to stack #18 October 2, 2026 16:52
Clusters ship with platform principals (system:kube-controller-manager,
the kube-system controller service accounts, eks:* and so on) that hold
broad RBAC grants by design. They dominate `::smt cluster-admin`,
`reaches` and `check_access` output without telling the operator
anything about their own configuration.

Add src/builtins.txt, a list of built-in Kubernetes and EKS principals
(exact names plus `prefix*` patterns), and src/builtins.rs with
`is_builtin`. SmtEncoder gains an `include_builtins` field (default
false) that candidate-principal collection in check_access_invariant,
check_namespace_isolation, check_reaches and direct_violations consults.

Behavior change: built-in principals are now hidden by default from
`::smt check_access`, `reaches`, `cluster-admin` and `check_isolation`.
Pass `--all` to `::smt reaches` or `::smt cluster-admin` to include
them. check_access and check_isolation have no flag and always hide
them. Escalation paths are still computed through built-in
intermediaries; only the listed principals are filtered.

flake.nix gains jq and ast-grep, which the header of builtins.txt uses
to regenerate the controller service account list from upstream
controller_policy.go.

Add unit tests for is_builtin and for the default-hidden versus
include_builtins behavior on the testdata fixture. Make the test
fixture temp dir unique per call so parallel tests do not delete each
other's manifests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ajwdev
ajwdev force-pushed the ajw-hide-builtin-principals branch from df9e0d0 to 079bb10 Compare October 2, 2026 16:56
@ajwdev
ajwdev merged commit 94b6b77 into main Oct 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant