redeploy authentic policies as code.

This commit is contained in:
2026-03-21 14:00:37 -05:00
parent 9ad585681f
commit c087f32355
26 changed files with 1408 additions and 240 deletions

View File

@@ -209,7 +209,7 @@ private_key_file=~/.ssh/ansible
remote_user=wed
# (pathspec) Colon-separated paths in which Ansible will search for Roles.
;roles_path=/Users/rblundon/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
roles_path=/opt/git/homelab/ansible/playbooks/roles:/Users/rblundon/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
# (string) Set the main callback used to display Ansible output. You can only have one at a time.
# You can have many other callbacks, but just one can be in charge of stdout.

View File

@@ -17,4 +17,16 @@ base_domain: "local.mk-labs.cloud"
terraform_server: "infra01"
# Traefik variables
traefik_server: "lightning-lane"
traefik_server: "lightning-lane"
step_ca_principal_mappings:
- local_user: wed
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon
- local_user: rblundon
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon

View File

@@ -1,207 +1,217 @@
$ANSIBLE_VAULT;1.1;AES256
61396632356133313461646463343234376438306463333931386136366534633166353766393731
3861336364626264653532626365393661313164323063370a353630666335313032636431383531
35643232376537383131383863323639353939623433613232643138393863666262353261343633
6130636437666531650a383637306363636634303733303837323738613733623566306137346333
38313536376330663164356439306662353036383933653433616165396536616630383339353938
61326563303465373535306163663632393538663265333138383030633533396537626631646663
34353366343636303363343864306136613161386632663266356438646666393465626139316439
66373563623432666536633666303935336530376563383533316233393134396334663438363631
66386136633937323835653563393663343934343236623464643064363432663439326138306365
38363732363438376630646633393065366434653631316332383563343737333962303064303234
34396534373032373463346631633737623664363864343361633030633137653262656139636564
35643864333663393662323361313133383632623261653036356439326436343363633765353438
65396465386632393461646238323866313964326531326434323137353434353534383230623161
38366132396330346636343262666236646339343435343438396665653964396334653933306132
63656435613265656535663363653335383637386235633335623935623362633363616539666139
30653338316263393163313464323565633964396465656662326266363734363761396433353535
63346334616664356433316638306433333361336366613361383637376636383936636361363237
32613839353934636132346162663861626564383765613837336239373436376562653732626432
33333963396365626137366635313462303962356164346438356166353866666563653237626139
35623334363335653733326463626533346165386461343231633364613464653136336433333734
38353163653138356130366665653338663832343336363163383736613730313865353238656237
66313935323966646464373235653063653139373565313864383835626535366634333066373139
30383764363565323264613063306564343363303234333836383131663966613730313766663131
63653365343230366436626134653864316261396365613430346235363965653666653631646365
39383436346561323363646363666664303935356661366665353230383436386433313264353331
31353737666338386635666431663966333564333563383437616537663833373763356266336632
30643662643732356132306163616131643237326132353066653163653339666435633839393639
33386133666434356362393834316630633765353736306537346435613838373139393632326433
62353863663530613065313065393038323039333939656138626436356162636639343764343337
61363438623361613337653465616435366662303632633865393731303735323337386464376235
62653738363933353763356363313266643937646439636236623665633430313934306130653734
62663933373930306436613761393737323862656639383865323133656631356331333930366564
39303733636365373662373038393133313862636536643132316637393137393834323830663064
35653635346433633333613233373338383363646631663238313337316637313662323735376362
35346430366331643366656261366635363461316233653664653065326437666332616466373633
38336662326563666462663737613834376534656136643764393234386133386165336462616161
63366432323238303038303333663761656437356561343430396136393066343465613934643361
32346566313466363161633564656439646635303737613463666335396239316365613962366366
30303236643338646231336561663431633034323136653236353339613336653335323261326336
63383364343336333833383063353631396662373062643931363762346365613965623739346366
62353938636636326539616363656563353064363934323962373564303535626566383031643965
36316538666337656130643461636561303031656536326563356334356532316130623939643732
37326532633631396338643763373835396665376330376539656464643530396639366330646330
65623862323839383364616432383736623061363836376363356266363563313763613863613538
65393962633965323932663331326532323137366433363432356332396531656130376663323766
33336436353637306131393861623462306463346138333330326565343666623138663439383038
65313063353834393433353837393165386334636164373834663730626537626630623866353664
62636530343731353064336436343465363566656231313765393635303664666365376661323935
30323233366362393736316432353432646166343261363631353161313033623931353561656633
63613764396161386336363065366432393730353764623438663364396461353065393432376636
37616334376338376265353064636333393464303066333231616138333466616261643537353431
39353031366435303132363938613161326663646664643838313165326133316165663662363730
38646230366366366464383861383137366136396565626637383134326330646661366466636664
35376637653665636238383062626562656536326637346239306434626437393161333463373363
39663732323339353232616535633130633462313764353930353765613634393331363363613038
66323930393536333662326462653831353732643466333732626532333163633266376631306137
37613239373865633864383436373861326439323136616439353464666435386561313365656466
65366336643930646639663362333264386264643461376461656266653263326262313635613639
39623436643735643361393339643237346530633766373939656562363161396636373434336264
33393636633035353434383361616436636434356331326635366538313461383933313932336239
63396236626634653136393265636232623136626563353265386261353562353432326364326566
33653533656462393966303663646466366431313831343631333734343731363838633037363231
30363233316530633162356230393732643337353436383335393732366665306432393731303438
30626633313336633439333136326566326333643261346236376666326336373164356266323061
66616535333233383636396534346562656436663266646466613764653566353861326232633033
33366637643137343038333734613361363362356165656631626636663137623237356330376237
63633738373832393939383265343834313431633966646534343730376339353032653230353530
38373665656634316537363261366137313638346439626636653339626564636138316432323062
34393533623639383235663361373431386335326530313663316330666330383437323030663438
31326532346135313335313137313233643965373536316531386665306639656239383364613430
63386139623133393966336465646362376662633834626464313834663865613234353863356264
38343138303331306538303333383238316363333938356162656535396237396262313233613862
36636231666433626132333235386163303338373831356139353464393234333365616561336437
61303133633135653930643861373537656438316364376637306430363461623064646261313032
32376465653838393533666631376431306435636364393462333138623732653633306361653765
30633631396430616232643339323966383037356433323136633266663132623937366363613936
66643531623234343761313833633066646133316663646533643335323139306537346532313630
38323065333938656531633165663063346335303236666461336438343033323166316138373766
63313066383136323461373934326162343538316136346537313135373337653764326665633662
36376234633562643965396363613366666432386238363536663730343532636638623665393263
61396664393866656434616139663163333239346531646636613637393866633665656435363733
38313761343566363464613539636465326564333963626433616366663762643537613633323638
31343232343462613861303964633564316362336135303630383366353364633538323233306538
36333436663562336134643361326131343565356436613064313237383131646562613865383632
34393663383736633565653965616534376338346337656530306132323233383330383937626537
30666636396633376363643466613163643432613332373732313264316161346166636131363930
31343962313338663338373463613464343830353432323835323736656131303665353262326634
31306632653737356562613664666636663937623430626664653333313331646236396563663965
33303962333466376362346534316630373161393430643062373431623233663065353434346162
34343465383435653335613834633261613064393835356565373138633638313832616138373065
64323763383438653036323537393162633237303334393730353664326166343963363232336637
61316631373562376332323933616334646139356161336265386332653435626537393163363936
65613931626366303739366338343531646334626365303836636536343634323030386564396433
62376565386131653135346634633663303961643335656235663632646434663739346433663465
65393063376239393233663266666530313561383433616466303965303230643766386336663130
66663132343531653432393466656634373232323938616633363261366564326664633461613566
35633263666639353366303031353533386163613333343862326231306639323861353139666630
30373630376336383365656633313037376233303638333935373663353030366466343564393062
35646135343732323630353032636336393433623135376364343232316264653738323764303663
37316231613465623461613832333466316361363436346565663662316366613336343339346130
35373935633437646135323163386532633634313766626432623931666539383432383263346566
33323938353463633766313964623463626635623935613234326535386266396665336462333163
37316161343030383633376531386266643862646535623337316536393535383238376330303562
31313163623134623430613266376635356534393535323639636465613766666339663634646563
32613031303931373164663238343361363465613464666639306461633433636230383834666262
31616565663538636539393431363634393061396465336462646562393837323531623934356139
65633735363935376236663532623037333531393463663165316437653033356430353733653462
66323038343163643537663738353336616234306534396433376233666436396236643732383631
35613937376430376662663439666539303235373264653639336362663064653632366230336463
34613330616362666232653665306532366461313133303866313933353433636561613036313734
64316431633162636639623839313239326232396462333134333439316661663363386539623132
31336638346561313866366331306164363737613736343634366330663434393538623962363035
62396239386133336262343130333632313766613039633961373232393766306464623361633038
61386635656461303132393430346531383362383638393232363261623862636261306266326235
32363465336332363237643836363630316337643533373534376666363737343566643765333764
34336635656661663238323131356162343530323364326632343732666431623566386331343739
33353831376135343835373636656464363637373736656330303836333237646434623763343532
63353537633039383165613438616364613136393132356435346436646662656334633961346335
65373533346537663434373731613131306639356565383365306436393631303038633937623464
39376232356439336136663131613663316134353031666130653338323465383863306535316131
37363763656237323164366235323434346463333363633034326566326634626337393463373938
32366636306230363037356636646561343663316561363339646137316437366265306164306638
32663135353832636336653539316534356530303538643739393737343832343636353535363331
64396266363837366130326231383762313932636538383565656437313133616437383464663366
66623532306362303736666433663038393832623037346230373530396564666666353935636137
32636537356663363836393761633861323962343164636438396665303931353337316534366262
61376136396635636435333361623336616632653834356236633136373234383538393662663730
38373038666161316162396634313133333164353430646662663637656135346131383766636432
63313737646262633437313333326638383561353131373766393966656135303461386164336265
30343630646334393566333864313136313130636534336139646333323963316132346166373239
33376566636231316266333039653363646262366334333132653839316232623937353066663036
65653465393162373931613438396435303335306537613734363963373764336566636233363763
65623638643965383836636166356431353534363632363034353262663264623836336630353132
36653938613130633435396534613532396365646333353634646666383738666163343838643230
32333236646535376665343465623730373637363964383436616439343839393034313365656536
61306366396430383465366330666662373035386333636237303632383034373439653765663364
64333163313263363664306630353061326461643532353661613865363666366132333366383863
38356463303762336139626335333664623331333530663034663731303336316264623235616463
34616430366333303766633566616331386136626438383433613038333932373232353338633935
63316132316139363735346634376236653665666334613736643731386562306166336161353230
66626564333930316236346537363630336463363031323237336636343237653266393638383435
63326337396532373461663130653362653364366337396639303330656661623933303762323937
38336437303439363636383730343162323938363266326264386439363537366532376562383266
38346534343539616465616166353661626163356164376633373663616466303632626231396336
30633439666532343563313833636338333461353839323637623034333434356330646332313638
64666366353762663166306163346237363737633365656463616261353934633335373731373338
65613965666236383831633862633865393763613337366336393934316639353064643936663161
65643661316135653234653937333566376439313764323662613037393366333464633063386532
64323465303939306332623964343963386432323338623132666633303634316365363635663262
37643961653330373035656566376564313234333538663934666333343931623130613261306565
35396237353837623737313730396435343966636237386337666438313864623961366333626136
61373131333135393665653962333237333363343462656464326165346430353838333632303830
31613434653238636665346163363333653463353433623134393864643437616339633334316537
62656137356564323934303162323466616262373461633863333432333233376163356638393065
38663537366333653837396463313233623164633839653534383866396265626264306161363038
63313132306165653730376430336638356539636665353530376633613730373061303566373637
37303138303832373433333363316664613532363034333564353136393966663066356339376532
33636338353364646234666434316265393036613935346333646632333835646132303235376166
32623631623834663965613331363837383764393837623535323237306637653235383739663863
39323461323266356433306562643431636566643032393265623961313132366334313635373666
33613435393063633432666365643662616534663638663538633338633638653738313466336664
65373261643731623966346563326464616439383137326366643463663732663436303732633862
32626331643865313935366530646633666135663638633664306436643566623131663236323133
33643039656261383561373032646464356336383864363935646233663832363065633235343261
36396534393135303334333661383336646561636232373663636230656233333963376138396466
33386463393038396663393161333534373065336464306134656436383036343030373964666533
39323238353833383137363431333165313366363336626636316663353361653330663663363335
30366635363765306236636338663836636537363866383264656563316535643461663336393535
33366564363636613564303934366366366162313838653235373639643166633361333434313339
34336630363331373335633333343637376438653662336636323931666635333765376133353163
34373535346636356564653038333965326237666133353633633462633265316637363737663266
32613734393634393361623564316361646564373339363035346339646462633736663337663930
39623538643630373338636564376264353535626533346366383831646666643233333963373232
38616166363964353135346438613233333131386165653030303435346263396433353162623861
31313561656538633765333362323732363666316562663664396239616132356531623334363939
65373663386135613939316631376536656332363436373936306230323966306231306332343938
62663961363266353161313337306236643832393465646661333635356537363732396431333666
30396165633138653436663762383738303263333864643136383866623866383165636430643564
32363033313361623431316632396135346236613133643535353964616133663634636337383933
30333532336635633034363335666537653237613937386538626263306166356332613438343765
38653837326664343064373835343432376663616133326566306562343930393439366365373437
33343462366438363139333938643064663536323862663939613262306361363966383834316632
31666363626135353734353533376365356464306262613664643030326539366434663438316661
62393835353738313465333036346637633134663665643164363335643938333432353930326666
65636664316231393430373162373830396365313131376236666266396333656235623764343737
61653232646633656135666633396263306434303738306662613264336265646331373937333231
31383239646634623439633435653939633132613465336333336533396439353434333366353231
66323039383561666364633962646138333230643334616634313230336563633336323463613065
66633535633138663065313138326433303063363237613732373363643262313838326133393237
64663364316531323831313363643463306261336362366362623030333630376131333864363063
34636233633737346233636562623930316564633136396365356161656231623837643166393765
31326330313530343466363066613131623437363366383866313735333932356531643966643765
34333531633364666564306131623739343731393436373333393431613464306266383765373139
37343234636665396162616339316665356334383361373736646534323565363333626661653533
34626430356437383635353034623466353332353533313537386165336461336263363937343230
31333461313235623635623833636133333166383430653336313961613130373764656336653366
33333361343936646333323866383966636461386439366663373762393933376565666236383136
62386265646430663131333037333539313065633434626130623361333833616139383539646639
61363034303131323935626537353066363936643161323236336331393837393932643231633138
61643061346465303233666261393265626466393563656361303935353364393062363038386635
31333561303763363766623532303536383632663565363761656232366630323035336638386263
32376365323330616533326533626261636532653764386236383766623236333830343535623435
63333432373239343232633161343335663839303962396238346564363936323062393135356539
35666135346636326135363834316162313063663239346134303438346337396562636538333935
64333735666666316133303636623531626666663738343765363831646237616666396431396535
6637353236393330613135623337333432303432313238633634
30386133633263613032383565326536626539353036313638383635623737356636643565366566
3563653933613063333537636166613661666663646234330a643731336366306564626135626165
38386663353234643066376365653862396462393063396633613436356566616338353339626165
3131346263633531660a346634623165323136663039313565336661393861373930633234336336
62633932663730646435343738353463373939363665303662653865386432653632666562353439
38356661316534343263613561633362326564626362623763643663363736303832326161356339
65366530386165383635303365613933623062623937333434303335363830313538336636343937
66316264363063363036656532376461633831366361396232326264666361386266643837386666
65666566636638316133613464613839306161636665356266346665336139616664356335343434
37613039346437633934656432643234663564616365653633323734666537656666306235633461
39316137333033363833626363386231626138613161383132386438613239346430393464633165
32393864643538323830303162363765386662303661343737376462616532346464333533633231
65643334666665353533643564656534373039323638393339386466316661646438626463643538
34396535343966326533333133353430393766633065303961396664336165353962613432376133
38616363396664383364623536373363353430323261303639316466393139333332366431666638
34626233343366366563373030356538636238343938656463643864653566353466643437613739
66313935613235353239306566303265316338386662653634633564663137353539663866383362
38663335643636613336353030626563376638393234326536656562323164646465356162393233
64343834633961613036343330373436316664316536343063333964623433666336303237363139
37326631666661623139376164666430633664343761366463383366346437376166633630306631
66303964373336613930663730336233383132393138343637636130306530656537363836626266
37383135613865363634623436323339336161343536393936653039326631336366363165303837
39343365373338373961623561366362653632646131386661613662386336326664313737326463
63636665356464656533613366393939393334396339303062643133653434376431343237633763
63663939363562373533386233326265393161653762363861393065653637373463366664356338
38626536316262623035303863333532373938396266646165313533316434396437666138363831
38396564376332343264343365336461633662326531356531643064306632306166383462666466
38343566623330366262333637626261626231396163636566326136303062623266623534343939
39343433626635616666303638646431616434363665346465646361353361353239643663303663
36343731343561626136343432363639373831346331366163653166303432323761616165653838
30636332343361326461656231663433373836303666316261623430333661343335656437393136
62303166626331363434383939346166393161336165346661633032363436393735613461376234
66643534353066396262356233373462373362623336343834613437636332343764393439653162
32353366313534373265336362623165383730356161316238336532633533646330336435326534
61643466643835623733303538316166646233643136653664653530376664333464393863366365
63613738393732393739393762613638383239303537353236636463663033396530376465333932
37326135336238396631333930373561646438313430323733353638356336636338656462613139
36373432633439613931656562316336653965313066386332643432653435643034376466343031
39633136656433336233393730356263376538656130353762303034336339356633656464393837
37623233613932383536623536653435396661313336326331653064616635316238373136623533
39653763393739373234346136353861383938353232336366336165333139323435636333656335
65373631396438633936643865323665653465666434373166363863626534323566663663323561
30353238636437653635386363363263376330323732613630613266343530393734383565643435
62356133633662393165313766323732386231333737613236373533383932623634336435363235
62353964636266336562353736386665646539323564633666316265313438326333653632313564
36356334386132393562663566386365623765363633313937333062393238393735383731653165
61646364633537363065366633646165643930353532633433656564333336376335353864623766
30316536613635373733303163326662363435336165346134303036383161396366636135623562
31393036323339373865633163643330393731386433613930633866393731373133383835346236
62356363663062373938636532343239366438396337313632616636333961306234663830313866
62646337353037666564653336376138326439633533396531393936313030333435383630316631
35353634663131343235616635386138306435303432653363363930656136356361663136376131
33373434616433366436326365616163313563343664623734306564623162623266326537636165
31633336366438343363393032323838383237323664653038376362643565653361646466623438
62323833386331323264616633653836343764663662646166383163653234333266353531343137
39613962316335326435356632626430363065316439623861303930643462666662663839643263
36666233373034363262656138626662383532393733396432363964653839303463376561306433
35643036633731613565323439643637336566396632663335393036663432653664333232346338
36343338333236663764643136373164373931653630626639306663333562323231643630343539
37303965393537636130356437393164366435633734613037306664346464663935346165373461
35313330316232333664356162383235653135623361386363643235366134373162633739393531
32613134633331376236373636636639333331353037343134346232636432306230346139343631
37613431616565363735656166333437343433306535613732653866653635633432353166313834
32623133363664653131636466343361616130353635303663663837396664626338393239343938
64383534316265623836316162383164636636306631373739313263653664306437313932316166
62363936613230316638643762366231653931643461323539613964346138366539303865303334
64393238306439616161316539346632626262653734383239343135323732653731333763656634
34306661613065633137643966333334666531653862623933383937646136343339323866383361
35366637373930613165646537653231343266613338373363303334316136633565383732373865
39373636373635626231666130343335323265626632303239393334643963616666343930323461
62393937643533376230313937663032326664636532616333623763326461363638303930666234
31663362393333356565343230633239646130356530623137333332383332316261646531633336
35393038386332353230633635353465616630306465613766636366613833376661633961623733
32316134323062366436363661343931306135316631666339313439653035613239383265386438
33363864366330626264643731663439303662646562396431373231353138363330663238313562
35663330303338633234653736386364346135616536613939366330343838616330613162303565
61356666376534636465323266396162383538636230616337656464343339353732386665393261
35303834653666616530393730626237386164343835613538333230636163653935353537623931
39613062323337353133653932326633633833396639633239346330613934626164333336353730
39613639386161393436356162633334643663623461323932633662336236363334373935613164
35313832653033356634316663396533386133353663383163333934376633393033613037353439
64643765366136643166343563646232386566636635363766616339386530346134323366666438
62623139663632373534353731326636386138393936316266393634383234613063633036366663
63346230373134626362323438656535393434666638306136356639303931313163613963623137
34366332646135633133316638323434653033633964356430626564666130633633613165373762
39613337663634373433633637653534643164636330396630313861316563663963363238333531
61613432373366396637643239613935636436353433323132663165633934353063623830363262
37613733613561623165383734313037303730346237626163616535313934616139373431613034
31333239653632643163366562373164386366343464393138303364343735643331633538373334
36343930663334366231363563316531313866616232643664633533343739306462323661313464
30313533356333333131656366643161373134613164303831636363306435336263363733303535
33383730626337343963323663313432646437323237363035376633613361313762356137636336
63383132363566303930306332363563303362333232313462326434643361643738373938663732
66663438666264383038346563306365363730323236613037376566303430353330613866646338
32386430636339663863623439323831656565373735666130616439316137373632326364613538
31623037386464313830336638646531633031623666313965323266373337643433643739643638
31663432653263636266666161636134643865383466366163303230653635383266346163643335
30333365616337323163363430323661383464613135376661623662346665623135373430333362
31346632333835653364633431616439633930303937643837633937663766656461326536613931
35323964393030363666353836316436343533393030653433353162366463326635396436363631
33333238646131343635313234353939393766656162313933353038313961343561653932353037
61356162633362386530376464663038343263383631343730343937326334333964623339316334
36323330333237643231646666626635646365383337323361336563663264643161643165363830
37323736353566316634396662663032633438386632333764663534306662383530316139393537
36633432613635346633656336626238346665646566313435393261333632336661383536656265
36326231626432656233363866646539363538393162623361333238396234393266653631353236
39383461326132663566306262623934313437663036386233316635343737346637623639323535
64326361313034376636366335383963643833353231353835303237343834303061343162363632
63393836363762643136666433353739393763663431656366336664383531323936323162623837
35323361623666356461623164373531363665343630316662343266323933333463653834336566
65333234363235333838316662383738333238363064373361333834316332636438613431363538
38333435643136353861666634373066346139336433303962313438613038326361653864343932
33396138663532646165653361653333393734626662343562666438363338383135323339386331
34616338346639376431303932333836363863343730383066383561393661626137343230363163
31663737333936396333636536643736356232666465373436306232323733353865393630303861
31356164643631643635323530633936323735643437613737383231326532373233396334616366
32663832626631636262326461663436353231366230313365353735363736626539643262393862
36636437663338356137303165613461663062646134303062616265613033363366303437616334
33353239303133613464376363383132373339306634313033663431636631393361643362343230
33353031393233363736313938643564376338303364343437656264633065356438386539633761
33346131303461616437303731373166303538323136373939366362616434393634383637353563
30303961316630623939663862623361386361666435303931626237393930313833333239393939
31376235346461353661363232616264656561333339633062623438613934313837653939643665
33653861373732393832343736646364343831323938386432643534313938393235323533633465
66623434613134303036636436383638666137623532306139346666623764623566393436333661
36336136656134316561666539323237646362616436346464656264666331613730623734393030
63626130303235633835633262373633363735346165303262306539663339663163343365353730
39386437623030643532306337373330613839393631653232666661613066393439646664306431
33616265356361613138333635613536336639326661653434353031323265636438343466353366
31666237646265373961663764313236663432373834616136363135353366666534336631636431
30353033393432366130313936363565323161316639343135613030373039383933376237303733
64396661376463626134333365623033306235353533303336643366366633306564626431346531
39393735363961356163666465396134653639626665353861626531333464373365653539303339
31643834373161373665383366336139313431366163343363626263333363626139646238313035
66343463336336376139333663303332626233356337653361616437363736313137303162666133
61656530646533353763316562363538333435636366653137303333666463646430333265626334
30313062393936393032323466396232643734383631656631393931393233346539373435323935
38303739353535656661333037616639313965393733316339316130626136383132323437373836
37356539663037646335376639303837393433613238636136633762616362366538383337343138
30613337653631303938363430326566613536653839363362633631306361386530646362343030
65663637306663383731646566626462376631303137383839363962376435623861616463623035
30353635663633653462373664326130396432393238663938393037383136303662366262376166
63613334653934656263396562643032646630333536633861336337306236313663653932646232
62346264393932323532373865643966393031303731663033383738393466366632373464376131
35336265626639336633323531636563376335386632376265333431363932633961326536336331
64656161393130613134646664656437383030613437646438383835663063313565613932383231
30626334313332363466333935343064613836623766353130336662383431623139333264393431
38343565613639636236393730643961623432316531663361383832313166396561393434356131
35366436616530313265346165653830323463323963663637366566613664666362333462356262
32646237663465306365313130386462356530343737306337623135303166373963613863326263
64323832663366346363326161313331316439313633643066326166626639373962393139383432
33643533666531666539663638613732346134633765333031626362336366666666633135313031
65633264396532363462373339366463383564646137663864386230343661633866353431623632
34376638343837306331356463626663376462316132396164643265346334346463393933393734
33313039333036616562643064396433666464326536393230393364343539306630323833653730
63626566366436626661656436613737376231346631646639326534643537636136616434316232
36306131636138663630646138326463623936623532303839623165623137363732343363383930
66333736336563616462346533393837396637663937376631346431373533316561356664383263
61663635663131666436373539646166373934333863323338626238633635396362663038623639
30396165353437663130613537313464333030353836346632313232353837626231303835666266
32633766323365303564313436346561626165386165623830393164333038306433316563323236
34343435306236386532346235643961343538383435333430366433346163353862366161613464
30316634313933613061636532353432626539316134636330623362613534376239643133363136
39613931303731333633646436623438363362386163643236613963313131383466306461366436
32353265643533636238646431353466306530303238323131653336396361303262356262613230
35353739653530646231313062643235623230363465333763333966356534373565326334306336
30336433363036626566613634303162376264333838653932396561383438316466383966343663
31626331623332316139376361366231343334356630653236333135626463336664323637306638
37303134666232303966613638616361613961356365613538323164343337386261643133393634
31306565373639323031346236633837306132373264643462613433393961303931376538356339
38633066313833383664393036333939333066633463333065396633313936306131366364303135
31613761616131616362633639363764376464646266323530616265363339363036653662643439
31313536646333393639346433336562643938646164636662316132326436616135303432386334
65663062653931643663636666313835646138323432373138353939613330613461643133613138
66636361643533386630316133356331623466663636333961633438613233353036666635376534
35383365376265383939303636316265663630333935623131303738376631656537656138343765
36643431623939633632323535363837363331323331393035366664316232343861626665633061
34346434666638393934643162653733323935646262396661363966643062346562613336333061
38363336366339633661666165383436663031306631643831643463663937653031393061306438
63656338323363336332353232373966363436646538343562393932653539316565656163386634
35306265393662326361393166373935356633323638663465616233376534646131353132663866
38346163613131326239636365343937653833356138393838316137313063653238376631346461
32323331626365323130613866653465353565343863636630366465383962623238636434663565
64343762623530623365383739326562616632626166613635383937343839626666306135333934
38336461373730633233373131323365613139616439636365383762663237383631353165336232
61613464386630396437393162653530396139636632393336623562303536353233633034366365
31396139646334376631316265393663316537643737383630643262613036326137366463623161
30346361383132373336616132383665333265363231303334623661336537343837656331613561
32343135383635356463663065346561303034663262643735646664303536363833383630623461
37616336386432313535373233386433663363623761313331633438363563396563626631336662
38653235633838613630623438373661333563623436383833333235326334386163663037386636
33303631616135396130663735353333346564656537393937613638616239663161313962613631
38386537653466353966346430633361303136643836326332633631336232646265613034326161
65633033393337363336326633306262316636663461346162633234376232646563363032343632
39643062313532646633343133313330316537343936646561613430303034303765633565396132
37636165373335303133316233363132303339626635663461366263366162643736616533313338
31353433363937343465346530306630393236636138643231393761623661326336356263306634
36643234326538316432363864666138643139313334393265623761626162306632386135336161
34326266306565343731626161643937663665366537643536636135613532643862353633333836
64356337313064663339333163613862393761356339633033346338353865303038323833373461
31346364663662316134383061313930323033356538626630373761613737343133303337613036
37373261303066313035663139653237336236643036323732313763343866393736383937363733
30393135653662666630353666316532303538366138386264663161656362633135343333613134
62633139613130666566383361366637633632663166643336303730616237626430623863363963
62316366633130343061366636393037323433643739646331306539376564666364383934383935
63376633343364326430373130316264393866373438653964373663653737633533393139363564
39336635386433343766353166323531633731616333666463323538393135636538383230633939
63363061623432346437303565626637326561306162613830363835373830383631636338376538
33343931353631393538306138393039626635666366363836333438663333323636623037303331
31663237343965663364643139306632666166616138316363316334613134343864316335383631
33323331336462656566613039313631643137363336643833646637383430363863373633633738
63666336643938663064613538373434636234373935383736373739363430343765393463626231
31643131636633386135366563316232343132376662643364626537656333643736626530653036
37653636646534353634633734373463313031626363376538316634383863393035353835643836
63353036633933323932646135396337393735383931373638643064626334366139623133386662
35626464653162396132

View File

@@ -0,0 +1,17 @@
$ANSIBLE_VAULT;1.1;AES256
64613361376364346139313833613465663361336634326430393261366630306466363935613139
3634363235343736643230623865386436333734663531310a343965396534336262356234623966
39353332626662636666383935383530613139626439373664323063633063316264383331646533
3366333837613731310a656462633638376432326365343135373863313665346566383933353630
37303565323630633739396433323165326262363863386233343134636236646366633765616432
33633165613239653762343935386637393437386431383961306436373765343736313634333933
30376463646464303066613561613564353938306664373464333966383664383034616439343735
38363966323366343465393530383736393364373361326234356365363163356632393834393464
39393530356235383830323065636535383138353864373237333164323436623737383435313261
64366362626232386438376131633533633162356432613835656465623762633464353936303236
63353633633262633461353963653534663336396134373435303266386162393965343165303335
65313436666334383965373837376664323861376162373834363439653539383231346634633737
30626431373739633930313937643938343165383536373465613535366562313439396533643864
36323032316131333962373732306334373939333363386564653465303261393337333466316130
32326533353165393635393130396164636363623937313566343333386562616662383038613565
35386638383365633362

View File

@@ -22,4 +22,6 @@ stepca_listen_port: 9000
stepca_oidc_provisioner_name: authentik
stepca_oidc_configuration_endpoint: "https://authentik.local.mk-labs.cloud/application/o/step-ca/.well-known/openid-configuration"
stepca_oidc_listen_address: ":10000"
stepca_oidc_domain: "local.mk-labs.cloud"
stepca_oidc_domains:
- "local.mk-labs.cloud"
- "protonmail.com"

View File

@@ -0,0 +1,17 @@
$ANSIBLE_VAULT;1.1;AES256
30383930323363386234333433636465393263613336646464666365643730386430353864616334
3865343031653162313736656437373666636136653263360a613961646133376262633164393535
31363434633634303035663133316230633538363936303266373931313661346563333832653032
6239376363646530620a303231363333363233623038326165316463383662656565626534396232
62333133623530643932643430663166373930353733363866336533643233373261333130613635
31633337376337663833613634666436383862386431636537373363343333323932363761653366
61353166613162346436396138316561646165303566376366323462663861616364336539313138
30386430373566353761383636626335393463376661356666303861353564313832346333396134
30653861363866336331336164323130623230666237356165613934333239386536373664643065
33643139346562346663313533643433353462363665323166313364373335366665373435643935
65303863663864393238393732303065343364306264396333376233666233346664323334336532
38373164383835663163363137643531303163396236623565666436363261393563343133333161
36663934303633663062346161636333396135336135616136303664636562363862353764343562
39643430396636313139336130656363306562363430346233313530663963366238326334623135
62383632613061316262323038303333323739303137363334626637666663666263613132336433
65346266393733633632

View File

@@ -65,6 +65,10 @@ papermc_server:
hosts:
arcade:
dev_servers:
hosts:
scrim:
semaphore_server:
hosts:
imagineering:
@@ -81,6 +85,14 @@ backup_servers:
hosts:
timekeeper:
talos_control:
hosts:
city-hall:
ansible_become: true
vars:
talosctl_version: "v1.12.4"
talos_cluster_name: "fastpass"
# ipaserver:
# hosts:
# infra01.int.mk-labs.cloud:

View File

@@ -0,0 +1,6 @@
---
- name: Apply common role
hosts: "{{ target | default('all') }}"
become: true
roles:
- common

View File

@@ -0,0 +1,7 @@
---
- name: Enroll host as step-ca SSH client
hosts: "{{ target | default('all') }}"
become: true
tasks:
- name: Include step-ca client enrollment
ansible.builtin.include_tasks: roles/common/tasks/step_ca_client.yml

View File

@@ -0,0 +1,15 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/install_talosctl.yml
# DESCRIPTION: Install talosctl on city-hall for managing the fastpass cluster.
# USAGE:
# cd ansible
# ansible-playbook -i inventory.yml playbooks/install_talosctl.yml
# ------------------------------------------------------------------------------
- name: Install talosctl
hosts: talos_control
become: true
roles:
- talosctl

View File

@@ -1,20 +1,25 @@
# ------------------------------------------------------------------------------
---
# ──────────────────────────────────────────────────────────────────────────────
# FILE: roles/authentik/tasks/main.yml
# DESCRIPTION: Deploys Authentik from boilerplate-generated files in the repo.
# The compose.yaml lives in boilerplates/authentik/.
# The .env file is templated to inject secrets from Ansible vault.
# ------------------------------------------------------------------------------
# Custom blueprints are synced from boilerplates/authentik/blueprints/.
# ──────────────────────────────────────────────────────────────────────────────
- name: Create Authentik directory structure
file:
path: "{{ authentik_base_dir }}"
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: '0775'
loop:
- "{{ authentik_base_dir }}"
- "{{ authentik_base_dir }}/blueprints"
- name: Copy compose.yaml from boilerplate
copy:
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/authentik/compose.yaml"
dest: "{{ authentik_base_dir }}/compose.yaml"
owner: "{{ ansible_user }}"
@@ -22,8 +27,17 @@
mode: '0644'
notify: restart authentik
- name: Sync custom blueprints
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/authentik/blueprints/"
dest: "{{ authentik_base_dir }}/blueprints/"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart authentik
- name: Deploy .env with secrets from vault
template:
ansible.builtin.template:
src: env.j2
dest: "{{ authentik_base_dir }}/.env"
owner: "{{ ansible_user }}"

View File

@@ -2,3 +2,10 @@
AUTHENTIK_SECRET_KEY={{ authentik_secret_key }}
DATABASE_PASSWORD={{ authentik_database_password }}
AUTHENTIK_ADMIN_PASSWORD={{ authentik_admin_password }}
# OIDC client credentials for blueprints
# These are substituted into blueprint YAML via ${VAR} syntax
PROXMOX_OIDC_CLIENT_ID={{ vault_proxmox_oidc_client_id }}
PROXMOX_OIDC_CLIENT_SECRET={{ vault_proxmox_oidc_client_secret }}
STEPCA_OIDC_CLIENT_ID={{ vault_stepca_oidc_client_id }}
STEPCA_OIDC_CLIENT_SECRET={{ vault_stepca_oidc_client_secret }}

View File

@@ -10,7 +10,7 @@
name: "{{ inventory_hostname | replace('_', '-') }}"
- name: Set timezone
timezone:
community.general.timezone:
name: "{{ common_timezone }}"
- name: Update apt cache
@@ -52,3 +52,30 @@
# --- Step-CA SSH certificate enrollment ---
- name: Enroll host in step-ca SSH CA
include_tasks: step_ca_client.yml
- name: Create authorized principals directory
ansible.builtin.file:
path: /etc/ssh/auth_principals
state: directory
owner: root
group: root
mode: '0755'
- name: Create authorized principals files
ansible.builtin.copy:
content: "{{ item.principals | join('\n') }}\n"
dest: "/etc/ssh/auth_principals/{{ item.local_user }}"
owner: root
group: root
mode: '0644'
loop: "{{ step_ca_principal_mappings }}"
notify: restart sshd
- name: Configure sshd AuthorizedPrincipalsFile
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
line: "AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u"
regexp: "^#?AuthorizedPrincipalsFile"
state: present
notify: restart sshd

View File

@@ -95,3 +95,29 @@
community.docker.docker_compose_v2:
project_src: "{{ stepca_base_dir }}"
state: present
- name: Template OIDC provisioner patch script
ansible.builtin.template:
src: patch_oidc_provisioner.py.j2
dest: "{{ stepca_base_dir }}/patch_oidc_provisioner.py"
owner: root
group: root
mode: "0700"
no_log: true
- name: Patch OIDC provisioner in ca.json
ansible.builtin.command:
cmd: python3 {{ stepca_base_dir }}/patch_oidc_provisioner.py
register: oidc_patch_result
changed_when: "'CHANGED' in oidc_patch_result.stdout"
- name: Restart step-ca if OIDC provisioner changed
community.docker.docker_compose_v2:
project_src: "{{ stepca_base_dir }}"
state: restarted
when: oidc_patch_result is changed
- name: Clean up patch script
ansible.builtin.file:
path: "{{ stepca_base_dir }}/patch_oidc_provisioner.py"
state: absent

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
# Managed by Ansible — do not edit manually
# Patches the OIDC provisioner in step-ca's ca.json with values from Ansible vars
import json
import sys
ca_json_path = "{{ stepca_data_dir }}/config/ca.json"
provisioner_name = "{{ stepca_oidc_provisioner_name }}"
desired_domains = {{ stepca_oidc_domains | to_json }}
desired_client_id = "{{ stepca_oidc_client_id }}"
desired_client_secret = "{{ stepca_oidc_client_secret }}"
desired_config_endpoint = "{{ stepca_oidc_configuration_endpoint }}"
desired_listen_address = "{{ stepca_oidc_listen_address }}"
with open(ca_json_path) as f:
cfg = json.load(f)
changed = False
found = False
for p in cfg["authority"]["provisioners"]:
if p.get("name") == provisioner_name and p.get("type") == "OIDC":
found = True
updates = {
"domains": desired_domains,
"clientID": desired_client_id,
"clientSecret": desired_client_secret,
"configurationEndpoint": desired_config_endpoint,
"listenAddress": desired_listen_address,
}
for key, value in updates.items():
if p.get(key) != value:
p[key] = value
changed = True
break
if not found:
# Add the OIDC provisioner if it doesn't exist
cfg["authority"]["provisioners"].append({
"type": "OIDC",
"name": provisioner_name,
"clientID": desired_client_id,
"clientSecret": desired_client_secret,
"configurationEndpoint": desired_config_endpoint,
"domains": desired_domains,
"listenAddress": desired_listen_address,
"claims": {"enableSSHCA": True},
"options": {"x509": {}, "ssh": {}},
})
changed = True
if changed:
with open(ca_json_path, "w") as f:
json.dump(cfg, f, indent=8)
print("CHANGED")
else:
print("OK")

View File

@@ -0,0 +1,15 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/talosctl/defaults/main.yml
# DESCRIPTION: Default variables for talosctl installation.
# ------------------------------------------------------------------------------
# Pin to a specific version for reproducibility.
# Update this when upgrading the fastpass cluster.
talosctl_version: "v1.12.4"
# Architecture of the target host (amd64 or arm64)
talosctl_arch: "amd64"
# Where to install the binary
talosctl_install_dir: "/usr/local/bin"

View File

@@ -0,0 +1,51 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/talosctl/tasks/main.yml
# DESCRIPTION: Install talosctl binary from GitHub releases.
# Downloads a pinned version, installs to /usr/local/bin,
# and verifies the installation.
# ------------------------------------------------------------------------------
- name: Check if talosctl is already installed
stat:
path: "{{ talosctl_install_dir }}/talosctl"
register: talosctl_binary
- name: Get installed talosctl version
command: "{{ talosctl_install_dir }}/talosctl version --client --short"
register: talosctl_installed_version
changed_when: false
failed_when: false
when: talosctl_binary.stat.exists
- name: Install talosctl
when: >
not talosctl_binary.stat.exists or
talosctl_version not in (talosctl_installed_version.stdout | default(''))
block:
- name: Download talosctl {{ talosctl_version }}
get_url:
url: "https://github.com/siderolabs/talos/releases/download/{{ talosctl_version }}/talosctl-linux-{{ talosctl_arch }}"
dest: "/tmp/talosctl"
mode: "0755"
- name: Install talosctl to {{ talosctl_install_dir }}
copy:
src: "/tmp/talosctl"
dest: "{{ talosctl_install_dir }}/talosctl"
mode: "0755"
remote_src: true
- name: Clean up downloaded binary
file:
path: "/tmp/talosctl"
state: absent
- name: Verify talosctl installation
command: "{{ talosctl_install_dir }}/talosctl version --client --short"
register: talosctl_verify
changed_when: false
- name: Display installed talosctl version
debug:
msg: "talosctl installed: {{ talosctl_verify.stdout }}"

View File

@@ -0,0 +1,17 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/talosctl/meta/main.yml
# ------------------------------------------------------------------------------
galaxy_info:
author: rblundon
description: Install talosctl CLI for managing TalosOS clusters
license: MIT
min_ansible_version: "2.14"
platforms:
- name: Ubuntu
versions:
- noble
dependencies:
- role: common

View File

@@ -0,0 +1,45 @@
# ──────────────────────────────────────────────────────────────────────────────
# Blueprint: Proxmox VE — OIDC Provider + Application
# ──────────────────────────────────────────────────────────────────────────────
version: 1
metadata:
name: mk-labs-proxmox
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
- model: authentik_providers_oauth2.oauth2provider
id: proxmox-provider
state: present
identifiers:
name: "Provider for Proxmox VE"
attrs:
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
client_type: confidential
client_id: !Env PROXMOX_OIDC_CLIENT_ID
client_secret: !Env PROXMOX_OIDC_CLIENT_SECRET
redirect_uris:
- url: "https://main-street-usa.local.mk-labs.cloud:8006"
matching_mode: strict
- url: "https://tomorrowland.local.mk-labs.cloud:8006"
matching_mode: strict
- url: "https://fantasyland.local.mk-labs.cloud:8006"
matching_mode: strict
sub_mode: hashed_user_id
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
- model: authentik_core.application
id: proxmox-application
state: present
identifiers:
slug: proxmox
attrs:
name: "Proxmox VE"
provider: !KeyOf proxmox-provider
group: "Infrastructure"
meta_launch_url: "https://main-street-usa.local.mk-labs.cloud:8006"
policy_engine_mode: any

View File

@@ -0,0 +1,40 @@
# ──────────────────────────────────────────────────────────────────────────────
# Blueprint: step-ca — OIDC Provider + Application
# ──────────────────────────────────────────────────────────────────────────────
version: 1
metadata:
name: mk-labs-step-ca
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
- model: authentik_providers_oauth2.oauth2provider
id: step-ca-provider
state: present
identifiers:
name: "Provider for step-ca"
attrs:
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
client_type: confidential
client_id: !Env STEPCA_OIDC_CLIENT_ID
client_secret: !Env STEPCA_OIDC_CLIENT_SECRET
redirect_uris:
- url: "http://127.0.0.1:10000"
matching_mode: strict
sub_mode: hashed_user_id
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
- model: authentik_core.application
id: step-ca-application
state: present
identifiers:
slug: step-ca
attrs:
name: "step-ca"
provider: !KeyOf step-ca-provider
group: "Infrastructure"
policy_engine_mode: any

View File

@@ -12,7 +12,11 @@ services:
- AUTHENTIK_POSTGRESQL__USER=authentik
- AUTHENTIK_POSTGRESQL__NAME=authentik
- AUTHENTIK_POSTGRESQL__PASSWORD=${DATABASE_PASSWORD}
- AUTHENTIK_REDIS__HOST=authentik_redis
# OIDC client credentials — consumed by blueprints via ${VAR} substitution
- PROXMOX_OIDC_CLIENT_ID=${PROXMOX_OIDC_CLIENT_ID}
- PROXMOX_OIDC_CLIENT_SECRET=${PROXMOX_OIDC_CLIENT_SECRET}
- STEPCA_OIDC_CLIENT_ID=${STEPCA_OIDC_CLIENT_ID}
- STEPCA_OIDC_CLIENT_SECRET=${STEPCA_OIDC_CLIENT_SECRET}
networks:
- authentik_backend
ports:
@@ -21,11 +25,10 @@ services:
volumes:
- authentik_data:/data
- authentik_templates:/templates
- ./blueprints:/blueprints/custom:ro
depends_on:
authentik_postgres:
condition: service_healthy
authentik_redis:
condition: service_healthy
authentik_worker:
image: ghcr.io/goauthentik/server:2025.12.4
@@ -39,8 +42,12 @@ services:
- AUTHENTIK_POSTGRESQL__USER=authentik
- AUTHENTIK_POSTGRESQL__NAME=authentik
- AUTHENTIK_POSTGRESQL__PASSWORD=${DATABASE_PASSWORD}
- AUTHENTIK_REDIS__HOST=authentik_redis
- AUTHENTIK_BOOTSTRAP_PASSWORD=${AUTHENTIK_ADMIN_PASSWORD}
# OIDC client credentials — consumed by blueprints via ${VAR} substitution
- PROXMOX_OIDC_CLIENT_ID=${PROXMOX_OIDC_CLIENT_ID}
- PROXMOX_OIDC_CLIENT_SECRET=${PROXMOX_OIDC_CLIENT_SECRET}
- STEPCA_OIDC_CLIENT_ID=${STEPCA_OIDC_CLIENT_ID}
- STEPCA_OIDC_CLIENT_SECRET=${STEPCA_OIDC_CLIENT_SECRET}
user: root
networks:
- authentik_backend
@@ -49,11 +56,10 @@ services:
- authentik_data:/data
- authentik_certs:/certs
- authentik_templates:/templates
- ./blueprints:/blueprints/custom:ro
depends_on:
authentik_postgres:
condition: service_healthy
authentik_redis:
condition: service_healthy
authentik_postgres:
image: docker.io/library/postgres:17.8
@@ -74,22 +80,6 @@ services:
volumes:
- authentik_postgres:/var/lib/postgresql/data
authentik_redis:
image: docker.io/library/redis:7-alpine
container_name: authentik-redis
restart: unless-stopped
command: --save 60 1 --loglevel warning
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 10s
interval: 10s
timeout: 5s
retries: 5
networks:
- authentik_backend
volumes:
- authentik_redis:/data
networks:
authentik_backend:
driver: bridge
@@ -97,8 +87,6 @@ networks:
volumes:
authentik_postgres:
driver: local
authentik_redis:
driver: local
authentik_data:
driver: local
authentik_certs:

View File

@@ -0,0 +1,733 @@
# Deploying Authentik (guest-relations) & Smallstep step-ca (turnstile)
## Overview
This guide documents the full deployment process for two services in the mk-labs homelab:
- **Authentik** — Identity provider and SSO platform, running on `guest-relations` (10.1.71.40)
- **Smallstep step-ca** — SSH Certificate Authority, running on `turnstile` (10.1.71.34)
Both follow the same provisioning pattern: Terraform creates the VM → Ansible configures the OS and deploys the application → Traefik provides reverse proxy and TLS termination (Authentik only; step-ca is accessed directly) → Authentik OIDC applications are codified as blueprints.
**Prerequisites:**
- Proxmox cluster (`magic-kingdom`) operational
- `city-hall` VM with Terraform CLI, Ansible CLI, Boilerplates CLI, and GitHub CLI (`gh`) installed
- `lightning-lane` (10.1.71.35) running Traefik with Cloudflare DNS-01 wildcard certs
- `monorail` (10.1.71.20) running Technitium DNS for `local.mk-labs.cloud`
- Ansible vault configured at `ansible/group_vars/all/vault`
---
## Part 1: Deploying Authentik (guest-relations)
Authentik is a Tier 1 service — it runs outside Kubernetes because other services depend on it for authentication. As of version 2025.10, Redis is no longer required — all caching, tasks, and WebSocket connections have been migrated to PostgreSQL. It runs three containers: server, worker, and PostgreSQL.
### 1.1 Create the Terraform tfvars
Create `terraform/proxmox/hosts/tfvars/guest-relations.tfvars`:
```hcl
# guest-relations — Authentik Identity Provider / SSO
# VM ID convention: third_octet × 1000 + fourth_octet = 71040
hostname = "guest-relations"
vm_id = 71040
ip_address = "10.1.71.40"
target_node = "main-street-usa"
template_name = "ubuntu-24.04-medium"
# Bootstrap mode — no n8n/NetBox pipeline available yet
started = true
use_dhcp = false
```
> **Note:** The medium template (2 vCPU / 4GB RAM / 16GB disk) is used because Authentik runs PostgreSQL alongside the application containers.
### 1.2 Provision the VM with Terraform
```bash
cd terraform/proxmox/hosts
terraform apply \
-var-file="tfvars/guest-relations.tfvars" \
-state="states/guest-relations.tfstate" \
-var="proxmox_api_url=https://main-street-usa.local.mk-labs.cloud:8006" \
-var="proxmox_api_token=terraform@pve!automation=<token>"
```
After Terraform completes, create a DHCP reservation in UniFi for `10.1.71.40` and start the VM.
### 1.3 Create DNS records on monorail
On `monorail` (Technitium DNS), create:
- **A record:** `guest-relations.local.mk-labs.cloud``10.1.71.40` (direct access)
- **A record:** `authentik.local.mk-labs.cloud``10.1.71.35` (points to lightning-lane for Traefik routing)
> **Critical rule:** All services behind Traefik must have their service DNS pointing to `lightning-lane` (10.1.71.35), not the backend VM's IP. Traefik routes based on the `Host()` header.
### 1.4 Generate the Compose stack with Boilerplates
On `city-hall`, generate the Authentik boilerplate:
```bash
boilerplates compose generate authentik
```
Use these settings during generation:
- `traefik_enabled: false` (Authentik is on a different VM than Traefik, so Docker labels won't work — we use Traefik's dynamic file config instead)
The boilerplate auto-generates three secrets:
- `AUTHENTIK_SECRET_KEY`
- `DATABASE_PASSWORD`
- `AUTHENTIK_ADMIN_PASSWORD`
Save these somewhere safe — the admin password is needed for first login.
Commit the generated files to `boilerplates/authentik/` at the repo root. Review the `compose.yaml` for any `None` placeholder values left by the boilerplate (timezone, network names, etc.) and fix them.
> **Post-2025.10:** If the boilerplate generates a Redis service, remove it. Authentik 2025.10+ no longer requires Redis. If upgrading from an older version and you see an orphan `authentik-redis` container warning, clean it up with `docker compose down --remove-orphans && docker compose up -d`.
### 1.5 Store secrets in Ansible Vault
Add Authentik secrets and OIDC blueprint credentials to `ansible/group_vars/all/vault`:
```bash
ansible-vault edit ansible/group_vars/all/vault
```
Add:
```yaml
# Authentik application secrets
authentik_secret_key: "<generated-secret-key>"
authentik_admin_password: "<generated-admin-password>"
authentik_database_password: "<generated-database-password>"
# OIDC client credentials for blueprints (pre-generated)
vault_proxmox_oidc_client_id: "<pre-generated-client-id>"
vault_proxmox_oidc_client_secret: "<pre-generated-client-secret>"
vault_stepca_oidc_client_id: "<pre-generated-client-id>"
vault_stepca_oidc_client_secret: "<pre-generated-client-secret>"
```
Pre-generate client IDs and secrets:
```python
python3 -c "
import secrets, string
def gen_id(): return secrets.token_hex(20)
def gen_secret(): return ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(128))
print(f'Client ID: {gen_id()}')
print(f'Client Secret: {gen_secret()}')
"
```
### 1.6 Create Authentik Blueprints
Blueprints are declarative YAML files that codify Authentik OIDC providers and applications. They are mounted into the Authentik container and applied automatically.
> **Critical:** Blueprint files must use the `.yaml` extension, not `.yml`. Authentik's blueprint discovery only scans for `.yaml` files.
> **Critical:** Use the `!Env` YAML tag to reference environment variables in blueprints, not `${VAR}` shell-style substitution. Example: `client_id: !Env STEPCA_OIDC_CLIENT_ID`
Create `boilerplates/authentik/blueprints/step-ca.yaml`:
```yaml
version: 1
metadata:
name: mk-labs-step-ca
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
- model: authentik_providers_oauth2.oauth2provider
id: step-ca-provider
state: present
identifiers:
name: "Provider for step-ca"
attrs:
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
client_type: confidential
client_id: !Env STEPCA_OIDC_CLIENT_ID
client_secret: !Env STEPCA_OIDC_CLIENT_SECRET
redirect_uris:
- url: "http://127.0.0.1:10000"
matching_mode: strict
sub_mode: hashed_user_id
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
- model: authentik_core.application
id: step-ca-application
state: present
identifiers:
slug: step-ca
attrs:
name: "step-ca"
provider: !KeyOf step-ca-provider
group: "Infrastructure"
policy_engine_mode: any
```
Create `boilerplates/authentik/blueprints/proxmox.yaml` following the same pattern, with `PROXMOX_OIDC_CLIENT_ID` / `PROXMOX_OIDC_CLIENT_SECRET` env vars and redirect URIs for each Proxmox node (`https://<hostname>:8006`, no trailing slash).
### 1.7 Update the Compose file for blueprints
The `compose.yaml` needs two additions to both the `authentik` (server) and `authentik_worker` services:
1. A volume mount for custom blueprints: `./blueprints:/blueprints/custom:ro`
2. Environment variables for OIDC credentials consumed by blueprints via `!Env`:
```yaml
environment:
# ... existing vars ...
- PROXMOX_OIDC_CLIENT_ID=${PROXMOX_OIDC_CLIENT_ID}
- PROXMOX_OIDC_CLIENT_SECRET=${PROXMOX_OIDC_CLIENT_SECRET}
- STEPCA_OIDC_CLIENT_ID=${STEPCA_OIDC_CLIENT_ID}
- STEPCA_OIDC_CLIENT_SECRET=${STEPCA_OIDC_CLIENT_SECRET}
volumes:
# ... existing volumes ...
- ./blueprints:/blueprints/custom:ro
```
The `.env` file (templated by Ansible) provides the actual values from vault.
### 1.8 Create the Ansible role and inventory
**Inventory entry** — add to `ansible/inventory.yml`:
```yaml
authentik_server:
hosts:
guest_relations:
ansible_host: 10.1.71.40
ansible_become: true
```
**Host vars** — create `ansible/host_vars/guest_relations/vars`:
```yaml
---
ip_address: 10.1.71.40
app_role: identity_provider
app_name: authentik
app_deployment: docker_compose
```
**Ansible role** — create `ansible/roles/authentik/` with:
- `tasks/main.yml` — creates the application directory, copies `compose.yaml` from `boilerplates/authentik/`, syncs the `blueprints/` directory, templates the `.env` file with vault secrets including OIDC credentials, and starts the stack
- `defaults/main.yml` — sets `authentik_base_dir: /opt/docker/authentik`
- `handlers/main.yml``restart authentik` handler using `docker_compose_v2`
- `templates/env.j2` — injects all secrets from vault including blueprint OIDC credentials
**Playbook** — create `ansible/playbooks/deploy_authentik.yml`:
```yaml
---
- name: Deploy Authentik identity provider
hosts: authentik_server
become: true
roles:
- common
- docker-host
- authentik
```
### 1.9 Deploy with Ansible
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/deploy_authentik.yml
```
This runs three roles in sequence: `common` (hostname, timezone, base packages, Chrony NTP pointing to sundial) → `docker-host` (Docker CE, adds `wed` user to docker group) → `authentik` (Compose stack + blueprints).
Authentik will discover and apply the blueprints within a minute of startup. Verify in the admin UI under **Customization → Blueprints** and **Applications → Applications**.
### 1.10 Create the Traefik dynamic config
Create `boilerplates/traefik/dynamic/authentik.yml`:
```yaml
http:
routers:
authentik:
rule: "Host(`authentik.local.mk-labs.cloud`)"
entryPoints:
- websecure
service: authentik
tls:
certResolver: cloudflare
middlewares:
- security-headers
services:
authentik:
loadBalancer:
servers:
- url: "http://10.1.71.40:8000"
middlewares:
authentik-forwardauth:
forwardAuth:
address: "http://10.1.71.40:8000/outpost.goauthentik.io/auth/nginx"
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
```
Deploy to lightning-lane:
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/update_traefik_routes.yml
```
### 1.11 Verify the deployment
Check all three containers are healthy on guest-relations:
```bash
ssh wed@guest-relations.local.mk-labs.cloud docker ps
```
Expected output: `authentik-server`, `authentik-worker`, and `authentik-postgres` all with status `Up ... (healthy)`.
Access `https://authentik.local.mk-labs.cloud` and log in with:
- Username: `akadmin`
- Password: the `AUTHENTIK_ADMIN_PASSWORD` from vault
### 1.12 Create your user in Authentik
Do not use `akadmin` for day-to-day logins. Create a dedicated user:
1. Log in as `akadmin` at `https://authentik.local.mk-labs.cloud/if/admin/`
2. Go to **Directory → Users → Create**
3. Set username to `rblundon`, fill in email and display name, mark as active
4. Set a password
5. Optionally create a `proxmox-admins` group under **Directory → Groups** and add `rblundon` to it
> Keep `rblundon` as a regular user (not an Authentik admin). Use `akadmin` for Authentik administration, `rblundon` for logging into downstream services. These are separate privilege domains.
---
## Part 2: Configuring Proxmox OIDC with Authentik
This configures SSO for the `magic-kingdom` Proxmox cluster using Authentik as the OIDC identity provider. The realm configuration is cluster-wide (stored in `/etc/pve/domains.cfg`), so it only needs to run against one node.
> **Note:** The Proxmox OIDC application is codified as a blueprint (see Part 1.6). The provider and application are created automatically when Authentik starts with the blueprint mounted. The steps below cover the Proxmox-side realm configuration only.
### 2.1 Store credentials in Ansible Vault
The Proxmox OIDC client credentials are the same pre-generated values used in the blueprint. Store them in `ansible/group_vars/proxmox/vault.yml`:
```bash
ansible-vault create group_vars/proxmox/vault.yml
```
```yaml
vault_proxmox_oidc_client_id: "<same-client-id-as-blueprint>"
vault_proxmox_oidc_client_key: "<same-client-secret-as-blueprint>"
```
### 2.2 Run the Ansible playbook (first pass — realm only)
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/configure_proxmox_oidc.yml
```
**The ACL task will fail on the first run.** This is expected — the user `rblundon@authentik` doesn't exist in Proxmox until the first OIDC login (the realm is configured with `--autocreate 1`).
### 2.3 First OIDC login
1. Open `https://main-street-usa.local.mk-labs.cloud:8006`
2. Change the realm dropdown to **authentik**
3. Click Login — you'll be redirected to Authentik
4. Sign in as `rblundon`
> **Gotcha:** If you're already logged into Authentik as `akadmin`, you'll be auto-logged in as akadmin. Log out of Authentik first at `https://authentik.local.mk-labs.cloud/if/flow/default-invalidation-flow/` or use an incognito window.
### 2.4 Run the Ansible playbook (second pass — ACL)
```bash
ansible-playbook -i inventory.yml playbooks/configure_proxmox_oidc.yml
```
The ACL task grants `rblundon@authentik` the `Administrator` role at path `/`.
### 2.5 Ansible implementation notes
- Tasks use `ansible.builtin.shell` (not `command`) because `command` splits multi-word `--scopes` arguments into separate args, breaking `pveum`
- `--username-claim` is only valid on `pveum realm add`, not `pveum realm modify`
- `no_log: true` is set on realm tasks to keep the client secret out of Ansible output
- The playbook targets only `main-street-usa` since realm config is cluster-wide via pmxcfs
---
## Part 3: Deploying step-ca (turnstile)
step-ca is a lightweight SSH Certificate Authority that issues short-lived certificates authenticated via OIDC through Authentik. It eliminates SSH key management — no more `authorized_keys` files across hosts.
> **History:** The `turnstile` hostname was originally assigned to Authentik. Authentik was renamed to `guest-relations`, freeing `turnstile` for step-ca.
### 3.1 Create the Terraform tfvars
Create `terraform/proxmox/hosts/tfvars/turnstile.tfvars`:
```hcl
# turnstile — Smallstep step-ca SSH Certificate Authority
# VM ID convention: 71000 + 34 = 71034
hostname = "turnstile"
vm_id = 71034
ip_address = "10.1.71.34"
target_node = "fantasyland"
clone_node = "fantasyland"
template_name = "ubuntu-24.04-small"
datastore = "liberty-tree"
vlan_id = 71
bridge = "vmbr0"
dns_servers = ["10.1.71.1"]
search_domain = "local.mk-labs.cloud"
```
### 3.2 Provision the VM with Terraform
```bash
cd terraform/proxmox/hosts
terraform apply \
-var-file="tfvars/turnstile.tfvars" \
-state="states/turnstile.tfstate" \
-var="proxmox_api_url=https://fantasyland.local.mk-labs.cloud:8006" \
-var="proxmox_api_token=terraform@pve!automation=<token>"
```
Create a DHCP reservation in UniFi for `10.1.71.34` and start the VM.
### 3.3 Create DNS record on monorail
- **A record:** `turnstile.local.mk-labs.cloud``10.1.71.34` (direct access — step-ca is NOT behind Traefik)
> **Note:** Unlike other services, step-ca is accessed directly on port 9000, not through Traefik. The `step` CLI needs to talk to the CA API with its own TLS trust chain.
### 3.4 Create the Ansible role and inventory
**Vault secrets** — create `ansible/host_vars/turnstile/vault`:
```yaml
stepca_ca_password: "<strong-password>"
stepca_oidc_client_id: "<same-client-id-as-blueprint>"
stepca_oidc_client_secret: "<same-client-secret-as-blueprint>"
```
**Host vars** — create `ansible/host_vars/turnstile/vars`:
```yaml
---
ip_address: 10.1.71.34
app_role: ssh_certificate_authority
app_name: step-ca
app_deployment: docker_compose
stepca_hostname: turnstile.local.mk-labs.cloud
stepca_dns_names: "turnstile.local.mk-labs.cloud,10.1.71.34"
stepca_ssh_enabled: true
stepca_listen_port: 9000
stepca_oidc_provisioner_name: authentik
stepca_oidc_configuration_endpoint: "https://authentik.local.mk-labs.cloud/application/o/step-ca/.well-known/openid-configuration"
stepca_oidc_listen_address: ":10000"
stepca_oidc_domains:
- "local.mk-labs.cloud"
- "protonmail.com"
```
> **Important:** The `stepca_oidc_domains` list must include every email domain that users in Authentik have. step-ca validates the OIDC token's email claim against this list and rejects any domain not listed.
**Ansible role** includes `templates/patch_oidc_provisioner.py.j2` which patches `ca.json` post-init to ensure the OIDC provisioner has correct domains, client ID, and secret. This is idempotent and eliminates the need for manual `step ca provisioner add`.
> **Init container gotcha:** The step-ca data directory must be owned by UID 1000 (`step` user), not root.
### 3.5 Deploy with Ansible
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/deploy_step_ca.yml
```
Note the CA fingerprint from the init output.
### 3.6 Bootstrap your workstation
```bash
step ca bootstrap --ca-url https://turnstile.local.mk-labs.cloud:9000 --fingerprint <ca-fingerprint>
```
Ensure your SSH agent is running:
```bash
eval "$(ssh-agent -s)"
```
### 3.7 Daily SSH workflow
```bash
step ssh login rblundon@local.mk-labs.cloud --provisioner authentik
```
This opens your browser to Authentik, you authenticate, and step-ca issues a short-lived SSH certificate (default 16 hours) loaded into your SSH agent.
Verify:
```bash
step ssh list
ssh-add -l
```
---
## Part 4: Host enrollment for step-ca
Host enrollment configures VMs to trust SSH certificates signed by step-ca and to present their own CA-signed host certificates.
### 4.1 Group variables
Add to `ansible/group_vars/all/`:
```yaml
# step-ca client configuration
step_ca_url: "https://turnstile.local.mk-labs.cloud:9000"
step_ca_fingerprint: "<root-ca-fingerprint>"
step_ca_provisioner_name: "admin"
# Principal-to-user mapping
step_ca_principal_mappings:
- local_user: wed
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon
- local_user: rblundon
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon
```
> **Why principal mappings?** The SSH certificate contains principals derived from your Authentik email (e.g., `ryan.blundon@protonmail.com`). When you `ssh wed@host`, sshd checks if any of `wed`'s authorized principals match the certificate. Without this mapping, certificate auth silently falls through to password auth.
### 4.2 What the enrollment role does
The `step_ca_client.yml` tasks:
1. **Install step CLI** — from Smallstep's apt repository
2. **Bootstrap CA trust**`step ca bootstrap` to trust the CA's root certificate
3. **Configure user certificate trust** — writes SSH user CA public key, adds `TrustedUserCAKeys` to sshd_config
4. **Create authorized principals directory**`/etc/ssh/auth_principals/`
5. **Create authorized principals files** — maps certificate principals to local users (e.g., `/etc/ssh/auth_principals/wed`)
6. **Configure AuthorizedPrincipalsFile** — adds `AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u` to sshd_config
7. **Sign host certificate** — generates a one-time token (delegated to Ansible controller) and signs the host's ECDSA key
8. **Configure sshd for host certificate** — adds `HostCertificate` and `HostKey` directives
9. **Automated renewal** — systemd timer for weekly host certificate renewal using SSHPOP
### 4.3 Enroll a host
```bash
cd ansible
ansible-playbook -i inventory.yml playbooks/deploy_common.yml -e target=scrim
```
> **Note:** The enrollment role requires Ubuntu (uses apt). Fedora hosts will fail on the step CLI install task.
> **Note:** The `step` CLI must be installed and bootstrapped on the Ansible controller (`city-hall`) for the `delegate_to: localhost` token generation tasks.
### 4.4 Test SSH with certificates
```bash
step ssh login rblundon@local.mk-labs.cloud --provisioner authentik
ssh scrim
```
Verify certificate authentication:
```bash
ssh -v scrim 2>&1 | grep -E "Offering|certificate|CERT"
```
### 4.5 SSH config for short hostnames
If `local.mk-labs.cloud` is configured as a DNS search domain on your workstation, short hostnames resolve automatically.
Recommended `~/.ssh/config`:
```
# mk-labs hosts — certificate auth via step-ca
Host *.local.mk-labs.cloud
User wed
# Short name resolution for mk-labs hosts
Host !10.1.71.* !*.local.mk-labs.cloud *
Match exec "nslookup %h.local.mk-labs.cloud >/dev/null 2>&1"
HostName %h.local.mk-labs.cloud
User wed
# Fallback key auth for hosts not yet enrolled
Host city-hall
HostName city-hall
User wed
IdentityFile ~/.ssh/ansible
```
> Do NOT use `IdentitiesOnly yes` for mk-labs hosts — this prevents SSH from offering the certificate from the agent.
---
## Appendix A: Troubleshooting
### Authentik
**Connection reset when hitting authentik.local.mk-labs.cloud** — verify DNS resolves to `10.1.71.35` (lightning-lane), check Traefik dashboard for router errors, verify Traefik can reach backend.
**Auto-logged in as akadmin instead of rblundon** — log out of Authentik at the invalidation flow URL or use incognito.
**Orphan Redis container warning** — run `docker compose down --remove-orphans && docker compose up -d`. Redis was removed in Authentik 2025.10.
### Authentik Blueprints
**Blueprints not discovered** — verify `.yaml` extension (not `.yml`). Check volume mount with `docker exec authentik-worker ls -la /blueprints/custom/`.
**OIDC client ID is literal `${VAR}` text** — use `!Env VAR_NAME` YAML tag, not `${VAR_NAME}`. Verify env vars in container with `docker exec authentik-worker env | grep STEPCA`.
### Proxmox OIDC
**"too many arguments" from pveum** — use `ansible.builtin.shell` with single-quoted `--scopes 'openid email profile'`.
**"Unknown option: username-claim" on modify** — only valid on `pveum realm add`. Delete realm and re-add.
**ACL update failed: user does not exist** — expected on first run. Log in via OIDC first, then re-run.
**Redirect URI mismatch** — must exactly match including `:8006` port and no trailing slash.
### step-ca
**"email is not allowed"** — add the user's email domain to `stepca_oidc_domains` in host_vars.
**"permission denied" during init** — fix data directory ownership: `sudo chown -R 1000:1000 /opt/docker/step-ca/data`.
**"no such file or directory: password"** — secrets directory and password file must be created before init runs.
**REMOTE HOST IDENTIFICATION HAS CHANGED** — clear old key: `ssh-keygen -f ~/.ssh/known_hosts -R <hostname>`. Goes away permanently once host certificates are enrolled.
### SSH Certificate Authentication
**Certificate offered but server rejects it** — check `AuthorizedPrincipalsFile` directive in sshd_config, verify `/etc/ssh/auth_principals/<user>` exists with matching principals, inspect cert with `step ssh list --raw | step ssh inspect`.
**"Could not open a connection to your authentication agent"** — start agent with `eval "$(ssh-agent -s)"`, re-run `step ssh login`.
**Short hostname asks for password but FQDN works** — ensure search domain is configured, ensure no `IdentitiesOnly yes` blocking the agent cert.
---
## Appendix B: File reference
```
homelab/
├── terraform/proxmox/hosts/
│ ├── tfvars/
│ │ ├── guest-relations.tfvars
│ │ └── turnstile.tfvars
│ └── states/ (gitignored)
├── boilerplates/
│ ├── authentik/
│ │ ├── compose.yaml (with blueprints volume mount)
│ │ └── blueprints/
│ │ ├── proxmox.yaml (must be .yaml not .yml)
│ │ └── step-ca.yaml (must be .yaml not .yml)
│ └── traefik/
│ └── dynamic/
│ └── authentik.yml
├── ansible/
│ ├── inventory.yml
│ ├── roles/
│ │ ├── common/
│ │ │ ├── tasks/
│ │ │ │ ├── main.yml
│ │ │ │ └── step_ca_client.yml
│ │ │ └── handlers/main.yml
│ │ ├── docker-host/
│ │ ├── authentik/
│ │ │ ├── tasks/main.yml
│ │ │ ├── defaults/main.yml
│ │ │ ├── handlers/main.yml
│ │ │ └── templates/env.j2
│ │ ├── step-ca/
│ │ │ ├── tasks/main.yml
│ │ │ ├── defaults/main.yml
│ │ │ ├── handlers/main.yml
│ │ │ └── templates/
│ │ │ ├── compose.yaml.j2
│ │ │ ├── env.j2
│ │ │ └── patch_oidc_provisioner.py.j2
│ │ └── proxmox/
│ │ ├── defaults/main.yml
│ │ └── tasks/
│ │ ├── main.yml
│ │ └── oidc.yml
│ ├── host_vars/
│ │ ├── guest_relations/vars
│ │ └── turnstile/
│ │ ├── vars
│ │ └── vault (encrypted)
│ ├── group_vars/
│ │ ├── all/
│ │ │ ├── vault (encrypted)
│ │ │ └── step_ca.yml
│ │ └── proxmox/
│ │ ├── oidc.yml
│ │ └── vault.yml (encrypted)
│ └── playbooks/
│ ├── deploy_authentik.yml
│ ├── deploy_step_ca.yml
│ ├── deploy_common.yml
│ ├── enroll_step_ca_client.yml
│ ├── configure_proxmox_oidc.yml
│ └── update_traefik_routes.yml
└── docs/guides/
└── service-deployment-authentik-and-step-ca.md
```
---
## Appendix C: Key decisions and learnings
- **Boilerplate-first for Compose** — if a Boilerplates CLI template exists, use it. Ansible copies the generated files; it does not template them. Only the `.env` is templated to inject vault secrets. step-ca has no boilerplate, so Ansible templates the compose file directly.
- **Traefik routing for cross-host services** — Docker labels only work when the service and Traefik share a Docker network (same host). For services on separate VMs, use Traefik's dynamic file configuration with the backend's raw IP and port.
- **DNS always points to lightning-lane** — service hostnames resolve to `10.1.71.35`, not to the backend VM. Exception: step-ca is accessed directly (port 9000) because the `step` CLI needs to trust the CA's own certificate chain.
- **Two-pass playbook for Proxmox OIDC** — the ACL task requires the user to exist in Proxmox, but the user is only created on first OIDC login. Run the playbook once (realm creation), log in, then run again (ACL assignment).
- **`pveum` CLI quirks** — multi-word `--scopes` arguments need `ansible.builtin.shell` with single-quoted values; `--username-claim` is only valid on `realm add`, not `realm modify`.
- **Naming convention** — Authentik was renamed from `turnstile` to `guest-relations` to free the `turnstile` hostname for step-ca. Service-facing DNS was unaffected because it points to Traefik, not the VM.
- **Authentik blueprints** — use `.yaml` extension (not `.yml`), use `!Env VAR_NAME` tag (not `${VAR_NAME}`) for environment variable substitution, mount at `/blueprints/custom:ro` in both server and worker containers.
- **Redis removed in Authentik 2025.10** — all caching uses PostgreSQL. Remove Redis from compose if upgrading.
- **Pre-generated OIDC credentials** — client IDs and secrets are pre-generated and stored in vault, shared between the blueprint (provider side) and the consuming service's vault (client side).
- **OIDC domain validation in step-ca** — the `--domain` flag restricts which email domains are accepted. Every Authentik user's email domain must be listed.
- **SSH principal mapping** — certificates contain principals derived from the OIDC email. `AuthorizedPrincipalsFile` maps certificate principals to local users. Without this, certificate auth silently falls through to password auth.
- **step-ca data directory ownership** — container runs as UID 1000. Directories created by Ansible as root cause "permission denied" during init.

1
terraform/proxmox/vm/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
states/

24
terraform/proxmox/vm/.terraform.lock.hcl generated Normal file
View File

@@ -0,0 +1,24 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/bpg/proxmox" {
version = "0.97.1"
constraints = ">= 0.74.0"
hashes = [
"h1:dM8LVw0VrXaf7JE5FIx9RFFz5Pe7qx3niSX4WA+fPhI=",
"zh:000fd1839d1119c6d996673a6206ae846bfc19554b0b0f717c19945b4d2836ae",
"zh:10f9342113ebd509101e9221bc5ad9fffbbe9b218db4446e69704dd829d4c52e",
"zh:1699d79995e398ac05272d73a326e8ad8360625c6f4c263314b04b9bc4263426",
"zh:18b767117d3619d4ab2044e3570e2ac2e9e51f5697a21d30d7892449c8943eff",
"zh:32bcbcc2e8931ba5e2bf735dd2825b588a34785fe91b4e7ffe4f5289171bb159",
"zh:5f62c0b7e648b92d4aa2242658c02dec2b9fda15508cc9b440d123983dfec197",
"zh:6596609b064b6ff1bece5a2701b7d400275e8e1f638cce8af982f1a0fc9ded6d",
"zh:73ae59f31d0d1bb364d79cf0b52ce2f203b5b69dc80a43c0584af0e272bb8a43",
"zh:8a98f8c70315438c3dd4ff417906d6908f2cc59286e2fc91a8968dbcd72afcbd",
"zh:a0b9ceb4723af321b30c91c3faf5b6513a2ba75289bc36d8b4d1cea75d2c5fbd",
"zh:a690356bee6cb924d811724dfa3e08d43ba6f7ec901cd543becbb1f7973cb8f8",
"zh:eefd1b61024ec1866fdc8fa20b292accaab65dcf8ce0f4b2a08f418efbeb6a14",
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
"zh:f6e2183f67a8b8bfbc332a6798d182727c836327f758deafebe332f92f315758",
]
}

1
terraform/unifi/dhcp/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
states/

24
terraform/unifi/dhcp/.terraform.lock.hcl generated Normal file
View File

@@ -0,0 +1,24 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/paultyng/unifi" {
version = "0.41.0"
constraints = ">= 0.41.0"
hashes = [
"h1:vE4C9E7NtYUC7otQrAvNNkDFBHqEMxkUlcqJhLWchLY=",
"zh:03ddd3aee05a08e1446f75a7b3f52810181d3307728cba08ce8fb67f109a9c00",
"zh:11b14b79ad02b0a55fd6116b10c0eb6fab432dd7d1f3527af0e2055adf292451",
"zh:18c0eb19889927f115a1e05d64f59b4e8d530ccdf1a8b574940a86be20973564",
"zh:2df9ca0c21830d2757758e574b19d0d4e54965ce80dbbfb3f124db1dac3d7e8f",
"zh:36274af3b7e8b08ba69c04a226c63e0dd2ec386c583288ebd7bc2a30e349ee8f",
"zh:413eb222ef30889bab33ccbfc46c9fb64307555da34eac4625d51e696ac72e1d",
"zh:4839814ff9f405a13397ffadd6f1052c770b88802280a4d8cde066f9a19718c7",
"zh:9547b7831852cc5b9c0fd13ab447d48539eae94582c8725ad255af36e31fb5d9",
"zh:a855c89b12326eb1c89bbf292a2bb1de3651794e3409d5012076ada89aabdc8a",
"zh:aef12a33b90fd77a9bf4e9d397966ccbfa4a037a648a1725074aff2db2d90fb0",
"zh:b3c72a6a02e29b4d21aa0d0831a272ca7cb82c3f8c2c3c7f09fcc2d2dcd78752",
"zh:c8354eaaab5f526e8e530b098544c7583a0f0b5b27d67500c7b3e9da56a3a7e5",
"zh:dc29f1e70f20ce86d3c6a66c7a817616f993a1cf9d941604dfd5222a06992c4c",
"zh:e772779333419f34d2c6da333c7f7d235a5a34f21ea47636b548e132aed74f3b",
]
}