diff --git a/.woodpecker/build-caddy.yml b/.woodpecker/build-caddy.yml new file mode 100644 index 00000000..e6508b9e --- /dev/null +++ b/.woodpecker/build-caddy.yml @@ -0,0 +1,31 @@ +when: + - event: push + path: ".woodpecker/build-caddy.yml" + - event: manual + +steps: + - name: build + image: golang:1.24 + commands: + - go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest + - xcaddy build v2.11.2 + --with github.com/caddy-dns/cloudflare + --with github.com/ss098/certmagic-s3 + --with github.com/hslatman/caddy-crowdsec-bouncer/http@v0.10.0 + --with github.com/hslatman/caddy-crowdsec-bouncer/appsec@v0.10.0 + --with github.com/mholt/caddy-l4 + --output caddy + - ./caddy version + - ./caddy list-modules | grep -c layer4 + + - name: release + image: woodpeckerci/plugin-gitea-release + settings: + base_url: https://gitea.renner.uno + api_key: + from_secret: gitea_token + files: + - caddy + title: latest + tag: latest + prerelease: false diff --git a/.woodpecker/deploy-infrastructure.yml b/.woodpecker/deploy-infrastructure.yml new file mode 100644 index 00000000..36416aa7 --- /dev/null +++ b/.woodpecker/deploy-infrastructure.yml @@ -0,0 +1,85 @@ +when: + - event: push + path: + - "opentofu/**" + - ".woodpecker/deploy-infrastructure.yml" + - event: manual + +steps: + - name: validate-secrets + image: alpine:3.21 + environment: + TF_VAR_proxmox_api_url: + from_secret: proxmox_api_url + AWS_ACCESS_KEY_ID: + from_secret: tf_rfs_access + commands: + - | + if [ -z "$TF_VAR_proxmox_api_url" ]; then echo "Missing proxmox_api_url secret"; exit 1; fi + if [ -z "$AWS_ACCESS_KEY_ID" ]; then echo "Missing tf_rfs_access secret"; exit 1; fi + echo "Secrets validated" + + - name: plan + image: ghcr.io/opentofu/opentofu:1.11 + directory: opentofu + environment: + TF_IN_AUTOMATION: "true" + TF_VAR_proxmox_api_url: + from_secret: proxmox_api_url + TF_VAR_proxmox_user: + from_secret: proxmox_user + TF_VAR_proxmox_token_id: + from_secret: proxmox_token_id + TF_VAR_proxmox_token_secret: + from_secret: proxmox_token_secret + AWS_ACCESS_KEY_ID: + from_secret: tf_rfs_access + AWS_SECRET_ACCESS_KEY: + from_secret: tf_rfs_secret + AWS_REGION: "us-east-1" + TF_VAR_unifi_username: + from_secret: unifi_username + TF_VAR_unifi_password: + from_secret: unifi_password + TF_VAR_unifi_api_url: + from_secret: unifi_api_url + commands: + - apk add --no-cache git + - tofu init -backend-config="access_key=$AWS_ACCESS_KEY_ID" -backend-config="secret_key=$AWS_SECRET_ACCESS_KEY" + - tofu plan -out=tfplan -no-color + - tofu show -no-color tfplan + + - name: apply + image: ghcr.io/opentofu/opentofu:1.11 + directory: opentofu + environment: + TF_IN_AUTOMATION: "true" + TF_VAR_proxmox_api_url: + from_secret: proxmox_api_url + TF_VAR_proxmox_user: + from_secret: proxmox_user + TF_VAR_proxmox_token_id: + from_secret: proxmox_token_id + TF_VAR_proxmox_token_secret: + from_secret: proxmox_token_secret + AWS_ACCESS_KEY_ID: + from_secret: tf_rfs_access + AWS_SECRET_ACCESS_KEY: + from_secret: tf_rfs_secret + AWS_REGION: "us-east-1" + TF_VAR_unifi_username: + from_secret: unifi_username + TF_VAR_unifi_password: + from_secret: unifi_password + TF_VAR_unifi_api_url: + from_secret: unifi_api_url + SSH_PRIVATE_KEY: + from_secret: ssh_private_key + commands: + - apk add --no-cache git openssh-client ansible + - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" | base64 -d > ~/.ssh/id_ed25519 + - chmod 600 ~/.ssh/id_ed25519 + - printf "Host *\n\tStrictHostKeyChecking no\n" > ~/.ssh/config + - tofu init -backend-config="access_key=$AWS_ACCESS_KEY_ID" -backend-config="secret_key=$AWS_SECRET_ACCESS_KEY" + - tofu apply -auto-approve tfplan diff --git a/.woodpecker/security-scan.yml b/.woodpecker/security-scan.yml new file mode 100644 index 00000000..b341f273 --- /dev/null +++ b/.woodpecker/security-scan.yml @@ -0,0 +1,44 @@ +when: + - event: push + path: + - "ansible/roles/**" + - "opentofu/**" + - ".woodpecker/security-scan.yml" + - event: cron + - event: manual + +steps: + - name: iac-scan + image: aquasec/trivy:latest + commands: + - trivy fs --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed . + + - name: image-scan-redis + image: aquasec/trivy:latest + commands: + - trivy image --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed docker.io/library/redis:7 + failure: ignore + + - name: image-scan-postgres + image: aquasec/trivy:latest + commands: + - trivy image --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed docker.io/library/postgres:15 + failure: ignore + + - name: image-scan-paperless + image: aquasec/trivy:latest + commands: + - trivy image --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed ghcr.io/paperless-ngx/paperless-ngx:latest + failure: ignore + + - name: image-scan-gotenberg + image: aquasec/trivy:latest + commands: + - trivy image --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed docker.io/gotenberg/gotenberg:8 + failure: ignore + + - name: image-scan-tika + image: aquasec/trivy:latest + commands: + - trivy image --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed docker.io/apache/tika:latest + failure: ignore diff --git a/ansible/inventory/group_vars/all/vault.yml b/ansible/inventory/group_vars/all/vault.yml index 3c66cee6..66d25e83 100644 --- a/ansible/inventory/group_vars/all/vault.yml +++ b/ansible/inventory/group_vars/all/vault.yml @@ -1,134 +1,146 @@ $ANSIBLE_VAULT;1.1;AES256 -64613561323132616332313332383530636162663732336662313633366633633863646466363566 -6334363462306533316636313338313062323065353938370a363539366139376232373036306231 -35636133313035623931353264336232663335323162653661333361333161326234306336633030 -6262343662616230330a306663623537643135653930333965613037653065343732633430633337 -35616636393763373736393562656262366564663664336264353164383434316163636230356537 -35383364313966333335643664353438393564386133363463383565623465616663396535363563 -32383663393434396631613934323335656230393532316436326262643731636132383234316238 -38653030626638346365643966626666666138616631646335343561383062376566623638373235 -38353264383238396233386636333532336536373237396636333232643066336361396334646437 -61346361393465663365363766396164613562323034633130653134623165613966623430376232 -65656266386439666266626231626136353635393566303866343233623365316562383463393830 -64336230613963323639343530623236363439633866336433356438383433336137323065633332 -37656237336663663431323832393465383633366137333833373865323037663436383831363663 -39663363643631626535363365353966333936363133613662633965316361306363376138646330 -30373530346136373233616539356435366434303865623532356132653937313664376461393433 -34363536363537376239363466383966373764373161366135303263626239616239313566373831 -30646638313936326165633337663339323338323461383534636439633238326236363938663865 -37653962333037323561643566356566326533613636313031646235623562333139666535616135 -35343134323931386163653331393232613963346261353863663061356630663737353834333532 -32323266323164386165316139656134613537356265353063616434393031323330623430373365 -61366238393666616235343465303731643662356132613732646533646464313439323932366336 -62643637636330653062303761356662343339343266343865336532653237346466623235653763 -61376137643238326562363566623165316565643165616366313138633534663136326337336366 -64636365656361303063663135333839313631336437376262626363386565643465363938306362 -62643833303434373761623738306563313534366166623035636233366537383061656333343562 -37323764356261303563383135613632396462633735626334393139383539306262653637663434 -66396363633761396463386539646336313334613966363466653736643161613430613037633636 -65383035613263323264386639303034633435343966393033356638373465356430653238626638 -37383035646162323834323931303534303935306163653935343130633439616531323334663162 -65313635656333316363646563353864393335306234303237656134333739363431363737356531 -33613534373233313363363463333261616135363131346161393635373533323531623037366664 -33386537323231653764656338626566666634613531663466656163383935356431616565316262 -65396238613630646533656632623339383735363136396366616136666262336461326333356636 -64663839643134353239323236393763303165366535653566653163386239646634346564383463 -38653739383864643537626637306530316238393061663663653862386562623365643133333433 -66343438303033616438343462313430383738386161653966373233613161626566373337336237 -36336535393837656631613864663632396236376663383437653766653735623230383365633639 -38653531623364306433363535316465313165613333393830343466663837393062323662396238 -66373632396461653332616438313039393764333835653530623766313637333632376338363865 -33396435623836643834623739633035323934346134343936303261663534336439363035633334 -37646232353934356630353932333737353361656362656366633164383365336134613333353566 -35663339303366653963613335343531623434653131376362656636623438386330363663326466 -39643531616131386333616231366533343531306364643334646664386438656565636664333835 -39646537376136303832353630663538613633626261333031636134313835316330333563333731 -32663839613237383730306634613833666639386538393361313330316338633465396134353238 -61313534666366626466306133373832656233633638613333343262356236646639666562653163 -31326131663061623831326663643737616566363139393365363464383130346161653932366437 -61386664653832663265373765623861383662663466653337623136306366343236643137663830 -62353539646335363632316663663465653764666533646131633361393731313461663939653338 -30396232353138386566616635343236333636343637383531613662353263353665646234613563 -65666662346361346332623037643732376537353832646637373066653366643162336263383236 -30333861323539623263653730623632653134326239633661666463643839616466643936386336 -31386162333731356361346133326461343361653330643533313736396535646365306635393739 -39303139393339336635646462343134336134333662663431333265643665313566373533346530 -31633430653236353932393863643635356539396138666535356434353666363530386562616636 -32626535663136373537343862363564643035306139623163666533306161326138663534356637 -31383162663837653538366163393762326631616134343133303636383265366430353765366263 -61313535303566383436363833353063633632613633643364306266663662373736373865363136 -64306162653765343463326465313935313261663866623639363830336565383632363763333438 -66393732616330303338386161376638663764353063383463653730303130313731366239333033 -64626561343863363565643932373161366331316131356561666531326637383566643137336637 -61653931323637623433323862373664313139653536383538303638326461616333386539326564 -34643634656662323832383666316436663335343136656364396134343961653738313730613162 -36653134313336363263336238393163653837653933363434353264313038356632626164313233 -35663366656535636663346239663332653161633765333534383662356139383237363830616430 -31363635616235666661303161356436653432396263343261623562616462666264613435313238 -64393039366130336337656362336264303538323735313136666132393563363633623066386237 -63626537323638306265323433333939383735626633383162363262303239373936303038383638 -30363331656137303435363862636365366538336337613437363236326339386230393232646239 -38613763326436396637356361323862393630306632386266353532383861326337343332663163 -35623938316330353731306136663565346265346535633530386131316662396434303034376666 -63366563396234656363363738333663373737663333313937653233376533316638636465376631 -61313964396264316137343335663365393638633230353332323231316132313666383338663033 -35653762303961393933353964356662643864636139663265363963373163643763643964643362 -35616235303830313564636431653031666334313063313862306233316562386235313363353735 -66626334313838316462616232336464336131386335386263666434363966653739316431646366 -61633330366232613237626133393365393733393162333864306239663066613330653739356563 -61343630373665623562383431383165306632336236363065626161346534633663383938643061 -65613565613934656366323065343537623932373435356563303535643038373563336462383438 -66376466666635333261313661333564393865343034646139396535363131613938663836393035 -65303863666666613733393437653561313661363738643562313464376430396530363530643836 -35333964663738363734313438383730316435333834616139636133626230633037363566636663 -62646633393237383631616664366361656234643438353530393738366662643931653665303837 -37353061383765623065313730303036303737376132393262366566353831323931633434663039 -37623466623432366261613561663365373138313432636263363239613364613139373530356531 -39323238386335383235336334376137356635373665613436343134643361653733643633323938 -32326163336335306262353938366335353164653239636233383665663761613835323938336337 -32616432646437326632373633373863343333353331383435316137313133386166626135623366 -66643833343164356434346666666532323339313365353731343364316634303561343230633639 -39663861326561393830333432326438626233313239636234323839306631356466336635656337 -32633263393565333834643736346537376333663363633266306332633130643936356330666231 -31373531353935363364353730313764623535313466376363643630633434643539383133643134 -33616531653063653436636231666234373466383031363866366130336134653066393930303263 -39306462643065333439383266326139316463666430313230626339303739626137333130346430 -34303339366462636565396634653664383363376462373731613135656563363762643563333864 -65363436373936383332396362643635613433333832376563643264326166333831663262336236 -65353631666162373162333533343439636265353038323761393738343861336231383365623061 -62313936373466623632636135616339363735313462343435313230336237303461313336353139 -62623139653063643536363066623338326662613266386531636166323965383038353333396131 -35323330616437343036626462306261346633653038313033613763373931666461373166323365 -35303231373332306238313066353565306632666433343861363063633563336233636339373661 -64613633623431313734653931386261353733383764653865663534316465323034316334333832 -35313461643365626465636138333433346434616138393933353138646366343938666463656633 -64366365346663376430313336623730336563373066613434386266303232646164376538656361 -64613932393666623534336463346164316664343065346330633966356633333661373433643333 -30313931653464353363306263666137613531326461646638343335613237393662373836386366 -34386264316566336464346636373435633638353639323934396534313635353233653163653963 -63313730323866616663663931383534613563393065333634306130393035313137316361373333 -66623137383238346666346663313165356232363930633334613134346466303462653563376335 -38313039323664653939343865623837363231643862393130336230356464666165623763316632 -63303561633535373866386364386162616665363130373563626439316333326438326565326565 -31623364336533383666336137356134343364383934383932363839363637636636356633313531 -66373437373238626461393866333662636136383732636534666133343232656466646636616562 -66656131666139386130343763656664393435633638373839333233373863633631386632663238 -37643430623337633536636461333137353437303930306337303564653635373230643364633361 -66636366646133343535343633663135623964613230353965393265353364653739303032303038 -37623230343864623235663436393562613538653362306561653032626262303733353062386633 -38353462363536373930363639653665633164383333396561383962353335353638333164663336 -32383365376434333639313365616631323232643136353135386639383166633366383763626234 -30323236366630313964653465626262376131653261333133313565613564313162633039643034 -37396561316465323465376230303939393936353064383132393236623865306336383563373531 -63623565346332353266626232306366393331363338623133313731333531623738346263343933 -63366534386363313535396466353431336263353631393133346363626661393163643666306563 -32356233376662653364626338373462363861303434313663646231636237326236663133386234 -61616430653666653933336438313062373636623466626534343361363437396535373839333331 -62393061366138613765303831343066666435643632373931343062323335313938383338393866 -64386636383634303039643161323139363536326536663439663365333530623262653734376662 -66303864666430623135393036643834376565646134306537393134373263663139396361623530 -33333365363964613361333137323939313630336535633562613734383763363464326431613463 -30376235373761323362363263373137633030373833303837303535643330363134663030623733 -37636330323337303439383035386465643235376162366166643563616163373230326263356333 -64333438396563663662333636393162333836653464383739363434303762333161393135323039 -62393963636238616339616563613366366230346434633234323732346637326537 +38366462313335633039306562356331316263336261356238306362306637323263376564316365 +6661626534313765326163343837633762383939666266610a306566386530613663663961626666 +63323564383763393533303534353763306264313634663264376561666264613634353937396666 +6239313263396637650a643232643165383232326630326230666637613565366637373639323361 +33316433303832646562373164326264383230613332643237633065663437393731306531346632 +62343237343038643337346365336261653862633466663138306639633739376234643362383833 +64356163666165613065643434393630326262386332393865306238376131646133396633393366 +33396663323137313231633864376639653330653131363933383236626536366539646131626165 +63663565636661336238326330363865383033613663343133626362383032373065336133653665 +64653231663534616330313536623465363036396539383130383065363234386362353662636533 +63316236363437633339336634343137386437386433613666613464376463626363376565333630 +37613761343933643831306333353231363234363734356331396335316434366561383834623838 +32353362376636636533613533333230363233626364353739643164646137316632626132353363 +37663136383661653030653039626336323631316161616235306230353335663665376265373064 +38663663373963313932383439313262373266303933383336343035623933613135333739333635 +37336334363761646666386636373331646462386430643732333139383762333237366133326538 +61393332663163653066316264303165616431343463643432646637383832613535306635636263 +63643132333762636137663130636636636239626633636333613032373635626530663633383036 +39643366336365623736366162646632633662636364353330313162333730666333303231646461 +33336138313139643066363138303263313665346536326634346565666536306530313539356166 +64363933613530633463646534376136386161346233346362313835666234336539343733346239 +33373636656263363566373761303662353037303132313039363036323739653231636364386263 +61613336306238363366616136643735343264646266366361663834643235376331373562323934 +63653735613038306433643836383734336333383361653661396633373332376334656661393365 +31623262353362376335396238616563326537363462346534373663326464303338663061353430 +31636638346136323662626539613430306561633235626465613236633937613032383861633962 +38343030356661636463353435363132666662643362376635656535373265306630306334643563 +61323766646135626337333365363237666134666636353233613838633138613663613565613762 +30326265343535613463383936386630373634396536636535356232373233336531323465306230 +61383633636663623139393834623435353833346261663737303066313866313464636138613433 +34326437353235363635646261663636313363356461653061663135356262653938393837323333 +63353466366565366435313039666534653633313133336532393838363335666332666335333538 +32336663363631396265383831643031313030303436306532333062356365333338653236356239 +38373261336638613464623039343535396562313231323865643130333263643536353865623434 +36353535646663616665353139653963393139396365633464323938336130303662633136303039 +34623338633235396138363863336539323765666539663839373363313538383235306537666632 +61386163386161376236333666336562613536363336643436633164326631653730383535326261 +38343062306334356462613833323765376239333335656331643663613665363465383866393161 +63393864323863643666663533306239353832326266623335393536343465306463356363646366 +64643434656434633132663635643634656232613734343032623634636439653563663130346332 +30376630393534306262376433383963373735303330656231353566666533393536373165366230 +35303137376631333634633230643633353234613134646162313031376466643433303165663138 +63373138393430643736653765626133316632396339353764663462306532386138326138616566 +33646538366538633937313234623963336564313663353030633361633130633035383166306664 +38313563353065643661373135336136363639363363626131643766616333313439643533336631 +61653461343639303137656136363733306365343462626339633636306163643532346435393839 +64653166343535663236353164346337623333343565643931633635306262373466383163636264 +33343362303432636535643863666632386365356334613264313333653366376230656663366635 +62323030323531323333343039646262373366353464366533323234666364383736663035346364 +63656166373337663636633532353331306561626433363131363865316261633733383039363339 +61623737363866373035663061313038623936313034613662616139623837393833333039313461 +38353434373731316137636133626462643335616632353762396539666363366532356637653964 +38613863336262346465323630626434643035376335323233393361633839353333643532623135 +35646336313166633332663438373032313532643333626466636130386435623063643866383434 +33386666613638353966333034616363316234633533303133623233346538313139333037646336 +30643862383436303333656663313336306163303266396132333036316437633239653731626539 +35613739316665616237616161343964646366303336613738643433353631373965333261336630 +63623235323734663939356432323733636532373066316263373863306561633330646663613436 +66623037316439653666353364386537316636666239663561626137343737306263313634336139 +61636430633964636233303362333636346563313866626133326461613836323739643466326465 +37386362303338323261353462333434326231303066666461643833306261653539646438336638 +33336631666436303236643963633234336261373331316231306630313538616439393138383363 +31646233626239653965323762333038653138366238306135383661306561383831333837633439 +35636138643961323332393131633438333137336438356334623135643766663630623165653036 +62626261373036623430633263633330316665353835633864633862373266346333616366613661 +33356233623638343939646465316431396534616439336632336138383566636338376266366539 +39336235653937633866393030623162393636323433636364616662356263336262623766646663 +39626235623262653264663935313066333964653838303666386665616463333566646139643865 +65643361366465303732306231363532313231313865623236616639643333356662366166383533 +38303337353261386134303936663637306139303066623332336162623364643830653866323931 +30626363653366383661363931366137343030316639333531306261373338623062373133306162 +33613836363865653330303032653461646163653264376138353061386563363966313236636363 +35306130333638663932636137666262316663353535313131616235326437353036643763663739 +63646437306265333636393136346261616464653635376538653262663131336161373766343132 +35663637333961383537663231373532363761626465336563386435646135306532643364653961 +61336462653933633833396666386331363331396437363633346366616336636431336336633734 +35373062386235303637346565306533353936633065633839303735643938393938393635356535 +35623061373833396663633362323731333563366331373031326230383965643561346563623562 +62313737366634643731633064316532353832386235633736623562623434653432356566616330 +31386561656636643163353931313964633935376530666334333937663434383835633763663265 +61336362613635663139356666343732383937306465613332656661323232613436343530643937 +34626338343436323735313530666537656638313964376134366338653861663434336339383534 +65303037626362616631353966633636393732306165313265306663633737316631346465333361 +62613835313832353731363038326137633064623432613765613938336432653333373130323130 +63373538633461343237323235393631663861643961636134656438346162643937336462623965 +33613037363861613635316431346332366366356436656438616532666435613536643237343834 +36646633306362646263666135653730643562373639316339393330636362336262343231303438 +35626134656330386438313738613462383930646132653639373839333030363630663363333263 +35336136353539306464623761616631316131646231643838396432363337313466396333366439 +38653538376665343863383438323837343235323064363032316662663866333139376364346562 +32326334323562626532643863303833656661356231353963306232386364363463343437356237 +37623366313632396639306239636263346261356635626537383537623366366233396235366435 +66643834353931353062643162353965646336316161353937346561646166323535353535386564 +61316131356662333831613137643837633937313932363565303533376464376464643565363262 +61666336643430656162643037653762636666373965393532326635633732343739373664633063 +66353231323562343939363436326664343666653930343931356464626364626231313935656138 +62306634303831653862633663653637663539366364313063333965396136623366653961643430 +38346266656263323836613836653139346339333066356234366165373434363633323661663631 +35653733323838383230656631326465643330636231383734633132653833333833373262626338 +65363431373266386332323138396261343931316435666232636232356431363861326535366337 +63346435656263373133366431376162366331383038383531653165323464636631336631373063 +33333431363835313861616565633531356634643037356663333233666134316533633362633364 +31366564626339646265613334326663353233663937306236313466626461383862356334326130 +62616533663636373331663839313533313631373931353331383661653264653735383063343638 +38643931343339333636393931323162353233323963323032666434376561313030366530626362 +32383432626434306237376539333338303336613138663135383332663038353265616664323638 +63333330653565636465393561656137633630663534313331626537303064643438616163666130 +37336633383162363364383636643662373263393062636536656534653936306365313736343834 +37386564626632363766613964383131316234643762333162363539323436653336346233386562 +33306565656433313138333966323837343761373566623839383234643461653433373665393164 +30633931356533383961623734623439636262356365386133616430326131353934383933643566 +66636465373236356530313131633238633236393362313964373230373738316165646235333862 +66373963356335343139646263366639623931643662373439616533666534326531653863363631 +30643736346430656534666238643161323539346463353430386436316532343832303234653234 +35366266376464323933316230326538626433373532626639346662646664396261306531366634 +33623230633133646238373736666430323062626265393261623362333333366632366537343033 +66656534393135343261656366656539373131353830313838376235336531643731396436633862 +34353061663234646336613363333565633464616235623236623831666436643933616361616130 +63666535363539353039356130653937623931643166626265386333633536356663643262623638 +61393462663466613462313665363235663534373039653634636664363633383336636463633663 +34333732613839663263313438626665323935633965613664656466373033393231373837633439 +32653432383838616236356337356563306237313939376365663965623635613439303337613230 +30353235306263346561623763616662376362626366313631396539616135336336666561663564 +61366136356565653832303038646365653034353765383237363336373763346434653932616432 +39626136633332616330646638386134613764373237633239366164643261313863616435316136 +63316234643737613638643738613837366237633139353136656565363661326366353338663334 +31333930363965623463666663643165343031333833313338653033666535623961623664653333 +64656632626633363833316164376161333631666131653736353038643735376437376534373133 +34333935366235656132303766653335373130396439653663656338306365353161333761656530 +37386637316532333838316537336461303830666235346633653831363438316664306531313834 +36656636393932646435666362323465646237373239303635306365323866656435633837646339 +31393738633534383431666263666561653031646634366337616439653932643439323438376232 +33353030356437313030316261346436626337346464663130323832643832383330643036306630 +65623364396464653062373736366262326538636336363437376464386137626166346439303866 +31306638396435323662303865633665646433373537613035303534346563323363636331643931 +30653435626237336235356338653838373839643238313961626563346439353164653031383561 +32613066336462326164346632363530323831343032343462623338363062633432613666373139 +34396664663832333739336466333761343464313062343433303330326366386633383039666361 +62303038343937393666363939643330616361623933343032666232623562623761323231623231 +62343264316432653564343363613963633135386332343834343338316435636361316431353137 +62396265386436306661643038326237356136623233353535343835343337626262626334386436 +62353062333639353831653838666531363836316131303835336539633833316439626338326534 +30303061393533646635373639333239366165626131373539383639643864303735303765623165 +64666163383735613335633239303735356365393935396664376466333765383764653731663764 +31626631363661633865313537306335303231636361626665336338653939373638 diff --git a/ansible/inventory/group_vars/woodpecker_agents/vars.yml b/ansible/inventory/group_vars/woodpecker_agents/vars.yml new file mode 100644 index 00000000..b62e9fb0 --- /dev/null +++ b/ansible/inventory/group_vars/woodpecker_agents/vars.yml @@ -0,0 +1,2 @@ +--- +woodpecker_grpc_secret: "{{ vault_woodpecker_grpc_secret }}" diff --git a/ansible/inventory/group_vars/woodpecker_server/vars.yml b/ansible/inventory/group_vars/woodpecker_server/vars.yml new file mode 100644 index 00000000..7de13a99 --- /dev/null +++ b/ansible/inventory/group_vars/woodpecker_server/vars.yml @@ -0,0 +1,4 @@ +--- +woodpecker_grpc_secret: "{{ vault_woodpecker_grpc_secret }}" +woodpecker_gitea_client: "{{ vault_woodpecker_gitea_client }}" +woodpecker_gitea_secret: "{{ vault_woodpecker_gitea_secret }}" diff --git a/ansible/inventory/pve_hosts.yml b/ansible/inventory/pve_hosts.yml index 9faa4db2..e568cfb6 100644 --- a/ansible/inventory/pve_hosts.yml +++ b/ansible/inventory/pve_hosts.yml @@ -34,3 +34,10 @@ nas-1.renner.uno ansible_user=ladmin ansible_python_interpreter=/usr/bin/python3 [grafana] grafana.srv.renner.uno ansible_user=ladmin + +[woodpecker_server] +woodpecker.srv.renner.uno ansible_user=root + +[woodpecker_agents] +wp-agent-1.srv.renner.uno ansible_user=root +wp-agent-2.srv.renner.uno ansible_user=root diff --git a/ansible/plays/install-woodpecker-agent.yml b/ansible/plays/install-woodpecker-agent.yml new file mode 100644 index 00000000..36787e4b --- /dev/null +++ b/ansible/plays/install-woodpecker-agent.yml @@ -0,0 +1,8 @@ +--- +- name: Install and Configure Woodpecker CI Agents + hosts: woodpecker_agents + become: true + roles: + - role: common + - role: docker-install + - role: woodpecker-agent diff --git a/ansible/plays/install-woodpecker-server.yml b/ansible/plays/install-woodpecker-server.yml new file mode 100644 index 00000000..f50c84aa --- /dev/null +++ b/ansible/plays/install-woodpecker-server.yml @@ -0,0 +1,8 @@ +--- +- name: Install and Configure Woodpecker CI Server + hosts: woodpecker_server + become: true + roles: + - role: common + - role: docker-install + - role: woodpecker-server diff --git a/ansible/roles/caddy-ha/templates/Caddyfile.j2 b/ansible/roles/caddy-ha/templates/Caddyfile.j2 index 3fa9ae10..8cf7648a 100644 --- a/ansible/roles/caddy-ha/templates/Caddyfile.j2 +++ b/ansible/roles/caddy-ha/templates/Caddyfile.j2 @@ -358,3 +358,11 @@ n8n.renner.uno { } # END ANSIBLE MANAGED BLOCK N8N +# BEGIN ANSIBLE MANAGED BLOCK WOODPECKER +ci.renner.uno { + import cloudflare + import custom_error + reverse_proxy http://woodpecker.srv.renner.uno:8000 +} +# END ANSIBLE MANAGED BLOCK WOODPECKER + diff --git a/ansible/roles/woodpecker-agent/defaults/main.yml b/ansible/roles/woodpecker-agent/defaults/main.yml new file mode 100644 index 00000000..8cd569b4 --- /dev/null +++ b/ansible/roles/woodpecker-agent/defaults/main.yml @@ -0,0 +1,14 @@ +--- +woodpecker_version: "3.13.0" + +# Server gRPC address (agent connects here) +woodpecker_server: "woodpecker.srv.renner.uno:9000" + +# Shared secret — must match server's WOODPECKER_AGENT_SECRET +# woodpecker_grpc_secret: "" + +# Max parallel workflows per agent +woodpecker_max_workflows: 2 + +# Docker Compose project directory +woodpecker_agent_compose_dir: "/opt/woodpecker-agent" diff --git a/ansible/roles/woodpecker-agent/handlers/main.yml b/ansible/roles/woodpecker-agent/handlers/main.yml new file mode 100644 index 00000000..23e65e32 --- /dev/null +++ b/ansible/roles/woodpecker-agent/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Restart woodpecker-agent + systemd: + name: woodpecker-agent + state: restarted + daemon_reload: yes diff --git a/ansible/roles/woodpecker-agent/tasks/main.yml b/ansible/roles/woodpecker-agent/tasks/main.yml new file mode 100644 index 00000000..2e577568 --- /dev/null +++ b/ansible/roles/woodpecker-agent/tasks/main.yml @@ -0,0 +1,34 @@ +--- +- name: Create Woodpecker agent directory + file: + path: "{{ woodpecker_agent_compose_dir }}" + state: directory + mode: "0755" + +- name: Deploy Docker Compose file + template: + src: docker-compose.yml.j2 + dest: "{{ woodpecker_agent_compose_dir }}/docker-compose.yml" + mode: "0600" + notify: Restart woodpecker-agent + +- name: Deploy environment file + template: + src: agent.env.j2 + dest: "{{ woodpecker_agent_compose_dir }}/.env" + mode: "0600" + notify: Restart woodpecker-agent + +- name: Create systemd service for Woodpecker agent + template: + src: woodpecker-agent.service.j2 + dest: /etc/systemd/system/woodpecker-agent.service + mode: "0644" + notify: Restart woodpecker-agent + +- name: Enable and start Woodpecker agent + systemd: + name: woodpecker-agent + state: started + enabled: yes + daemon_reload: yes diff --git a/ansible/roles/woodpecker-agent/templates/agent.env.j2 b/ansible/roles/woodpecker-agent/templates/agent.env.j2 new file mode 100644 index 00000000..0a34e965 --- /dev/null +++ b/ansible/roles/woodpecker-agent/templates/agent.env.j2 @@ -0,0 +1,5 @@ +WOODPECKER_SERVER={{ woodpecker_server }} +WOODPECKER_AGENT_SECRET={{ woodpecker_grpc_secret }} +WOODPECKER_MAX_WORKFLOWS={{ woodpecker_max_workflows }} +WOODPECKER_BACKEND=docker +WOODPECKER_HOSTNAME={{ inventory_hostname }} diff --git a/ansible/roles/woodpecker-agent/templates/docker-compose.yml.j2 b/ansible/roles/woodpecker-agent/templates/docker-compose.yml.j2 new file mode 100644 index 00000000..083ac41f --- /dev/null +++ b/ansible/roles/woodpecker-agent/templates/docker-compose.yml.j2 @@ -0,0 +1,13 @@ +services: + woodpecker-agent: + image: woodpeckerci/woodpecker-agent:v{{ woodpecker_version }} + container_name: woodpecker-agent + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - woodpecker-agent-config:/etc/woodpecker + env_file: + - .env + +volumes: + woodpecker-agent-config: diff --git a/ansible/roles/woodpecker-agent/templates/woodpecker-agent.service.j2 b/ansible/roles/woodpecker-agent/templates/woodpecker-agent.service.j2 new file mode 100644 index 00000000..0a7d7571 --- /dev/null +++ b/ansible/roles/woodpecker-agent/templates/woodpecker-agent.service.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Woodpecker CI Agent +Documentation=https://woodpecker-ci.org/ +After=docker.service network.target +Requires=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory={{ woodpecker_agent_compose_dir }} +ExecStart=/usr/bin/docker compose up -d +ExecStop=/usr/bin/docker compose down +ExecReload=/usr/bin/docker compose restart +TimeoutStartSec=120 + +[Install] +WantedBy=multi-user.target diff --git a/ansible/roles/woodpecker-server/defaults/main.yml b/ansible/roles/woodpecker-server/defaults/main.yml new file mode 100644 index 00000000..9ff8b73b --- /dev/null +++ b/ansible/roles/woodpecker-server/defaults/main.yml @@ -0,0 +1,38 @@ +--- +woodpecker_version: "3.13.0" + +# Server configuration +woodpecker_host: "https://ci.renner.uno" +woodpecker_server_addr: ":8000" +woodpecker_grpc_addr: ":9000" + +# Gitea forge +woodpecker_gitea: true +woodpecker_gitea_url: "https://gitea.renner.uno" +# OAuth client ID and secret — set from vault +# woodpecker_gitea_client: "" +# woodpecker_gitea_secret: "" + +# Agent shared secret — set from vault +# woodpecker_grpc_secret: "" + +# Admin users (Gitea usernames) +woodpecker_admin: "gitea_admin,k.renner" + +# Allow open registration (any Gitea user can log in) +woodpecker_open: true + +# Database +woodpecker_database_driver: "sqlite3" + +# Data directory (mounted volume) +woodpecker_data_dir: "/var/lib/woodpecker" + +# Docker Compose project directory +woodpecker_compose_dir: "/opt/woodpecker" + +# Prometheus metrics +woodpecker_prometheus_auth_token: "" + +# Webhook config for Gitea (must allow local connections) +woodpecker_expert_webhook_host: "" diff --git a/ansible/roles/woodpecker-server/handlers/main.yml b/ansible/roles/woodpecker-server/handlers/main.yml new file mode 100644 index 00000000..abaf5869 --- /dev/null +++ b/ansible/roles/woodpecker-server/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Restart woodpecker-server + systemd: + name: woodpecker-server + state: restarted + daemon_reload: yes diff --git a/ansible/roles/woodpecker-server/tasks/main.yml b/ansible/roles/woodpecker-server/tasks/main.yml new file mode 100644 index 00000000..14afb02d --- /dev/null +++ b/ansible/roles/woodpecker-server/tasks/main.yml @@ -0,0 +1,37 @@ +--- +- name: Create Woodpecker directories + file: + path: "{{ item }}" + state: directory + mode: "0755" + loop: + - "{{ woodpecker_compose_dir }}" + - "{{ woodpecker_data_dir }}" + +- name: Deploy Docker Compose file + template: + src: docker-compose.yml.j2 + dest: "{{ woodpecker_compose_dir }}/docker-compose.yml" + mode: "0600" + notify: Restart woodpecker-server + +- name: Deploy environment file + template: + src: woodpecker.env.j2 + dest: "{{ woodpecker_compose_dir }}/.env" + mode: "0600" + notify: Restart woodpecker-server + +- name: Create systemd service for Woodpecker + template: + src: woodpecker-server.service.j2 + dest: /etc/systemd/system/woodpecker-server.service + mode: "0644" + notify: Restart woodpecker-server + +- name: Enable and start Woodpecker server + systemd: + name: woodpecker-server + state: started + enabled: yes + daemon_reload: yes diff --git a/ansible/roles/woodpecker-server/templates/docker-compose.yml.j2 b/ansible/roles/woodpecker-server/templates/docker-compose.yml.j2 new file mode 100644 index 00000000..946dd662 --- /dev/null +++ b/ansible/roles/woodpecker-server/templates/docker-compose.yml.j2 @@ -0,0 +1,12 @@ +services: + woodpecker-server: + image: woodpeckerci/woodpecker-server:v{{ woodpecker_version }} + container_name: woodpecker-server + restart: unless-stopped + ports: + - "8000:8000" + - "9000:9000" + volumes: + - {{ woodpecker_data_dir }}:/var/lib/woodpecker/ + env_file: + - .env diff --git a/ansible/roles/woodpecker-server/templates/woodpecker-server.service.j2 b/ansible/roles/woodpecker-server/templates/woodpecker-server.service.j2 new file mode 100644 index 00000000..9bbf7feb --- /dev/null +++ b/ansible/roles/woodpecker-server/templates/woodpecker-server.service.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Woodpecker CI Server +Documentation=https://woodpecker-ci.org/ +After=docker.service network.target +Requires=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory={{ woodpecker_compose_dir }} +ExecStart=/usr/bin/docker compose up -d +ExecStop=/usr/bin/docker compose down +ExecReload=/usr/bin/docker compose restart +TimeoutStartSec=120 + +[Install] +WantedBy=multi-user.target diff --git a/ansible/roles/woodpecker-server/templates/woodpecker.env.j2 b/ansible/roles/woodpecker-server/templates/woodpecker.env.j2 new file mode 100644 index 00000000..99517f28 --- /dev/null +++ b/ansible/roles/woodpecker-server/templates/woodpecker.env.j2 @@ -0,0 +1,26 @@ +WOODPECKER_HOST={{ woodpecker_host }} +WOODPECKER_SERVER_ADDR={{ woodpecker_server_addr }} +WOODPECKER_GRPC_ADDR={{ woodpecker_grpc_addr }} +WOODPECKER_OPEN={{ woodpecker_open | lower }} +WOODPECKER_ADMIN={{ woodpecker_admin }} + +# Gitea forge +WOODPECKER_GITEA={{ woodpecker_gitea | lower }} +WOODPECKER_GITEA_URL={{ woodpecker_gitea_url }} +WOODPECKER_GITEA_CLIENT={{ woodpecker_gitea_client }} +WOODPECKER_GITEA_SECRET={{ woodpecker_gitea_secret }} + +# Agent authentication +WOODPECKER_AGENT_SECRET={{ woodpecker_grpc_secret }} + +# Database +WOODPECKER_DATABASE_DRIVER={{ woodpecker_database_driver }} + +{% if woodpecker_prometheus_auth_token | default('') | length > 0 %} +# Prometheus metrics +WOODPECKER_PROMETHEUS_AUTH_TOKEN={{ woodpecker_prometheus_auth_token }} +{% endif %} + +{% if woodpecker_expert_webhook_host | default('') | length > 0 %} +WOODPECKER_EXPERT_WEBHOOK_HOST={{ woodpecker_expert_webhook_host }} +{% endif %} diff --git a/opentofu/locals.tf b/opentofu/locals.tf index 132a6ca2..0832a368 100644 --- a/opentofu/locals.tf +++ b/opentofu/locals.tf @@ -4,6 +4,7 @@ locals { "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGfe3HJqFR+jIGrboweseAO7XjIVE24sje/b1HybgU9C ansible-runner@ci-new" ]) + # Legacy Gitea runners — kept for state management during migration gitea_runners = [ for i in range(var.gitea_runner_count) : { vmid = 905 + i @@ -23,6 +24,24 @@ locals { } ] + woodpecker_agents = [ + for i in range(var.woodpecker_agent_count) : { + vmid = 910 + i + name = "wp-agent-${i + 1}.srv.renner.uno" + node = "jupiter" + memory = 2048 + cores = 2 + type = "lxc" + state = "started" + tags = "woodpecker;ci;docker" + bridge = "v40srv" + disk_size = "30G" + storage = "" + nesting = true + ostemplate = "local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst" + } + ] + rustfs_instances = [ for i in range(var.rustfs_count) : { vmid = 800 + i diff --git a/opentofu/lxc_231_woodpecker.tf b/opentofu/lxc_231_woodpecker.tf new file mode 100644 index 00000000..cb7370f7 --- /dev/null +++ b/opentofu/lxc_231_woodpecker.tf @@ -0,0 +1,50 @@ +# Woodpecker CI Server +# Lightweight CI/CD engine with Gitea integration +# Replaces Gitea Actions for better UI and worker management + +module "woodpecker_srv_renner_uno" { + source = "./modules/proxmox_lxc" + + hostname = "woodpecker.srv.renner.uno" + vmid = 231 + target_node = "jupiter" + memory = 1024 + cores = 2 + + unprivileged = true + + network_bridge = "v40srv" + + storage = "local-zfs" + disk_size = "10G" + + ostemplate = "local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst" + + ssh_public_keys = local.common_ssh_keys + + tags = "ci;docker;woodpecker" + + onboot = true + start = true + + features = { + nesting = true + fuse = false + keyctl = false + mknod = false + } + + ingress_cnames = ["ci.renner.uno"] + cnames = [] + + description = <<-EOT +Woodpecker CI Server +https://woodpecker-ci.org/ + +Deployed via Ansible role: woodpecker-server +Web UI: https://ci.renner.uno (port 8000) +gRPC: port 9000 (agent communication) +Auth: Gitea OAuth2 +Database: SQLite +EOT +} diff --git a/opentofu/variables.tf b/opentofu/variables.tf index b152c757..48105a17 100644 --- a/opentofu/variables.tf +++ b/opentofu/variables.tf @@ -40,6 +40,12 @@ variable "rustfs_count" { default = 3 } +variable "woodpecker_agent_count" { + description = "Number of Woodpecker CI agents to deploy" + type = number + default = 2 +} + variable "ssh_public_key" { description = "Public SSH key to inject into containers" type = string diff --git a/opentofu/woodpecker_agents.tf b/opentofu/woodpecker_agents.tf new file mode 100644 index 00000000..4630c97a --- /dev/null +++ b/opentofu/woodpecker_agents.tf @@ -0,0 +1,33 @@ +# Woodpecker CI Agents +# Docker-based build agents connecting to woodpecker.srv.renner.uno via gRPC + +module "woodpecker_agents" { + source = "./modules/proxmox_lxc" + + for_each = { + for lxc in local.woodpecker_agents : lxc.vmid => lxc + } + + hostname = each.value.name + target_node = each.value.node + vmid = each.value.vmid + memory = each.value.memory + cores = each.value.cores + unprivileged = true + tags = join(",", compact([each.value.tags, "transient"])) + ostemplate = each.value.ostemplate + storage = lookup(each.value, "storage", "local-zfs") + disk_size = each.value.disk_size + + ssh_public_keys = local.common_ssh_keys + + start = each.value.state == "started" ? true : false + network_bridge = each.value.bridge + + features = { + nesting = each.value.nesting + fuse = false + keyctl = false + mknod = false + } +}