# Run it on Kubernetes

Run strazad on a throwaway kind cluster through the Helm chart, sign in through a port-forward, and read one deny with its reason.

- Who: You, as the admin
- Where: Two terminals and a browser, on a machine with Docker
- Profile: Standalone

In short: You install the Helm chart on a throwaway kind cluster in the standalone profile: one pod with its own store, event broker and sign-in page. Through a port-forward you sign in as the admin and ask what the server decides for `rm -rf`. The starter policy denies it with its reason, and you delete the cluster.


YourunstrazadonathrowawayKubernetesclusteronyourownmachinethroughtheHelmchart,andworkasitsadminfromtwoterminalsandabrowser.Yousigninthroughaport-forwardandasktheserverwhatitdecidesfor`rm-rf`.Attheendyouhavereadonedenywithitsreason,andyoudeletethecluster.Thechartrunsinitsstandaloneprofilehere:onepodwithanembeddeddatabase,anembeddedeventbrokerandthebuilt-insign-inpage.Noexternalservicestandsbetweenyouandthefirstdecision.##Beforeyoustart{.nostep}-DockerEngine,kind,kubectlandHelm.-Acloneoftherepository,becausethecommandsreadthechartfrom`deploy/helm/straza`.-`strazactl`onyourPATH,from[Install](https://docs.straza.ai/guides/operate/install/index.md).Thechartpullsthereleaseimage`ghcr.io/strazahq/straza`bydefault,andbuildingyourownimagefromtherepositoryisanoptionalsectionbelow.Oneterminalisenoughforeverythingexcepttheport-forward,whichholdsasecondone.##CheckthetoolsCLIonly:Theclusterandthechartareterminalwork.Theconsoleopensoncetheserverruns.kindrunsawholeKubernetesnodeasoneDockercontainer,soDockeristheonlyservicethathastoberunningbeforeyoustart.Confirmthatthefourtoolsanswer.Terminal1,yourmachine:```shdockerversion--format'DockerEngine{{.Server.Version}}'kindversionkubectlversion--clienthelmversion--short``````textDockerEngine29.4.0kindv0.33.0go1.26.7linux/amd64ClientVersion:v1.37.0KustomizeVersion:v5.8.1v3.16.4+g7877b45```Thesearetheversionsthispagewastestedwith.kindandkubectlaresinglestaticbinariesfromtheirreleasepages,andeachpagepublishesaSHA-256filetocheckthedownloadagainst.Theclusterneedsabout1.5GBofdiskforthenodeimageandtheserverimagetogether,andthenodeandthepodtogetheruseabout600MBofmemory.##StarttheclusterCreatethecluster.kindpullsitsnodeimagethefirsttimeandstartsonecontainerthatrunsthecontrolplane.Terminal1,yourmachine:```shkindcreatecluster--namestrazakubectlgetnodes```Youshouldsee:Thenode`straza-control-plane`withthestatus`Ready`.```textCreatingcluster"straza"...✓Ensuringnodeimage(kindest/node:v1.37.0)🖼✓Preparingnodes📦✓Writingconfiguration📜✓Startingcontrol-plane🕹️✓InstallingCNI🔌✓InstallingStorageClass💾Setkubectlcontextto"kind-straza"NAMESTATUSROLESAGEVERSIONstraza-control-planeReadycontrol-plane30sv1.37.0```Thein-progresslinesandkind'sclosinghintsaretrimmed.`kindcreatecluster`alsowritesthecontext`kind-straza`intoyourkubeconfigandselectsit,whichiswhythe`kubectl`commandsbelownamenocluster.##Optional:buildyourownimage{.nostep}Skipthissectionifyouusethereleaseimage.IfyourunStrazafromsource,buildtheserverimagefromtherepositoryrootwiththeversiongitdescribes,sothepodreportsthesameversionthebinariesfromInstallwould.Terminal1,therepositoryroot:```shSTRAZA_VERSION=$(gitdescribe--tags--always)dockerbuild-fdeploy/Dockerfile--build-argVERSION=$STRAZA_VERSION--build-argCOMMIT=$(gitrev-parse--shortHEAD)-tstraza:$STRAZA_VERSION.```Dockerprintsthebuildsteps,andtheGocompiletakesthelongest.Withoutthetwobuildargumentsthepodwouldreporttheversion`dev`.Thefinishedimageisabout120MB.TheDockerfilehastwostages.AGo1.26imagecompiles`strazad`and`strazactl`withCGOoff.Thefinalimageisbuiltfrom`scratch`andholdsthetwostaticbinaries,theCAbundleandthelicenseandnoticefilesunder`/licenses/`,runningasuser65532withthedatadirectorysetto`/var/lib/straza`.The`.dockerignore`fileattherepositoryrootkeepslocalstatesuchas`bin`andthetoolcachesoutofthebuildcontext,sothecontextisthesourcetreealone.Handtheimagetothecluster,becauseakindnodecannotseeyourmachine'simagestore.Terminal1,yourmachine:```shkindloaddocker-imagestraza:$STRAZA_VERSION--namestraza```Youshouldsee:kindreportsthattheimageisnotyetpresentonthenode`straza-control-plane`,andloadsit.Theloadcopiestheimageintothenode'sownimagestore.ThatiswhatletsthechartrunitwithapullpolicyofNever,becausenothingonthenodeeverasksaregistryforit.Addthreevaluestotheinstallcommandofthenextsectionsothechartusesit:`--setimage.repository=straza--setimage.tag=$STRAZA_VERSION--setimage.pullPolicy=Never`.##InstallthechartThechart'sdefaultsdescribetheenterpriseshape:tworeplicas,abundledPostgres,abundledNATSandanexternalidentityprovider.Threevaluesturnitintotheone-podstandaloneshapeofthistutorial.Theimageis`ghcr.io/strazahq/straza`atthechart'sappVersion,whichis2.0.0forthisrelease.Terminal1,therepositoryroot:```shhelminstallstrazadeploy/helm/straza\--setprofile=standalone--setreplicaCount=1\--setpublicUrl=http://127.0.0.1:18420\--wait--timeout3m```Youshouldsee:Thereleasestatus`deployed`,followedbythechart'snotes.Theynametherelease`straza-straza`,theimage`ghcr.io/strazahq/straza:2.0.1`oryourowntag,theprofile`standalone`,onereplica,thepublicaddress`http://127.0.0.1:18420`,embeddedper-podeventsandaper-podSQLitestore.Eachvaluehasareason:|Value|Why||---|---||`profile=standalone`|Selectstheembeddedstoreandbroker,anddropsthebundledbackends,whichthechartrendersonlyundertheenterpriseprofile.||`replicaCount=1`|Hastogowiththestandaloneprofile.Thechartrefusestorenderastandalonereleasewithmorethanonereplica,becauseeachpodwouldownitsownSQLitefile.||`publicUrl`|Theaddressyourclientsdial.Itbecomestheissuerinsideeverysessiontokenandthebaseofeverylinktheserverhandsout,includingthesign-inpagetheconsolesendsyoutoinamoment,soithastobetheport-forwardaddressyouopennext.Leftempty,thechartderivesthein-clusterServicename`http://straza-straza.default.svc:8420`,whichisrightforclientsinsidetheclusterandunreachablefromyourbrowser.|`--wait`returnsoncethepodpassesitsreadinessprobe.Checkthepod:Terminal1,yourmachine:```shkubectlgetpods``````textNAMEREADYSTATUSRESTARTSAGEstraza-straza-78467cff98-tfqx61/1Running022s```Youshouldsee:Onepod,`1/1`ready,withthestatus`Running`.Ifthisfails:`ImagePullBackOff`:Thenodecouldnotpullthereleaseimage.`kubectldescribepod-lapp.kubernetes.io/name=straza`endswiththeregistry'sreply,andthetagandthenode'snetworkaccessarethetwothingstocheck.`ErrImageNeverPull`:Thepod'seventssaytheimage"isnotpresentwithpullpolicyofNever",sotheloadofyourownimagedidnotreachthiscluster.Run`kindloaddocker-image`againwiththesame`--name`,thendeletethepodwith`kubectldeletepod-lapp.kubernetes.io/name=straza`,andtheDeploymentreplacesit.Thefirstboothappenedinsidethepod,soitslogiswheretheone-timepasswordswent.Readthemnow.Terminal1,yourmachine:```shkubectllogsdeploy/straza-straza```Youshouldsee:Onelinewiththepasswordof`admin`andonewiththepasswordof`break-glass`,anda`strazadserving`linefortheprofilestandaloneat`http://127.0.0.1:18420`.>Actnow:Copytheadminpasswordfromyourownlog>>Eachpasswordisprintedonce.Yousigninwiththeadminoneinamoment.Thepod'sdatadirectory`/var/lib/straza`isanemptyDir.ItholdstheSQLitefile,theembeddedbroker'sstoreandtheapprovercertificatethestandaloneprofilemintsforitself.Thestoreandtheadminyouareabouttousethereforeexistexactlyaslongasthispoddoes.Thatistherightshapeforathrowawayclusterandthewrongoneforanythingyouintendtokeep,whichiswhytheproductionshapeon[KuberneteswithHelm](https://docs.straza.ai/guides/operate/kubernetes-with-helm/index.md)putsthestoreinPostgresandtheeventsinNATS.##Reachtheserverthroughaport-forwardCLIonly:Theport-forwardrunsinaterminalinbothforms.Theconsoleneedsittoo.TheServiceisaClusterIP,sonothingoutsidetheclusterreachesituntilyouforwardaport.Inasecondterminal,forwardlocalport18420totheServiceandleaveitrunning.Terminal2,port-forward,keepitrunning:```shkubectlport-forwardsvc/straza-straza18420:8420``````textForwardingfrom127.0.0.1:18420->8420Forwardingfrom[::1]:18420->8420```Thelocalportis18420ratherthantheserver'sown8420,sothatastandaloneserveralreadylisteningon8420onyourmachine,fromthefirsttutorialforexample,isnevermistakenforthisone.Theaddresshastomatchthe`publicUrl`yousetatinstall.Backinthefirstterminal,asktheserverwhatitisandwhetheritisready.Terminal1,yourmachine:```shcurl-shttp://127.0.0.1:18420/versioncurl-shttp://127.0.0.1:18420/readyz```ThefirstanswerisonelineofJSON.Its`version`istheoneintheimage,andits`profile`is`standalone`.Its`approver`blockdescribesasecondlistenerthatthestandaloneprofilemintsforphoneapprovalatthepod'sownIP.Thechartpublishesnoportforit,sonothingoutsidetheclusterreachesit,andthistutorialdoesnotuseit.Thesecondanswersaysthepodisready:```text{"status":"ok","components":{"bus":"ok","store":"ok"}}```##SigninBothformsofthisstepstartintheconsole,whereapersonsignsin.Open`http://127.0.0.1:18420/console/`inyourbrowserandpress**Signin**.![Theconsole'ssign-incardwiththebuttonSignin](https://docs.straza.ai/shots/signin-dark.png)Theconsole'ssign-incard.1.ThetabgoestothepagetitledSignintoStraza.2.Enter`admin`andthepasswordfromthepodlog,andpress**Signin**.3.Thetabcomesbacktotheconsole,whichsays`Signingyouin`.Youshouldsee:Theconsoleopenson**Overview**.Thefootofthesidebarsays`standalone`andtheserver'sbuild.Theaddressofthesign-inpageisthe`publicUrl`fromtheinstall,andthatisthereasonthevaluehadtobetheport-forwardaddress.WiththeCLI:`strazactl`hasnosign-inofitsown.ItrunsonanadminAPItokenthatyoumintintheconsole.Clickpathintheconsole:"Settings"›"APItokens"›"NewAPItoken"Nameit`admin-terminal`,pick`expiresin30days`andthejob**Fullroot**,press**Minttoken**,andcopythetokenfromthesheetthatfollows,becauseitisshownonlyonce.Thengiveitandtheserveraddressto`strazactl`.Pastethetokenatthe`read`lineandpressEnter.`read-rs`readsthepastedtokenwithoutshowingitandkeepsitoutoftheshellhistory.Terminal1,administration:```shexportSTRAZA_SERVER=http://127.0.0.1:18420read-rsSTRAZA_API_TOKEN&&exportSTRAZA_API_TOKEN```Whoeverholdsthetokenactsasanadministratoruntilitexpiresorisrevoked,sokeepitinthisterminalandneverwhereanagentrunsasyou.Itgoesawaywiththepod'sstorewhenyoudeletethecluster.Ifthisfails:Anaddressat`straza-straza.default.svc`:Thereleasewasinstalledwithout`publicUrl`,andabrowseronyourmachinecannotresolvethatname.Run`helmuninstallstraza`andruntheinstallblockagainwiththevalue.Thenreadthenewadminpasswordfromthenewpod'slog,becausethedatadirectorywentawaywiththeoldpod.##ReadthedenyNowasktheserverwhatitwoulddecideforacommand,beforeanyagentisenrolled.Neitherformrunsthecommandorrecordsanything.Intheconsole:Clickpathintheconsole:"Policies"›"standalone-starter"›"Testacall"1.Under**Who**,pick`admin`.Thestarterpolicyappliestoeveryone,sotheadmincanstandinforthepersonwhocalls.2.Pick**Shellcommand**,type`rm-rf/tmp/x`in**Thecommandline**,andpress**Test**.Youshouldsee:**Denied**,decidedbyrule`block-recursive-delete`inpolicy`standalone-starter`,withtherule'sreason.WiththeCLI:Terminal1,administration:```shstrazactlpolicysimulate--rolesdev--toolshell.exec--command'rm-rf/tmp/x'``````textThiscallwouldbedenied.Decidedbyruleblock-recursive-deleteinpolicystandalone-starter:Strazastarterpolicy:recursiveforce-deleteisdenied.Deletefilesindividually,oranadmincaneditthestandalone-starterPolicySet.Simulatedagainstthepoliciesliverightnow,yourfileincludedifyoupassedone.Thisistoday'sanswer,notareplayofanypastdecision.subjectrolesdev·attestationnonesnapshot705a13b9b35902f8295ee4126287d2c84de8afb01674fd6592ac14544adfe539(live)wireeffect=deny·ruleId=block-recursive-delete·setName=standalone-starter·snapshot=705a13b9notethisverdictappliesoncethissnapshotreachestheclient;strazadoctorprovesaclientisgoverned```Youshouldsee:`Thiscallwouldbedenied.`andtherule`block-recursive-delete`inpolicy`standalone-starter`.Theruleappliestoeveryone,sotherole`dev`needsnodefinitionfortheanswertocomeback.Thesamecommandwith`gitstatus`answers"Thiscallwouldbeallowed."andnamestheprofiledefaultasthereason,sincenorulementionsit.Thesnapshotidnamestheexactpolicystatethatdecided.Agovernedclientdownloadsthatsamecompiledsnapshotanddecidesagainstitlocally,whichiswhatthenoteattheendoftheanswermeans.TherulebelongstothestarterPolicySetthatafreshstandalonestoreseedsatitsfirstboot,theone[Yourfirstgovernedsession](https://docs.straza.ai/evaluate/try-it-on-one-laptop/index.md)showedinfull.##DeletetheclusterCLIonly:Theclustergoesawayfromaterminal.Stoptheport-forwardinthesecondterminalwithCtrl-C,thenremovethereleaseandthecluster.Terminal1,yourmachine:```shhelmuninstallstrazakinddeletecluster--namestraza``````textrelease"straza"uninstalledDeletingcluster"straza"...Deletednodes:["straza-control-plane"]```Ifyoubuiltyourownimage,`dockerrmistraza:$STRAZA_VERSION`removesitfromyourmachineaswell.TheuninstallremovestheDeploymentandtheServiceand,withthepod,theemptyDirthatheldthestore,sonothingofthisserversurvivesit.Theclusterdeletionstopsandremovesthenodecontainer,anddropsthe`kind-straza`contextfromyourkubeconfig.ThreethingsstayinDockerafterwards:|Whatstays|Size|Howtoremoveit||---|---|---||Thenodeimage`kindest/node:v1.37.0`,whichthenext`kindcreatecluster`reuses|1.34GB|`dockerrmi`withitsimageid,sincekindpullsitbydigestandleavesituntagged||Thebuildcacheoftheoptionalimagebuild|about3.2GB|`dockerbuilderprune`||kind'sDockernetworknamed`kind`||`dockernetworkrmkind`|##Next{.nostep}-[KuberneteswithHelm](https://docs.straza.ai/guides/operate/kubernetes-with-helm/index.md)istheproductionshapeonaclusteryoukeep,withPostgresandNATSbehindthepodsandyouridentityproviderinfront.-[Whatjusthappened](https://docs.straza.ai/evaluate/how-it-works/index.md)nameseachpiecethatactedhere.


Walked on v1.1.0-117-g106081a8 on 2026-10-06, except every cluster step from kind to teardown, whose outputs come from an earlier walk, the console steps and the browser sign-ins. A Linux host with Helm 3.16.4 and no Kubernetes cluster, so the cluster, the image build and load, the install, the pod checks, the port-forward and the teardown were not run, and their pasted outputs come from the kind walk of 2026-09-19 at v1.0.0-1235-ge8f5cdea. The install's values and the chart's notes were rendered with helm template from chart 1.1.0, and the version and readiness checks, the login with the form post the sign-in page sends and the simulated deny ran against a standalone strazad in an Alpine 3.20 container. The console steps were not clicked. The browser sign-ins of the console and of strazactl login were written from the code on 2026-10-22 and not walked, and strazactl no longer signs in. Console screenshots show strazad v1.0.0-1582-gc6e78918-dirty, standalone.

